diff options
Diffstat (limited to 'drivers/net/ethernet/xilinx')
-rw-r--r-- | drivers/net/ethernet/xilinx/Kconfig | 15 | ||||
-rw-r--r-- | drivers/net/ethernet/xilinx/ll_temac.h | 193 | ||||
-rw-r--r-- | drivers/net/ethernet/xilinx/ll_temac_main.c | 359 | ||||
-rw-r--r-- | drivers/net/ethernet/xilinx/ll_temac_mdio.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/xilinx/xilinx_axienet.h | 198 | ||||
-rw-r--r-- | drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 1397 | ||||
-rw-r--r-- | drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c | 64 | ||||
-rw-r--r-- | drivers/net/ethernet/xilinx/xilinx_emaclite.c | 136 |
8 files changed, 1457 insertions, 911 deletions
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig index 6304ebd8b5c6..0014729b8865 100644 --- a/drivers/net/ethernet/xilinx/Kconfig +++ b/drivers/net/ethernet/xilinx/Kconfig @@ -1,12 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only # -# Xilink device configuration +# Xilinx device configuration # config NET_VENDOR_XILINX bool "Xilinx devices" default y - ---help--- + help If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the @@ -18,23 +18,24 @@ if NET_VENDOR_XILINX config XILINX_EMACLITE tristate "Xilinx 10/100 Ethernet Lite support" - depends on PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS + depends on HAS_IOMEM select PHYLIB - ---help--- + help This driver supports the 10/100 Ethernet Lite from Xilinx. config XILINX_AXI_EMAC tristate "Xilinx 10/100/1000 AXI Ethernet support" + depends on HAS_IOMEM select PHYLINK - ---help--- + help This driver supports the 10/100/1000 Ethernet from Xilinx for the AXI bus interface used in Xilinx Virtex FPGAs and Soc's. config XILINX_LL_TEMAC tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" - depends on PPC || MICROBLAZE || X86 || COMPILE_TEST + depends on HAS_IOMEM select PHYLIB - ---help--- + help This driver supports the Xilinx 10/100/1000 LocalLink TEMAC core used in Xilinx Spartan and Virtex FPGAs diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h index 53fb8141f1a6..6668d1b760d8 100644 --- a/drivers/net/ethernet/xilinx/ll_temac.h +++ b/drivers/net/ethernet/xilinx/ll_temac.h @@ -21,36 +21,45 @@ /* Configuration options */ /* Accept all incoming packets. - * This option defaults to disabled (cleared) */ + * This option defaults to disabled (cleared) + */ #define XTE_OPTION_PROMISC (1 << 0) /* Jumbo frame support for Tx & Rx. - * This option defaults to disabled (cleared) */ + * This option defaults to disabled (cleared) + */ #define XTE_OPTION_JUMBO (1 << 1) /* VLAN Rx & Tx frame support. - * This option defaults to disabled (cleared) */ + * This option defaults to disabled (cleared) + */ #define XTE_OPTION_VLAN (1 << 2) /* Enable recognition of flow control frames on Rx - * This option defaults to enabled (set) */ + * This option defaults to enabled (set) + */ #define XTE_OPTION_FLOW_CONTROL (1 << 4) /* Strip FCS and PAD from incoming frames. * Note: PAD from VLAN frames is not stripped. - * This option defaults to disabled (set) */ + * This option defaults to disabled (set) + */ #define XTE_OPTION_FCS_STRIP (1 << 5) /* Generate FCS field and add PAD automatically for outgoing frames. - * This option defaults to enabled (set) */ + * This option defaults to enabled (set) + */ #define XTE_OPTION_FCS_INSERT (1 << 6) /* Enable Length/Type error checking for incoming frames. When this option is -set, the MAC will filter frames that have a mismatched type/length field -and if XTE_OPTION_REPORT_RXERR is set, the user is notified when these -types of frames are encountered. When this option is cleared, the MAC will -allow these types of frames to be received. -This option defaults to enabled (set) */ + * set, the MAC will filter frames that have a mismatched type/length field + * and if XTE_OPTION_REPORT_RXERR is set, the user is notified when these + * types of frames are encountered. When this option is cleared, the MAC will + * allow these types of frames to be received. + * This option defaults to enabled (set) + */ #define XTE_OPTION_LENTYPE_ERR (1 << 7) /* Enable the transmitter. - * This option defaults to enabled (set) */ + * This option defaults to enabled (set) + */ #define XTE_OPTION_TXEN (1 << 11) /* Enable the receiver -* This option defaults to enabled (set) */ + * This option defaults to enabled (set) + */ #define XTE_OPTION_RXEN (1 << 12) /* Default options set when device is initialized or reset */ @@ -68,18 +77,18 @@ This option defaults to enabled (set) */ #define TX_TAILDESC_PTR 0x04 /* rw */ #define TX_CHNL_CTRL 0x05 /* rw */ /* - 0:7 24:31 IRQTimeout - 8:15 16:23 IRQCount - 16:20 11:15 Reserved - 21 10 0 - 22 9 UseIntOnEnd - 23 8 LdIRQCnt - 24 7 IRQEn - 25:28 3:6 Reserved - 29 2 IrqErrEn - 30 1 IrqDlyEn - 31 0 IrqCoalEn -*/ + * 0:7 24:31 IRQTimeout + * 8:15 16:23 IRQCount + * 16:20 11:15 Reserved + * 21 10 0 + * 22 9 UseIntOnEnd + * 23 8 LdIRQCnt + * 24 7 IRQEn + * 25:28 3:6 Reserved + * 29 2 IrqErrEn + * 30 1 IrqDlyEn + * 31 0 IrqCoalEn + */ #define CHNL_CTRL_IRQ_IOE (1 << 9) #define CHNL_CTRL_IRQ_EN (1 << 7) #define CHNL_CTRL_IRQ_ERR_EN (1 << 2) @@ -87,35 +96,35 @@ This option defaults to enabled (set) */ #define CHNL_CTRL_IRQ_COAL_EN (1 << 0) #define TX_IRQ_REG 0x06 /* rw */ /* - 0:7 24:31 DltTmrValue - 8:15 16:23 ClscCntrValue - 16:17 14:15 Reserved - 18:21 10:13 ClscCnt - 22:23 8:9 DlyCnt - 24:28 3::7 Reserved - 29 2 ErrIrq - 30 1 DlyIrq - 31 0 CoalIrq + * 0:7 24:31 DltTmrValue + * 8:15 16:23 ClscCntrValue + * 16:17 14:15 Reserved + * 18:21 10:13 ClscCnt + * 22:23 8:9 DlyCnt + * 24:28 3::7 Reserved + * 29 2 ErrIrq + * 30 1 DlyIrq + * 31 0 CoalIrq */ #define TX_CHNL_STS 0x07 /* r */ /* - 0:9 22:31 Reserved - 10 21 TailPErr - 11 20 CmpErr - 12 19 AddrErr - 13 18 NxtPErr - 14 17 CurPErr - 15 16 BsyWr - 16:23 8:15 Reserved - 24 7 Error - 25 6 IOE - 26 5 SOE - 27 4 Cmplt - 28 3 SOP - 29 2 EOP - 30 1 EngBusy - 31 0 Reserved -*/ + * 0:9 22:31 Reserved + * 10 21 TailPErr + * 11 20 CmpErr + * 12 19 AddrErr + * 13 18 NxtPErr + * 14 17 CurPErr + * 15 16 BsyWr + * 16:23 8:15 Reserved + * 24 7 Error + * 25 6 IOE + * 26 5 SOE + * 27 4 Cmplt + * 28 3 SOP + * 29 2 EOP + * 30 1 EngBusy + * 31 0 Reserved + */ #define RX_NXTDESC_PTR 0x08 /* r */ #define RX_CURBUF_ADDR 0x09 /* r */ @@ -124,17 +133,17 @@ This option defaults to enabled (set) */ #define RX_TAILDESC_PTR 0x0c /* rw */ #define RX_CHNL_CTRL 0x0d /* rw */ /* - 0:7 24:31 IRQTimeout - 8:15 16:23 IRQCount - 16:20 11:15 Reserved - 21 10 0 - 22 9 UseIntOnEnd - 23 8 LdIRQCnt - 24 7 IRQEn - 25:28 3:6 Reserved - 29 2 IrqErrEn - 30 1 IrqDlyEn - 31 0 IrqCoalEn + * 0:7 24:31 IRQTimeout + * 8:15 16:23 IRQCount + * 16:20 11:15 Reserved + * 21 10 0 + * 22 9 UseIntOnEnd + * 23 8 LdIRQCnt + * 24 7 IRQEn + * 25:28 3:6 Reserved + * 29 2 IrqErrEn + * 30 1 IrqDlyEn + * 31 0 IrqCoalEn */ #define RX_IRQ_REG 0x0e /* rw */ #define IRQ_COAL (1 << 0) @@ -142,13 +151,13 @@ This option defaults to enabled (set) */ #define IRQ_ERR (1 << 2) #define IRQ_DMAERR (1 << 7) /* this is not documented ??? */ /* - 0:7 24:31 DltTmrValue - 8:15 16:23 ClscCntrValue - 16:17 14:15 Reserved - 18:21 10:13 ClscCnt - 22:23 8:9 DlyCnt - 24:28 3::7 Reserved -*/ + * 0:7 24:31 DltTmrValue + * 8:15 16:23 ClscCntrValue + * 16:17 14:15 Reserved + * 18:21 10:13 ClscCnt + * 22:23 8:9 DlyCnt + * 24:28 3::7 Reserved + */ #define RX_CHNL_STS 0x0f /* r */ #define CHNL_STS_ENGBUSY (1 << 1) #define CHNL_STS_EOP (1 << 2) @@ -165,23 +174,23 @@ This option defaults to enabled (set) */ #define CHNL_STS_CMPERR (1 << 20) #define CHNL_STS_TAILERR (1 << 21) /* - 0:9 22:31 Reserved - 10 21 TailPErr - 11 20 CmpErr - 12 19 AddrErr - 13 18 NxtPErr - 14 17 CurPErr - 15 16 BsyWr - 16:23 8:15 Reserved - 24 7 Error - 25 6 IOE - 26 5 SOE - 27 4 Cmplt - 28 3 SOP - 29 2 EOP - 30 1 EngBusy - 31 0 Reserved -*/ + * 0:9 22:31 Reserved + * 10 21 TailPErr + * 11 20 CmpErr + * 12 19 AddrErr + * 13 18 NxtPErr + * 14 17 CurPErr + * 15 16 BsyWr + * 16:23 8:15 Reserved + * 24 7 Error + * 25 6 IOE + * 26 5 SOE + * 27 4 Cmplt + * 28 3 SOP + * 29 2 EOP + * 30 1 EngBusy + * 31 0 Reserved + */ #define DMA_CONTROL_REG 0x10 /* rw */ #define DMA_CONTROL_RST (1 << 0) @@ -271,7 +280,7 @@ This option defaults to enabled (set) */ #define XTE_TIE_OFFSET 0x000003A4 /* Interrupt enable */ -/** MII Mamagement Control register (MGTCR) */ +/* MII Management Control register (MGTCR) */ #define XTE_MGTDR_OFFSET 0x000003B0 /* MII data */ #define XTE_MIIMAI_OFFSET 0x000003B4 /* MII control */ @@ -283,7 +292,7 @@ This option defaults to enabled (set) */ #define STS_CTRL_APP0_ERR (1 << 31) #define STS_CTRL_APP0_IRQONEND (1 << 30) -/* undoccumented */ +/* undocumented */ #define STS_CTRL_APP0_STOPONEND (1 << 29) #define STS_CTRL_APP0_CMPLT (1 << 28) #define STS_CTRL_APP0_SOP (1 << 27) @@ -369,18 +378,20 @@ struct temac_local { /* Buffer descriptors */ struct cdmac_bd *tx_bd_v; dma_addr_t tx_bd_p; + u32 tx_bd_num; struct cdmac_bd *rx_bd_v; dma_addr_t rx_bd_p; + u32 rx_bd_num; int tx_bd_ci; - int tx_bd_next; int tx_bd_tail; int rx_bd_ci; int rx_bd_tail; /* DMA channel control setup */ - u32 tx_chnl_ctrl; - u32 rx_chnl_ctrl; + u8 coalesce_count_tx; + u8 coalesce_delay_tx; u8 coalesce_count_rx; + u8 coalesce_delay_rx; struct delayed_work restart_work; }; diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 9461acec6f70..1066420d6a83 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -58,8 +58,11 @@ #include "ll_temac.h" -#define TX_BD_NUM 64 -#define RX_BD_NUM 128 +/* Descriptors defines for Tx and Rx DMA */ +#define TX_BD_NUM_DEFAULT 64 +#define RX_BD_NUM_DEFAULT 1024 +#define TX_BD_NUM_MAX 4096 +#define RX_BD_NUM_MAX 4096 /* --------------------------------------------------------------------- * Low level register access functions @@ -103,7 +106,7 @@ static bool hard_acs_rdy_or_timeout(struct temac_local *lp, ktime_t timeout) */ #define HARD_ACS_RDY_POLL_NS (20 * NSEC_PER_MSEC) -/** +/* * temac_indirect_busywait - Wait for current indirect register access * to complete. */ @@ -114,11 +117,11 @@ int temac_indirect_busywait(struct temac_local *lp) spin_until_cond(hard_acs_rdy_or_timeout(lp, timeout)); if (WARN_ON(!hard_acs_rdy(lp))) return -ETIMEDOUT; - else - return 0; + + return 0; } -/** +/* * temac_indirect_in32 - Indirect register read access. This function * must be called without lp->indirect_lock being held. */ @@ -133,7 +136,7 @@ u32 temac_indirect_in32(struct temac_local *lp, int reg) return val; } -/** +/* * temac_indirect_in32_locked - Indirect register read access. This * function must be called with lp->indirect_lock being held. Use * this together with spin_lock_irqsave/spin_lock_irqrestore to avoid @@ -161,7 +164,7 @@ u32 temac_indirect_in32_locked(struct temac_local *lp, int reg) return temac_ior(lp, XTE_LSW0_OFFSET); } -/** +/* * temac_indirect_out32 - Indirect register write access. This function * must be called without lp->indirect_lock being held. */ @@ -174,7 +177,7 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value) spin_unlock_irqrestore(lp->indirect_lock, flags); } -/** +/* * temac_indirect_out32_locked - Indirect register write access. This * function must be called with lp->indirect_lock being held. Use * this together with spin_lock_irqsave/spin_lock_irqrestore to avoid @@ -199,7 +202,7 @@ void temac_indirect_out32_locked(struct temac_local *lp, int reg, u32 value) WARN_ON(temac_indirect_busywait(lp)); } -/** +/* * temac_dma_in32_* - Memory mapped DMA read, these function expects a * register input that is based on DCR word addresses which are then * converted to memory mapped byte addresses. To be assigned to @@ -215,7 +218,7 @@ static u32 temac_dma_in32_le(struct temac_local *lp, int reg) return ioread32(lp->sdma_regs + (reg << 2)); } -/** +/* * temac_dma_out32_* - Memory mapped DMA read, these function expects * a register input that is based on DCR word addresses which are then * converted to memory mapped byte addresses. To be assigned to @@ -237,7 +240,7 @@ static void temac_dma_out32_le(struct temac_local *lp, int reg, u32 value) */ #ifdef CONFIG_PPC_DCR -/** +/* * temac_dma_dcr_in32 - DCR based DMA read */ static u32 temac_dma_dcr_in(struct temac_local *lp, int reg) @@ -245,7 +248,7 @@ static u32 temac_dma_dcr_in(struct temac_local *lp, int reg) return dcr_read(lp->sdma_dcrs, reg); } -/** +/* * temac_dma_dcr_out32 - DCR based DMA write */ static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32 value) @@ -253,12 +256,12 @@ static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32 value) dcr_write(lp->sdma_dcrs, reg, value); } -/** +/* * temac_dcr_setup - If the DMA is DCR based, then setup the address and * I/O functions */ static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op, - struct device_node *np) + struct device_node *np) { unsigned int dcrs; @@ -283,14 +286,14 @@ static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op, * such as with MicroBlaze and x86 */ static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op, - struct device_node *np) + struct device_node *np) { return -1; } #endif -/** +/* * temac_dma_bd_release - Release buffer descriptor rings */ static void temac_dma_bd_release(struct net_device *ndev) @@ -301,26 +304,24 @@ static void temac_dma_bd_release(struct net_device *ndev) /* Reset Local Link (DMA) */ lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); - for (i = 0; i < RX_BD_NUM; i++) { + for (i = 0; i < lp->rx_bd_num; i++) { if (!lp->rx_skb[i]) break; - else { - dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys, - XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE); - dev_kfree_skb(lp->rx_skb[i]); - } + dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys, + XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE); + dev_kfree_skb(lp->rx_skb[i]); } if (lp->rx_bd_v) dma_free_coherent(ndev->dev.parent, - sizeof(*lp->rx_bd_v) * RX_BD_NUM, - lp->rx_bd_v, lp->rx_bd_p); + sizeof(*lp->rx_bd_v) * lp->rx_bd_num, + lp->rx_bd_v, lp->rx_bd_p); if (lp->tx_bd_v) dma_free_coherent(ndev->dev.parent, - sizeof(*lp->tx_bd_v) * TX_BD_NUM, - lp->tx_bd_v, lp->tx_bd_p); + sizeof(*lp->tx_bd_v) * lp->tx_bd_num, + lp->tx_bd_v, lp->tx_bd_p); } -/** +/* * temac_dma_bd_init - Setup buffer descriptor rings */ static int temac_dma_bd_init(struct net_device *ndev) @@ -330,36 +331,37 @@ static int temac_dma_bd_init(struct net_device *ndev) dma_addr_t skb_dma_addr; int i; - lp->rx_skb = devm_kcalloc(&ndev->dev, RX_BD_NUM, sizeof(*lp->rx_skb), - GFP_KERNEL); + lp->rx_skb = devm_kcalloc(&ndev->dev, lp->rx_bd_num, + sizeof(*lp->rx_skb), GFP_KERNEL); if (!lp->rx_skb) goto out; /* allocate the tx and rx ring buffer descriptors. */ /* returns a virtual address and a physical address. */ lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, - sizeof(*lp->tx_bd_v) * TX_BD_NUM, + sizeof(*lp->tx_bd_v) * lp->tx_bd_num, &lp->tx_bd_p, GFP_KERNEL); if (!lp->tx_bd_v) goto out; lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, - sizeof(*lp->rx_bd_v) * RX_BD_NUM, + sizeof(*lp->rx_bd_v) * lp->rx_bd_num, &lp->rx_bd_p, GFP_KERNEL); if (!lp->rx_bd_v) goto out; - for (i = 0; i < TX_BD_NUM; i++) { + for (i = 0; i < lp->tx_bd_num; i++) { lp->tx_bd_v[i].next = cpu_to_be32(lp->tx_bd_p - + sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM)); + + sizeof(*lp->tx_bd_v) * ((i + 1) % lp->tx_bd_num)); } - for (i = 0; i < RX_BD_NUM; i++) { + for (i = 0; i < lp->rx_bd_num; i++) { lp->rx_bd_v[i].next = cpu_to_be32(lp->rx_bd_p - + sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM)); + + sizeof(*lp->rx_bd_v) * ((i + 1) % lp->rx_bd_num)); - skb = netdev_alloc_skb_ip_align(ndev, - XTE_MAX_JUMBO_FRAME_SIZE); + skb = __netdev_alloc_skb_ip_align(ndev, + XTE_MAX_JUMBO_FRAME_SIZE, + GFP_KERNEL); if (!skb) goto out; @@ -376,21 +378,22 @@ static int temac_dma_bd_init(struct net_device *ndev) } /* Configure DMA channel (irq setup) */ - lp->dma_out(lp, TX_CHNL_CTRL, lp->tx_chnl_ctrl | + lp->dma_out(lp, TX_CHNL_CTRL, + lp->coalesce_delay_tx << 24 | lp->coalesce_count_tx << 16 | 0x00000400 | // Use 1 Bit Wide Counters. Currently Not Used! CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN | CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN); - lp->dma_out(lp, RX_CHNL_CTRL, lp->rx_chnl_ctrl | + lp->dma_out(lp, RX_CHNL_CTRL, + lp->coalesce_delay_rx << 24 | lp->coalesce_count_rx << 16 | CHNL_CTRL_IRQ_IOE | CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN | CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN); /* Init descriptor indexes */ lp->tx_bd_ci = 0; - lp->tx_bd_next = 0; lp->tx_bd_tail = 0; lp->rx_bd_ci = 0; - lp->rx_bd_tail = RX_BD_NUM - 1; + lp->rx_bd_tail = lp->rx_bd_num - 1; /* Enable RX DMA transfers */ wmb(); @@ -425,7 +428,8 @@ static void temac_do_set_mac_address(struct net_device *ndev) (ndev->dev_addr[2] << 16) | (ndev->dev_addr[3] << 24)); /* There are reserved bits in EUAW1 - * so don't affect them Set MAC bits [47:32] in EUAW1 */ + * so don't affect them Set MAC bits [47:32] in EUAW1 + */ temac_indirect_out32_locked(lp, XTE_UAW1_OFFSET, (ndev->dev_addr[4] & 0x000000ff) | (ndev->dev_addr[5] << 8)); @@ -434,7 +438,7 @@ static void temac_do_set_mac_address(struct net_device *ndev) static int temac_init_mac_address(struct net_device *ndev, const void *address) { - ether_addr_copy(ndev->dev_addr, address); + eth_hw_addr_set(ndev, address); if (!is_valid_ether_addr(ndev->dev_addr)) eth_hw_addr_random(ndev); temac_do_set_mac_address(ndev); @@ -447,7 +451,7 @@ static int temac_set_mac_address(struct net_device *ndev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - memcpy(ndev->dev_addr, addr->sa_data, ETH_ALEN); + eth_hw_addr_set(ndev, addr->sa_data); temac_do_set_mac_address(ndev); return 0; } @@ -525,71 +529,71 @@ static struct temac_option { { .opt = XTE_OPTION_JUMBO, .reg = XTE_RXC1_OFFSET, - .m_or =XTE_RXC1_RXJMBO_MASK, + .m_or = XTE_RXC1_RXJMBO_MASK, }, /* Turn on VLAN packet support for both Rx and Tx */ { .opt = XTE_OPTION_VLAN, .reg = XTE_TXC_OFFSET, - .m_or =XTE_TXC_TXVLAN_MASK, + .m_or = XTE_TXC_TXVLAN_MASK, }, { .opt = XTE_OPTION_VLAN, .reg = XTE_RXC1_OFFSET, - .m_or =XTE_RXC1_RXVLAN_MASK, + .m_or = XTE_RXC1_RXVLAN_MASK, }, /* Turn on FCS stripping on receive packets */ { .opt = XTE_OPTION_FCS_STRIP, .reg = XTE_RXC1_OFFSET, - .m_or =XTE_RXC1_RXFCS_MASK, + .m_or = XTE_RXC1_RXFCS_MASK, }, /* Turn on FCS insertion on transmit packets */ { .opt = XTE_OPTION_FCS_INSERT, .reg = XTE_TXC_OFFSET, - .m_or =XTE_TXC_TXFCS_MASK, + .m_or = XTE_TXC_TXFCS_MASK, }, /* Turn on length/type field checking on receive packets */ { .opt = XTE_OPTION_LENTYPE_ERR, .reg = XTE_RXC1_OFFSET, - .m_or =XTE_RXC1_RXLT_MASK, + .m_or = XTE_RXC1_RXLT_MASK, }, /* Turn on flow control */ { .opt = XTE_OPTION_FLOW_CONTROL, .reg = XTE_FCC_OFFSET, - .m_or =XTE_FCC_RXFLO_MASK, + .m_or = XTE_FCC_RXFLO_MASK, }, /* Turn on flow control */ { .opt = XTE_OPTION_FLOW_CONTROL, .reg = XTE_FCC_OFFSET, - .m_or =XTE_FCC_TXFLO_MASK, + .m_or = XTE_FCC_TXFLO_MASK, }, /* Turn on promiscuous frame filtering (all frames are received ) */ { .opt = XTE_OPTION_PROMISC, .reg = XTE_AFM_OFFSET, - .m_or =XTE_AFM_EPPRM_MASK, + .m_or = XTE_AFM_EPPRM_MASK, }, /* Enable transmitter if not already enabled */ { .opt = XTE_OPTION_TXEN, .reg = XTE_TXC_OFFSET, - .m_or =XTE_TXC_TXEN_MASK, + .m_or = XTE_TXC_TXEN_MASK, }, /* Enable receiver? */ { .opt = XTE_OPTION_RXEN, .reg = XTE_RXC1_OFFSET, - .m_or =XTE_RXC1_RXEN_MASK, + .m_or = XTE_RXC1_RXEN_MASK, }, {} }; -/** +/* * temac_setoptions */ static u32 temac_setoptions(struct net_device *ndev, u32 options) @@ -636,7 +640,7 @@ static void temac_device_reset(struct net_device *ndev) udelay(1); if (--timeout == 0) { dev_err(&ndev->dev, - "temac_device_reset RX reset timeout!!\n"); + "%s RX reset timeout!!\n", __func__); break; } } @@ -648,7 +652,7 @@ static void temac_device_reset(struct net_device *ndev) udelay(1); if (--timeout == 0) { dev_err(&ndev->dev, - "temac_device_reset TX reset timeout!!\n"); + "%s TX reset timeout!!\n", __func__); break; } } @@ -667,7 +671,7 @@ static void temac_device_reset(struct net_device *ndev) udelay(1); if (--timeout == 0) { dev_err(&ndev->dev, - "temac_device_reset DMA reset timeout!!\n"); + "%s DMA reset timeout!!\n", __func__); break; } } @@ -675,7 +679,7 @@ static void temac_device_reset(struct net_device *ndev) if (temac_dma_bd_init(ndev)) { dev_err(&ndev->dev, - "temac_device_reset descriptor allocation failed\n"); + "%s descriptor allocation failed\n", __func__); } spin_lock_irqsave(lp->indirect_lock, flags); @@ -686,7 +690,8 @@ static void temac_device_reset(struct net_device *ndev) spin_unlock_irqrestore(lp->indirect_lock, flags); /* Sync default options with HW - * but leave receiver and transmitter disabled. */ + * but leave receiver and transmitter disabled. + */ temac_setoptions(ndev, lp->options & ~(XTE_OPTION_TXEN | XTE_OPTION_RXEN)); @@ -718,9 +723,15 @@ static void temac_adjust_link(struct net_device *ndev) mii_speed &= ~XTE_EMCFG_LINKSPD_MASK; switch (phy->speed) { - case SPEED_1000: mii_speed |= XTE_EMCFG_LINKSPD_1000; break; - case SPEED_100: mii_speed |= XTE_EMCFG_LINKSPD_100; break; - case SPEED_10: mii_speed |= XTE_EMCFG_LINKSPD_10; break; + case SPEED_1000: + mii_speed |= XTE_EMCFG_LINKSPD_1000; + break; + case SPEED_100: + mii_speed |= XTE_EMCFG_LINKSPD_100; + break; + case SPEED_10: + mii_speed |= XTE_EMCFG_LINKSPD_10; + break; } /* Write new speed setting out to TEMAC */ @@ -770,12 +781,15 @@ static void temac_start_xmit_done(struct net_device *ndev) stat = be32_to_cpu(cur_p->app0); while (stat & STS_CTRL_APP0_CMPLT) { + /* Make sure that the other fields are read after bd is + * released by dma + */ + rmb(); dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys), be32_to_cpu(cur_p->len), DMA_TO_DEVICE); skb = (struct sk_buff *)ptr_from_txbd(cur_p); if (skb) dev_consume_skb_irq(skb); - cur_p->app0 = 0; cur_p->app1 = 0; cur_p->app2 = 0; cur_p->app3 = 0; @@ -784,8 +798,14 @@ static void temac_start_xmit_done(struct net_device *ndev) ndev->stats.tx_packets++; ndev->stats.tx_bytes += be32_to_cpu(cur_p->len); + /* app0 must be visible last, as it is used to flag + * availability of the bd + */ + smp_mb(); + cur_p->app0 = 0; + lp->tx_bd_ci++; - if (lp->tx_bd_ci >= TX_BD_NUM) + if (lp->tx_bd_ci >= lp->tx_bd_num) lp->tx_bd_ci = 0; cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; @@ -810,8 +830,11 @@ static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag) if (cur_p->app0) return NETDEV_TX_BUSY; + /* Make sure to read next bd app0 after this one */ + rmb(); + tail++; - if (tail >= TX_BD_NUM) + if (tail >= lp->tx_bd_num) tail = 0; cur_p = &lp->tx_bd_v[tail]; @@ -826,14 +849,13 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct temac_local *lp = netdev_priv(ndev); struct cdmac_bd *cur_p; - dma_addr_t start_p, tail_p, skb_dma_addr; + dma_addr_t tail_p, skb_dma_addr; int ii; unsigned long num_frag; skb_frag_t *frag; num_frag = skb_shinfo(skb)->nr_frags; frag = &skb_shinfo(skb)->frags[0]; - start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; if (temac_check_tx_bd_space(lp, num_frag + 1)) { @@ -846,7 +868,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) smp_mb(); /* Space might have just been freed - check again */ - if (temac_check_tx_bd_space(lp, num_frag)) + if (temac_check_tx_bd_space(lp, num_frag + 1)) return NETDEV_TX_BUSY; netif_wake_queue(ndev); @@ -873,10 +895,9 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_OK; } cur_p->phys = cpu_to_be32(skb_dma_addr); - ptr_to_txbd((void *)skb, cur_p); for (ii = 0; ii < num_frag; ii++) { - if (++lp->tx_bd_tail >= TX_BD_NUM) + if (++lp->tx_bd_tail >= lp->tx_bd_num) lp->tx_bd_tail = 0; cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; @@ -886,7 +907,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) DMA_TO_DEVICE); if (dma_mapping_error(ndev->dev.parent, skb_dma_addr)) { if (--lp->tx_bd_tail < 0) - lp->tx_bd_tail = TX_BD_NUM - 1; + lp->tx_bd_tail = lp->tx_bd_num - 1; cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; while (--ii >= 0) { --frag; @@ -895,7 +916,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) skb_frag_size(frag), DMA_TO_DEVICE); if (--lp->tx_bd_tail < 0) - lp->tx_bd_tail = TX_BD_NUM - 1; + lp->tx_bd_tail = lp->tx_bd_num - 1; cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; } dma_unmap_single(ndev->dev.parent, @@ -912,9 +933,14 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) } cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_EOP); + /* Mark last fragment with skb address, so it can be consumed + * in temac_start_xmit_done() + */ + ptr_to_txbd((void *)skb, cur_p); + tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; lp->tx_bd_tail++; - if (lp->tx_bd_tail >= TX_BD_NUM) + if (lp->tx_bd_tail >= lp->tx_bd_num) lp->tx_bd_tail = 0; skb_tx_timestamp(skb); @@ -923,6 +949,9 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) wmb(); lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ + if (temac_check_tx_bd_space(lp, MAX_SKB_FRAGS + 1)) + netif_stop_queue(ndev); + return NETDEV_TX_OK; } @@ -934,7 +963,7 @@ static int ll_temac_recv_buffers_available(struct temac_local *lp) return 0; available = 1 + lp->rx_bd_tail - lp->rx_bd_ci; if (available <= 0) - available += RX_BD_NUM; + available += lp->rx_bd_num; return available; } @@ -984,9 +1013,8 @@ static void ll_temac_recv(struct net_device *ndev) if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) && (skb->protocol == htons(ETH_P_IP)) && (skb->len > 64)) { - /* Convert from device endianness (be32) to cpu - * endiannes, and if necessary swap the bytes + * endianness, and if necessary swap the bytes * (back) for proper IP checksum byte order * (be16). */ @@ -1003,7 +1031,7 @@ static void ll_temac_recv(struct net_device *ndev) ndev->stats.rx_bytes += length; rx_bd = lp->rx_bd_ci; - if (++lp->rx_bd_ci >= RX_BD_NUM) + if (++lp->rx_bd_ci >= lp->rx_bd_num) lp->rx_bd_ci = 0; } while (rx_bd != lp->rx_bd_tail); @@ -1034,7 +1062,7 @@ static void ll_temac_recv(struct net_device *ndev) dma_addr_t skb_dma_addr; rx_bd = lp->rx_bd_tail + 1; - if (rx_bd >= RX_BD_NUM) + if (rx_bd >= lp->rx_bd_num) rx_bd = 0; bd = &lp->rx_bd_v[rx_bd]; @@ -1215,7 +1243,7 @@ static const struct net_device_ops temac_netdev_ops = { .ndo_set_rx_mode = temac_set_multicast_list, .ndo_set_mac_address = temac_set_mac_address, .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = phy_do_ioctl_running, + .ndo_eth_ioctl = phy_do_ioctl_running, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = temac_poll_controller, #endif @@ -1250,13 +1278,108 @@ static const struct attribute_group temac_attr_group = { .attrs = temac_device_attrs, }; -/* ethtool support */ +/* --------------------------------------------------------------------- + * ethtool support + */ + +static void +ll_temac_ethtools_get_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering, + struct kernel_ethtool_ringparam *kernel_ering, + struct netlink_ext_ack *extack) +{ + struct temac_local *lp = netdev_priv(ndev); + + ering->rx_max_pending = RX_BD_NUM_MAX; + ering->rx_mini_max_pending = 0; + ering->rx_jumbo_max_pending = 0; + ering->tx_max_pending = TX_BD_NUM_MAX; + ering->rx_pending = lp->rx_bd_num; + ering->rx_mini_pending = 0; + ering->rx_jumbo_pending = 0; + ering->tx_pending = lp->tx_bd_num; +} + +static int +ll_temac_ethtools_set_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering, + struct kernel_ethtool_ringparam *kernel_ering, + struct netlink_ext_ack *extack) +{ + struct temac_local *lp = netdev_priv(ndev); + + if (ering->rx_pending > RX_BD_NUM_MAX || + ering->rx_mini_pending || + ering->rx_jumbo_pending || + ering->rx_pending > TX_BD_NUM_MAX) + return -EINVAL; + + if (netif_running(ndev)) + return -EBUSY; + + lp->rx_bd_num = ering->rx_pending; + lp->tx_bd_num = ering->tx_pending; + return 0; +} + +static int +ll_temac_ethtools_get_coalesce(struct net_device *ndev, + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct temac_local *lp = netdev_priv(ndev); + + ec->rx_max_coalesced_frames = lp->coalesce_count_rx; + ec->tx_max_coalesced_frames = lp->coalesce_count_tx; + ec->rx_coalesce_usecs = (lp->coalesce_delay_rx * 512) / 100; + ec->tx_coalesce_usecs = (lp->coalesce_delay_tx * 512) / 100; + return 0; +} + +static int +ll_temac_ethtools_set_coalesce(struct net_device *ndev, + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct temac_local *lp = netdev_priv(ndev); + + if (netif_running(ndev)) { + netdev_err(ndev, + "Please stop netif before applying configuration\n"); + return -EFAULT; + } + + if (ec->rx_max_coalesced_frames) + lp->coalesce_count_rx = ec->rx_max_coalesced_frames; + if (ec->tx_max_coalesced_frames) + lp->coalesce_count_tx = ec->tx_max_coalesced_frames; + /* With typical LocalLink clock speed of 200 MHz and + * C_PRESCALAR=1023, each delay count corresponds to 5.12 us. + */ + if (ec->rx_coalesce_usecs) + lp->coalesce_delay_rx = + min(255U, (ec->rx_coalesce_usecs * 100) / 512); + if (ec->tx_coalesce_usecs) + lp->coalesce_delay_tx = + min(255U, (ec->tx_coalesce_usecs * 100) / 512); + + return 0; +} + static const struct ethtool_ops temac_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES, .nway_reset = phy_ethtool_nway_reset, .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, + .get_ringparam = ll_temac_ethtools_get_ringparam, + .set_ringparam = ll_temac_ethtools_set_ringparam, + .get_coalesce = ll_temac_ethtools_get_coalesce, + .set_coalesce = ll_temac_ethtools_set_coalesce, }; static int temac_probe(struct platform_device *pdev) @@ -1265,8 +1388,7 @@ static int temac_probe(struct platform_device *pdev) struct device_node *temac_np = dev_of_node(&pdev->dev), *dma_np; struct temac_local *lp; struct net_device *ndev; - struct resource *res; - const void *addr; + u8 addr[ETH_ALEN]; __be32 *p; bool little_endian; int rc = 0; @@ -1300,6 +1422,8 @@ static int temac_probe(struct platform_device *pdev) lp->ndev = ndev; lp->dev = &pdev->dev; lp->options = XTE_OPTION_DEFAULTS; + lp->rx_bd_num = RX_BD_NUM_DEFAULT; + lp->tx_bd_num = TX_BD_NUM_DEFAULT; spin_lock_init(&lp->rx_lock); INIT_DELAYED_WORK(&lp->restart_work, ll_temac_restart_work_func); @@ -1315,16 +1439,16 @@ static int temac_probe(struct platform_device *pdev) lp->indirect_lock = devm_kmalloc(&pdev->dev, sizeof(*lp->indirect_lock), GFP_KERNEL); + if (!lp->indirect_lock) + return -ENOMEM; spin_lock_init(lp->indirect_lock); } /* map device registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - lp->regs = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); + lp->regs = devm_platform_ioremap_resource_byname(pdev, 0); if (IS_ERR(lp->regs)) { dev_err(&pdev->dev, "could not map TEMAC registers\n"); - return PTR_ERR(lp->regs); + return -ENOMEM; } /* Select register access functions with the specified @@ -1364,6 +1488,14 @@ static int temac_probe(struct platform_device *pdev) /* Can checksum TCP/UDP over IPv4. */ ndev->features |= NETIF_F_IP_CSUM; + /* Defaults for IRQ delay/coalescing setup. These are + * configuration values, so does not belong in device-tree. + */ + lp->coalesce_delay_tx = 0x10; + lp->coalesce_count_tx = 0x22; + lp->coalesce_delay_rx = 0xff; + lp->coalesce_count_rx = 0x07; + /* Setup LocalLink DMA */ if (temac_np) { /* Find the DMA node, map the DMA registers, and @@ -1388,7 +1520,7 @@ static int temac_probe(struct platform_device *pdev) of_node_put(dma_np); return PTR_ERR(lp->sdma_regs); } - if (of_get_property(dma_np, "little-endian", NULL)) { + if (of_property_read_bool(dma_np, "little-endian")) { lp->dma_in = temac_dma_in32_le; lp->dma_out = temac_dma_out32_le; } else { @@ -1402,21 +1534,11 @@ static int temac_probe(struct platform_device *pdev) lp->rx_irq = irq_of_parse_and_map(dma_np, 0); lp->tx_irq = irq_of_parse_and_map(dma_np, 1); - /* Use defaults for IRQ delay/coalescing setup. These - * are configuration values, so does not belong in - * device-tree. - */ - lp->tx_chnl_ctrl = 0x10220000; - lp->rx_chnl_ctrl = 0xff070000; - lp->coalesce_count_rx = 0x07; - /* Finished with the DMA node; drop the reference */ of_node_put(dma_np); } else if (pdata) { /* 2nd memory resource specifies DMA registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - lp->sdma_regs = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); + lp->sdma_regs = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(lp->sdma_regs)) { dev_err(&pdev->dev, "could not map DMA registers\n"); @@ -1435,37 +1557,28 @@ static int temac_probe(struct platform_device *pdev) lp->tx_irq = platform_get_irq(pdev, 1); /* IRQ delay/coalescing setup */ - if (pdata->tx_irq_timeout || pdata->tx_irq_count) - lp->tx_chnl_ctrl = (pdata->tx_irq_timeout << 24) | - (pdata->tx_irq_count << 16); - else - lp->tx_chnl_ctrl = 0x10220000; + if (pdata->tx_irq_timeout || pdata->tx_irq_count) { + lp->coalesce_delay_tx = pdata->tx_irq_timeout; + lp->coalesce_count_tx = pdata->tx_irq_count; + } if (pdata->rx_irq_timeout || pdata->rx_irq_count) { - lp->rx_chnl_ctrl = (pdata->rx_irq_timeout << 24) | - (pdata->rx_irq_count << 16); + lp->coalesce_delay_rx = pdata->rx_irq_timeout; lp->coalesce_count_rx = pdata->rx_irq_count; - } else { - lp->rx_chnl_ctrl = 0xff070000; - lp->coalesce_count_rx = 0x07; } } /* Error handle returned DMA RX and TX interrupts */ - if (lp->rx_irq < 0) { - if (lp->rx_irq != -EPROBE_DEFER) - dev_err(&pdev->dev, "could not get DMA RX irq\n"); - return lp->rx_irq; - } - if (lp->tx_irq < 0) { - if (lp->tx_irq != -EPROBE_DEFER) - dev_err(&pdev->dev, "could not get DMA TX irq\n"); - return lp->tx_irq; - } + if (lp->rx_irq < 0) + return dev_err_probe(&pdev->dev, lp->rx_irq, + "could not get DMA RX irq\n"); + if (lp->tx_irq < 0) + return dev_err_probe(&pdev->dev, lp->tx_irq, + "could not get DMA TX irq\n"); if (temac_np) { /* Retrieve the MAC address */ - addr = of_get_mac_address(temac_np); - if (IS_ERR(addr)) { + rc = of_get_mac_address(temac_np, addr); + if (rc) { dev_err(&pdev->dev, "could not find MAC address\n"); return -ENODEV; } diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c index 6fd2dea4e60f..2371c072b53f 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c +++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c @@ -29,7 +29,8 @@ static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg) /* Write the PHY address to the MIIM Access Initiator register. * When the transfer completes, the PHY register value will appear - * in the LSW0 register */ + * in the LSW0 register + */ spin_lock_irqsave(lp->indirect_lock, flags); temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg); rc = temac_indirect_in32_locked(lp, XTE_MIIMAI_OFFSET); @@ -88,7 +89,8 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev) } /* Enable the MDIO bus by asserting the enable bit and writing - * in the clock config */ + * in the clock config + */ temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div); bus = devm_mdiobus_alloc(&pdev->dev); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h index 2dacfc85b3ba..6370c447ac5c 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h @@ -119,11 +119,11 @@ #define XAXIDMA_IRQ_ERROR_MASK 0x00004000 /* Error interrupt */ #define XAXIDMA_IRQ_ALL_MASK 0x00007000 /* All interrupts */ -/* Default TX/RX Threshold and waitbound values for SGDMA mode */ +/* Default TX/RX Threshold and delay timer values for SGDMA mode */ #define XAXIDMA_DFT_TX_THRESHOLD 24 -#define XAXIDMA_DFT_TX_WAITBOUND 254 -#define XAXIDMA_DFT_RX_THRESHOLD 24 -#define XAXIDMA_DFT_RX_WAITBOUND 254 +#define XAXIDMA_DFT_TX_USEC 50 +#define XAXIDMA_DFT_RX_THRESHOLD 1 +#define XAXIDMA_DFT_RX_USEC 50 #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */ @@ -161,17 +161,11 @@ #define XAE_FCC_OFFSET 0x0000040C /* Flow Control Configuration */ #define XAE_EMMC_OFFSET 0x00000410 /* EMAC mode configuration */ #define XAE_PHYC_OFFSET 0x00000414 /* RGMII/SGMII configuration */ +#define XAE_ID_OFFSET 0x000004F8 /* Identification register */ #define XAE_MDIO_MC_OFFSET 0x00000500 /* MII Management Config */ #define XAE_MDIO_MCR_OFFSET 0x00000504 /* MII Management Control */ #define XAE_MDIO_MWD_OFFSET 0x00000508 /* MII Management Write Data */ #define XAE_MDIO_MRD_OFFSET 0x0000050C /* MII Management Read Data */ -#define XAE_MDIO_MIS_OFFSET 0x00000600 /* MII Management Interrupt Status */ -/* MII Mgmt Interrupt Pending register offset */ -#define XAE_MDIO_MIP_OFFSET 0x00000620 -/* MII Management Interrupt Enable register offset */ -#define XAE_MDIO_MIE_OFFSET 0x00000640 -/* MII Management Interrupt Clear register offset. */ -#define XAE_MDIO_MIC_OFFSET 0x00000660 #define XAE_UAW0_OFFSET 0x00000700 /* Unicast address word 0 */ #define XAE_UAW1_OFFSET 0x00000704 /* Unicast address word 1 */ #define XAE_FMI_OFFSET 0x00000708 /* Filter Mask Index */ @@ -192,7 +186,7 @@ #define XAE_RAF_TXVSTRPMODE_MASK 0x00000180 /* Tx VLAN STRIP mode */ #define XAE_RAF_RXVSTRPMODE_MASK 0x00000600 /* Rx VLAN STRIP mode */ #define XAE_RAF_NEWFNCENBL_MASK 0x00000800 /* New function mode */ -/* Exteneded Multicast Filtering mode */ +/* Extended Multicast Filtering mode */ #define XAE_RAF_EMULTIFLTRENBL_MASK 0x00001000 #define XAE_RAF_STATSRST_MASK 0x00002000 /* Stats. Counter Reset */ #define XAE_RAF_RXBADFRMEN_MASK 0x00004000 /* Recv Bad Frame Enable */ @@ -335,6 +329,7 @@ #define XAE_FEATURE_PARTIAL_TX_CSUM (1 << 1) #define XAE_FEATURE_FULL_RX_CSUM (1 << 2) #define XAE_FEATURE_FULL_TX_CSUM (1 << 3) +#define XAE_FEATURE_DMA_64BIT (1 << 4) #define XAE_NO_CSUM_OFFLOAD 0 @@ -344,12 +339,16 @@ #define DELAY_OF_ONE_MILLISEC 1000 +/* Xilinx PCS/PMA PHY register for switching 1000BaseX or SGMII */ +#define XLNX_MII_STD_SELECT_REG 0x11 +#define XLNX_MII_STD_SELECT_SGMII BIT(0) + /** * struct axidma_bd - Axi Dma buffer descriptor layout * @next: MM2S/S2MM Next Descriptor Pointer - * @reserved1: Reserved and not used + * @next_msb: MM2S/S2MM Next Descriptor Pointer (high 32 bits) * @phys: MM2S/S2MM Buffer Address - * @reserved2: Reserved and not used + * @phys_msb: MM2S/S2MM Buffer Address (high 32 bits) * @reserved3: Reserved and not used * @reserved4: Reserved and not used * @cntrl: MM2S/S2MM Control value @@ -362,9 +361,9 @@ */ struct axidma_bd { u32 next; /* Physical address of next buffer descriptor */ - u32 reserved1; + u32 next_msb; /* high 32 bits for IP >= v7.1, reserved on older IP */ u32 phys; - u32 reserved2; + u32 phys_msb; /* for IP >= v7.1, reserved for older IP */ u32 reserved3; u32 reserved4; u32 cntrl; @@ -377,33 +376,54 @@ struct axidma_bd { struct sk_buff *skb; } __aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT); +#define XAE_NUM_MISC_CLOCKS 3 + /** * struct axienet_local - axienet private per device data * @ndev: Pointer for net_device to which it will be attached. * @dev: Pointer to device structure * @phy_node: Pointer to device node structure + * @phylink: Pointer to phylink instance + * @phylink_config: phylink configuration settings + * @pcs_phy: Reference to PCS/PMA PHY if used + * @pcs: phylink pcs structure for PCS PHY + * @switch_x_sgmii: Whether switchable 1000BaseX/SGMII mode is enabled in the core + * @axi_clk: AXI4-Lite bus clock + * @misc_clks: Misc ethernet clocks (AXI4-Stream, Ref, MGT clocks) * @mii_bus: Pointer to MII bus structure + * @mii_clk_div: MII bus clock divider value * @regs_start: Resource start for axienet device addresses * @regs: Base address for the axienet_local device address space * @dma_regs: Base address for the axidma device address space - * @dma_err_tasklet: Tasklet structure to process Axi DMA errors + * @napi_rx: NAPI RX control structure + * @rx_dma_cr: Nominal content of RX DMA control register + * @rx_bd_v: Virtual address of the RX buffer descriptor ring + * @rx_bd_p: Physical address(start address) of the RX buffer descr. ring + * @rx_bd_num: Size of RX buffer descriptor ring + * @rx_bd_ci: Stores the index of the Rx buffer descriptor in the ring being + * accessed currently. + * @rx_packets: RX packet count for statistics + * @rx_bytes: RX byte count for statistics + * @rx_stat_sync: Synchronization object for RX stats + * @napi_tx: NAPI TX control structure + * @tx_dma_cr: Nominal content of TX DMA control register + * @tx_bd_v: Virtual address of the TX buffer descriptor ring + * @tx_bd_p: Physical address(start address) of the TX buffer descr. ring + * @tx_bd_num: Size of TX buffer descriptor ring + * @tx_bd_ci: Stores the next Tx buffer descriptor in the ring that may be + * complete. Only updated at runtime by TX NAPI poll. + * @tx_bd_tail: Stores the index of the next Tx buffer descriptor in the ring + * to be populated. + * @tx_packets: TX packet count for statistics + * @tx_bytes: TX byte count for statistics + * @tx_stat_sync: Synchronization object for TX stats + * @dma_err_task: Work structure to process Axi DMA errors * @tx_irq: Axidma TX IRQ number * @rx_irq: Axidma RX IRQ number + * @eth_irq: Ethernet core IRQ number * @phy_mode: Phy type to identify between MII/GMII/RGMII/SGMII/1000 Base-X * @options: AxiEthernet option word - * @last_link: Phy link state in which the PHY was negotiated earlier * @features: Stores the extended features supported by the axienet hw - * @tx_bd_v: Virtual address of the TX buffer descriptor ring - * @tx_bd_p: Physical address(start address) of the TX buffer descr. ring - * @rx_bd_v: Virtual address of the RX buffer descriptor ring - * @rx_bd_p: Physical address(start address) of the RX buffer descr. ring - * @tx_bd_ci: Stores the index of the Tx buffer descriptor in the ring being - * accessed currently. Used while alloc. BDs before a TX starts - * @tx_bd_tail: Stores the index of the Tx buffer descriptor in the ring being - * accessed currently. Used while processing BDs after the TX - * completed. - * @rx_bd_ci: Stores the index of the Rx buffer descriptor in the ring being - * accessed currently. * @max_frm_size: Stores the maximum size of the frame that can be that * Txed/Rxed in the existing hardware. If jumbo option is * supported, the maximum frame size would be 9k. Else it is @@ -412,50 +432,63 @@ struct axidma_bd { * @csum_offload_on_tx_path: Stores the checksum selection on TX side. * @csum_offload_on_rx_path: Stores the checksum selection on RX side. * @coalesce_count_rx: Store the irq coalesce on RX side. + * @coalesce_usec_rx: IRQ coalesce delay for RX * @coalesce_count_tx: Store the irq coalesce on TX side. + * @coalesce_usec_tx: IRQ coalesce delay for TX */ struct axienet_local { struct net_device *ndev; struct device *dev; - /* Connection to PHY device */ - struct device_node *phy_node; - struct phylink *phylink; struct phylink_config phylink_config; - /* Clock for AXI bus */ - struct clk *clk; + struct mdio_device *pcs_phy; + struct phylink_pcs pcs; + + bool switch_x_sgmii; + + struct clk *axi_clk; + struct clk_bulk_data misc_clks[XAE_NUM_MISC_CLOCKS]; - /* MDIO bus data */ - struct mii_bus *mii_bus; /* MII bus reference */ + struct mii_bus *mii_bus; + u8 mii_clk_div; - /* IO registers, dma functions and IRQs */ resource_size_t regs_start; void __iomem *regs; void __iomem *dma_regs; - struct tasklet_struct dma_err_tasklet; + struct napi_struct napi_rx; + u32 rx_dma_cr; + struct axidma_bd *rx_bd_v; + dma_addr_t rx_bd_p; + u32 rx_bd_num; + u32 rx_bd_ci; + u64_stats_t rx_packets; + u64_stats_t rx_bytes; + struct u64_stats_sync rx_stat_sync; + + struct napi_struct napi_tx; + u32 tx_dma_cr; + struct axidma_bd *tx_bd_v; + dma_addr_t tx_bd_p; + u32 tx_bd_num; + u32 tx_bd_ci; + u32 tx_bd_tail; + u64_stats_t tx_packets; + u64_stats_t tx_bytes; + struct u64_stats_sync tx_stat_sync; + + struct work_struct dma_err_task; int tx_irq; int rx_irq; int eth_irq; phy_interface_t phy_mode; - u32 options; /* Current options word */ + u32 options; u32 features; - /* Buffer descriptors */ - struct axidma_bd *tx_bd_v; - dma_addr_t tx_bd_p; - u32 tx_bd_num; - struct axidma_bd *rx_bd_v; - dma_addr_t rx_bd_p; - u32 rx_bd_num; - u32 tx_bd_ci; - u32 tx_bd_tail; - u32 rx_bd_ci; - u32 max_frm_size; u32 rxmem; @@ -463,7 +496,9 @@ struct axienet_local { int csum_offload_on_rx_path; u32 coalesce_count_rx; + u32 coalesce_usec_rx; u32 coalesce_count_tx; + u32 coalesce_usec_tx; }; /** @@ -497,6 +532,18 @@ static inline u32 axinet_ior_read_mcr(struct axienet_local *lp) return axienet_ior(lp, XAE_MDIO_MCR_OFFSET); } +static inline void axienet_lock_mii(struct axienet_local *lp) +{ + if (lp->mii_bus) + mutex_lock(&lp->mii_bus->mdio_lock); +} + +static inline void axienet_unlock_mii(struct axienet_local *lp) +{ + if (lp->mii_bus) + mutex_unlock(&lp->mii_bus->mdio_lock); +} + /** * axienet_iow - Memory mapped Axi Ethernet register write * @lp: Pointer to axienet local structure @@ -512,6 +559,57 @@ static inline void axienet_iow(struct axienet_local *lp, off_t offset, iowrite32(value, lp->regs + offset); } +/** + * axienet_dma_out32 - Memory mapped Axi DMA register write. + * @lp: Pointer to axienet local structure + * @reg: Address offset from the base address of the Axi DMA core + * @value: Value to be written into the Axi DMA register + * + * This function writes the desired value into the corresponding Axi DMA + * register. + */ + +static inline void axienet_dma_out32(struct axienet_local *lp, + off_t reg, u32 value) +{ + iowrite32(value, lp->dma_regs + reg); +} + +#if defined(CONFIG_64BIT) && defined(iowrite64) +/** + * axienet_dma_out64 - Memory mapped Axi DMA register write. + * @lp: Pointer to axienet local structure + * @reg: Address offset from the base address of the Axi DMA core + * @value: Value to be written into the Axi DMA register + * + * This function writes the desired value into the corresponding Axi DMA + * register. + */ +static inline void axienet_dma_out64(struct axienet_local *lp, + off_t reg, u64 value) +{ + iowrite64(value, lp->dma_regs + reg); +} + +static inline void axienet_dma_out_addr(struct axienet_local *lp, off_t reg, + dma_addr_t addr) +{ + if (lp->features & XAE_FEATURE_DMA_64BIT) + axienet_dma_out64(lp, reg, addr); + else + axienet_dma_out32(lp, reg, lower_32_bits(addr)); +} + +#else /* CONFIG_64BIT */ + +static inline void axienet_dma_out_addr(struct axienet_local *lp, off_t reg, + dma_addr_t addr) +{ + axienet_dma_out32(lp, reg, lower_32_bits(addr)); +} + +#endif /* CONFIG_64BIT */ + /* Function prototypes visible in xilinx_axienet_mdio.c for other files */ int axienet_mdio_enable(struct axienet_local *lp); void axienet_mdio_disable(struct axienet_local *lp); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 20746b801959..d1d772580da9 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -7,7 +7,7 @@ * Copyright (c) 2008-2009 Secret Lab Technologies Ltd. * Copyright (c) 2010 - 2011 Michal Simek <monstr@monstr.eu> * Copyright (c) 2010 - 2011 PetaLogix - * Copyright (c) 2019 SED Systems, a division of Calian Ltd. + * Copyright (c) 2019 - 2022 Calian Advanced Technologies * Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved. * * This is a driver for the Xilinx Axi Ethernet which is used in the Virtex6 @@ -33,7 +33,7 @@ #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/skbuff.h> -#include <linux/spinlock.h> +#include <linux/math64.h> #include <linux/phy.h> #include <linux/mii.h> #include <linux/ethtool.h> @@ -41,8 +41,9 @@ #include "xilinx_axienet.h" /* Descriptors defines for Tx and Rx DMA */ -#define TX_BD_NUM_DEFAULT 64 +#define TX_BD_NUM_DEFAULT 128 #define RX_BD_NUM_DEFAULT 1024 +#define TX_BD_NUM_MIN (MAX_SKB_FRAGS + 1) #define TX_BD_NUM_MAX 4096 #define RX_BD_NUM_MAX 4096 @@ -132,19 +133,23 @@ static inline u32 axienet_dma_in32(struct axienet_local *lp, off_t reg) return ioread32(lp->dma_regs + reg); } -/** - * axienet_dma_out32 - Memory mapped Axi DMA register write. - * @lp: Pointer to axienet local structure - * @reg: Address offset from the base address of the Axi DMA core - * @value: Value to be written into the Axi DMA register - * - * This function writes the desired value into the corresponding Axi DMA - * register. - */ -static inline void axienet_dma_out32(struct axienet_local *lp, - off_t reg, u32 value) +static void desc_set_phys_addr(struct axienet_local *lp, dma_addr_t addr, + struct axidma_bd *desc) +{ + desc->phys = lower_32_bits(addr); + if (lp->features & XAE_FEATURE_DMA_64BIT) + desc->phys_msb = upper_32_bits(addr); +} + +static dma_addr_t desc_get_phys_addr(struct axienet_local *lp, + struct axidma_bd *desc) { - iowrite32(value, lp->dma_regs + reg); + dma_addr_t ret = desc->phys; + + if (lp->features & XAE_FEATURE_DMA_64BIT) + ret |= ((dma_addr_t)desc->phys_msb << 16) << 16; + + return ret; } /** @@ -160,24 +165,111 @@ static void axienet_dma_bd_release(struct net_device *ndev) int i; struct axienet_local *lp = netdev_priv(ndev); + /* If we end up here, tx_bd_v must have been DMA allocated. */ + dma_free_coherent(lp->dev, + sizeof(*lp->tx_bd_v) * lp->tx_bd_num, + lp->tx_bd_v, + lp->tx_bd_p); + + if (!lp->rx_bd_v) + return; + for (i = 0; i < lp->rx_bd_num; i++) { - dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys, - lp->max_frm_size, DMA_FROM_DEVICE); + dma_addr_t phys; + + /* A NULL skb means this descriptor has not been initialised + * at all. + */ + if (!lp->rx_bd_v[i].skb) + break; + dev_kfree_skb(lp->rx_bd_v[i].skb); - } - if (lp->rx_bd_v) { - dma_free_coherent(ndev->dev.parent, - sizeof(*lp->rx_bd_v) * lp->rx_bd_num, - lp->rx_bd_v, - lp->rx_bd_p); - } - if (lp->tx_bd_v) { - dma_free_coherent(ndev->dev.parent, - sizeof(*lp->tx_bd_v) * lp->tx_bd_num, - lp->tx_bd_v, - lp->tx_bd_p); + /* For each descriptor, we programmed cntrl with the (non-zero) + * descriptor size, after it had been successfully allocated. + * So a non-zero value in there means we need to unmap it. + */ + if (lp->rx_bd_v[i].cntrl) { + phys = desc_get_phys_addr(lp, &lp->rx_bd_v[i]); + dma_unmap_single(lp->dev, phys, + lp->max_frm_size, DMA_FROM_DEVICE); + } } + + dma_free_coherent(lp->dev, + sizeof(*lp->rx_bd_v) * lp->rx_bd_num, + lp->rx_bd_v, + lp->rx_bd_p); +} + +/** + * axienet_usec_to_timer - Calculate IRQ delay timer value + * @lp: Pointer to the axienet_local structure + * @coalesce_usec: Microseconds to convert into timer value + */ +static u32 axienet_usec_to_timer(struct axienet_local *lp, u32 coalesce_usec) +{ + u32 result; + u64 clk_rate = 125000000; /* arbitrary guess if no clock rate set */ + + if (lp->axi_clk) + clk_rate = clk_get_rate(lp->axi_clk); + + /* 1 Timeout Interval = 125 * (clock period of SG clock) */ + result = DIV64_U64_ROUND_CLOSEST((u64)coalesce_usec * clk_rate, + (u64)125000000); + if (result > 255) + result = 255; + + return result; +} + +/** + * axienet_dma_start - Set up DMA registers and start DMA operation + * @lp: Pointer to the axienet_local structure + */ +static void axienet_dma_start(struct axienet_local *lp) +{ + /* Start updating the Rx channel control register */ + lp->rx_dma_cr = (lp->coalesce_count_rx << XAXIDMA_COALESCE_SHIFT) | + XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_ERROR_MASK; + /* Only set interrupt delay timer if not generating an interrupt on + * the first RX packet. Otherwise leave at 0 to disable delay interrupt. + */ + if (lp->coalesce_count_rx > 1) + lp->rx_dma_cr |= (axienet_usec_to_timer(lp, lp->coalesce_usec_rx) + << XAXIDMA_DELAY_SHIFT) | + XAXIDMA_IRQ_DELAY_MASK; + axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, lp->rx_dma_cr); + + /* Start updating the Tx channel control register */ + lp->tx_dma_cr = (lp->coalesce_count_tx << XAXIDMA_COALESCE_SHIFT) | + XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_ERROR_MASK; + /* Only set interrupt delay timer if not generating an interrupt on + * the first TX packet. Otherwise leave at 0 to disable delay interrupt. + */ + if (lp->coalesce_count_tx > 1) + lp->tx_dma_cr |= (axienet_usec_to_timer(lp, lp->coalesce_usec_tx) + << XAXIDMA_DELAY_SHIFT) | + XAXIDMA_IRQ_DELAY_MASK; + axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, lp->tx_dma_cr); + + /* Populate the tail pointer and bring the Rx Axi DMA engine out of + * halted state. This will make the Rx side ready for reception. + */ + axienet_dma_out_addr(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p); + lp->rx_dma_cr |= XAXIDMA_CR_RUNSTOP_MASK; + axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, lp->rx_dma_cr); + axienet_dma_out_addr(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p + + (sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1))); + + /* Write to the RS (Run-stop) bit in the Tx channel control register. + * Tx channel is now ready to run. But only after we write to the + * tail pointer register that the Tx channel will start transmitting. + */ + axienet_dma_out_addr(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p); + lp->tx_dma_cr |= XAXIDMA_CR_RUNSTOP_MASK; + axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, lp->tx_dma_cr); } /** @@ -192,7 +284,6 @@ static void axienet_dma_bd_release(struct net_device *ndev) */ static int axienet_dma_bd_init(struct net_device *ndev) { - u32 cr; int i; struct sk_buff *skb; struct axienet_local *lp = netdev_priv(ndev); @@ -203,85 +294,54 @@ static int axienet_dma_bd_init(struct net_device *ndev) lp->rx_bd_ci = 0; /* Allocate the Tx and Rx buffer descriptors. */ - lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, + lp->tx_bd_v = dma_alloc_coherent(lp->dev, sizeof(*lp->tx_bd_v) * lp->tx_bd_num, &lp->tx_bd_p, GFP_KERNEL); if (!lp->tx_bd_v) - goto out; + return -ENOMEM; - lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, + lp->rx_bd_v = dma_alloc_coherent(lp->dev, sizeof(*lp->rx_bd_v) * lp->rx_bd_num, &lp->rx_bd_p, GFP_KERNEL); if (!lp->rx_bd_v) goto out; for (i = 0; i < lp->tx_bd_num; i++) { - lp->tx_bd_v[i].next = lp->tx_bd_p + - sizeof(*lp->tx_bd_v) * - ((i + 1) % lp->tx_bd_num); + dma_addr_t addr = lp->tx_bd_p + + sizeof(*lp->tx_bd_v) * + ((i + 1) % lp->tx_bd_num); + + lp->tx_bd_v[i].next = lower_32_bits(addr); + if (lp->features & XAE_FEATURE_DMA_64BIT) + lp->tx_bd_v[i].next_msb = upper_32_bits(addr); } for (i = 0; i < lp->rx_bd_num; i++) { - lp->rx_bd_v[i].next = lp->rx_bd_p + - sizeof(*lp->rx_bd_v) * - ((i + 1) % lp->rx_bd_num); + dma_addr_t addr; + + addr = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * + ((i + 1) % lp->rx_bd_num); + lp->rx_bd_v[i].next = lower_32_bits(addr); + if (lp->features & XAE_FEATURE_DMA_64BIT) + lp->rx_bd_v[i].next_msb = upper_32_bits(addr); skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size); if (!skb) goto out; lp->rx_bd_v[i].skb = skb; - lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent, - skb->data, - lp->max_frm_size, - DMA_FROM_DEVICE); + addr = dma_map_single(lp->dev, skb->data, + lp->max_frm_size, DMA_FROM_DEVICE); + if (dma_mapping_error(lp->dev, addr)) { + netdev_err(ndev, "DMA mapping error\n"); + goto out; + } + desc_set_phys_addr(lp, addr, &lp->rx_bd_v[i]); + lp->rx_bd_v[i].cntrl = lp->max_frm_size; } - /* Start updating the Rx channel control register */ - cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - /* Update the interrupt coalesce count */ - cr = ((cr & ~XAXIDMA_COALESCE_MASK) | - ((lp->coalesce_count_rx) << XAXIDMA_COALESCE_SHIFT)); - /* Update the delay timer count */ - cr = ((cr & ~XAXIDMA_DELAY_MASK) | - (XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT)); - /* Enable coalesce, delay timer and error interrupts */ - cr |= XAXIDMA_IRQ_ALL_MASK; - /* Write to the Rx channel control register */ - axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr); - - /* Start updating the Tx channel control register */ - cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - /* Update the interrupt coalesce count */ - cr = (((cr & ~XAXIDMA_COALESCE_MASK)) | - ((lp->coalesce_count_tx) << XAXIDMA_COALESCE_SHIFT)); - /* Update the delay timer count */ - cr = (((cr & ~XAXIDMA_DELAY_MASK)) | - (XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT)); - /* Enable coalesce, delay timer and error interrupts */ - cr |= XAXIDMA_IRQ_ALL_MASK; - /* Write to the Tx channel control register */ - axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr); - - /* Populate the tail pointer and bring the Rx Axi DMA engine out of - * halted state. This will make the Rx side ready for reception. - */ - axienet_dma_out32(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p); - cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, - cr | XAXIDMA_CR_RUNSTOP_MASK); - axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p + - (sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1))); - - /* Write to the RS (Run-stop) bit in the Tx channel control register. - * Tx channel is now ready to run. But only after we write to the - * tail pointer register that the Tx channel will start transmitting. - */ - axienet_dma_out32(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p); - cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, - cr | XAXIDMA_CR_RUNSTOP_MASK); + axienet_dma_start(lp); return 0; out: @@ -303,7 +363,7 @@ static void axienet_set_mac_address(struct net_device *ndev, struct axienet_local *lp = netdev_priv(ndev); if (address) - memcpy(ndev->dev_addr, address, ETH_ALEN); + eth_hw_addr_set(ndev, address); if (!is_valid_ether_addr(ndev->dev_addr)) eth_hw_addr_random(ndev); @@ -437,9 +497,11 @@ static void axienet_setoptions(struct net_device *ndev, u32 options) lp->options |= options; } -static void __axienet_device_reset(struct axienet_local *lp) +static int __axienet_device_reset(struct axienet_local *lp) { - u32 timeout; + u32 value; + int ret; + /* Reset Axi DMA. This would reset Axi Ethernet core as well. The reset * process of Axi DMA takes a while to complete as all pending * commands/transfers will be flushed or completed during this @@ -448,16 +510,64 @@ static void __axienet_device_reset(struct axienet_local *lp) * they both reset the entire DMA core, so only one needs to be used. */ axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, XAXIDMA_CR_RESET_MASK); - timeout = DELAY_OF_ONE_MILLISEC; - while (axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET) & - XAXIDMA_CR_RESET_MASK) { - udelay(1); - if (--timeout == 0) { - netdev_err(lp->ndev, "%s: DMA reset timeout!\n", - __func__); - break; - } + ret = read_poll_timeout(axienet_dma_in32, value, + !(value & XAXIDMA_CR_RESET_MASK), + DELAY_OF_ONE_MILLISEC, 50000, false, lp, + XAXIDMA_TX_CR_OFFSET); + if (ret) { + dev_err(lp->dev, "%s: DMA reset timeout!\n", __func__); + return ret; } + + /* Wait for PhyRstCmplt bit to be set, indicating the PHY reset has finished */ + ret = read_poll_timeout(axienet_ior, value, + value & XAE_INT_PHYRSTCMPLT_MASK, + DELAY_OF_ONE_MILLISEC, 50000, false, lp, + XAE_IS_OFFSET); + if (ret) { + dev_err(lp->dev, "%s: timeout waiting for PhyRstCmplt\n", __func__); + return ret; + } + + return 0; +} + +/** + * axienet_dma_stop - Stop DMA operation + * @lp: Pointer to the axienet_local structure + */ +static void axienet_dma_stop(struct axienet_local *lp) +{ + int count; + u32 cr, sr; + + cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); + cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK); + axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr); + synchronize_irq(lp->rx_irq); + + cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); + cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK); + axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr); + synchronize_irq(lp->tx_irq); + + /* Give DMAs a chance to halt gracefully */ + sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET); + for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) { + msleep(20); + sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET); + } + + sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET); + for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) { + msleep(20); + sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET); + } + + /* Do a reset to ensure DMA is really stopped */ + axienet_lock_mii(lp); + __axienet_device_reset(lp); + axienet_unlock_mii(lp); } /** @@ -467,23 +577,27 @@ static void __axienet_device_reset(struct axienet_local *lp) * This function is called to reset and initialize the Axi Ethernet core. This * is typically called during initialization. It does a reset of the Axi DMA * Rx/Tx channels and initializes the Axi DMA BDs. Since Axi DMA reset lines - * areconnected to Axi Ethernet reset lines, this in turn resets the Axi + * are connected to Axi Ethernet reset lines, this in turn resets the Axi * Ethernet core. No separate hardware reset is done for the Axi Ethernet * core. + * Returns 0 on success or a negative error number otherwise. */ -static void axienet_device_reset(struct net_device *ndev) +static int axienet_device_reset(struct net_device *ndev) { u32 axienet_status; struct axienet_local *lp = netdev_priv(ndev); + int ret; - __axienet_device_reset(lp); + ret = __axienet_device_reset(lp); + if (ret) + return ret; lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE; lp->options |= XAE_OPTION_VLAN; lp->options &= (~XAE_OPTION_JUMBO); if ((ndev->mtu > XAE_MTU) && - (ndev->mtu <= XAE_JUMBO_MTU)) { + (ndev->mtu <= XAE_JUMBO_MTU)) { lp->max_frm_size = ndev->mtu + VLAN_ETH_HLEN + XAE_TRL_SIZE; @@ -491,9 +605,11 @@ static void axienet_device_reset(struct net_device *ndev) lp->options |= XAE_OPTION_JUMBO; } - if (axienet_dma_bd_init(ndev)) { + ret = axienet_dma_bd_init(ndev); + if (ret) { netdev_err(ndev, "%s: descriptor allocation failed\n", __func__); + return ret; } axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET); @@ -518,59 +634,67 @@ static void axienet_device_reset(struct net_device *ndev) axienet_setoptions(ndev, lp->options); netif_trans_update(ndev); + + return 0; } /** - * axienet_start_xmit_done - Invoked once a transmit is completed by the - * Axi DMA Tx channel. - * @ndev: Pointer to the net_device structure + * axienet_free_tx_chain - Clean up a series of linked TX descriptors. + * @lp: Pointer to the axienet_local structure + * @first_bd: Index of first descriptor to clean up + * @nr_bds: Max number of descriptors to clean up + * @force: Whether to clean descriptors even if not complete + * @sizep: Pointer to a u32 filled with the total sum of all bytes + * in all cleaned-up descriptors. Ignored if NULL. + * @budget: NAPI budget (use 0 when not called from NAPI poll) * - * This function is invoked from the Axi DMA Tx isr to notify the completion - * of transmit operation. It clears fields in the corresponding Tx BDs and - * unmaps the corresponding buffer so that CPU can regain ownership of the - * buffer. It finally invokes "netif_wake_queue" to restart transmission if - * required. + * Would either be called after a successful transmit operation, or after + * there was an error when setting up the chain. + * Returns the number of descriptors handled. */ -static void axienet_start_xmit_done(struct net_device *ndev) +static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd, + int nr_bds, bool force, u32 *sizep, int budget) { - u32 size = 0; - u32 packets = 0; - struct axienet_local *lp = netdev_priv(ndev); struct axidma_bd *cur_p; - unsigned int status = 0; - - cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; - status = cur_p->status; - while (status & XAXIDMA_BD_STS_COMPLETE_MASK) { - dma_unmap_single(ndev->dev.parent, cur_p->phys, - (cur_p->cntrl & XAXIDMA_BD_CTRL_LENGTH_MASK), - DMA_TO_DEVICE); - if (cur_p->skb) - dev_consume_skb_irq(cur_p->skb); - /*cur_p->phys = 0;*/ + unsigned int status; + dma_addr_t phys; + int i; + + for (i = 0; i < nr_bds; i++) { + cur_p = &lp->tx_bd_v[(first_bd + i) % lp->tx_bd_num]; + status = cur_p->status; + + /* If force is not specified, clean up only descriptors + * that have been completed by the MAC. + */ + if (!force && !(status & XAXIDMA_BD_STS_COMPLETE_MASK)) + break; + + /* Ensure we see complete descriptor update */ + dma_rmb(); + phys = desc_get_phys_addr(lp, cur_p); + dma_unmap_single(lp->dev, phys, + (cur_p->cntrl & XAXIDMA_BD_CTRL_LENGTH_MASK), + DMA_TO_DEVICE); + + if (cur_p->skb && (status & XAXIDMA_BD_STS_COMPLETE_MASK)) + napi_consume_skb(cur_p->skb, budget); + cur_p->app0 = 0; cur_p->app1 = 0; cur_p->app2 = 0; cur_p->app4 = 0; - cur_p->status = 0; cur_p->skb = NULL; + /* ensure our transmit path and device don't prematurely see status cleared */ + wmb(); + cur_p->cntrl = 0; + cur_p->status = 0; - size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; - packets++; - - if (++lp->tx_bd_ci >= lp->tx_bd_num) - lp->tx_bd_ci = 0; - cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; - status = cur_p->status; + if (sizep) + *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; } - ndev->stats.tx_packets += packets; - ndev->stats.tx_bytes += size; - - /* Matches barrier in axienet_start_xmit */ - smp_mb(); - - netif_wake_queue(ndev); + return i; } /** @@ -584,19 +708,73 @@ static void axienet_start_xmit_done(struct net_device *ndev) * This function is invoked before BDs are allocated and transmission starts. * This function returns 0 if a BD or group of BDs can be allocated for * transmission. If the BD or any of the BDs are not free the function - * returns a busy status. This is invoked from axienet_start_xmit. + * returns a busy status. */ static inline int axienet_check_tx_bd_space(struct axienet_local *lp, int num_frag) { struct axidma_bd *cur_p; - cur_p = &lp->tx_bd_v[(lp->tx_bd_tail + num_frag) % lp->tx_bd_num]; - if (cur_p->status & XAXIDMA_BD_STS_ALL_MASK) + + /* Ensure we see all descriptor updates from device or TX polling */ + rmb(); + cur_p = &lp->tx_bd_v[(READ_ONCE(lp->tx_bd_tail) + num_frag) % + lp->tx_bd_num]; + if (cur_p->cntrl) return NETDEV_TX_BUSY; return 0; } /** + * axienet_tx_poll - Invoked once a transmit is completed by the + * Axi DMA Tx channel. + * @napi: Pointer to NAPI structure. + * @budget: Max number of TX packets to process. + * + * Return: Number of TX packets processed. + * + * This function is invoked from the NAPI processing to notify the completion + * of transmit operation. It clears fields in the corresponding Tx BDs and + * unmaps the corresponding buffer so that CPU can regain ownership of the + * buffer. It finally invokes "netif_wake_queue" to restart transmission if + * required. + */ +static int axienet_tx_poll(struct napi_struct *napi, int budget) +{ + struct axienet_local *lp = container_of(napi, struct axienet_local, napi_tx); + struct net_device *ndev = lp->ndev; + u32 size = 0; + int packets; + + packets = axienet_free_tx_chain(lp, lp->tx_bd_ci, budget, false, &size, budget); + + if (packets) { + lp->tx_bd_ci += packets; + if (lp->tx_bd_ci >= lp->tx_bd_num) + lp->tx_bd_ci %= lp->tx_bd_num; + + u64_stats_update_begin(&lp->tx_stat_sync); + u64_stats_add(&lp->tx_packets, packets); + u64_stats_add(&lp->tx_bytes, size); + u64_stats_update_end(&lp->tx_stat_sync); + + /* Matches barrier in axienet_start_xmit */ + smp_mb(); + + if (!axienet_check_tx_bd_space(lp, MAX_SKB_FRAGS + 1)) + netif_wake_queue(ndev); + } + + if (packets < budget && napi_complete_done(napi, packets)) { + /* Re-enable TX completion interrupts. This should + * cause an immediate interrupt if any TX packets are + * already pending. + */ + axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, lp->tx_dma_cr); + } + return packets; +} + +/** * axienet_start_xmit - Starts the transmission. * @skb: sk_buff pointer that contains data to be Txed. * @ndev: Pointer to net_device structure. @@ -617,27 +795,26 @@ axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) u32 csum_start_off; u32 csum_index_off; skb_frag_t *frag; - dma_addr_t tail_p; + dma_addr_t tail_p, phys; + u32 orig_tail_ptr, new_tail_ptr; struct axienet_local *lp = netdev_priv(ndev); struct axidma_bd *cur_p; - num_frag = skb_shinfo(skb)->nr_frags; - cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; + orig_tail_ptr = lp->tx_bd_tail; + new_tail_ptr = orig_tail_ptr; - if (axienet_check_tx_bd_space(lp, num_frag)) { - if (netif_queue_stopped(ndev)) - return NETDEV_TX_BUSY; + num_frag = skb_shinfo(skb)->nr_frags; + cur_p = &lp->tx_bd_v[orig_tail_ptr]; + if (axienet_check_tx_bd_space(lp, num_frag + 1)) { + /* Should not happen as last start_xmit call should have + * checked for sufficient space and queue should only be + * woken when sufficient space is available. + */ netif_stop_queue(ndev); - - /* Matches barrier in axienet_start_xmit_done */ - smp_mb(); - - /* Space might have just been freed - check again */ - if (axienet_check_tx_bd_space(lp, num_frag)) - return NETDEV_TX_BUSY; - - netif_wake_queue(ndev); + if (net_ratelimit()) + netdev_warn(ndev, "TX ring unexpectedly full\n"); + return NETDEV_TX_BUSY; } if (skb->ip_summed == CHECKSUM_PARTIAL) { @@ -655,113 +832,176 @@ axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) cur_p->app0 |= 2; /* Tx Full Checksum Offload Enabled */ } + phys = dma_map_single(lp->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(lp->dev, phys))) { + if (net_ratelimit()) + netdev_err(ndev, "TX DMA mapping error\n"); + ndev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + desc_set_phys_addr(lp, phys, cur_p); cur_p->cntrl = skb_headlen(skb) | XAXIDMA_BD_CTRL_TXSOF_MASK; - cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, - skb_headlen(skb), DMA_TO_DEVICE); for (ii = 0; ii < num_frag; ii++) { - if (++lp->tx_bd_tail >= lp->tx_bd_num) - lp->tx_bd_tail = 0; - cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; + if (++new_tail_ptr >= lp->tx_bd_num) + new_tail_ptr = 0; + cur_p = &lp->tx_bd_v[new_tail_ptr]; frag = &skb_shinfo(skb)->frags[ii]; - cur_p->phys = dma_map_single(ndev->dev.parent, - skb_frag_address(frag), - skb_frag_size(frag), - DMA_TO_DEVICE); + phys = dma_map_single(lp->dev, + skb_frag_address(frag), + skb_frag_size(frag), + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(lp->dev, phys))) { + if (net_ratelimit()) + netdev_err(ndev, "TX DMA mapping error\n"); + ndev->stats.tx_dropped++; + axienet_free_tx_chain(lp, orig_tail_ptr, ii + 1, + true, NULL, 0); + return NETDEV_TX_OK; + } + desc_set_phys_addr(lp, phys, cur_p); cur_p->cntrl = skb_frag_size(frag); } cur_p->cntrl |= XAXIDMA_BD_CTRL_TXEOF_MASK; cur_p->skb = skb; - tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; + tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * new_tail_ptr; + if (++new_tail_ptr >= lp->tx_bd_num) + new_tail_ptr = 0; + WRITE_ONCE(lp->tx_bd_tail, new_tail_ptr); + /* Start the transfer */ - axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p); - if (++lp->tx_bd_tail >= lp->tx_bd_num) - lp->tx_bd_tail = 0; + axienet_dma_out_addr(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p); + + /* Stop queue if next transmit may not have space */ + if (axienet_check_tx_bd_space(lp, MAX_SKB_FRAGS + 1)) { + netif_stop_queue(ndev); + + /* Matches barrier in axienet_tx_poll */ + smp_mb(); + + /* Space might have just been freed - check again */ + if (!axienet_check_tx_bd_space(lp, MAX_SKB_FRAGS + 1)) + netif_wake_queue(ndev); + } return NETDEV_TX_OK; } /** - * axienet_recv - Is called from Axi DMA Rx Isr to complete the received - * BD processing. - * @ndev: Pointer to net_device structure. + * axienet_rx_poll - Triggered by RX ISR to complete the BD processing. + * @napi: Pointer to NAPI structure. + * @budget: Max number of RX packets to process. * - * This function is invoked from the Axi DMA Rx isr to process the Rx BDs. It - * does minimal processing and invokes "netif_rx" to complete further - * processing. + * Return: Number of RX packets processed. */ -static void axienet_recv(struct net_device *ndev) +static int axienet_rx_poll(struct napi_struct *napi, int budget) { u32 length; u32 csumstatus; u32 size = 0; - u32 packets = 0; + int packets = 0; dma_addr_t tail_p = 0; - struct axienet_local *lp = netdev_priv(ndev); - struct sk_buff *skb, *new_skb; struct axidma_bd *cur_p; + struct sk_buff *skb, *new_skb; + struct axienet_local *lp = container_of(napi, struct axienet_local, napi_rx); cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; - while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) { - tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; + while (packets < budget && (cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) { + dma_addr_t phys; - dma_unmap_single(ndev->dev.parent, cur_p->phys, - lp->max_frm_size, - DMA_FROM_DEVICE); + /* Ensure we see complete descriptor update */ + dma_rmb(); skb = cur_p->skb; cur_p->skb = NULL; - length = cur_p->app4 & 0x0000FFFF; - - skb_put(skb, length); - skb->protocol = eth_type_trans(skb, ndev); - /*skb_checksum_none_assert(skb);*/ - skb->ip_summed = CHECKSUM_NONE; - - /* if we're doing Rx csum offload, set it up */ - if (lp->features & XAE_FEATURE_FULL_RX_CSUM) { - csumstatus = (cur_p->app2 & - XAE_FULL_CSUM_STATUS_MASK) >> 3; - if ((csumstatus == XAE_IP_TCP_CSUM_VALIDATED) || - (csumstatus == XAE_IP_UDP_CSUM_VALIDATED)) { - skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* skb could be NULL if a previous pass already received the + * packet for this slot in the ring, but failed to refill it + * with a newly allocated buffer. In this case, don't try to + * receive it again. + */ + if (likely(skb)) { + length = cur_p->app4 & 0x0000FFFF; + + phys = desc_get_phys_addr(lp, cur_p); + dma_unmap_single(lp->dev, phys, lp->max_frm_size, + DMA_FROM_DEVICE); + + skb_put(skb, length); + skb->protocol = eth_type_trans(skb, lp->ndev); + /*skb_checksum_none_assert(skb);*/ + skb->ip_summed = CHECKSUM_NONE; + + /* if we're doing Rx csum offload, set it up */ + if (lp->features & XAE_FEATURE_FULL_RX_CSUM) { + csumstatus = (cur_p->app2 & + XAE_FULL_CSUM_STATUS_MASK) >> 3; + if (csumstatus == XAE_IP_TCP_CSUM_VALIDATED || + csumstatus == XAE_IP_UDP_CSUM_VALIDATED) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 && + skb->protocol == htons(ETH_P_IP) && + skb->len > 64) { + skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF); + skb->ip_summed = CHECKSUM_COMPLETE; } - } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 && - skb->protocol == htons(ETH_P_IP) && - skb->len > 64) { - skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF); - skb->ip_summed = CHECKSUM_COMPLETE; - } - netif_rx(skb); + napi_gro_receive(napi, skb); - size += length; - packets++; + size += length; + packets++; + } - new_skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size); + new_skb = napi_alloc_skb(napi, lp->max_frm_size); if (!new_skb) - return; + break; + + phys = dma_map_single(lp->dev, new_skb->data, + lp->max_frm_size, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(lp->dev, phys))) { + if (net_ratelimit()) + netdev_err(lp->ndev, "RX DMA mapping error\n"); + dev_kfree_skb(new_skb); + break; + } + desc_set_phys_addr(lp, phys, cur_p); - cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data, - lp->max_frm_size, - DMA_FROM_DEVICE); cur_p->cntrl = lp->max_frm_size; cur_p->status = 0; cur_p->skb = new_skb; + /* Only update tail_p to mark this slot as usable after it has + * been successfully refilled. + */ + tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; + if (++lp->rx_bd_ci >= lp->rx_bd_num) lp->rx_bd_ci = 0; cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; } - ndev->stats.rx_packets += packets; - ndev->stats.rx_bytes += size; + u64_stats_update_begin(&lp->rx_stat_sync); + u64_stats_add(&lp->rx_packets, packets); + u64_stats_add(&lp->rx_bytes, size); + u64_stats_update_end(&lp->rx_stat_sync); if (tail_p) - axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p); + axienet_dma_out_addr(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p); + + if (packets < budget && napi_complete_done(napi, packets)) { + /* Re-enable RX completion interrupts. This should + * cause an immediate interrupt if any RX packets are + * already pending. + */ + axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, lp->rx_dma_cr); + } + return packets; } /** @@ -771,45 +1011,40 @@ static void axienet_recv(struct net_device *ndev) * * Return: IRQ_HANDLED if device generated a TX interrupt, IRQ_NONE otherwise. * - * This is the Axi DMA Tx done Isr. It invokes "axienet_start_xmit_done" - * to complete the BD processing. + * This is the Axi DMA Tx done Isr. It invokes NAPI polling to complete the + * TX BD processing. */ static irqreturn_t axienet_tx_irq(int irq, void *_ndev) { - u32 cr; unsigned int status; struct net_device *ndev = _ndev; struct axienet_local *lp = netdev_priv(ndev); status = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET); - if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) { - axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status); - axienet_start_xmit_done(lp->ndev); - goto out; - } + if (!(status & XAXIDMA_IRQ_ALL_MASK)) return IRQ_NONE; - if (status & XAXIDMA_IRQ_ERROR_MASK) { - dev_err(&ndev->dev, "DMA Tx error 0x%x\n", status); - dev_err(&ndev->dev, "Current BD is at: 0x%x\n", - (lp->tx_bd_v[lp->tx_bd_ci]).phys); - - cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - /* Disable coalesce, delay timer and error interrupts */ - cr &= (~XAXIDMA_IRQ_ALL_MASK); - /* Write to the Tx channel control register */ - axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr); - cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - /* Disable coalesce, delay timer and error interrupts */ - cr &= (~XAXIDMA_IRQ_ALL_MASK); - /* Write to the Rx channel control register */ - axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr); + axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status); + + if (unlikely(status & XAXIDMA_IRQ_ERROR_MASK)) { + netdev_err(ndev, "DMA Tx error 0x%x\n", status); + netdev_err(ndev, "Current BD is at: 0x%x%08x\n", + (lp->tx_bd_v[lp->tx_bd_ci]).phys_msb, + (lp->tx_bd_v[lp->tx_bd_ci]).phys); + schedule_work(&lp->dma_err_task); + } else { + /* Disable further TX completion interrupts and schedule + * NAPI to handle the completions. + */ + u32 cr = lp->tx_dma_cr; - tasklet_schedule(&lp->dma_err_tasklet); - axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status); + cr &= ~(XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK); + axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr); + + napi_schedule(&lp->napi_tx); } -out: + return IRQ_HANDLED; } @@ -820,45 +1055,40 @@ out: * * Return: IRQ_HANDLED if device generated a RX interrupt, IRQ_NONE otherwise. * - * This is the Axi DMA Rx Isr. It invokes "axienet_recv" to complete the BD + * This is the Axi DMA Rx Isr. It invokes NAPI polling to complete the RX BD * processing. */ static irqreturn_t axienet_rx_irq(int irq, void *_ndev) { - u32 cr; unsigned int status; struct net_device *ndev = _ndev; struct axienet_local *lp = netdev_priv(ndev); status = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET); - if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) { - axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status); - axienet_recv(lp->ndev); - goto out; - } + if (!(status & XAXIDMA_IRQ_ALL_MASK)) return IRQ_NONE; - if (status & XAXIDMA_IRQ_ERROR_MASK) { - dev_err(&ndev->dev, "DMA Rx error 0x%x\n", status); - dev_err(&ndev->dev, "Current BD is at: 0x%x\n", - (lp->rx_bd_v[lp->rx_bd_ci]).phys); - - cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - /* Disable coalesce, delay timer and error interrupts */ - cr &= (~XAXIDMA_IRQ_ALL_MASK); - /* Finally write to the Tx channel control register */ - axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr); - cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - /* Disable coalesce, delay timer and error interrupts */ - cr &= (~XAXIDMA_IRQ_ALL_MASK); - /* write to the Rx channel control register */ + axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status); + + if (unlikely(status & XAXIDMA_IRQ_ERROR_MASK)) { + netdev_err(ndev, "DMA Rx error 0x%x\n", status); + netdev_err(ndev, "Current BD is at: 0x%x%08x\n", + (lp->rx_bd_v[lp->rx_bd_ci]).phys_msb, + (lp->rx_bd_v[lp->rx_bd_ci]).phys); + schedule_work(&lp->dma_err_task); + } else { + /* Disable further RX completion interrupts and schedule + * NAPI receive. + */ + u32 cr = lp->rx_dma_cr; + + cr &= ~(XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK); axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr); - tasklet_schedule(&lp->dma_err_tasklet); - axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status); + napi_schedule(&lp->napi_rx); } -out: + return IRQ_HANDLED; } @@ -891,7 +1121,7 @@ static irqreturn_t axienet_eth_irq(int irq, void *_ndev) return IRQ_HANDLED; } -static void axienet_dma_err_handler(unsigned long data); +static void axienet_dma_err_handler(struct work_struct *work); /** * axienet_open - Driver open routine. @@ -913,19 +1143,13 @@ static int axienet_open(struct net_device *ndev) dev_dbg(&ndev->dev, "axienet_open()\n"); - /* Disable the MDIO interface till Axi Ethernet Reset is completed. - * When we do an Axi Ethernet reset, it resets the complete core - * including the MDIO. MDIO must be disabled before resetting - * and re-enabled afterwards. + /* When we do an Axi Ethernet reset, it resets the complete core + * including the MDIO. MDIO must be disabled before resetting. * Hold MDIO bus lock to avoid MDIO accesses during the reset. */ - mutex_lock(&lp->mii_bus->mdio_lock); - axienet_mdio_disable(lp); - axienet_device_reset(ndev); - ret = axienet_mdio_enable(lp); - mutex_unlock(&lp->mii_bus->mdio_lock); - if (ret < 0) - return ret; + axienet_lock_mii(lp); + ret = axienet_device_reset(ndev); + axienet_unlock_mii(lp); ret = phylink_of_phy_connect(lp->phylink, lp->dev->of_node, 0); if (ret) { @@ -935,9 +1159,11 @@ static int axienet_open(struct net_device *ndev) phylink_start(lp->phylink); - /* Enable tasklets for Axi DMA error handling */ - tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler, - (unsigned long) lp); + /* Enable worker thread for Axi DMA error handling */ + INIT_WORK(&lp->dma_err_task, axienet_dma_err_handler); + + napi_enable(&lp->napi_rx); + napi_enable(&lp->napi_tx); /* Enable interrupts for Axi DMA Tx */ ret = request_irq(lp->tx_irq, axienet_tx_irq, IRQF_SHARED, @@ -964,9 +1190,11 @@ err_eth_irq: err_rx_irq: free_irq(lp->tx_irq, ndev); err_tx_irq: + napi_disable(&lp->napi_tx); + napi_disable(&lp->napi_rx); phylink_stop(lp->phylink); phylink_disconnect_phy(lp->phylink); - tasklet_kill(&lp->dma_err_tasklet); + cancel_work_sync(&lp->dma_err_task); dev_err(lp->dev, "request_irq() failed\n"); return ret; } @@ -983,49 +1211,24 @@ err_tx_irq: */ static int axienet_stop(struct net_device *ndev) { - u32 cr, sr; - int count; struct axienet_local *lp = netdev_priv(ndev); dev_dbg(&ndev->dev, "axienet_close()\n"); + napi_disable(&lp->napi_tx); + napi_disable(&lp->napi_rx); + phylink_stop(lp->phylink); phylink_disconnect_phy(lp->phylink); axienet_setoptions(ndev, lp->options & ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); - cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK); - axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr); - - cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK); - axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr); + axienet_dma_stop(lp); axienet_iow(lp, XAE_IE_OFFSET, 0); - /* Give DMAs a chance to halt gracefully */ - sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET); - for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) { - msleep(20); - sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET); - } - - sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET); - for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) { - msleep(20); - sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET); - } - - /* Do a reset to ensure DMA is really stopped */ - mutex_lock(&lp->mii_bus->mdio_lock); - axienet_mdio_disable(lp); - __axienet_device_reset(lp); - axienet_mdio_enable(lp); - mutex_unlock(&lp->mii_bus->mdio_lock); - - tasklet_kill(&lp->dma_err_tasklet); + cancel_work_sync(&lp->dma_err_task); if (lp->eth_irq > 0) free_irq(lp->eth_irq, ndev); @@ -1083,13 +1286,46 @@ static void axienet_poll_controller(struct net_device *ndev) } #endif +static int axienet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct axienet_local *lp = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + return phylink_mii_ioctl(lp->phylink, rq, cmd); +} + +static void +axienet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) +{ + struct axienet_local *lp = netdev_priv(dev); + unsigned int start; + + netdev_stats_to_stats64(stats, &dev->stats); + + do { + start = u64_stats_fetch_begin_irq(&lp->rx_stat_sync); + stats->rx_packets = u64_stats_read(&lp->rx_packets); + stats->rx_bytes = u64_stats_read(&lp->rx_bytes); + } while (u64_stats_fetch_retry_irq(&lp->rx_stat_sync, start)); + + do { + start = u64_stats_fetch_begin_irq(&lp->tx_stat_sync); + stats->tx_packets = u64_stats_read(&lp->tx_packets); + stats->tx_bytes = u64_stats_read(&lp->tx_bytes); + } while (u64_stats_fetch_retry_irq(&lp->tx_stat_sync, start)); +} + static const struct net_device_ops axienet_netdev_ops = { .ndo_open = axienet_open, .ndo_stop = axienet_stop, .ndo_start_xmit = axienet_start_xmit, + .ndo_get_stats64 = axienet_get_stats64, .ndo_change_mtu = axienet_change_mtu, .ndo_set_mac_address = netdev_set_mac_address, .ndo_validate_addr = eth_validate_addr, + .ndo_eth_ioctl = axienet_ioctl, .ndo_set_rx_mode = axienet_set_multicast_list, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = axienet_poll_controller, @@ -1107,8 +1343,8 @@ static const struct net_device_ops axienet_netdev_ops = { static void axienet_ethtools_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *ed) { - strlcpy(ed->driver, DRIVER_NAME, sizeof(ed->driver)); - strlcpy(ed->version, DRIVER_VERSION, sizeof(ed->version)); + strscpy(ed->driver, DRIVER_NAME, sizeof(ed->driver)); + strscpy(ed->version, DRIVER_VERSION, sizeof(ed->version)); } /** @@ -1139,7 +1375,7 @@ static int axienet_ethtools_get_regs_len(struct net_device *ndev) static void axienet_ethtools_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *ret) { - u32 *data = (u32 *) ret; + u32 *data = (u32 *)ret; size_t len = sizeof(u32) * AXIENET_REGS_N; struct axienet_local *lp = netdev_priv(ndev); @@ -1170,10 +1406,6 @@ static void axienet_ethtools_get_regs(struct net_device *ndev, data[20] = axienet_ior(lp, XAE_MDIO_MCR_OFFSET); data[21] = axienet_ior(lp, XAE_MDIO_MWD_OFFSET); data[22] = axienet_ior(lp, XAE_MDIO_MRD_OFFSET); - data[23] = axienet_ior(lp, XAE_MDIO_MIS_OFFSET); - data[24] = axienet_ior(lp, XAE_MDIO_MIP_OFFSET); - data[25] = axienet_ior(lp, XAE_MDIO_MIE_OFFSET); - data[26] = axienet_ior(lp, XAE_MDIO_MIC_OFFSET); data[27] = axienet_ior(lp, XAE_UAW0_OFFSET); data[28] = axienet_ior(lp, XAE_UAW1_OFFSET); data[29] = axienet_ior(lp, XAE_FMI_OFFSET); @@ -1189,8 +1421,11 @@ static void axienet_ethtools_get_regs(struct net_device *ndev, data[39] = axienet_dma_in32(lp, XAXIDMA_RX_TDESC_OFFSET); } -static void axienet_ethtools_get_ringparam(struct net_device *ndev, - struct ethtool_ringparam *ering) +static void +axienet_ethtools_get_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering, + struct kernel_ethtool_ringparam *kernel_ering, + struct netlink_ext_ack *extack) { struct axienet_local *lp = netdev_priv(ndev); @@ -1204,15 +1439,19 @@ static void axienet_ethtools_get_ringparam(struct net_device *ndev, ering->tx_pending = lp->tx_bd_num; } -static int axienet_ethtools_set_ringparam(struct net_device *ndev, - struct ethtool_ringparam *ering) +static int +axienet_ethtools_set_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering, + struct kernel_ethtool_ringparam *kernel_ering, + struct netlink_ext_ack *extack) { struct axienet_local *lp = netdev_priv(ndev); if (ering->rx_pending > RX_BD_NUM_MAX || ering->rx_mini_pending || ering->rx_jumbo_pending || - ering->rx_pending > TX_BD_NUM_MAX) + ering->tx_pending < TX_BD_NUM_MIN || + ering->tx_pending > TX_BD_NUM_MAX) return -EINVAL; if (netif_running(ndev)) @@ -1266,6 +1505,8 @@ axienet_ethtools_set_pauseparam(struct net_device *ndev, * axienet_ethtools_get_coalesce - Get DMA interrupt coalescing count. * @ndev: Pointer to net_device structure * @ecoalesce: Pointer to ethtool_coalesce structure + * @kernel_coal: ethtool CQE mode setting structure + * @extack: extack for reporting error messages * * This implements ethtool command for getting the DMA interrupt coalescing * count on Tx and Rx paths. Issue "ethtool -c ethX" under linux prompt to @@ -1273,17 +1514,18 @@ axienet_ethtools_set_pauseparam(struct net_device *ndev, * * Return: 0 always */ -static int axienet_ethtools_get_coalesce(struct net_device *ndev, - struct ethtool_coalesce *ecoalesce) +static int +axienet_ethtools_get_coalesce(struct net_device *ndev, + struct ethtool_coalesce *ecoalesce, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) { - u32 regval = 0; struct axienet_local *lp = netdev_priv(ndev); - regval = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - ecoalesce->rx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK) - >> XAXIDMA_COALESCE_SHIFT; - regval = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - ecoalesce->tx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK) - >> XAXIDMA_COALESCE_SHIFT; + + ecoalesce->rx_max_coalesced_frames = lp->coalesce_count_rx; + ecoalesce->rx_coalesce_usecs = lp->coalesce_usec_rx; + ecoalesce->tx_max_coalesced_frames = lp->coalesce_count_tx; + ecoalesce->tx_coalesce_usecs = lp->coalesce_usec_tx; return 0; } @@ -1291,6 +1533,8 @@ static int axienet_ethtools_get_coalesce(struct net_device *ndev, * axienet_ethtools_set_coalesce - Set DMA interrupt coalescing count. * @ndev: Pointer to net_device structure * @ecoalesce: Pointer to ethtool_coalesce structure + * @kernel_coal: ethtool CQE mode setting structure + * @extack: extack for reporting error messages * * This implements ethtool command for setting the DMA interrupt coalescing * count on Tx and Rx paths. Issue "ethtool -C ethX rx-frames 5" under linux @@ -1298,8 +1542,11 @@ static int axienet_ethtools_get_coalesce(struct net_device *ndev, * * Return: 0, on success, Non-zero error value on failure. */ -static int axienet_ethtools_set_coalesce(struct net_device *ndev, - struct ethtool_coalesce *ecoalesce) +static int +axienet_ethtools_set_coalesce(struct net_device *ndev, + struct ethtool_coalesce *ecoalesce, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) { struct axienet_local *lp = netdev_priv(ndev); @@ -1309,31 +1556,14 @@ static int axienet_ethtools_set_coalesce(struct net_device *ndev, return -EFAULT; } - if ((ecoalesce->rx_coalesce_usecs) || - (ecoalesce->rx_coalesce_usecs_irq) || - (ecoalesce->rx_max_coalesced_frames_irq) || - (ecoalesce->tx_coalesce_usecs) || - (ecoalesce->tx_coalesce_usecs_irq) || - (ecoalesce->tx_max_coalesced_frames_irq) || - (ecoalesce->stats_block_coalesce_usecs) || - (ecoalesce->use_adaptive_rx_coalesce) || - (ecoalesce->use_adaptive_tx_coalesce) || - (ecoalesce->pkt_rate_low) || - (ecoalesce->rx_coalesce_usecs_low) || - (ecoalesce->rx_max_coalesced_frames_low) || - (ecoalesce->tx_coalesce_usecs_low) || - (ecoalesce->tx_max_coalesced_frames_low) || - (ecoalesce->pkt_rate_high) || - (ecoalesce->rx_coalesce_usecs_high) || - (ecoalesce->rx_max_coalesced_frames_high) || - (ecoalesce->tx_coalesce_usecs_high) || - (ecoalesce->tx_max_coalesced_frames_high) || - (ecoalesce->rate_sample_interval)) - return -EOPNOTSUPP; if (ecoalesce->rx_max_coalesced_frames) lp->coalesce_count_rx = ecoalesce->rx_max_coalesced_frames; + if (ecoalesce->rx_coalesce_usecs) + lp->coalesce_usec_rx = ecoalesce->rx_coalesce_usecs; if (ecoalesce->tx_max_coalesced_frames) lp->coalesce_count_tx = ecoalesce->tx_max_coalesced_frames; + if (ecoalesce->tx_coalesce_usecs) + lp->coalesce_usec_tx = ecoalesce->tx_coalesce_usecs; return 0; } @@ -1356,7 +1586,16 @@ axienet_ethtools_set_link_ksettings(struct net_device *ndev, return phylink_ethtool_ksettings_set(lp->phylink, cmd); } +static int axienet_ethtools_nway_reset(struct net_device *dev) +{ + struct axienet_local *lp = netdev_priv(dev); + + return phylink_ethtool_nway_reset(lp->phylink); +} + static const struct ethtool_ops axienet_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES | + ETHTOOL_COALESCE_USECS, .get_drvinfo = axienet_ethtools_get_drvinfo, .get_regs_len = axienet_ethtools_get_regs_len, .get_regs = axienet_ethtools_get_regs, @@ -1369,78 +1608,96 @@ static const struct ethtool_ops axienet_ethtool_ops = { .set_coalesce = axienet_ethtools_set_coalesce, .get_link_ksettings = axienet_ethtools_get_link_ksettings, .set_link_ksettings = axienet_ethtools_set_link_ksettings, + .nway_reset = axienet_ethtools_nway_reset, }; -static void axienet_validate(struct phylink_config *config, - unsigned long *supported, - struct phylink_link_state *state) +static struct axienet_local *pcs_to_axienet_local(struct phylink_pcs *pcs) { - struct net_device *ndev = to_net_dev(config->dev); - struct axienet_local *lp = netdev_priv(ndev); - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; - - /* Only support the mode we are configured for */ - if (state->interface != PHY_INTERFACE_MODE_NA && - state->interface != lp->phy_mode) { - netdev_warn(ndev, "Cannot use PHY mode %s, supported: %s\n", - phy_modes(state->interface), - phy_modes(lp->phy_mode)); - bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); - return; - } + return container_of(pcs, struct axienet_local, pcs); +} + +static void axienet_pcs_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) +{ + struct mdio_device *pcs_phy = pcs_to_axienet_local(pcs)->pcs_phy; - phylink_set(mask, Autoneg); - phylink_set_port_modes(mask); + phylink_mii_c22_pcs_get_state(pcs_phy, state); +} - phylink_set(mask, Asym_Pause); - phylink_set(mask, Pause); - phylink_set(mask, 1000baseX_Full); - phylink_set(mask, 10baseT_Full); - phylink_set(mask, 100baseT_Full); - phylink_set(mask, 1000baseT_Full); +static void axienet_pcs_an_restart(struct phylink_pcs *pcs) +{ + struct mdio_device *pcs_phy = pcs_to_axienet_local(pcs)->pcs_phy; - bitmap_and(supported, supported, mask, - __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_and(state->advertising, state->advertising, mask, - __ETHTOOL_LINK_MODE_MASK_NBITS); + phylink_mii_c22_pcs_an_restart(pcs_phy); } -static void axienet_mac_pcs_get_state(struct phylink_config *config, - struct phylink_link_state *state) +static int axienet_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) { - struct net_device *ndev = to_net_dev(config->dev); + struct mdio_device *pcs_phy = pcs_to_axienet_local(pcs)->pcs_phy; + struct net_device *ndev = pcs_to_axienet_local(pcs)->ndev; struct axienet_local *lp = netdev_priv(ndev); - u32 emmc_reg, fcc_reg; - - state->interface = lp->phy_mode; + int ret; - emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET); - if (emmc_reg & XAE_EMMC_LINKSPD_1000) - state->speed = SPEED_1000; - else if (emmc_reg & XAE_EMMC_LINKSPD_100) - state->speed = SPEED_100; - else - state->speed = SPEED_10; + if (lp->switch_x_sgmii) { + ret = mdiodev_write(pcs_phy, XLNX_MII_STD_SELECT_REG, + interface == PHY_INTERFACE_MODE_SGMII ? + XLNX_MII_STD_SELECT_SGMII : 0); + if (ret < 0) { + netdev_warn(ndev, + "Failed to switch PHY interface: %d\n", + ret); + return ret; + } + } - state->pause = 0; - fcc_reg = axienet_ior(lp, XAE_FCC_OFFSET); - if (fcc_reg & XAE_FCC_FCTX_MASK) - state->pause |= MLO_PAUSE_TX; - if (fcc_reg & XAE_FCC_FCRX_MASK) - state->pause |= MLO_PAUSE_RX; + ret = phylink_mii_c22_pcs_config(pcs_phy, mode, interface, advertising); + if (ret < 0) + netdev_warn(ndev, "Failed to configure PCS: %d\n", ret); - state->an_complete = 0; - state->duplex = 1; + return ret; } -static void axienet_mac_an_restart(struct phylink_config *config) +static const struct phylink_pcs_ops axienet_pcs_ops = { + .pcs_get_state = axienet_pcs_get_state, + .pcs_config = axienet_pcs_config, + .pcs_an_restart = axienet_pcs_an_restart, +}; + +static struct phylink_pcs *axienet_mac_select_pcs(struct phylink_config *config, + phy_interface_t interface) { - /* Unsupported, do nothing */ + struct net_device *ndev = to_net_dev(config->dev); + struct axienet_local *lp = netdev_priv(ndev); + + if (interface == PHY_INTERFACE_MODE_1000BASEX || + interface == PHY_INTERFACE_MODE_SGMII) + return &lp->pcs; + + return NULL; } static void axienet_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { + /* nothing meaningful to do */ +} + +static void axienet_mac_link_down(struct phylink_config *config, + unsigned int mode, + phy_interface_t interface) +{ + /* nothing meaningful to do */ +} + +static void axienet_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ struct net_device *ndev = to_net_dev(config->dev); struct axienet_local *lp = netdev_priv(ndev); u32 emmc_reg, fcc_reg; @@ -1448,7 +1705,7 @@ static void axienet_mac_config(struct phylink_config *config, unsigned int mode, emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET); emmc_reg &= ~XAE_EMMC_LINKSPEED_MASK; - switch (state->speed) { + switch (speed) { case SPEED_1000: emmc_reg |= XAE_EMMC_LINKSPD_1000; break; @@ -1467,80 +1724,63 @@ static void axienet_mac_config(struct phylink_config *config, unsigned int mode, axienet_iow(lp, XAE_EMMC_OFFSET, emmc_reg); fcc_reg = axienet_ior(lp, XAE_FCC_OFFSET); - if (state->pause & MLO_PAUSE_TX) + if (tx_pause) fcc_reg |= XAE_FCC_FCTX_MASK; else fcc_reg &= ~XAE_FCC_FCTX_MASK; - if (state->pause & MLO_PAUSE_RX) + if (rx_pause) fcc_reg |= XAE_FCC_FCRX_MASK; else fcc_reg &= ~XAE_FCC_FCRX_MASK; axienet_iow(lp, XAE_FCC_OFFSET, fcc_reg); } -static void axienet_mac_link_down(struct phylink_config *config, - unsigned int mode, - phy_interface_t interface) -{ - /* nothing meaningful to do */ -} - -static void axienet_mac_link_up(struct phylink_config *config, - unsigned int mode, - phy_interface_t interface, - struct phy_device *phy) -{ - /* nothing meaningful to do */ -} - static const struct phylink_mac_ops axienet_phylink_ops = { - .validate = axienet_validate, - .mac_pcs_get_state = axienet_mac_pcs_get_state, - .mac_an_restart = axienet_mac_an_restart, + .validate = phylink_generic_validate, + .mac_select_pcs = axienet_mac_select_pcs, .mac_config = axienet_mac_config, .mac_link_down = axienet_mac_link_down, .mac_link_up = axienet_mac_link_up, }; /** - * axienet_dma_err_handler - Tasklet handler for Axi DMA Error - * @data: Data passed + * axienet_dma_err_handler - Work queue task for Axi DMA Error + * @work: pointer to work_struct * * Resets the Axi DMA and Axi Ethernet devices, and reconfigures the * Tx/Rx BDs. */ -static void axienet_dma_err_handler(unsigned long data) +static void axienet_dma_err_handler(struct work_struct *work) { + u32 i; u32 axienet_status; - u32 cr, i; - struct axienet_local *lp = (struct axienet_local *) data; - struct net_device *ndev = lp->ndev; struct axidma_bd *cur_p; + struct axienet_local *lp = container_of(work, struct axienet_local, + dma_err_task); + struct net_device *ndev = lp->ndev; + + napi_disable(&lp->napi_tx); + napi_disable(&lp->napi_rx); axienet_setoptions(ndev, lp->options & ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); - /* Disable the MDIO interface till Axi Ethernet Reset is completed. - * When we do an Axi Ethernet reset, it resets the complete core - * including the MDIO. MDIO must be disabled before resetting - * and re-enabled afterwards. - * Hold MDIO bus lock to avoid MDIO accesses during the reset. - */ - mutex_lock(&lp->mii_bus->mdio_lock); - axienet_mdio_disable(lp); - __axienet_device_reset(lp); - axienet_mdio_enable(lp); - mutex_unlock(&lp->mii_bus->mdio_lock); + + axienet_dma_stop(lp); for (i = 0; i < lp->tx_bd_num; i++) { cur_p = &lp->tx_bd_v[i]; - if (cur_p->phys) - dma_unmap_single(ndev->dev.parent, cur_p->phys, + if (cur_p->cntrl) { + dma_addr_t addr = desc_get_phys_addr(lp, cur_p); + + dma_unmap_single(lp->dev, addr, (cur_p->cntrl & XAXIDMA_BD_CTRL_LENGTH_MASK), DMA_TO_DEVICE); + } if (cur_p->skb) dev_kfree_skb_irq(cur_p->skb); cur_p->phys = 0; + cur_p->phys_msb = 0; cur_p->cntrl = 0; cur_p->status = 0; cur_p->app0 = 0; @@ -1565,50 +1805,7 @@ static void axienet_dma_err_handler(unsigned long data) lp->tx_bd_tail = 0; lp->rx_bd_ci = 0; - /* Start updating the Rx channel control register */ - cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - /* Update the interrupt coalesce count */ - cr = ((cr & ~XAXIDMA_COALESCE_MASK) | - (XAXIDMA_DFT_RX_THRESHOLD << XAXIDMA_COALESCE_SHIFT)); - /* Update the delay timer count */ - cr = ((cr & ~XAXIDMA_DELAY_MASK) | - (XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT)); - /* Enable coalesce, delay timer and error interrupts */ - cr |= XAXIDMA_IRQ_ALL_MASK; - /* Finally write to the Rx channel control register */ - axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr); - - /* Start updating the Tx channel control register */ - cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - /* Update the interrupt coalesce count */ - cr = (((cr & ~XAXIDMA_COALESCE_MASK)) | - (XAXIDMA_DFT_TX_THRESHOLD << XAXIDMA_COALESCE_SHIFT)); - /* Update the delay timer count */ - cr = (((cr & ~XAXIDMA_DELAY_MASK)) | - (XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT)); - /* Enable coalesce, delay timer and error interrupts */ - cr |= XAXIDMA_IRQ_ALL_MASK; - /* Finally write to the Tx channel control register */ - axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr); - - /* Populate the tail pointer and bring the Rx Axi DMA engine out of - * halted state. This will make the Rx side ready for reception. - */ - axienet_dma_out32(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p); - cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, - cr | XAXIDMA_CR_RUNSTOP_MASK); - axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p + - (sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1))); - - /* Write to the RS (Run-stop) bit in the Tx channel control register. - * Tx channel is now ready to run. But only after we write to the - * tail pointer register that the Tx channel will start transmitting - */ - axienet_dma_out32(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p); - cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, - cr | XAXIDMA_CR_RUNSTOP_MASK); + axienet_dma_start(lp); axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET); axienet_status &= ~XAE_RCW1_RX_MASK; @@ -1629,6 +1826,8 @@ static void axienet_dma_err_handler(unsigned long data) axienet_set_mac_address(ndev, NULL); axienet_set_multicast_list(ndev); axienet_setoptions(ndev, lp->options); + napi_enable(&lp->napi_rx); + napi_enable(&lp->napi_tx); } /** @@ -1649,8 +1848,9 @@ static int axienet_probe(struct platform_device *pdev) struct device_node *np; struct axienet_local *lp; struct net_device *ndev; - const void *mac_addr; struct resource *ethres; + u8 mac_addr[ETH_ALEN]; + int addr_width = 32; u32 value; ndev = alloc_etherdev(sizeof(*lp)); @@ -1675,13 +1875,47 @@ static int axienet_probe(struct platform_device *pdev) lp->options = XAE_OPTION_DEFAULTS; lp->rx_bd_num = RX_BD_NUM_DEFAULT; lp->tx_bd_num = TX_BD_NUM_DEFAULT; + + u64_stats_init(&lp->rx_stat_sync); + u64_stats_init(&lp->tx_stat_sync); + + netif_napi_add(ndev, &lp->napi_rx, axienet_rx_poll); + netif_napi_add(ndev, &lp->napi_tx, axienet_tx_poll); + + lp->axi_clk = devm_clk_get_optional(&pdev->dev, "s_axi_lite_clk"); + if (!lp->axi_clk) { + /* For backward compatibility, if named AXI clock is not present, + * treat the first clock specified as the AXI clock. + */ + lp->axi_clk = devm_clk_get_optional(&pdev->dev, NULL); + } + if (IS_ERR(lp->axi_clk)) { + ret = PTR_ERR(lp->axi_clk); + goto free_netdev; + } + ret = clk_prepare_enable(lp->axi_clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable AXI clock: %d\n", ret); + goto free_netdev; + } + + lp->misc_clks[0].id = "axis_clk"; + lp->misc_clks[1].id = "ref_clk"; + lp->misc_clks[2].id = "mgt_clk"; + + ret = devm_clk_bulk_get_optional(&pdev->dev, XAE_NUM_MISC_CLOCKS, lp->misc_clks); + if (ret) + goto cleanup_clk; + + ret = clk_bulk_prepare_enable(XAE_NUM_MISC_CLOCKS, lp->misc_clks); + if (ret) + goto cleanup_clk; + /* Map device registers */ - ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - lp->regs = devm_ioremap_resource(&pdev->dev, ethres); + lp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, ðres); if (IS_ERR(lp->regs)) { - dev_err(&pdev->dev, "could not map Axi Ethernet regs.\n"); ret = PTR_ERR(lp->regs); - goto free_netdev; + goto cleanup_clk; } lp->regs_start = ethres->start; @@ -1734,6 +1968,9 @@ static int axienet_probe(struct platform_device *pdev) */ of_property_read_u32(pdev->dev.of_node, "xlnx,rxmem", &lp->rxmem); + lp->switch_x_sgmii = of_property_read_bool(pdev->dev.of_node, + "xlnx,switch-x-sgmii"); + /* Start with the proprietary, and broken phy_type */ ret = of_property_read_u32(pdev->dev.of_node, "xlnx,phy-type", &value); if (!ret) { @@ -1756,12 +1993,18 @@ static int axienet_probe(struct platform_device *pdev) break; default: ret = -EINVAL; - goto free_netdev; + goto cleanup_clk; } } else { ret = of_get_phy_mode(pdev->dev.of_node, &lp->phy_mode); if (ret) - goto free_netdev; + goto cleanup_clk; + } + if (lp->switch_x_sgmii && lp->phy_mode != PHY_INTERFACE_MODE_SGMII && + lp->phy_mode != PHY_INTERFACE_MODE_1000BASEX) { + dev_err(&pdev->dev, "xlnx,switch-x-sgmii only supported with SGMII or 1000BaseX\n"); + ret = -EINVAL; + goto cleanup_clk; } /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ @@ -1774,32 +2017,65 @@ static int axienet_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to get DMA resource\n"); of_node_put(np); - goto free_netdev; + goto cleanup_clk; } lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares); lp->rx_irq = irq_of_parse_and_map(np, 1); lp->tx_irq = irq_of_parse_and_map(np, 0); of_node_put(np); - lp->eth_irq = platform_get_irq(pdev, 0); + lp->eth_irq = platform_get_irq_optional(pdev, 0); } else { /* Check for these resources directly on the Ethernet node. */ - struct resource *res = platform_get_resource(pdev, - IORESOURCE_MEM, 1); - lp->dma_regs = devm_ioremap_resource(&pdev->dev, res); + lp->dma_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); lp->rx_irq = platform_get_irq(pdev, 1); lp->tx_irq = platform_get_irq(pdev, 0); - lp->eth_irq = platform_get_irq(pdev, 2); + lp->eth_irq = platform_get_irq_optional(pdev, 2); } if (IS_ERR(lp->dma_regs)) { dev_err(&pdev->dev, "could not map DMA regs\n"); ret = PTR_ERR(lp->dma_regs); - goto free_netdev; + goto cleanup_clk; } if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) { dev_err(&pdev->dev, "could not determine irqs\n"); ret = -ENOMEM; - goto free_netdev; + goto cleanup_clk; + } + + /* Autodetect the need for 64-bit DMA pointers. + * When the IP is configured for a bus width bigger than 32 bits, + * writing the MSB registers is mandatory, even if they are all 0. + * We can detect this case by writing all 1's to one such register + * and see if that sticks: when the IP is configured for 32 bits + * only, those registers are RES0. + * Those MSB registers were introduced in IP v7.1, which we check first. + */ + if ((axienet_ior(lp, XAE_ID_OFFSET) >> 24) >= 0x9) { + void __iomem *desc = lp->dma_regs + XAXIDMA_TX_CDESC_OFFSET + 4; + + iowrite32(0x0, desc); + if (ioread32(desc) == 0) { /* sanity check */ + iowrite32(0xffffffff, desc); + if (ioread32(desc) > 0) { + lp->features |= XAE_FEATURE_DMA_64BIT; + addr_width = 64; + dev_info(&pdev->dev, + "autodetected 64-bit DMA range\n"); + } + iowrite32(0x0, desc); + } + } + if (!IS_ENABLED(CONFIG_64BIT) && lp->features & XAE_FEATURE_DMA_64BIT) { + dev_err(&pdev->dev, "64-bit addressable DMA is not compatible with 32-bit archecture\n"); + ret = -EINVAL; + goto cleanup_clk; + } + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_width)); + if (ret) { + dev_err(&pdev->dev, "No suitable DMA available\n"); + goto cleanup_clk; } /* Check for Ethernet core IRQ (optional) */ @@ -1807,41 +2083,68 @@ static int axienet_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Ethernet core IRQ not defined\n"); /* Retrieve the MAC address */ - mac_addr = of_get_mac_address(pdev->dev.of_node); - if (IS_ERR(mac_addr)) { - dev_warn(&pdev->dev, "could not find MAC address property: %ld\n", - PTR_ERR(mac_addr)); - mac_addr = NULL; + ret = of_get_mac_address(pdev->dev.of_node, mac_addr); + if (!ret) { + axienet_set_mac_address(ndev, mac_addr); + } else { + dev_warn(&pdev->dev, "could not find MAC address property: %d\n", + ret); + axienet_set_mac_address(ndev, NULL); } - axienet_set_mac_address(ndev, mac_addr); lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD; + lp->coalesce_usec_rx = XAXIDMA_DFT_RX_USEC; lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD; + lp->coalesce_usec_tx = XAXIDMA_DFT_TX_USEC; - lp->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); - if (lp->phy_node) { - lp->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(lp->clk)) { - dev_warn(&pdev->dev, "Failed to get clock: %ld\n", - PTR_ERR(lp->clk)); - lp->clk = NULL; - } else { - ret = clk_prepare_enable(lp->clk); - if (ret) { - dev_err(&pdev->dev, "Unable to enable clock: %d\n", - ret); - goto free_netdev; - } - } + /* Reset core now that clocks are enabled, prior to accessing MDIO */ + ret = __axienet_device_reset(lp); + if (ret) + goto cleanup_clk; - ret = axienet_mdio_setup(lp); - if (ret) - dev_warn(&pdev->dev, - "error registering MDIO bus: %d\n", ret); + ret = axienet_mdio_setup(lp); + if (ret) + dev_warn(&pdev->dev, + "error registering MDIO bus: %d\n", ret); + + if (lp->phy_mode == PHY_INTERFACE_MODE_SGMII || + lp->phy_mode == PHY_INTERFACE_MODE_1000BASEX) { + np = of_parse_phandle(pdev->dev.of_node, "pcs-handle", 0); + if (!np) { + /* Deprecated: Always use "pcs-handle" for pcs_phy. + * Falling back to "phy-handle" here is only for + * backward compatibility with old device trees. + */ + np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); + } + if (!np) { + dev_err(&pdev->dev, "pcs-handle (preferred) or phy-handle required for 1000BaseX/SGMII\n"); + ret = -EINVAL; + goto cleanup_mdio; + } + lp->pcs_phy = of_mdio_find_device(np); + if (!lp->pcs_phy) { + ret = -EPROBE_DEFER; + of_node_put(np); + goto cleanup_mdio; + } + of_node_put(np); + lp->pcs.ops = &axienet_pcs_ops; + lp->pcs.poll = true; } lp->phylink_config.dev = &ndev->dev; lp->phylink_config.type = PHYLINK_NETDEV; + lp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE | + MAC_10FD | MAC_100FD | MAC_1000FD; + + __set_bit(lp->phy_mode, lp->phylink_config.supported_interfaces); + if (lp->switch_x_sgmii) { + __set_bit(PHY_INTERFACE_MODE_1000BASEX, + lp->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_SGMII, + lp->phylink_config.supported_interfaces); + } lp->phylink = phylink_create(&lp->phylink_config, pdev->dev.fwnode, lp->phy_mode, @@ -1849,17 +2152,29 @@ static int axienet_probe(struct platform_device *pdev) if (IS_ERR(lp->phylink)) { ret = PTR_ERR(lp->phylink); dev_err(&pdev->dev, "phylink_create error (%i)\n", ret); - goto free_netdev; + goto cleanup_mdio; } ret = register_netdev(lp->ndev); if (ret) { dev_err(lp->dev, "register_netdev() error (%i)\n", ret); - goto free_netdev; + goto cleanup_phylink; } return 0; +cleanup_phylink: + phylink_destroy(lp->phylink); + +cleanup_mdio: + if (lp->pcs_phy) + put_device(&lp->pcs_phy->dev); + if (lp->mii_bus) + axienet_mdio_teardown(lp); +cleanup_clk: + clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks); + clk_disable_unprepare(lp->axi_clk); + free_netdev: free_netdev(ndev); @@ -1876,13 +2191,13 @@ static int axienet_remove(struct platform_device *pdev) if (lp->phylink) phylink_destroy(lp->phylink); - axienet_mdio_teardown(lp); + if (lp->pcs_phy) + put_device(&lp->pcs_phy->dev); - if (lp->clk) - clk_disable_unprepare(lp->clk); + axienet_mdio_teardown(lp); - of_node_put(lp->phy_node); - lp->phy_node = NULL; + clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks); + clk_disable_unprepare(lp->axi_clk); free_netdev(ndev); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c index 435ed308d990..0b3b6935c558 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c @@ -30,6 +30,23 @@ static int axienet_mdio_wait_until_ready(struct axienet_local *lp) 1, 20000); } +/* Enable the MDIO MDC. Called prior to a read/write operation */ +static void axienet_mdio_mdc_enable(struct axienet_local *lp) +{ + axienet_iow(lp, XAE_MDIO_MC_OFFSET, + ((u32)lp->mii_clk_div | XAE_MDIO_MC_MDIOEN_MASK)); +} + +/* Disable the MDIO MDC. Called after a read/write operation*/ +static void axienet_mdio_mdc_disable(struct axienet_local *lp) +{ + u32 mc_reg; + + mc_reg = axienet_ior(lp, XAE_MDIO_MC_OFFSET); + axienet_iow(lp, XAE_MDIO_MC_OFFSET, + (mc_reg & ~XAE_MDIO_MC_MDIOEN_MASK)); +} + /** * axienet_mdio_read - MDIO interface read function * @bus: Pointer to mii bus structure @@ -48,9 +65,13 @@ static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg) int ret; struct axienet_local *lp = bus->priv; + axienet_mdio_mdc_enable(lp); + ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) + if (ret < 0) { + axienet_mdio_mdc_disable(lp); return ret; + } axienet_iow(lp, XAE_MDIO_MCR_OFFSET, (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) & @@ -61,14 +82,17 @@ static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg) XAE_MDIO_MCR_OP_READ_MASK)); ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) + if (ret < 0) { + axienet_mdio_mdc_disable(lp); return ret; + } rc = axienet_ior(lp, XAE_MDIO_MRD_OFFSET) & 0x0000FFFF; dev_dbg(lp->dev, "axienet_mdio_read(phy_id=%i, reg=%x) == %x\n", phy_id, reg, rc); + axienet_mdio_mdc_disable(lp); return rc; } @@ -82,7 +106,7 @@ static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg) * Return: 0 on success, -ETIMEDOUT on a timeout * * Writes the value to the requested register by first writing the value - * into MWD register. The the MCR register is then appropriately setup + * into MWD register. The MCR register is then appropriately setup * to finish the write operation. */ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg, @@ -94,11 +118,15 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg, dev_dbg(lp->dev, "axienet_mdio_write(phy_id=%i, reg=%x, val=%x)\n", phy_id, reg, val); + axienet_mdio_mdc_enable(lp); + ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) + if (ret < 0) { + axienet_mdio_mdc_disable(lp); return ret; + } - axienet_iow(lp, XAE_MDIO_MWD_OFFSET, (u32) val); + axienet_iow(lp, XAE_MDIO_MWD_OFFSET, (u32)val); axienet_iow(lp, XAE_MDIO_MCR_OFFSET, (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) & XAE_MDIO_MCR_PHYAD_MASK) | @@ -108,8 +136,11 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg, XAE_MDIO_MCR_OP_WRITE_MASK)); ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) + if (ret < 0) { + axienet_mdio_mdc_disable(lp); return ret; + } + axienet_mdio_mdc_disable(lp); return 0; } @@ -124,10 +155,12 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg, **/ int axienet_mdio_enable(struct axienet_local *lp) { - u32 clk_div, host_clock; + u32 host_clock; - if (lp->clk) { - host_clock = clk_get_rate(lp->clk); + lp->mii_clk_div = 0; + + if (lp->axi_clk) { + host_clock = clk_get_rate(lp->axi_clk); } else { struct device_node *np1; @@ -176,19 +209,19 @@ int axienet_mdio_enable(struct axienet_local *lp) * "clock-frequency" from the CPU */ - clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1; + lp->mii_clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1; /* If there is any remainder from the division of * fHOST / (MAX_MDIO_FREQ * 2), then we need to add * 1 to the clock divisor or we will surely be above 2.5 MHz */ if (host_clock % (MAX_MDIO_FREQ * 2)) - clk_div++; + lp->mii_clk_div++; netdev_dbg(lp->ndev, "Setting MDIO clock divisor to %u/%u Hz host clock.\n", - clk_div, host_clock); + lp->mii_clk_div, host_clock); - axienet_iow(lp, XAE_MDIO_MC_OFFSET, clk_div | XAE_MDIO_MC_MDIOEN_MASK); + axienet_iow(lp, XAE_MDIO_MC_OFFSET, lp->mii_clk_div | XAE_MDIO_MC_MDIOEN_MASK); return axienet_mdio_wait_until_ready(lp); } @@ -211,8 +244,8 @@ void axienet_mdio_disable(struct axienet_local *lp) * Return: 0 on success, -ETIMEDOUT on a timeout, -ENOMEM when * mdiobus_alloc (to allocate memory for mii bus structure) fails. * - * Sets up the MDIO interface by initializing the MDIO clock and enabling the - * MDIO interface in hardware. Register the MDIO interface. + * Sets up the MDIO interface by initializing the MDIO clock. + * Register the MDIO interface. **/ int axienet_mdio_setup(struct axienet_local *lp) { @@ -246,6 +279,7 @@ int axienet_mdio_setup(struct axienet_local *lp) lp->mii_bus = NULL; return ret; } + axienet_mdio_mdc_disable(lp); return 0; } diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 0c26f5bcc523..a3967f8de417 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -1,11 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* - * Xilinx EmacLite Linux driver for the Xilinx Ethernet MAC Lite device. +/* Xilinx EmacLite Linux driver for the Xilinx Ethernet MAC Lite device. * * This is a new flat driver which is based on the original emac_lite * driver from John Williams <john.williams@xilinx.com>. * - * 2007 - 2013 (c) Xilinx, Inc. + * Copyright (c) 2007 - 2013 Xilinx, Inc. */ #include <linux/module.h> @@ -91,13 +90,7 @@ #define XEL_ARP_PACKET_SIZE 28 /* Max ARP packet size */ #define XEL_HEADER_IP_LENGTH_OFFSET 16 /* IP Length Offset */ - - #define TX_TIMEOUT (60 * HZ) /* Tx timeout is 60 seconds. */ -#define ALIGNMENT 4 - -/* BUFFER_ALIGN(adr) calculates the number of bytes to the next alignment. */ -#define BUFFER_ALIGN(adr) ((ALIGNMENT - ((u32)adr)) % ALIGNMENT) #ifdef __BIG_ENDIAN #define xemaclite_readl ioread32be @@ -115,7 +108,7 @@ * @next_tx_buf_to_use: next Tx buffer to write to * @next_rx_buf_to_use: next Rx buffer to read from * @base_addr: base address of the Emaclite device - * @reset_lock: lock used for synchronization + * @reset_lock: lock to serialize xmit and tx_timeout execution * @deferred_skb: holds an skb (for transmission at a later time) when the * Tx buffer is not free * @phy_dev: pointer to the PHY device @@ -124,7 +117,6 @@ * @last_link: last link status */ struct net_local { - struct net_device *ndev; bool tx_ping_pong; @@ -133,7 +125,7 @@ struct net_local { u32 next_rx_buf_to_use; void __iomem *base_addr; - spinlock_t reset_lock; + spinlock_t reset_lock; /* serialize xmit and tx_timeout execution */ struct sk_buff *deferred_skb; struct phy_device *phy_dev; @@ -144,7 +136,6 @@ struct net_local { int last_link; }; - /*************************/ /* EmacLite driver calls */ /*************************/ @@ -206,12 +197,13 @@ static void xemaclite_disable_interrupts(struct net_local *drvdata) * This function writes data from a 16-bit aligned buffer to a 32-bit aligned * address in the EmacLite device. */ -static void xemaclite_aligned_write(void *src_ptr, u32 *dest_ptr, - unsigned length) +static void xemaclite_aligned_write(const void *src_ptr, u32 *dest_ptr, + unsigned int length) { + const u16 *from_u16_ptr; u32 align_buffer; u32 *to_u32_ptr; - u16 *from_u16_ptr, *to_u16_ptr; + u16 *to_u16_ptr; to_u32_ptr = dest_ptr; from_u16_ptr = src_ptr; @@ -264,7 +256,7 @@ static void xemaclite_aligned_write(void *src_ptr, u32 *dest_ptr, * to a 16-bit aligned buffer. */ static void xemaclite_aligned_read(u32 *src_ptr, u8 *dest_ptr, - unsigned length) + unsigned int length) { u16 *to_u16_ptr, *from_u16_ptr; u32 *from_u32_ptr; @@ -329,7 +321,6 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data, reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET); if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK)) == 0) { - /* Switch to next buffer if configured */ if (drvdata->tx_ping_pong != 0) drvdata->next_tx_buf_to_use ^= XEL_BUFFER_OFFSET; @@ -338,15 +329,16 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data, * if it is configured in HW */ - addr = (void __iomem __force *)((u32 __force)addr ^ + addr = (void __iomem __force *)((uintptr_t __force)addr ^ XEL_BUFFER_OFFSET); reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET); if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK)) != 0) return -1; /* Buffers were full, return failure */ - } else + } else { return -1; /* Buffer was full, return failure */ + } /* Write the frame to the buffer */ xemaclite_aligned_write(data, (u32 __force *)addr, byte_count); @@ -399,8 +391,9 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data, int maxlen) * will correct on subsequent calls */ if (drvdata->rx_ping_pong != 0) - addr = (void __iomem __force *)((u32 __force)addr ^ - XEL_BUFFER_OFFSET); + addr = (void __iomem __force *) + ((uintptr_t __force)addr ^ + XEL_BUFFER_OFFSET); else return 0; /* No data was available */ @@ -421,7 +414,6 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data, int maxlen) * or an IP packet or an ARP packet */ if (proto_type > ETH_DATA_LEN) { - if (proto_type == ETH_P_IP) { length = ((ntohl(xemaclite_readl(addr + XEL_HEADER_IP_LENGTH_OFFSET + @@ -431,23 +423,25 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data, int maxlen) length = min_t(u16, length, ETH_DATA_LEN); length += ETH_HLEN + ETH_FCS_LEN; - } else if (proto_type == ETH_P_ARP) + } else if (proto_type == ETH_P_ARP) { length = XEL_ARP_PACKET_SIZE + ETH_HLEN + ETH_FCS_LEN; - else + } else { /* Field contains type other than IP or ARP, use max * frame size and let user parse it */ length = ETH_FRAME_LEN + ETH_FCS_LEN; - } else + } + } else { /* Use the length in the frame, plus the header and trailer */ length = proto_type + ETH_HLEN + ETH_FCS_LEN; + } if (WARN_ON(length > maxlen)) length = maxlen; /* Read from the EmacLite device */ xemaclite_aligned_read((u32 __force *)(addr + XEL_RXBUFF_OFFSET), - data, length); + data, length); /* Acknowledge the frame */ reg_data = xemaclite_readl(addr + XEL_RSR_OFFSET); @@ -469,7 +463,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data, int maxlen) * buffers (if configured). */ static void xemaclite_update_address(struct net_local *drvdata, - u8 *address_ptr) + const u8 *address_ptr) { void __iomem *addr; u32 reg_data; @@ -496,7 +490,7 @@ static void xemaclite_update_address(struct net_local *drvdata, * @dev: Pointer to the network device instance * @address: Void pointer to the sockaddr structure * - * This function copies the HW address from the sockaddr strucutre to the + * This function copies the HW address from the sockaddr structure to the * net_device structure and updates the address in HW. * * Return: Error if the net device is busy or 0 if the addr is set @@ -510,7 +504,7 @@ static int xemaclite_set_mac_address(struct net_device *dev, void *address) if (netif_running(dev)) return -EBUSY; - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + eth_hw_addr_set(dev, addr->sa_data); xemaclite_update_address(lp, dev->dev_addr); return 0; } @@ -518,6 +512,7 @@ static int xemaclite_set_mac_address(struct net_device *dev, void *address) /** * xemaclite_tx_timeout - Callback for Tx Timeout * @dev: Pointer to the network device + * @txqueue: Unused * * This function is called when Tx time out occurs for Emaclite device. */ @@ -596,11 +591,10 @@ static void xemaclite_rx_handler(struct net_device *dev) { struct net_local *lp = netdev_priv(dev); struct sk_buff *skb; - unsigned int align; u32 len; len = ETH_FRAME_LEN + ETH_FCS_LEN; - skb = netdev_alloc_skb(dev, len + ALIGNMENT); + skb = netdev_alloc_skb(dev, len + NET_IP_ALIGN); if (!skb) { /* Couldn't get memory. */ dev->stats.rx_dropped++; @@ -608,16 +602,7 @@ static void xemaclite_rx_handler(struct net_device *dev) return; } - /* A new skb should have the data halfword aligned, but this code is - * here just in case that isn't true. Calculate how many - * bytes we should reserve to get the data to start on a word - * boundary - */ - align = BUFFER_ALIGN(skb->data); - if (align) - skb_reserve(skb, align); - - skb_reserve(skb, 2); + skb_reserve(skb, NET_IP_ALIGN); len = xemaclite_recv_data(lp, (u8 *)skb->data, len); @@ -668,8 +653,7 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id) /* Check if the Transmission for the first buffer is completed */ tx_status = xemaclite_readl(base_addr + XEL_TSR_OFFSET); if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) && - (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { - + (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK; xemaclite_writel(tx_status, base_addr + XEL_TSR_OFFSET); @@ -679,8 +663,7 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id) /* Check if the Transmission for the second buffer is completed */ tx_status = xemaclite_readl(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) && - (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { - + (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK; xemaclite_writel(tx_status, base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); @@ -820,10 +803,10 @@ static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg, static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev) { struct mii_bus *bus; - int rc; struct resource res; struct device_node *np = of_get_parent(lp->phy_node); struct device_node *npp; + int rc, ret; /* Don't register the MDIO bus if the phy_node or its parent node * can't be found. @@ -833,16 +816,24 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev) return -ENODEV; } npp = of_get_parent(np); - - of_address_to_resource(npp, 0, &res); + ret = of_address_to_resource(npp, 0, &res); + of_node_put(npp); + if (ret) { + dev_err(dev, "%s resource error!\n", + dev->of_node->full_name); + of_node_put(np); + return ret; + } if (lp->ndev->mem_start != res.start) { struct phy_device *phydev; + phydev = of_phy_find_device(lp->phy_node); if (!phydev) dev_info(dev, "MDIO of the phy is not registered yet\n"); else put_device(&phydev->mdio.dev); + of_node_put(np); return 0; } @@ -855,6 +846,7 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev) bus = mdiobus_alloc(); if (!bus) { dev_err(dev, "Failed to allocate mdiobus\n"); + of_node_put(np); return -ENOMEM; } @@ -867,6 +859,7 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev) bus->parent = dev; rc = of_mdiobus_register(bus, np); + of_node_put(np); if (rc) { dev_err(dev, "Failed to register mdio bus.\n"); goto err_register; @@ -923,8 +916,6 @@ static int xemaclite_open(struct net_device *dev) xemaclite_disable_interrupts(lp); if (lp->phy_node) { - u32 bmcr; - lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node, xemaclite_adjust_link, 0, PHY_INTERFACE_MODE_MII); @@ -935,19 +926,6 @@ static int xemaclite_open(struct net_device *dev) /* EmacLite doesn't support giga-bit speeds */ phy_set_max_speed(lp->phy_dev, SPEED_100); - - /* Don't advertise 1000BASE-T Full/Half duplex speeds */ - phy_write(lp->phy_dev, MII_CTRL1000, 0); - - /* Advertise only 10 and 100mbps full/half duplex speeds */ - phy_write(lp->phy_dev, MII_ADVERTISE, ADVERTISE_ALL | - ADVERTISE_CSMA); - - /* Restart auto negotiation */ - bmcr = phy_read(lp->phy_dev, MII_BMCR); - bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); - phy_write(lp->phy_dev, MII_BMCR, bmcr); - phy_start(lp->phy_dev); } @@ -1082,7 +1060,7 @@ static bool get_bool(struct platform_device *ofdev, const char *s) static void xemaclite_ethtools_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *ed) { - strlcpy(ed->driver, DRIVER_NAME, sizeof(ed->driver)); + strscpy(ed->driver, DRIVER_NAME, sizeof(ed->driver)); } static const struct ethtool_ops xemaclite_ethtool_ops = { @@ -1113,7 +1091,6 @@ static int xemaclite_of_probe(struct platform_device *ofdev) struct net_device *ndev = NULL; struct net_local *lp = NULL; struct device *dev = &ofdev->dev; - const void *mac_address; int rc = 0; @@ -1131,14 +1108,11 @@ static int xemaclite_of_probe(struct platform_device *ofdev) lp->ndev = ndev; /* Get IRQ for the device */ - res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "no IRQ found\n"); - rc = -ENXIO; + rc = platform_get_irq(ofdev, 0); + if (rc < 0) goto error; - } - ndev->irq = res->start; + ndev->irq = rc; res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); lp->base_addr = devm_ioremap_resource(&ofdev->dev, res); @@ -1155,12 +1129,9 @@ static int xemaclite_of_probe(struct platform_device *ofdev) lp->next_rx_buf_to_use = 0x0; lp->tx_ping_pong = get_bool(ofdev, "xlnx,tx-ping-pong"); lp->rx_ping_pong = get_bool(ofdev, "xlnx,rx-ping-pong"); - mac_address = of_get_mac_address(ofdev->dev.of_node); - if (!IS_ERR(mac_address)) { - /* Set the MAC address. */ - ether_addr_copy(ndev->dev_addr, mac_address); - } else { + rc = of_get_ethdev_address(ofdev->dev.of_node, ndev); + if (rc) { dev_warn(dev, "No MAC address found, using random\n"); eth_hw_addr_random(ndev); } @@ -1187,15 +1158,16 @@ static int xemaclite_of_probe(struct platform_device *ofdev) if (rc) { dev_err(dev, "Cannot register network device, aborting\n"); - goto error; + goto put_node; } dev_info(dev, - "Xilinx EmacLite at 0x%08X mapped to 0x%08X, irq=%d\n", - (unsigned int __force)ndev->mem_start, - (unsigned int __force)lp->base_addr, ndev->irq); + "Xilinx EmacLite at 0x%08lX mapped to 0x%p, irq=%d\n", + (unsigned long __force)ndev->mem_start, lp->base_addr, ndev->irq); return 0; +put_node: + of_node_put(lp->phy_node); error: free_netdev(ndev); return rc; @@ -1266,7 +1238,7 @@ static const struct net_device_ops xemaclite_netdev_ops = { .ndo_start_xmit = xemaclite_send, .ndo_set_mac_address = xemaclite_set_mac_address, .ndo_tx_timeout = xemaclite_tx_timeout, - .ndo_do_ioctl = xemaclite_ioctl, + .ndo_eth_ioctl = xemaclite_ioctl, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = xemaclite_poll_controller, #endif |