diff options
Diffstat (limited to 'drivers/net/ethernet/mediatek/airoha_eth.c')
-rw-r--r-- | drivers/net/ethernet/mediatek/airoha_eth.c | 533 |
1 files changed, 297 insertions, 236 deletions
diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c index 1c5b85a86df1..930f180688e5 100644 --- a/drivers/net/ethernet/mediatek/airoha_eth.c +++ b/drivers/net/ethernet/mediatek/airoha_eth.c @@ -18,6 +18,7 @@ #include <uapi/linux/ppp_defs.h> #define AIROHA_MAX_NUM_GDM_PORTS 1 +#define AIROHA_MAX_NUM_QDMA 2 #define AIROHA_MAX_NUM_RSTS 3 #define AIROHA_MAX_NUM_XSI_RSTS 5 #define AIROHA_MAX_MTU 2000 @@ -66,9 +67,11 @@ #define FE_RST_GDM3_MBI_ARB_MASK BIT(2) #define FE_RST_CORE_MASK BIT(0) +#define REG_FE_WAN_MAC_H 0x0030 #define REG_FE_LAN_MAC_H 0x0040 -#define REG_FE_LAN_MAC_LMIN 0x0044 -#define REG_FE_LAN_MAC_LMAX 0x0048 + +#define REG_FE_MAC_LMIN(_n) ((_n) + 0x04) +#define REG_FE_MAC_LMAX(_n) ((_n) + 0x08) #define REG_FE_CDM1_OQ_MAP0 0x0050 #define REG_FE_CDM1_OQ_MAP1 0x0054 @@ -727,7 +730,7 @@ struct airoha_queue_entry { }; struct airoha_queue { - struct airoha_eth *eth; + struct airoha_qdma *qdma; /* protect concurrent queue accesses */ spinlock_t lock; @@ -746,7 +749,7 @@ struct airoha_queue { }; struct airoha_tx_irq_queue { - struct airoha_eth *eth; + struct airoha_qdma *qdma; struct napi_struct napi; u32 *q; @@ -782,9 +785,30 @@ struct airoha_hw_stats { u64 rx_len[7]; }; +struct airoha_qdma { + struct airoha_eth *eth; + void __iomem *regs; + + /* protect concurrent irqmask accesses */ + spinlock_t irq_lock; + u32 irqmask[QDMA_INT_REG_MAX]; + int irq; + + struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ]; + + struct airoha_queue q_tx[AIROHA_NUM_TX_RING]; + struct airoha_queue q_rx[AIROHA_NUM_RX_RING]; + + /* descriptor and packet buffers for qdma hw forward */ + struct { + void *desc; + void *q; + } hfwd; +}; + struct airoha_gdm_port { + struct airoha_qdma *qdma; struct net_device *dev; - struct airoha_eth *eth; int id; struct airoha_hw_stats stats; @@ -794,31 +818,15 @@ struct airoha_eth { struct device *dev; unsigned long state; - - void __iomem *qdma_regs; void __iomem *fe_regs; - /* protect concurrent irqmask accesses */ - spinlock_t irq_lock; - u32 irqmask[QDMA_INT_REG_MAX]; - int irq; - struct reset_control_bulk_data rsts[AIROHA_MAX_NUM_RSTS]; struct reset_control_bulk_data xsi_rsts[AIROHA_MAX_NUM_XSI_RSTS]; - struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS]; - struct net_device *napi_dev; - struct airoha_queue q_tx[AIROHA_NUM_TX_RING]; - struct airoha_queue q_rx[AIROHA_NUM_RX_RING]; - - struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ]; - /* descriptor and packet buffers for qdma hw forward */ - struct { - void *desc; - void *q; - } hfwd; + struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA]; + struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS]; }; static u32 airoha_rr(void __iomem *base, u32 offset) @@ -850,60 +858,72 @@ static u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val) #define airoha_fe_clear(eth, offset, val) \ airoha_rmw((eth)->fe_regs, (offset), (val), 0) -#define airoha_qdma_rr(eth, offset) \ - airoha_rr((eth)->qdma_regs, (offset)) -#define airoha_qdma_wr(eth, offset, val) \ - airoha_wr((eth)->qdma_regs, (offset), (val)) -#define airoha_qdma_rmw(eth, offset, mask, val) \ - airoha_rmw((eth)->qdma_regs, (offset), (mask), (val)) -#define airoha_qdma_set(eth, offset, val) \ - airoha_rmw((eth)->qdma_regs, (offset), 0, (val)) -#define airoha_qdma_clear(eth, offset, val) \ - airoha_rmw((eth)->qdma_regs, (offset), (val), 0) - -static void airoha_qdma_set_irqmask(struct airoha_eth *eth, int index, +#define airoha_qdma_rr(qdma, offset) \ + airoha_rr((qdma)->regs, (offset)) +#define airoha_qdma_wr(qdma, offset, val) \ + airoha_wr((qdma)->regs, (offset), (val)) +#define airoha_qdma_rmw(qdma, offset, mask, val) \ + airoha_rmw((qdma)->regs, (offset), (mask), (val)) +#define airoha_qdma_set(qdma, offset, val) \ + airoha_rmw((qdma)->regs, (offset), 0, (val)) +#define airoha_qdma_clear(qdma, offset, val) \ + airoha_rmw((qdma)->regs, (offset), (val), 0) + +static void airoha_qdma_set_irqmask(struct airoha_qdma *qdma, int index, u32 clear, u32 set) { unsigned long flags; - if (WARN_ON_ONCE(index >= ARRAY_SIZE(eth->irqmask))) + if (WARN_ON_ONCE(index >= ARRAY_SIZE(qdma->irqmask))) return; - spin_lock_irqsave(ð->irq_lock, flags); + spin_lock_irqsave(&qdma->irq_lock, flags); - eth->irqmask[index] &= ~clear; - eth->irqmask[index] |= set; - airoha_qdma_wr(eth, REG_INT_ENABLE(index), eth->irqmask[index]); + qdma->irqmask[index] &= ~clear; + qdma->irqmask[index] |= set; + airoha_qdma_wr(qdma, REG_INT_ENABLE(index), qdma->irqmask[index]); /* Read irq_enable register in order to guarantee the update above * completes in the spinlock critical section. */ - airoha_qdma_rr(eth, REG_INT_ENABLE(index)); + airoha_qdma_rr(qdma, REG_INT_ENABLE(index)); - spin_unlock_irqrestore(ð->irq_lock, flags); + spin_unlock_irqrestore(&qdma->irq_lock, flags); } -static void airoha_qdma_irq_enable(struct airoha_eth *eth, int index, +static void airoha_qdma_irq_enable(struct airoha_qdma *qdma, int index, u32 mask) { - airoha_qdma_set_irqmask(eth, index, 0, mask); + airoha_qdma_set_irqmask(qdma, index, 0, mask); } -static void airoha_qdma_irq_disable(struct airoha_eth *eth, int index, +static void airoha_qdma_irq_disable(struct airoha_qdma *qdma, int index, u32 mask) { - airoha_qdma_set_irqmask(eth, index, mask, 0); + airoha_qdma_set_irqmask(qdma, index, mask, 0); } -static void airoha_set_macaddr(struct airoha_eth *eth, const u8 *addr) +static bool airhoa_is_lan_gdm_port(struct airoha_gdm_port *port) { - u32 val; + /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. + * GDM{2,3,4} can be used as wan port connected to an external + * phy module. + */ + return port->id == 1; +} +static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr) +{ + struct airoha_eth *eth = port->qdma->eth; + u32 val, reg; + + reg = airhoa_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H + : REG_FE_WAN_MAC_H; val = (addr[0] << 16) | (addr[1] << 8) | addr[2]; - airoha_fe_wr(eth, REG_FE_LAN_MAC_H, val); + airoha_fe_wr(eth, reg, val); val = (addr[3] << 16) | (addr[4] << 8) | addr[5]; - airoha_fe_wr(eth, REG_FE_LAN_MAC_LMIN, val); - airoha_fe_wr(eth, REG_FE_LAN_MAC_LMAX, val); + airoha_fe_wr(eth, REG_FE_MAC_LMIN(reg), val); + airoha_fe_wr(eth, REG_FE_MAC_LMAX(reg), val); } static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr, @@ -1383,8 +1403,9 @@ static int airoha_fe_init(struct airoha_eth *eth) static int airoha_qdma_fill_rx_queue(struct airoha_queue *q) { enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool); - struct airoha_eth *eth = q->eth; - int qid = q - ð->q_rx[0]; + struct airoha_qdma *qdma = q->qdma; + struct airoha_eth *eth = qdma->eth; + int qid = q - &qdma->q_rx[0]; int nframes = 0; while (q->queued < q->ndesc - 1) { @@ -1420,7 +1441,8 @@ static int airoha_qdma_fill_rx_queue(struct airoha_queue *q) WRITE_ONCE(desc->msg2, 0); WRITE_ONCE(desc->msg3, 0); - airoha_qdma_rmw(eth, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, + airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), + RX_RING_CPU_IDX_MASK, FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head)); } @@ -1450,8 +1472,9 @@ static int airoha_qdma_get_gdm_port(struct airoha_eth *eth, static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) { enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool); - struct airoha_eth *eth = q->eth; - int qid = q - ð->q_rx[0]; + struct airoha_qdma *qdma = q->qdma; + struct airoha_eth *eth = qdma->eth; + int qid = q - &qdma->q_rx[0]; int done = 0; while (done < budget) { @@ -1513,7 +1536,6 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) static int airoha_qdma_rx_napi_poll(struct napi_struct *napi, int budget) { struct airoha_queue *q = container_of(napi, struct airoha_queue, napi); - struct airoha_eth *eth = q->eth; int cur, done = 0; do { @@ -1522,14 +1544,14 @@ static int airoha_qdma_rx_napi_poll(struct napi_struct *napi, int budget) } while (cur && done < budget); if (done < budget && napi_complete(napi)) - airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX1, + airoha_qdma_irq_enable(q->qdma, QDMA_INT_REG_IDX1, RX_DONE_INT_MASK); return done; } -static int airoha_qdma_init_rx_queue(struct airoha_eth *eth, - struct airoha_queue *q, int ndesc) +static int airoha_qdma_init_rx_queue(struct airoha_queue *q, + struct airoha_qdma *qdma, int ndesc) { const struct page_pool_params pp_params = { .order = 0, @@ -1538,15 +1560,16 @@ static int airoha_qdma_init_rx_queue(struct airoha_eth *eth, .dma_dir = DMA_FROM_DEVICE, .max_len = PAGE_SIZE, .nid = NUMA_NO_NODE, - .dev = eth->dev, + .dev = qdma->eth->dev, .napi = &q->napi, }; - int qid = q - ð->q_rx[0], thr; + struct airoha_eth *eth = qdma->eth; + int qid = q - &qdma->q_rx[0], thr; dma_addr_t dma_addr; q->buf_size = PAGE_SIZE / 2; q->ndesc = ndesc; - q->eth = eth; + q->qdma = qdma; q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry), GFP_KERNEL); @@ -1568,14 +1591,15 @@ static int airoha_qdma_init_rx_queue(struct airoha_eth *eth, netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll); - airoha_qdma_wr(eth, REG_RX_RING_BASE(qid), dma_addr); - airoha_qdma_rmw(eth, REG_RX_RING_SIZE(qid), RX_RING_SIZE_MASK, + airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr); + airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid), + RX_RING_SIZE_MASK, FIELD_PREP(RX_RING_SIZE_MASK, ndesc)); thr = clamp(ndesc >> 3, 1, 32); - airoha_qdma_rmw(eth, REG_RX_RING_SIZE(qid), RX_RING_THR_MASK, + airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid), RX_RING_THR_MASK, FIELD_PREP(RX_RING_THR_MASK, thr)); - airoha_qdma_rmw(eth, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, + airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head)); airoha_qdma_fill_rx_queue(q); @@ -1585,7 +1609,7 @@ static int airoha_qdma_init_rx_queue(struct airoha_eth *eth, static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q) { - struct airoha_eth *eth = q->eth; + struct airoha_eth *eth = q->qdma->eth; while (q->queued) { struct airoha_queue_entry *e = &q->entry[q->tail]; @@ -1599,11 +1623,11 @@ static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q) } } -static int airoha_qdma_init_rx(struct airoha_eth *eth) +static int airoha_qdma_init_rx(struct airoha_qdma *qdma) { int i; - for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) { + for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { int err; if (!(RX_DONE_INT_MASK & BIT(i))) { @@ -1611,7 +1635,7 @@ static int airoha_qdma_init_rx(struct airoha_eth *eth) continue; } - err = airoha_qdma_init_rx_queue(eth, ð->q_rx[i], + err = airoha_qdma_init_rx_queue(&qdma->q_rx[i], qdma, RX_DSCP_NUM(i)); if (err) return err; @@ -1623,12 +1647,14 @@ static int airoha_qdma_init_rx(struct airoha_eth *eth) static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) { struct airoha_tx_irq_queue *irq_q; + struct airoha_qdma *qdma; struct airoha_eth *eth; int id, done = 0; irq_q = container_of(napi, struct airoha_tx_irq_queue, napi); - eth = irq_q->eth; - id = irq_q - ð->q_tx_irq[0]; + qdma = irq_q->qdma; + id = irq_q - &qdma->q_tx_irq[0]; + eth = qdma->eth; while (irq_q->queued > 0 && done < budget) { u32 qid, last, val = irq_q->q[irq_q->head]; @@ -1645,10 +1671,10 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) last = FIELD_GET(IRQ_DESC_IDX_MASK, val); qid = FIELD_GET(IRQ_RING_IDX_MASK, val); - if (qid >= ARRAY_SIZE(eth->q_tx)) + if (qid >= ARRAY_SIZE(qdma->q_tx)) continue; - q = ð->q_tx[qid]; + q = &qdma->q_tx[qid]; if (!q->ndesc) continue; @@ -1697,28 +1723,29 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) int i, len = done >> 7; for (i = 0; i < len; i++) - airoha_qdma_rmw(eth, REG_IRQ_CLEAR_LEN(id), + airoha_qdma_rmw(qdma, REG_IRQ_CLEAR_LEN(id), IRQ_CLEAR_LEN_MASK, 0x80); - airoha_qdma_rmw(eth, REG_IRQ_CLEAR_LEN(id), + airoha_qdma_rmw(qdma, REG_IRQ_CLEAR_LEN(id), IRQ_CLEAR_LEN_MASK, (done & 0x7f)); } if (done < budget && napi_complete(napi)) - airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX0, + airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX0, TX_DONE_INT_MASK(id)); return done; } -static int airoha_qdma_init_tx_queue(struct airoha_eth *eth, - struct airoha_queue *q, int size) +static int airoha_qdma_init_tx_queue(struct airoha_queue *q, + struct airoha_qdma *qdma, int size) { - int i, qid = q - ð->q_tx[0]; + struct airoha_eth *eth = qdma->eth; + int i, qid = q - &qdma->q_tx[0]; dma_addr_t dma_addr; spin_lock_init(&q->lock); q->ndesc = size; - q->eth = eth; + q->qdma = qdma; q->free_thr = 1 + MAX_SKB_FRAGS; q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry), @@ -1738,20 +1765,20 @@ static int airoha_qdma_init_tx_queue(struct airoha_eth *eth, WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val)); } - airoha_qdma_wr(eth, REG_TX_RING_BASE(qid), dma_addr); - airoha_qdma_rmw(eth, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK, + airoha_qdma_wr(qdma, REG_TX_RING_BASE(qid), dma_addr); + airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK, FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head)); - airoha_qdma_rmw(eth, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK, + airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK, FIELD_PREP(TX_RING_DMA_IDX_MASK, q->head)); return 0; } -static int airoha_qdma_tx_irq_init(struct airoha_eth *eth, - struct airoha_tx_irq_queue *irq_q, - int size) +static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q, + struct airoha_qdma *qdma, int size) { - int id = irq_q - ð->q_tx_irq[0]; + int id = irq_q - &qdma->q_tx_irq[0]; + struct airoha_eth *eth = qdma->eth; dma_addr_t dma_addr; netif_napi_add_tx(eth->napi_dev, &irq_q->napi, @@ -1763,30 +1790,30 @@ static int airoha_qdma_tx_irq_init(struct airoha_eth *eth, memset(irq_q->q, 0xff, size * sizeof(u32)); irq_q->size = size; - irq_q->eth = eth; + irq_q->qdma = qdma; - airoha_qdma_wr(eth, REG_TX_IRQ_BASE(id), dma_addr); - airoha_qdma_rmw(eth, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK, + airoha_qdma_wr(qdma, REG_TX_IRQ_BASE(id), dma_addr); + airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK, FIELD_PREP(TX_IRQ_DEPTH_MASK, size)); - airoha_qdma_rmw(eth, REG_TX_IRQ_CFG(id), TX_IRQ_THR_MASK, + airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_THR_MASK, FIELD_PREP(TX_IRQ_THR_MASK, 1)); return 0; } -static int airoha_qdma_init_tx(struct airoha_eth *eth) +static int airoha_qdma_init_tx(struct airoha_qdma *qdma) { int i, err; - for (i = 0; i < ARRAY_SIZE(eth->q_tx_irq); i++) { - err = airoha_qdma_tx_irq_init(eth, ð->q_tx_irq[i], + for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) { + err = airoha_qdma_tx_irq_init(&qdma->q_tx_irq[i], qdma, IRQ_QUEUE_LEN(i)); if (err) return err; } - for (i = 0; i < ARRAY_SIZE(eth->q_tx); i++) { - err = airoha_qdma_init_tx_queue(eth, ð->q_tx[i], + for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { + err = airoha_qdma_init_tx_queue(&qdma->q_tx[i], qdma, TX_DSCP_NUM); if (err) return err; @@ -1797,7 +1824,7 @@ static int airoha_qdma_init_tx(struct airoha_eth *eth) static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q) { - struct airoha_eth *eth = q->eth; + struct airoha_eth *eth = q->qdma->eth; spin_lock_bh(&q->lock); while (q->queued) { @@ -1814,34 +1841,35 @@ static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q) spin_unlock_bh(&q->lock); } -static int airoha_qdma_init_hfwd_queues(struct airoha_eth *eth) +static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma) { + struct airoha_eth *eth = qdma->eth; dma_addr_t dma_addr; u32 status; int size; size = HW_DSCP_NUM * sizeof(struct airoha_qdma_fwd_desc); - eth->hfwd.desc = dmam_alloc_coherent(eth->dev, size, &dma_addr, - GFP_KERNEL); - if (!eth->hfwd.desc) + qdma->hfwd.desc = dmam_alloc_coherent(eth->dev, size, &dma_addr, + GFP_KERNEL); + if (!qdma->hfwd.desc) return -ENOMEM; - airoha_qdma_wr(eth, REG_FWD_DSCP_BASE, dma_addr); + airoha_qdma_wr(qdma, REG_FWD_DSCP_BASE, dma_addr); size = AIROHA_MAX_PACKET_SIZE * HW_DSCP_NUM; - eth->hfwd.q = dmam_alloc_coherent(eth->dev, size, &dma_addr, - GFP_KERNEL); - if (!eth->hfwd.q) + qdma->hfwd.q = dmam_alloc_coherent(eth->dev, size, &dma_addr, + GFP_KERNEL); + if (!qdma->hfwd.q) return -ENOMEM; - airoha_qdma_wr(eth, REG_FWD_BUF_BASE, dma_addr); + airoha_qdma_wr(qdma, REG_FWD_BUF_BASE, dma_addr); - airoha_qdma_rmw(eth, REG_HW_FWD_DSCP_CFG, + airoha_qdma_rmw(qdma, REG_HW_FWD_DSCP_CFG, HW_FWD_DSCP_PAYLOAD_SIZE_MASK, FIELD_PREP(HW_FWD_DSCP_PAYLOAD_SIZE_MASK, 0)); - airoha_qdma_rmw(eth, REG_FWD_DSCP_LOW_THR, FWD_DSCP_LOW_THR_MASK, + airoha_qdma_rmw(qdma, REG_FWD_DSCP_LOW_THR, FWD_DSCP_LOW_THR_MASK, FIELD_PREP(FWD_DSCP_LOW_THR_MASK, 128)); - airoha_qdma_rmw(eth, REG_LMGR_INIT_CFG, + airoha_qdma_rmw(qdma, REG_LMGR_INIT_CFG, LMGR_INIT_START | LMGR_SRAM_MODE_MASK | HW_FWD_DESC_NUM_MASK, FIELD_PREP(HW_FWD_DESC_NUM_MASK, HW_DSCP_NUM) | @@ -1849,87 +1877,87 @@ static int airoha_qdma_init_hfwd_queues(struct airoha_eth *eth) return read_poll_timeout(airoha_qdma_rr, status, !(status & LMGR_INIT_START), USEC_PER_MSEC, - 30 * USEC_PER_MSEC, true, eth, + 30 * USEC_PER_MSEC, true, qdma, REG_LMGR_INIT_CFG); } -static void airoha_qdma_init_qos(struct airoha_eth *eth) +static void airoha_qdma_init_qos(struct airoha_qdma *qdma) { - airoha_qdma_clear(eth, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_SCALE_MASK); - airoha_qdma_set(eth, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_BASE_MASK); + airoha_qdma_clear(qdma, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_SCALE_MASK); + airoha_qdma_set(qdma, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_BASE_MASK); - airoha_qdma_clear(eth, REG_PSE_BUF_USAGE_CFG, + airoha_qdma_clear(qdma, REG_PSE_BUF_USAGE_CFG, PSE_BUF_ESTIMATE_EN_MASK); - airoha_qdma_set(eth, REG_EGRESS_RATE_METER_CFG, + airoha_qdma_set(qdma, REG_EGRESS_RATE_METER_CFG, EGRESS_RATE_METER_EN_MASK | EGRESS_RATE_METER_EQ_RATE_EN_MASK); /* 2047us x 31 = 63.457ms */ - airoha_qdma_rmw(eth, REG_EGRESS_RATE_METER_CFG, + airoha_qdma_rmw(qdma, REG_EGRESS_RATE_METER_CFG, EGRESS_RATE_METER_WINDOW_SZ_MASK, FIELD_PREP(EGRESS_RATE_METER_WINDOW_SZ_MASK, 0x1f)); - airoha_qdma_rmw(eth, REG_EGRESS_RATE_METER_CFG, + airoha_qdma_rmw(qdma, REG_EGRESS_RATE_METER_CFG, EGRESS_RATE_METER_TIMESLICE_MASK, FIELD_PREP(EGRESS_RATE_METER_TIMESLICE_MASK, 0x7ff)); /* ratelimit init */ - airoha_qdma_set(eth, REG_GLB_TRTCM_CFG, GLB_TRTCM_EN_MASK); + airoha_qdma_set(qdma, REG_GLB_TRTCM_CFG, GLB_TRTCM_EN_MASK); /* fast-tick 25us */ - airoha_qdma_rmw(eth, REG_GLB_TRTCM_CFG, GLB_FAST_TICK_MASK, + airoha_qdma_rmw(qdma, REG_GLB_TRTCM_CFG, GLB_FAST_TICK_MASK, FIELD_PREP(GLB_FAST_TICK_MASK, 25)); - airoha_qdma_rmw(eth, REG_GLB_TRTCM_CFG, GLB_SLOW_TICK_RATIO_MASK, + airoha_qdma_rmw(qdma, REG_GLB_TRTCM_CFG, GLB_SLOW_TICK_RATIO_MASK, FIELD_PREP(GLB_SLOW_TICK_RATIO_MASK, 40)); - airoha_qdma_set(eth, REG_EGRESS_TRTCM_CFG, EGRESS_TRTCM_EN_MASK); - airoha_qdma_rmw(eth, REG_EGRESS_TRTCM_CFG, EGRESS_FAST_TICK_MASK, + airoha_qdma_set(qdma, REG_EGRESS_TRTCM_CFG, EGRESS_TRTCM_EN_MASK); + airoha_qdma_rmw(qdma, REG_EGRESS_TRTCM_CFG, EGRESS_FAST_TICK_MASK, FIELD_PREP(EGRESS_FAST_TICK_MASK, 25)); - airoha_qdma_rmw(eth, REG_EGRESS_TRTCM_CFG, + airoha_qdma_rmw(qdma, REG_EGRESS_TRTCM_CFG, EGRESS_SLOW_TICK_RATIO_MASK, FIELD_PREP(EGRESS_SLOW_TICK_RATIO_MASK, 40)); - airoha_qdma_set(eth, REG_INGRESS_TRTCM_CFG, INGRESS_TRTCM_EN_MASK); - airoha_qdma_clear(eth, REG_INGRESS_TRTCM_CFG, + airoha_qdma_set(qdma, REG_INGRESS_TRTCM_CFG, INGRESS_TRTCM_EN_MASK); + airoha_qdma_clear(qdma, REG_INGRESS_TRTCM_CFG, INGRESS_TRTCM_MODE_MASK); - airoha_qdma_rmw(eth, REG_INGRESS_TRTCM_CFG, INGRESS_FAST_TICK_MASK, + airoha_qdma_rmw(qdma, REG_INGRESS_TRTCM_CFG, INGRESS_FAST_TICK_MASK, FIELD_PREP(INGRESS_FAST_TICK_MASK, 125)); - airoha_qdma_rmw(eth, REG_INGRESS_TRTCM_CFG, + airoha_qdma_rmw(qdma, REG_INGRESS_TRTCM_CFG, INGRESS_SLOW_TICK_RATIO_MASK, FIELD_PREP(INGRESS_SLOW_TICK_RATIO_MASK, 8)); - airoha_qdma_set(eth, REG_SLA_TRTCM_CFG, SLA_TRTCM_EN_MASK); - airoha_qdma_rmw(eth, REG_SLA_TRTCM_CFG, SLA_FAST_TICK_MASK, + airoha_qdma_set(qdma, REG_SLA_TRTCM_CFG, SLA_TRTCM_EN_MASK); + airoha_qdma_rmw(qdma, REG_SLA_TRTCM_CFG, SLA_FAST_TICK_MASK, FIELD_PREP(SLA_FAST_TICK_MASK, 25)); - airoha_qdma_rmw(eth, REG_SLA_TRTCM_CFG, SLA_SLOW_TICK_RATIO_MASK, + airoha_qdma_rmw(qdma, REG_SLA_TRTCM_CFG, SLA_SLOW_TICK_RATIO_MASK, FIELD_PREP(SLA_SLOW_TICK_RATIO_MASK, 40)); } -static int airoha_qdma_hw_init(struct airoha_eth *eth) +static int airoha_qdma_hw_init(struct airoha_qdma *qdma) { int i; /* clear pending irqs */ - for (i = 0; i < ARRAY_SIZE(eth->irqmask); i++) - airoha_qdma_wr(eth, REG_INT_STATUS(i), 0xffffffff); + for (i = 0; i < ARRAY_SIZE(qdma->irqmask); i++) + airoha_qdma_wr(qdma, REG_INT_STATUS(i), 0xffffffff); /* setup irqs */ - airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX0, INT_IDX0_MASK); - airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX1, INT_IDX1_MASK); - airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX4, INT_IDX4_MASK); + airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX0, INT_IDX0_MASK); + airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX1, INT_IDX1_MASK); + airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX4, INT_IDX4_MASK); /* setup irq binding */ - for (i = 0; i < ARRAY_SIZE(eth->q_tx); i++) { - if (!eth->q_tx[i].ndesc) + for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { + if (!qdma->q_tx[i].ndesc) continue; if (TX_RING_IRQ_BLOCKING_MAP_MASK & BIT(i)) - airoha_qdma_set(eth, REG_TX_RING_BLOCKING(i), + airoha_qdma_set(qdma, REG_TX_RING_BLOCKING(i), TX_RING_IRQ_BLOCKING_CFG_MASK); else - airoha_qdma_clear(eth, REG_TX_RING_BLOCKING(i), + airoha_qdma_clear(qdma, REG_TX_RING_BLOCKING(i), TX_RING_IRQ_BLOCKING_CFG_MASK); } - airoha_qdma_wr(eth, REG_QDMA_GLOBAL_CFG, + airoha_qdma_wr(qdma, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_RX_2B_OFFSET_MASK | FIELD_PREP(GLOBAL_CFG_DMA_PREFERENCE_MASK, 3) | GLOBAL_CFG_CPU_TXR_RR_MASK | @@ -1940,18 +1968,18 @@ static int airoha_qdma_hw_init(struct airoha_eth *eth) GLOBAL_CFG_TX_WB_DONE_MASK | FIELD_PREP(GLOBAL_CFG_MAX_ISSUE_NUM_MASK, 2)); - airoha_qdma_init_qos(eth); + airoha_qdma_init_qos(qdma); /* disable qdma rx delay interrupt */ - for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) { - if (!eth->q_rx[i].ndesc) + for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { + if (!qdma->q_rx[i].ndesc) continue; - airoha_qdma_clear(eth, REG_RX_DELAY_INT_IDX(i), + airoha_qdma_clear(qdma, REG_RX_DELAY_INT_IDX(i), RX_DELAY_INT_MASK); } - airoha_qdma_set(eth, REG_TXQ_CNGST_CFG, + airoha_qdma_set(qdma, REG_TXQ_CNGST_CFG, TXQ_CNGST_DROP_EN | TXQ_CNGST_DEI_DROP_EN); return 0; @@ -1959,150 +1987,180 @@ static int airoha_qdma_hw_init(struct airoha_eth *eth) static irqreturn_t airoha_irq_handler(int irq, void *dev_instance) { - struct airoha_eth *eth = dev_instance; - u32 intr[ARRAY_SIZE(eth->irqmask)]; + struct airoha_qdma *qdma = dev_instance; + u32 intr[ARRAY_SIZE(qdma->irqmask)]; int i; - for (i = 0; i < ARRAY_SIZE(eth->irqmask); i++) { - intr[i] = airoha_qdma_rr(eth, REG_INT_STATUS(i)); - intr[i] &= eth->irqmask[i]; - airoha_qdma_wr(eth, REG_INT_STATUS(i), intr[i]); + for (i = 0; i < ARRAY_SIZE(qdma->irqmask); i++) { + intr[i] = airoha_qdma_rr(qdma, REG_INT_STATUS(i)); + intr[i] &= qdma->irqmask[i]; + airoha_qdma_wr(qdma, REG_INT_STATUS(i), intr[i]); } - if (!test_bit(DEV_STATE_INITIALIZED, ð->state)) + if (!test_bit(DEV_STATE_INITIALIZED, &qdma->eth->state)) return IRQ_NONE; if (intr[1] & RX_DONE_INT_MASK) { - airoha_qdma_irq_disable(eth, QDMA_INT_REG_IDX1, + airoha_qdma_irq_disable(qdma, QDMA_INT_REG_IDX1, RX_DONE_INT_MASK); - for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) { - if (!eth->q_rx[i].ndesc) + for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { + if (!qdma->q_rx[i].ndesc) continue; if (intr[1] & BIT(i)) - napi_schedule(ð->q_rx[i].napi); + napi_schedule(&qdma->q_rx[i].napi); } } if (intr[0] & INT_TX_MASK) { - for (i = 0; i < ARRAY_SIZE(eth->q_tx_irq); i++) { - struct airoha_tx_irq_queue *irq_q = ð->q_tx_irq[i]; + for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) { + struct airoha_tx_irq_queue *irq_q = &qdma->q_tx_irq[i]; u32 status, head; if (!(intr[0] & TX_DONE_INT_MASK(i))) continue; - airoha_qdma_irq_disable(eth, QDMA_INT_REG_IDX0, + airoha_qdma_irq_disable(qdma, QDMA_INT_REG_IDX0, TX_DONE_INT_MASK(i)); - status = airoha_qdma_rr(eth, REG_IRQ_STATUS(i)); + status = airoha_qdma_rr(qdma, REG_IRQ_STATUS(i)); head = FIELD_GET(IRQ_HEAD_IDX_MASK, status); irq_q->head = head % irq_q->size; irq_q->queued = FIELD_GET(IRQ_ENTRY_LEN_MASK, status); - napi_schedule(ð->q_tx_irq[i].napi); + napi_schedule(&qdma->q_tx_irq[i].napi); } } return IRQ_HANDLED; } -static int airoha_qdma_init(struct airoha_eth *eth) +static int airoha_qdma_init(struct platform_device *pdev, + struct airoha_eth *eth, + struct airoha_qdma *qdma) { - int err; + int err, id = qdma - ð->qdma[0]; + const char *res; - err = devm_request_irq(eth->dev, eth->irq, airoha_irq_handler, - IRQF_SHARED, KBUILD_MODNAME, eth); - if (err) - return err; + spin_lock_init(&qdma->irq_lock); + qdma->eth = eth; - err = airoha_qdma_init_rx(eth); + res = devm_kasprintf(eth->dev, GFP_KERNEL, "qdma%d", id); + if (!res) + return -ENOMEM; + + qdma->regs = devm_platform_ioremap_resource_byname(pdev, res); + if (IS_ERR(qdma->regs)) + return dev_err_probe(eth->dev, PTR_ERR(qdma->regs), + "failed to iomap qdma%d regs\n", id); + + qdma->irq = platform_get_irq(pdev, 4 * id); + if (qdma->irq < 0) + return qdma->irq; + + err = devm_request_irq(eth->dev, qdma->irq, airoha_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, qdma); if (err) return err; - err = airoha_qdma_init_tx(eth); + err = airoha_qdma_init_rx(qdma); if (err) return err; - err = airoha_qdma_init_hfwd_queues(eth); + err = airoha_qdma_init_tx(qdma); if (err) return err; - err = airoha_qdma_hw_init(eth); + err = airoha_qdma_init_hfwd_queues(qdma); if (err) return err; - set_bit(DEV_STATE_INITIALIZED, ð->state); - - return 0; + return airoha_qdma_hw_init(qdma); } -static int airoha_hw_init(struct airoha_eth *eth) +static int airoha_hw_init(struct platform_device *pdev, + struct airoha_eth *eth) { - int err; + int err, i; /* disable xsi */ - reset_control_bulk_assert(ARRAY_SIZE(eth->xsi_rsts), eth->xsi_rsts); + err = reset_control_bulk_assert(ARRAY_SIZE(eth->xsi_rsts), + eth->xsi_rsts); + if (err) + return err; + + err = reset_control_bulk_assert(ARRAY_SIZE(eth->rsts), eth->rsts); + if (err) + return err; - reset_control_bulk_assert(ARRAY_SIZE(eth->rsts), eth->rsts); - msleep(20); - reset_control_bulk_deassert(ARRAY_SIZE(eth->rsts), eth->rsts); msleep(20); + err = reset_control_bulk_deassert(ARRAY_SIZE(eth->rsts), eth->rsts); + if (err) + return err; + msleep(20); err = airoha_fe_init(eth); if (err) return err; - return airoha_qdma_init(eth); + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) { + err = airoha_qdma_init(pdev, eth, ð->qdma[i]); + if (err) + return err; + } + + set_bit(DEV_STATE_INITIALIZED, ð->state); + + return 0; } -static void airoha_hw_cleanup(struct airoha_eth *eth) +static void airoha_hw_cleanup(struct airoha_qdma *qdma) { int i; - for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) { - if (!eth->q_rx[i].ndesc) + for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { + if (!qdma->q_rx[i].ndesc) continue; - napi_disable(ð->q_rx[i].napi); - netif_napi_del(ð->q_rx[i].napi); - airoha_qdma_cleanup_rx_queue(ð->q_rx[i]); - if (eth->q_rx[i].page_pool) - page_pool_destroy(eth->q_rx[i].page_pool); + napi_disable(&qdma->q_rx[i].napi); + netif_napi_del(&qdma->q_rx[i].napi); + airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]); + if (qdma->q_rx[i].page_pool) + page_pool_destroy(qdma->q_rx[i].page_pool); } - for (i = 0; i < ARRAY_SIZE(eth->q_tx_irq); i++) { - napi_disable(ð->q_tx_irq[i].napi); - netif_napi_del(ð->q_tx_irq[i].napi); + for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) { + napi_disable(&qdma->q_tx_irq[i].napi); + netif_napi_del(&qdma->q_tx_irq[i].napi); } - for (i = 0; i < ARRAY_SIZE(eth->q_tx); i++) { - if (!eth->q_tx[i].ndesc) + for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { + if (!qdma->q_tx[i].ndesc) continue; - airoha_qdma_cleanup_tx_queue(ð->q_tx[i]); + airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); } } -static void airoha_qdma_start_napi(struct airoha_eth *eth) +static void airoha_qdma_start_napi(struct airoha_qdma *qdma) { int i; - for (i = 0; i < ARRAY_SIZE(eth->q_tx_irq); i++) - napi_enable(ð->q_tx_irq[i].napi); + for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) + napi_enable(&qdma->q_tx_irq[i].napi); - for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) { - if (!eth->q_rx[i].ndesc) + for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { + if (!qdma->q_rx[i].ndesc) continue; - napi_enable(ð->q_rx[i].napi); + napi_enable(&qdma->q_rx[i].napi); } } static void airoha_update_hw_stats(struct airoha_gdm_port *port) { - struct airoha_eth *eth = port->eth; + struct airoha_eth *eth = port->qdma->eth; u32 val, i = 0; spin_lock(&port->stats.lock); @@ -2247,23 +2305,24 @@ static void airoha_update_hw_stats(struct airoha_gdm_port *port) static int airoha_dev_open(struct net_device *dev) { struct airoha_gdm_port *port = netdev_priv(dev); - struct airoha_eth *eth = port->eth; + struct airoha_qdma *qdma = port->qdma; int err; netif_tx_start_all_queues(dev); - err = airoha_set_gdm_ports(eth, true); + err = airoha_set_gdm_ports(qdma->eth, true); if (err) return err; if (netdev_uses_dsa(dev)) - airoha_fe_set(eth, REG_GDM_INGRESS_CFG(port->id), + airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id), GDM_STAG_EN_MASK); else - airoha_fe_clear(eth, REG_GDM_INGRESS_CFG(port->id), + airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id), GDM_STAG_EN_MASK); - airoha_qdma_set(eth, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_TX_DMA_EN_MASK); - airoha_qdma_set(eth, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_RX_DMA_EN_MASK); + airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, + GLOBAL_CFG_TX_DMA_EN_MASK | + GLOBAL_CFG_RX_DMA_EN_MASK); return 0; } @@ -2271,16 +2330,17 @@ static int airoha_dev_open(struct net_device *dev) static int airoha_dev_stop(struct net_device *dev) { struct airoha_gdm_port *port = netdev_priv(dev); - struct airoha_eth *eth = port->eth; + struct airoha_qdma *qdma = port->qdma; int err; netif_tx_disable(dev); - err = airoha_set_gdm_ports(eth, false); + err = airoha_set_gdm_ports(qdma->eth, false); if (err) return err; - airoha_qdma_clear(eth, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_TX_DMA_EN_MASK); - airoha_qdma_clear(eth, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_RX_DMA_EN_MASK); + airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, + GLOBAL_CFG_TX_DMA_EN_MASK | + GLOBAL_CFG_RX_DMA_EN_MASK); return 0; } @@ -2294,7 +2354,7 @@ static int airoha_dev_set_macaddr(struct net_device *dev, void *p) if (err) return err; - airoha_set_macaddr(port->eth, dev->dev_addr); + airoha_set_macaddr(port, dev->dev_addr); return 0; } @@ -2303,7 +2363,7 @@ static int airoha_dev_init(struct net_device *dev) { struct airoha_gdm_port *port = netdev_priv(dev); - airoha_set_macaddr(port->eth, dev->dev_addr); + airoha_set_macaddr(port, dev->dev_addr); return 0; } @@ -2337,7 +2397,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, struct airoha_gdm_port *port = netdev_priv(dev); u32 msg0 = 0, msg1, len = skb_headlen(skb); int i, qid = skb_get_queue_mapping(skb); - struct airoha_eth *eth = port->eth; + struct airoha_qdma *qdma = port->qdma; u32 nr_frags = 1 + sinfo->nr_frags; struct netdev_queue *txq; struct airoha_queue *q; @@ -2367,7 +2427,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) | FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f); - q = ð->q_tx[qid]; + q = &qdma->q_tx[qid]; if (WARN_ON_ONCE(!q->ndesc)) goto error; @@ -2411,7 +2471,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, e->dma_addr = addr; e->dma_len = len; - airoha_qdma_rmw(eth, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK, + airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), + TX_RING_CPU_IDX_MASK, FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); data = skb_frag_address(frag); @@ -2448,7 +2509,7 @@ static void airoha_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct airoha_gdm_port *port = netdev_priv(dev); - struct airoha_eth *eth = port->eth; + struct airoha_eth *eth = port->qdma->eth; strscpy(info->driver, eth->dev->driver->name, sizeof(info->driver)); strscpy(info->bus_info, dev_name(eth->dev), sizeof(info->bus_info)); @@ -2529,6 +2590,7 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth, struct device_node *np) { const __be32 *id_ptr = of_get_property(np, "reg", NULL); struct airoha_gdm_port *port; + struct airoha_qdma *qdma; struct net_device *dev; int err, index; u32 id; @@ -2558,6 +2620,7 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth, struct device_node *np) return -ENOMEM; } + qdma = ð->qdma[index % AIROHA_MAX_NUM_QDMA]; dev->netdev_ops = &airoha_netdev_ops; dev->ethtool_ops = &airoha_ethtool_ops; dev->max_mtu = AIROHA_MAX_MTU; @@ -2567,6 +2630,7 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth, struct device_node *np) NETIF_F_SG | NETIF_F_TSO; dev->features |= dev->hw_features; dev->dev.of_node = np; + dev->irq = qdma->irq; SET_NETDEV_DEV(dev, eth->dev); err = of_get_ethdev_address(np, dev); @@ -2582,8 +2646,8 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth, struct device_node *np) port = netdev_priv(dev); u64_stats_init(&port->stats.syncp); spin_lock_init(&port->stats.lock); + port->qdma = qdma; port->dev = dev; - port->eth = eth; port->id = id; eth->ports[index] = port; @@ -2613,11 +2677,6 @@ static int airoha_probe(struct platform_device *pdev) return dev_err_probe(eth->dev, PTR_ERR(eth->fe_regs), "failed to iomap fe regs\n"); - eth->qdma_regs = devm_platform_ioremap_resource_byname(pdev, "qdma0"); - if (IS_ERR(eth->qdma_regs)) - return dev_err_probe(eth->dev, PTR_ERR(eth->qdma_regs), - "failed to iomap qdma regs\n"); - eth->rsts[0].id = "fe"; eth->rsts[1].id = "pdma"; eth->rsts[2].id = "qdma"; @@ -2642,11 +2701,6 @@ static int airoha_probe(struct platform_device *pdev) return err; } - spin_lock_init(ð->irq_lock); - eth->irq = platform_get_irq(pdev, 0); - if (eth->irq < 0) - return eth->irq; - eth->napi_dev = alloc_netdev_dummy(0); if (!eth->napi_dev) return -ENOMEM; @@ -2656,11 +2710,13 @@ static int airoha_probe(struct platform_device *pdev) strscpy(eth->napi_dev->name, "qdma_eth", sizeof(eth->napi_dev->name)); platform_set_drvdata(pdev, eth); - err = airoha_hw_init(eth); + err = airoha_hw_init(pdev, eth); if (err) goto error; - airoha_qdma_start_napi(eth); + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) + airoha_qdma_start_napi(ð->qdma[i]); + for_each_child_of_node(pdev->dev.of_node, np) { if (!of_device_is_compatible(np, "airoha,eth-mac")) continue; @@ -2678,7 +2734,9 @@ static int airoha_probe(struct platform_device *pdev) return 0; error: - airoha_hw_cleanup(eth); + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) + airoha_hw_cleanup(ð->qdma[i]); + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -2696,7 +2754,9 @@ static void airoha_remove(struct platform_device *pdev) struct airoha_eth *eth = platform_get_drvdata(pdev); int i; - airoha_hw_cleanup(eth); + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) + airoha_hw_cleanup(ð->qdma[i]); + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; @@ -2715,6 +2775,7 @@ static const struct of_device_id of_airoha_match[] = { { .compatible = "airoha,en7581-eth" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_airoha_match); static struct platform_driver airoha_driver = { .probe = airoha_probe, |