Commit 808cee16 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-lan966x-add-support-for-fdma'

Horatiu Vultur says:

====================
net: lan966x: Add support for FDMA

Currently when injecting or extracting a frame from CPU, the frame
is given to the HW each word at a time. There is another way to
inject/extract frames from CPU using FDMA(Frame Direct Memory Access).
In this way the entire frame is given to the HW. This improves both
RX and TX bitrate.
====================

Tested-by: Michael Walle <michael@walle.cc> # on kontron-kswitch-d10
Link: https://lore.kernel.org/r/20220408070357.559899-1-horatiu.vultur@microchip.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents d6967d04 2ea1cbac
......@@ -8,4 +8,4 @@ obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o
lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
lan966x_mac.o lan966x_ethtool.o lan966x_switchdev.o \
lan966x_vlan.o lan966x_fdb.o lan966x_mdb.o \
lan966x_ptp.o
lan966x_ptp.o lan966x_fdma.o
This diff is collapsed.
......@@ -24,9 +24,6 @@
#define XTR_NOT_READY 0x07000080U
#define XTR_VALID_BYTES(x) (4 - (((x) >> 24) & 3))
#define READL_SLEEP_US 10
#define READL_TIMEOUT_US 100000000
#define IO_RANGES 2
static const struct of_device_id lan966x_match[] = {
......@@ -43,6 +40,7 @@ struct lan966x_main_io_resource {
static const struct lan966x_main_io_resource lan966x_main_iomap[] = {
{ TARGET_CPU, 0xc0000, 0 }, /* 0xe00c0000 */
{ TARGET_FDMA, 0xc0400, 0 }, /* 0xe00c0400 */
{ TARGET_ORG, 0, 1 }, /* 0xe2000000 */
{ TARGET_GCB, 0x4000, 1 }, /* 0xe2004000 */
{ TARGET_QS, 0x8000, 1 }, /* 0xe2008000 */
......@@ -343,7 +341,10 @@ static int lan966x_port_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_lock(&lan966x->tx_lock);
err = lan966x_port_ifh_xmit(skb, ifh, dev);
if (port->lan966x->fdma)
err = lan966x_fdma_xmit(skb, ifh, dev);
else
err = lan966x_port_ifh_xmit(skb, ifh, dev);
spin_unlock(&lan966x->tx_lock);
return err;
......@@ -353,12 +354,24 @@ static int lan966x_port_change_mtu(struct net_device *dev, int new_mtu)
{
struct lan966x_port *port = netdev_priv(dev);
struct lan966x *lan966x = port->lan966x;
int old_mtu = dev->mtu;
int err;
lan_wr(DEV_MAC_MAXLEN_CFG_MAX_LEN_SET(new_mtu),
lan966x, DEV_MAC_MAXLEN_CFG(port->chip_port));
dev->mtu = new_mtu;
return 0;
if (!lan966x->fdma)
return 0;
err = lan966x_fdma_change_mtu(lan966x);
if (err) {
lan_wr(DEV_MAC_MAXLEN_CFG_MAX_LEN_SET(old_mtu),
lan966x, DEV_MAC_MAXLEN_CFG(port->chip_port));
dev->mtu = old_mtu;
}
return err;
}
static int lan966x_mc_unsync(struct net_device *dev, const unsigned char *addr)
......@@ -432,8 +445,7 @@ bool lan966x_netdevice_check(const struct net_device *dev)
return dev->netdev_ops == &lan966x_port_netdev_ops;
}
static bool lan966x_hw_offload(struct lan966x *lan966x, u32 port,
struct sk_buff *skb)
bool lan966x_hw_offload(struct lan966x *lan966x, u32 port, struct sk_buff *skb)
{
u32 val;
......@@ -514,7 +526,7 @@ static int lan966x_rx_frame_word(struct lan966x *lan966x, u8 grp, u32 *rval)
}
}
static void lan966x_ifh_get_src_port(void *ifh, u64 *src_port)
void lan966x_ifh_get_src_port(void *ifh, u64 *src_port)
{
packing(ifh, src_port, IFH_POS_SRCPORT + IFH_WID_SRCPORT - 1,
IFH_POS_SRCPORT, IFH_LEN * 4, UNPACK, 0);
......@@ -526,7 +538,7 @@ static void lan966x_ifh_get_len(void *ifh, u64 *len)
IFH_POS_LEN, IFH_LEN * 4, UNPACK, 0);
}
static void lan966x_ifh_get_timestamp(void *ifh, u64 *timestamp)
void lan966x_ifh_get_timestamp(void *ifh, u64 *timestamp)
{
packing(ifh, timestamp, IFH_POS_TIMESTAMP + IFH_WID_TIMESTAMP - 1,
IFH_POS_TIMESTAMP, IFH_LEN * 4, UNPACK, 0);
......@@ -646,6 +658,9 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x)
if (port->dev)
unregister_netdev(port->dev);
if (lan966x->fdma && lan966x->fdma_ndev == port->dev)
lan966x_fdma_netdev_deinit(lan966x, port->dev);
if (port->phylink) {
rtnl_lock();
lan966x_port_stop(port->dev);
......@@ -665,6 +680,9 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x)
disable_irq(lan966x->ana_irq);
lan966x->ana_irq = -ENXIO;
}
if (lan966x->fdma)
devm_free_irq(lan966x->dev, lan966x->fdma_irq, lan966x);
}
static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
......@@ -793,12 +811,12 @@ static void lan966x_init(struct lan966x *lan966x)
/* Do byte-swap and expect status after last data word
* Extraction: Mode: manual extraction) | Byte_swap
*/
lan_wr(QS_XTR_GRP_CFG_MODE_SET(1) |
lan_wr(QS_XTR_GRP_CFG_MODE_SET(lan966x->fdma ? 2 : 1) |
QS_XTR_GRP_CFG_BYTE_SWAP_SET(1),
lan966x, QS_XTR_GRP_CFG(0));
/* Injection: Mode: manual injection | Byte_swap */
lan_wr(QS_INJ_GRP_CFG_MODE_SET(1) |
lan_wr(QS_INJ_GRP_CFG_MODE_SET(lan966x->fdma ? 2 : 1) |
QS_INJ_GRP_CFG_BYTE_SWAP_SET(1),
lan966x, QS_INJ_GRP_CFG(0));
......@@ -1020,6 +1038,17 @@ static int lan966x_probe(struct platform_device *pdev)
lan966x->ptp = 1;
}
lan966x->fdma_irq = platform_get_irq_byname(pdev, "fdma");
if (lan966x->fdma_irq > 0) {
err = devm_request_irq(&pdev->dev, lan966x->fdma_irq,
lan966x_fdma_irq_handler, 0,
"fdma irq", lan966x);
if (err)
return dev_err_probe(&pdev->dev, err, "Unable to use fdma irq");
lan966x->fdma = true;
}
/* init switch */
lan966x_init(lan966x);
lan966x_stats_init(lan966x);
......@@ -1058,8 +1087,15 @@ static int lan966x_probe(struct platform_device *pdev)
if (err)
goto cleanup_fdb;
err = lan966x_fdma_init(lan966x);
if (err)
goto cleanup_ptp;
return 0;
cleanup_ptp:
lan966x_ptp_deinit(lan966x);
cleanup_fdb:
lan966x_fdb_deinit(lan966x);
......@@ -1079,6 +1115,7 @@ static int lan966x_remove(struct platform_device *pdev)
{
struct lan966x *lan966x = platform_get_drvdata(pdev);
lan966x_fdma_deinit(lan966x);
lan966x_cleanup_ports(lan966x);
cancel_delayed_work_sync(&lan966x->stats_work);
......
......@@ -17,6 +17,9 @@
#define TABLE_UPDATE_SLEEP_US 10
#define TABLE_UPDATE_TIMEOUT_US 100000
#define READL_SLEEP_US 10
#define READL_TIMEOUT_US 100000000
#define LAN966X_BUFFER_CELL_SZ 64
#define LAN966X_BUFFER_MEMORY (160 * 1024)
#define LAN966X_BUFFER_MIN_SZ 60
......@@ -58,6 +61,22 @@
#define IFH_REW_OP_ONE_STEP_PTP 0x3
#define IFH_REW_OP_TWO_STEP_PTP 0x4
#define FDMA_RX_DCB_MAX_DBS 1
#define FDMA_TX_DCB_MAX_DBS 1
#define FDMA_DCB_INFO_DATAL(x) ((x) & GENMASK(15, 0))
#define FDMA_DCB_STATUS_BLOCKL(x) ((x) & GENMASK(15, 0))
#define FDMA_DCB_STATUS_SOF BIT(16)
#define FDMA_DCB_STATUS_EOF BIT(17)
#define FDMA_DCB_STATUS_INTR BIT(18)
#define FDMA_DCB_STATUS_DONE BIT(19)
#define FDMA_DCB_STATUS_BLOCKO(x) (((x) << 20) & GENMASK(31, 20))
#define FDMA_DCB_INVALID_DATA 0x1
#define FDMA_XTR_CHANNEL 6
#define FDMA_INJ_CHANNEL 0
#define FDMA_DCB_MAX 512
/* MAC table entry types.
* ENTRYTYPE_NORMAL is subject to aging.
* ENTRYTYPE_LOCKED is not subject to aging.
......@@ -73,6 +92,83 @@ enum macaccess_entry_type {
struct lan966x_port;
struct lan966x_db {
u64 dataptr;
u64 status;
};
struct lan966x_rx_dcb {
u64 nextptr;
u64 info;
struct lan966x_db db[FDMA_RX_DCB_MAX_DBS];
};
struct lan966x_tx_dcb {
u64 nextptr;
u64 info;
struct lan966x_db db[FDMA_TX_DCB_MAX_DBS];
};
struct lan966x_rx {
struct lan966x *lan966x;
/* Pointer to the array of hardware dcbs. */
struct lan966x_rx_dcb *dcbs;
/* Pointer to the last address in the dcbs. */
struct lan966x_rx_dcb *last_entry;
/* For each DB, there is a page */
struct page *page[FDMA_DCB_MAX][FDMA_RX_DCB_MAX_DBS];
/* Represents the db_index, it can have a value between 0 and
* FDMA_RX_DCB_MAX_DBS, once it reaches the value of FDMA_RX_DCB_MAX_DBS
* it means that the DCB can be reused.
*/
int db_index;
/* Represents the index in the dcbs. It has a value between 0 and
* FDMA_DCB_MAX
*/
int dcb_index;
/* Represents the dma address to the dcbs array */
dma_addr_t dma;
/* Represents the page order that is used to allocate the pages for the
* RX buffers. This value is calculated based on max MTU of the devices.
*/
u8 page_order;
u8 channel_id;
};
struct lan966x_tx_dcb_buf {
struct net_device *dev;
struct sk_buff *skb;
dma_addr_t dma_addr;
bool used;
bool ptp;
};
struct lan966x_tx {
struct lan966x *lan966x;
/* Pointer to the dcb list */
struct lan966x_tx_dcb *dcbs;
u16 last_in_use;
/* Represents the DMA address to the first entry of the dcb entries. */
dma_addr_t dma;
/* Array of dcbs that are given to the HW */
struct lan966x_tx_dcb_buf *dcbs_buf;
u8 channel_id;
bool activated;
};
struct lan966x_stat_layout {
u32 offset;
char name[ETH_GSTRING_LEN];
......@@ -134,6 +230,7 @@ struct lan966x {
int xtr_irq;
int ana_irq;
int ptp_irq;
int fdma_irq;
/* worqueue for fdb */
struct workqueue_struct *fdb_work;
......@@ -150,6 +247,13 @@ struct lan966x {
spinlock_t ptp_ts_id_lock; /* lock for ts_id */
struct mutex ptp_lock; /* lock for ptp interface state */
u16 ptp_skbs;
/* fdma */
bool fdma;
struct net_device *fdma_ndev;
struct lan966x_rx rx;
struct lan966x_tx tx;
struct napi_struct napi;
};
struct lan966x_port_config {
......@@ -195,6 +299,11 @@ bool lan966x_netdevice_check(const struct net_device *dev);
void lan966x_register_notifier_blocks(void);
void lan966x_unregister_notifier_blocks(void);
bool lan966x_hw_offload(struct lan966x *lan966x, u32 port, struct sk_buff *skb);
void lan966x_ifh_get_src_port(void *ifh, u64 *src_port);
void lan966x_ifh_get_timestamp(void *ifh, u64 *timestamp);
void lan966x_stats_get(struct net_device *dev,
struct rtnl_link_stats64 *stats);
int lan966x_stats_init(struct lan966x *lan966x);
......@@ -284,6 +393,14 @@ void lan966x_ptp_txtstamp_release(struct lan966x_port *port,
struct sk_buff *skb);
irqreturn_t lan966x_ptp_irq_handler(int irq, void *args);
int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev);
int lan966x_fdma_change_mtu(struct lan966x *lan966x);
void lan966x_fdma_netdev_init(struct lan966x *lan966x, struct net_device *dev);
void lan966x_fdma_netdev_deinit(struct lan966x *lan966x, struct net_device *dev);
int lan966x_fdma_init(struct lan966x *lan966x);
void lan966x_fdma_deinit(struct lan966x *lan966x);
irqreturn_t lan966x_fdma_irq_handler(int irq, void *args);
static inline void __iomem *lan_addr(void __iomem *base[],
int id, int tinst, int tcnt,
int gbase, int ginst,
......
......@@ -393,6 +393,9 @@ void lan966x_port_init(struct lan966x_port *port)
lan966x_port_config_down(port);
if (lan966x->fdma)
lan966x_fdma_netdev_init(lan966x, port->dev);
if (config->portmode != PHY_INTERFACE_MODE_QSGMII)
return;
......
......@@ -17,6 +17,7 @@ enum lan966x_target {
TARGET_CHIP_TOP = 5,
TARGET_CPU = 6,
TARGET_DEV = 13,
TARGET_FDMA = 21,
TARGET_GCB = 27,
TARGET_ORG = 36,
TARGET_PTP = 41,
......@@ -578,6 +579,111 @@ enum lan966x_target {
#define DEV_PCS1G_STICKY_LINK_DOWN_STICKY_GET(x)\
FIELD_GET(DEV_PCS1G_STICKY_LINK_DOWN_STICKY, x)
/* FDMA:FDMA:FDMA_CH_ACTIVATE */
#define FDMA_CH_ACTIVATE __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 0, 0, 1, 4)
#define FDMA_CH_ACTIVATE_CH_ACTIVATE GENMASK(7, 0)
#define FDMA_CH_ACTIVATE_CH_ACTIVATE_SET(x)\
FIELD_PREP(FDMA_CH_ACTIVATE_CH_ACTIVATE, x)
#define FDMA_CH_ACTIVATE_CH_ACTIVATE_GET(x)\
FIELD_GET(FDMA_CH_ACTIVATE_CH_ACTIVATE, x)
/* FDMA:FDMA:FDMA_CH_RELOAD */
#define FDMA_CH_RELOAD __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 4, 0, 1, 4)
#define FDMA_CH_RELOAD_CH_RELOAD GENMASK(7, 0)
#define FDMA_CH_RELOAD_CH_RELOAD_SET(x)\
FIELD_PREP(FDMA_CH_RELOAD_CH_RELOAD, x)
#define FDMA_CH_RELOAD_CH_RELOAD_GET(x)\
FIELD_GET(FDMA_CH_RELOAD_CH_RELOAD, x)
/* FDMA:FDMA:FDMA_CH_DISABLE */
#define FDMA_CH_DISABLE __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 8, 0, 1, 4)
#define FDMA_CH_DISABLE_CH_DISABLE GENMASK(7, 0)
#define FDMA_CH_DISABLE_CH_DISABLE_SET(x)\
FIELD_PREP(FDMA_CH_DISABLE_CH_DISABLE, x)
#define FDMA_CH_DISABLE_CH_DISABLE_GET(x)\
FIELD_GET(FDMA_CH_DISABLE_CH_DISABLE, x)
/* FDMA:FDMA:FDMA_CH_DB_DISCARD */
#define FDMA_CH_DB_DISCARD __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 16, 0, 1, 4)
#define FDMA_CH_DB_DISCARD_DB_DISCARD GENMASK(7, 0)
#define FDMA_CH_DB_DISCARD_DB_DISCARD_SET(x)\
FIELD_PREP(FDMA_CH_DB_DISCARD_DB_DISCARD, x)
#define FDMA_CH_DB_DISCARD_DB_DISCARD_GET(x)\
FIELD_GET(FDMA_CH_DB_DISCARD_DB_DISCARD, x)
/* FDMA:FDMA:FDMA_DCB_LLP */
#define FDMA_DCB_LLP(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 52, r, 8, 4)
/* FDMA:FDMA:FDMA_DCB_LLP1 */
#define FDMA_DCB_LLP1(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 84, r, 8, 4)
/* FDMA:FDMA:FDMA_CH_ACTIVE */
#define FDMA_CH_ACTIVE __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 180, 0, 1, 4)
/* FDMA:FDMA:FDMA_CH_CFG */
#define FDMA_CH_CFG(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 224, r, 8, 4)
#define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY BIT(4)
#define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_SET(x)\
FIELD_PREP(FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY, x)
#define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_GET(x)\
FIELD_GET(FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY, x)
#define FDMA_CH_CFG_CH_INJ_PORT BIT(3)
#define FDMA_CH_CFG_CH_INJ_PORT_SET(x)\
FIELD_PREP(FDMA_CH_CFG_CH_INJ_PORT, x)
#define FDMA_CH_CFG_CH_INJ_PORT_GET(x)\
FIELD_GET(FDMA_CH_CFG_CH_INJ_PORT, x)
#define FDMA_CH_CFG_CH_DCB_DB_CNT GENMASK(2, 1)
#define FDMA_CH_CFG_CH_DCB_DB_CNT_SET(x)\
FIELD_PREP(FDMA_CH_CFG_CH_DCB_DB_CNT, x)
#define FDMA_CH_CFG_CH_DCB_DB_CNT_GET(x)\
FIELD_GET(FDMA_CH_CFG_CH_DCB_DB_CNT, x)
#define FDMA_CH_CFG_CH_MEM BIT(0)
#define FDMA_CH_CFG_CH_MEM_SET(x)\
FIELD_PREP(FDMA_CH_CFG_CH_MEM, x)
#define FDMA_CH_CFG_CH_MEM_GET(x)\
FIELD_GET(FDMA_CH_CFG_CH_MEM, x)
/* FDMA:FDMA:FDMA_PORT_CTRL */
#define FDMA_PORT_CTRL(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 376, r, 2, 4)
#define FDMA_PORT_CTRL_INJ_STOP BIT(4)
#define FDMA_PORT_CTRL_INJ_STOP_SET(x)\
FIELD_PREP(FDMA_PORT_CTRL_INJ_STOP, x)
#define FDMA_PORT_CTRL_INJ_STOP_GET(x)\
FIELD_GET(FDMA_PORT_CTRL_INJ_STOP, x)
#define FDMA_PORT_CTRL_XTR_STOP BIT(2)
#define FDMA_PORT_CTRL_XTR_STOP_SET(x)\
FIELD_PREP(FDMA_PORT_CTRL_XTR_STOP, x)
#define FDMA_PORT_CTRL_XTR_STOP_GET(x)\
FIELD_GET(FDMA_PORT_CTRL_XTR_STOP, x)
/* FDMA:FDMA:FDMA_INTR_DB */
#define FDMA_INTR_DB __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 392, 0, 1, 4)
/* FDMA:FDMA:FDMA_INTR_DB_ENA */
#define FDMA_INTR_DB_ENA __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 396, 0, 1, 4)
#define FDMA_INTR_DB_ENA_INTR_DB_ENA GENMASK(7, 0)
#define FDMA_INTR_DB_ENA_INTR_DB_ENA_SET(x)\
FIELD_PREP(FDMA_INTR_DB_ENA_INTR_DB_ENA, x)
#define FDMA_INTR_DB_ENA_INTR_DB_ENA_GET(x)\
FIELD_GET(FDMA_INTR_DB_ENA_INTR_DB_ENA, x)
/* FDMA:FDMA:FDMA_INTR_ERR */
#define FDMA_INTR_ERR __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 400, 0, 1, 4)
/* FDMA:FDMA:FDMA_ERRORS */
#define FDMA_ERRORS __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 412, 0, 1, 4)
/* PTP:PTP_CFG:PTP_DOM_CFG */
#define PTP_DOM_CFG __REG(TARGET_PTP, 0, 1, 512, 0, 1, 16, 12, 0, 1, 4)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment