diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/net/ethernet/xilinx')
9 files changed, 0 insertions, 5470 deletions
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/Kconfig b/ANDROID_3.4.5/drivers/net/ethernet/xilinx/Kconfig deleted file mode 100644 index 5778a4ae..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/Kconfig +++ /dev/null @@ -1,44 +0,0 @@ -# -# Xilink device configuration -# - -config NET_VENDOR_XILINX - bool "Xilinx devices" - default y - depends on PPC || PPC32 || MICROBLAZE - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Xilinx devices. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_XILINX - -config XILINX_EMACLITE - tristate "Xilinx 10/100 Ethernet Lite support" - depends on (PPC32 || MICROBLAZE) - select PHYLIB - ---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 (PPC32 || MICROBLAZE) - select PHYLIB - ---help--- - This driver supports the 10/100/1000 Ethernet from Xilinx for the - AXI bus interface used in Xilinx Virtex FPGAs. - -config XILINX_LL_TEMAC - tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" - depends on (PPC || MICROBLAZE) - select PHYLIB - ---help--- - This driver supports the Xilinx 10/100/1000 LocalLink TEMAC - core used in Xilinx Spartan and Virtex FPGAs - -endif # NET_VENDOR_XILINX diff --git a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/Makefile b/ANDROID_3.4.5/drivers/net/ethernet/xilinx/Makefile deleted file mode 100644 index 214205e9..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the Xilink network device drivers. -# - -ll_temac-objs := ll_temac_main.o ll_temac_mdio.o -obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o -obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o -xilinx_emac-objs := xilinx_axienet_main.o xilinx_axienet_mdio.o -obj-$(CONFIG_XILINX_AXI_EMAC) += xilinx_emac.o diff --git a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/ll_temac.h b/ANDROID_3.4.5/drivers/net/ethernet/xilinx/ll_temac.h deleted file mode 100644 index 522abe2f..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/ll_temac.h +++ /dev/null @@ -1,385 +0,0 @@ - -#ifndef XILINX_LL_TEMAC_H -#define XILINX_LL_TEMAC_H - -#include <linux/netdevice.h> -#include <linux/of.h> -#include <linux/spinlock.h> - -#ifdef CONFIG_PPC_DCR -#include <asm/dcr.h> -#include <asm/dcr-regs.h> -#endif - -/* packet size info */ -#define XTE_HDR_SIZE 14 /* size of Ethernet header */ -#define XTE_TRL_SIZE 4 /* size of Ethernet trailer (FCS) */ -#define XTE_JUMBO_MTU 9000 -#define XTE_MAX_JUMBO_FRAME_SIZE (XTE_JUMBO_MTU + XTE_HDR_SIZE + XTE_TRL_SIZE) - -/* Configuration options */ - -/* Accept all incoming packets. - * This option defaults to disabled (cleared) */ -#define XTE_OPTION_PROMISC (1 << 0) -/* Jumbo frame support for Tx & Rx. - * This option defaults to disabled (cleared) */ -#define XTE_OPTION_JUMBO (1 << 1) -/* VLAN Rx & Tx frame support. - * 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) */ -#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) */ -#define XTE_OPTION_FCS_STRIP (1 << 5) -/* Generate FCS field and add PAD automatically for outgoing frames. - * 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) */ -#define XTE_OPTION_LENTYPE_ERR (1 << 7) -/* Enable the transmitter. - * This option defaults to enabled (set) */ -#define XTE_OPTION_TXEN (1 << 11) -/* Enable the receiver -* This option defaults to enabled (set) */ -#define XTE_OPTION_RXEN (1 << 12) - -/* Default options set when device is initialized or reset */ -#define XTE_OPTION_DEFAULTS \ - (XTE_OPTION_TXEN | \ - XTE_OPTION_FLOW_CONTROL | \ - XTE_OPTION_RXEN) - -/* XPS_LL_TEMAC SDMA registers definition */ - -#define TX_NXTDESC_PTR 0x00 /* r */ -#define TX_CURBUF_ADDR 0x01 /* r */ -#define TX_CURBUF_LENGTH 0x02 /* r */ -#define TX_CURDESC_PTR 0x03 /* rw */ -#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 -*/ -#define CHNL_CTRL_IRQ_IOE (1 << 9) -#define CHNL_CTRL_IRQ_EN (1 << 7) -#define CHNL_CTRL_IRQ_ERR_EN (1 << 2) -#define CHNL_CTRL_IRQ_DLY_EN (1 << 1) -#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 - */ -#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 -*/ - -#define RX_NXTDESC_PTR 0x08 /* r */ -#define RX_CURBUF_ADDR 0x09 /* r */ -#define RX_CURBUF_LENGTH 0x0a /* r */ -#define RX_CURDESC_PTR 0x0b /* rw */ -#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 - */ -#define RX_IRQ_REG 0x0e /* rw */ -#define IRQ_COAL (1 << 0) -#define IRQ_DLY (1 << 1) -#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 -*/ -#define RX_CHNL_STS 0x0f /* r */ -#define CHNL_STS_ENGBUSY (1 << 1) -#define CHNL_STS_EOP (1 << 2) -#define CHNL_STS_SOP (1 << 3) -#define CHNL_STS_CMPLT (1 << 4) -#define CHNL_STS_SOE (1 << 5) -#define CHNL_STS_IOE (1 << 6) -#define CHNL_STS_ERR (1 << 7) - -#define CHNL_STS_BSYWR (1 << 16) -#define CHNL_STS_CURPERR (1 << 17) -#define CHNL_STS_NXTPERR (1 << 18) -#define CHNL_STS_ADDRERR (1 << 19) -#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 -*/ - -#define DMA_CONTROL_REG 0x10 /* rw */ -#define DMA_CONTROL_RST (1 << 0) -#define DMA_TAIL_ENABLE (1 << 2) - -/* XPS_LL_TEMAC direct registers definition */ - -#define XTE_RAF0_OFFSET 0x00 -#define RAF0_RST (1 << 0) -#define RAF0_MCSTREJ (1 << 1) -#define RAF0_BCSTREJ (1 << 2) -#define XTE_TPF0_OFFSET 0x04 -#define XTE_IFGP0_OFFSET 0x08 -#define XTE_ISR0_OFFSET 0x0c -#define ISR0_HARDACSCMPLT (1 << 0) -#define ISR0_AUTONEG (1 << 1) -#define ISR0_RXCMPLT (1 << 2) -#define ISR0_RXREJ (1 << 3) -#define ISR0_RXFIFOOVR (1 << 4) -#define ISR0_TXCMPLT (1 << 5) -#define ISR0_RXDCMLCK (1 << 6) - -#define XTE_IPR0_OFFSET 0x10 -#define XTE_IER0_OFFSET 0x14 - -#define XTE_MSW0_OFFSET 0x20 -#define XTE_LSW0_OFFSET 0x24 -#define XTE_CTL0_OFFSET 0x28 -#define XTE_RDY0_OFFSET 0x2c - -#define XTE_RSE_MIIM_RR_MASK 0x0002 -#define XTE_RSE_MIIM_WR_MASK 0x0004 -#define XTE_RSE_CFG_RR_MASK 0x0020 -#define XTE_RSE_CFG_WR_MASK 0x0040 -#define XTE_RDY0_HARD_ACS_RDY_MASK (0x10000) - -/* XPS_LL_TEMAC indirect registers offset definition */ - -#define XTE_RXC0_OFFSET 0x00000200 /* Rx configuration word 0 */ -#define XTE_RXC1_OFFSET 0x00000240 /* Rx configuration word 1 */ -#define XTE_RXC1_RXRST_MASK (1 << 31) /* Receiver reset */ -#define XTE_RXC1_RXJMBO_MASK (1 << 30) /* Jumbo frame enable */ -#define XTE_RXC1_RXFCS_MASK (1 << 29) /* FCS not stripped */ -#define XTE_RXC1_RXEN_MASK (1 << 28) /* Receiver enable */ -#define XTE_RXC1_RXVLAN_MASK (1 << 27) /* VLAN enable */ -#define XTE_RXC1_RXHD_MASK (1 << 26) /* Half duplex */ -#define XTE_RXC1_RXLT_MASK (1 << 25) /* Length/type check disable */ - -#define XTE_TXC_OFFSET 0x00000280 /* Tx configuration */ -#define XTE_TXC_TXRST_MASK (1 << 31) /* Transmitter reset */ -#define XTE_TXC_TXJMBO_MASK (1 << 30) /* Jumbo frame enable */ -#define XTE_TXC_TXFCS_MASK (1 << 29) /* Generate FCS */ -#define XTE_TXC_TXEN_MASK (1 << 28) /* Transmitter enable */ -#define XTE_TXC_TXVLAN_MASK (1 << 27) /* VLAN enable */ -#define XTE_TXC_TXHD_MASK (1 << 26) /* Half duplex */ - -#define XTE_FCC_OFFSET 0x000002C0 /* Flow control config */ -#define XTE_FCC_RXFLO_MASK (1 << 29) /* Rx flow control enable */ -#define XTE_FCC_TXFLO_MASK (1 << 30) /* Tx flow control enable */ - -#define XTE_EMCFG_OFFSET 0x00000300 /* EMAC configuration */ -#define XTE_EMCFG_LINKSPD_MASK 0xC0000000 /* Link speed */ -#define XTE_EMCFG_HOSTEN_MASK (1 << 26) /* Host interface enable */ -#define XTE_EMCFG_LINKSPD_10 0x00000000 /* 10 Mbit LINKSPD_MASK */ -#define XTE_EMCFG_LINKSPD_100 (1 << 30) /* 100 Mbit LINKSPD_MASK */ -#define XTE_EMCFG_LINKSPD_1000 (1 << 31) /* 1000 Mbit LINKSPD_MASK */ - -#define XTE_GMIC_OFFSET 0x00000320 /* RGMII/SGMII config */ -#define XTE_MC_OFFSET 0x00000340 /* MDIO configuration */ -#define XTE_UAW0_OFFSET 0x00000380 /* Unicast address word 0 */ -#define XTE_UAW1_OFFSET 0x00000384 /* Unicast address word 1 */ - -#define XTE_MAW0_OFFSET 0x00000388 /* Multicast addr word 0 */ -#define XTE_MAW1_OFFSET 0x0000038C /* Multicast addr word 1 */ -#define XTE_AFM_OFFSET 0x00000390 /* Promiscuous mode */ -#define XTE_AFM_EPPRM_MASK (1 << 31) /* Promiscuous mode enable */ - -/* Interrupt Request status */ -#define XTE_TIS_OFFSET 0x000003A0 -#define TIS_FRIS (1 << 0) -#define TIS_MRIS (1 << 1) -#define TIS_MWIS (1 << 2) -#define TIS_ARIS (1 << 3) -#define TIS_AWIS (1 << 4) -#define TIS_CRIS (1 << 5) -#define TIS_CWIS (1 << 6) - -#define XTE_TIE_OFFSET 0x000003A4 /* Interrupt enable */ - -/** MII Mamagement Control register (MGTCR) */ -#define XTE_MGTDR_OFFSET 0x000003B0 /* MII data */ -#define XTE_MIIMAI_OFFSET 0x000003B4 /* MII control */ - -#define CNTLREG_WRITE_ENABLE_MASK 0x8000 -#define CNTLREG_EMAC1SEL_MASK 0x0400 -#define CNTLREG_ADDRESSCODE_MASK 0x03ff - -/* CDMAC descriptor status bit definitions */ - -#define STS_CTRL_APP0_ERR (1 << 31) -#define STS_CTRL_APP0_IRQONEND (1 << 30) -/* undoccumented */ -#define STS_CTRL_APP0_STOPONEND (1 << 29) -#define STS_CTRL_APP0_CMPLT (1 << 28) -#define STS_CTRL_APP0_SOP (1 << 27) -#define STS_CTRL_APP0_EOP (1 << 26) -#define STS_CTRL_APP0_ENGBUSY (1 << 25) -/* undocumented */ -#define STS_CTRL_APP0_ENGRST (1 << 24) - -#define TX_CONTROL_CALC_CSUM_MASK 1 - -#define MULTICAST_CAM_TABLE_NUM 4 - -/* TEMAC Synthesis features */ -#define TEMAC_FEATURE_RX_CSUM (1 << 0) -#define TEMAC_FEATURE_TX_CSUM (1 << 1) - -/* TX/RX CURDESC_PTR points to first descriptor */ -/* TX/RX TAILDESC_PTR points to last descriptor in linked list */ - -/** - * struct cdmac_bd - LocalLink buffer descriptor format - * - * app0 bits: - * 0 Error - * 1 IrqOnEnd generate an interrupt at completion of DMA op - * 2 reserved - * 3 completed Current descriptor completed - * 4 SOP TX - marks first desc/ RX marks first desct - * 5 EOP TX marks last desc/RX marks last desc - * 6 EngBusy DMA is processing - * 7 reserved - * 8:31 application specific - */ -struct cdmac_bd { - u32 next; /* Physical address of next buffer descriptor */ - u32 phys; - u32 len; - u32 app0; - u32 app1; /* TX start << 16 | insert */ - u32 app2; /* TX csum */ - u32 app3; - u32 app4; /* skb for TX length for RX */ -}; - -struct temac_local { - struct net_device *ndev; - struct device *dev; - - /* Connection to PHY device */ - struct phy_device *phy_dev; /* Pointer to PHY device */ - struct device_node *phy_node; - - /* MDIO bus data */ - struct mii_bus *mii_bus; /* MII bus reference */ - int mdio_irqs[PHY_MAX_ADDR]; /* IRQs table for MDIO bus */ - - /* IO registers, dma functions and IRQs */ - void __iomem *regs; - void __iomem *sdma_regs; -#ifdef CONFIG_PPC_DCR - dcr_host_t sdma_dcrs; -#endif - u32 (*dma_in)(struct temac_local *, int); - void (*dma_out)(struct temac_local *, int, u32); - - int tx_irq; - int rx_irq; - int emac_num; - - struct sk_buff **rx_skb; - spinlock_t rx_lock; - struct mutex indirect_mutex; - u32 options; /* Current options word */ - int last_link; - unsigned int temac_features; - - /* Buffer descriptors */ - struct cdmac_bd *tx_bd_v; - dma_addr_t tx_bd_p; - struct cdmac_bd *rx_bd_v; - dma_addr_t rx_bd_p; - int tx_bd_ci; - int tx_bd_next; - int tx_bd_tail; - int rx_bd_ci; -}; - -/* xilinx_temac.c */ -u32 temac_ior(struct temac_local *lp, int offset); -void temac_iow(struct temac_local *lp, int offset, u32 value); -int temac_indirect_busywait(struct temac_local *lp); -u32 temac_indirect_in32(struct temac_local *lp, int reg); -void temac_indirect_out32(struct temac_local *lp, int reg, u32 value); - - -/* xilinx_temac_mdio.c */ -int temac_mdio_setup(struct temac_local *lp, struct device_node *np); -void temac_mdio_teardown(struct temac_local *lp); - -#endif /* XILINX_LL_TEMAC_H */ diff --git a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/ll_temac_main.c b/ANDROID_3.4.5/drivers/net/ethernet/xilinx/ll_temac_main.c deleted file mode 100644 index d21591a2..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/ll_temac_main.c +++ /dev/null @@ -1,1189 +0,0 @@ -/* - * Driver for Xilinx TEMAC Ethernet device - * - * Copyright (c) 2008 Nissin Systems Co., Ltd., Yoshio Kashiwagi - * Copyright (c) 2005-2008 DLA Systems, David H. Lynch Jr. <dhlii@dlasys.net> - * Copyright (c) 2008-2009 Secret Lab Technologies Ltd. - * - * This is a driver for the Xilinx ll_temac ipcore which is often used - * in the Virtex and Spartan series of chips. - * - * Notes: - * - The ll_temac hardware uses indirect access for many of the TEMAC - * registers, include the MDIO bus. However, indirect access to MDIO - * registers take considerably more clock cycles than to TEMAC registers. - * MDIO accesses are long, so threads doing them should probably sleep - * rather than busywait. However, since only one indirect access can be - * in progress at any given time, that means that *all* indirect accesses - * could end up sleeping (to wait for an MDIO access to complete). - * Fortunately none of the indirect accesses are on the 'hot' path for tx - * or rx, so this should be okay. - * - * TODO: - * - Factor out locallink DMA code into separate driver - * - Fix multicast assignment. - * - Fix support for hardware checksumming. - * - Testing. Lots and lots of testing. - * - */ - -#include <linux/delay.h> -#include <linux/etherdevice.h> -#include <linux/init.h> -#include <linux/mii.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/netdevice.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_mdio.h> -#include <linux/of_platform.h> -#include <linux/of_address.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/tcp.h> /* needed for sizeof(tcphdr) */ -#include <linux/udp.h> /* needed for sizeof(udphdr) */ -#include <linux/phy.h> -#include <linux/in.h> -#include <linux/io.h> -#include <linux/ip.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> - -#include "ll_temac.h" - -#define TX_BD_NUM 64 -#define RX_BD_NUM 128 - -/* --------------------------------------------------------------------- - * Low level register access functions - */ - -u32 temac_ior(struct temac_local *lp, int offset) -{ - return in_be32((u32 *)(lp->regs + offset)); -} - -void temac_iow(struct temac_local *lp, int offset, u32 value) -{ - out_be32((u32 *) (lp->regs + offset), value); -} - -int temac_indirect_busywait(struct temac_local *lp) -{ - long end = jiffies + 2; - - while (!(temac_ior(lp, XTE_RDY0_OFFSET) & XTE_RDY0_HARD_ACS_RDY_MASK)) { - if (end - jiffies <= 0) { - WARN_ON(1); - return -ETIMEDOUT; - } - msleep(1); - } - return 0; -} - -/** - * temac_indirect_in32 - * - * lp->indirect_mutex must be held when calling this function - */ -u32 temac_indirect_in32(struct temac_local *lp, int reg) -{ - u32 val; - - if (temac_indirect_busywait(lp)) - return -ETIMEDOUT; - temac_iow(lp, XTE_CTL0_OFFSET, reg); - if (temac_indirect_busywait(lp)) - return -ETIMEDOUT; - val = temac_ior(lp, XTE_LSW0_OFFSET); - - return val; -} - -/** - * temac_indirect_out32 - * - * lp->indirect_mutex must be held when calling this function - */ -void temac_indirect_out32(struct temac_local *lp, int reg, u32 value) -{ - if (temac_indirect_busywait(lp)) - return; - temac_iow(lp, XTE_LSW0_OFFSET, value); - temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg); - temac_indirect_busywait(lp); -} - -/** - * temac_dma_in32 - Memory mapped DMA read, this function expects a - * register input that is based on DCR word addresses which - * are then converted to memory mapped byte addresses - */ -static u32 temac_dma_in32(struct temac_local *lp, int reg) -{ - return in_be32((u32 *)(lp->sdma_regs + (reg << 2))); -} - -/** - * temac_dma_out32 - Memory mapped DMA read, this function expects a - * register input that is based on DCR word addresses which - * are then converted to memory mapped byte addresses - */ -static void temac_dma_out32(struct temac_local *lp, int reg, u32 value) -{ - out_be32((u32 *)(lp->sdma_regs + (reg << 2)), value); -} - -/* DMA register access functions can be DCR based or memory mapped. - * The PowerPC 440 is DCR based, the PowerPC 405 and MicroBlaze are both - * memory mapped. - */ -#ifdef CONFIG_PPC_DCR - -/** - * temac_dma_dcr_in32 - DCR based DMA read - */ -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) -{ - 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) -{ - unsigned int dcrs; - - /* setup the dcr address mapping if it's in the device tree */ - - dcrs = dcr_resource_start(np, 0); - if (dcrs != 0) { - lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0)); - lp->dma_in = temac_dma_dcr_in; - lp->dma_out = temac_dma_dcr_out; - dev_dbg(&op->dev, "DCR base: %x\n", dcrs); - return 0; - } - /* no DCR in the device tree, indicate a failure */ - return -1; -} - -#else - -/* - * temac_dcr_setup - This is a stub for when DCR is not supported, - * such as with MicroBlaze - */ -static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op, - 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) -{ - struct temac_local *lp = netdev_priv(ndev); - int i; - - /* Reset Local Link (DMA) */ - lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); - - for (i = 0; i < 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]); - } - } - 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); - 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); - if (lp->rx_skb) - kfree(lp->rx_skb); -} - -/** - * temac_dma_bd_init - Setup buffer descriptor rings - */ -static int temac_dma_bd_init(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - struct sk_buff *skb; - int i; - - lp->rx_skb = kcalloc(RX_BD_NUM, sizeof(*lp->rx_skb), GFP_KERNEL); - if (!lp->rx_skb) { - dev_err(&ndev->dev, - "can't allocate memory for DMA RX buffer\n"); - 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, - &lp->tx_bd_p, GFP_KERNEL); - if (!lp->tx_bd_v) { - dev_err(&ndev->dev, - "unable to allocate DMA TX buffer descriptors"); - goto out; - } - lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, - sizeof(*lp->rx_bd_v) * RX_BD_NUM, - &lp->rx_bd_p, GFP_KERNEL); - if (!lp->rx_bd_v) { - dev_err(&ndev->dev, - "unable to allocate DMA RX buffer descriptors"); - goto out; - } - - memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM); - for (i = 0; i < TX_BD_NUM; i++) { - lp->tx_bd_v[i].next = lp->tx_bd_p + - sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM); - } - - memset(lp->rx_bd_v, 0, sizeof(*lp->rx_bd_v) * RX_BD_NUM); - for (i = 0; i < RX_BD_NUM; i++) { - lp->rx_bd_v[i].next = lp->rx_bd_p + - sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM); - - skb = netdev_alloc_skb_ip_align(ndev, - XTE_MAX_JUMBO_FRAME_SIZE); - - if (skb == 0) { - dev_err(&ndev->dev, "alloc_skb error %d\n", i); - goto out; - } - lp->rx_skb[i] = skb; - /* returns physical address of skb->data */ - lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent, - skb->data, - XTE_MAX_JUMBO_FRAME_SIZE, - DMA_FROM_DEVICE); - lp->rx_bd_v[i].len = XTE_MAX_JUMBO_FRAME_SIZE; - lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND; - } - - lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 | - CHNL_CTRL_IRQ_EN | - CHNL_CTRL_IRQ_DLY_EN | - CHNL_CTRL_IRQ_COAL_EN); - /* 0x10220483 */ - /* 0x00100483 */ - lp->dma_out(lp, RX_CHNL_CTRL, 0xff070000 | - CHNL_CTRL_IRQ_EN | - CHNL_CTRL_IRQ_DLY_EN | - CHNL_CTRL_IRQ_COAL_EN | - CHNL_CTRL_IRQ_IOE); - /* 0xff010283 */ - - lp->dma_out(lp, RX_CURDESC_PTR, lp->rx_bd_p); - lp->dma_out(lp, RX_TAILDESC_PTR, - lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1))); - lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p); - - return 0; - -out: - temac_dma_bd_release(ndev); - return -ENOMEM; -} - -/* --------------------------------------------------------------------- - * net_device_ops - */ - -static int temac_set_mac_address(struct net_device *ndev, void *address) -{ - struct temac_local *lp = netdev_priv(ndev); - - if (address) - memcpy(ndev->dev_addr, address, ETH_ALEN); - - if (!is_valid_ether_addr(ndev->dev_addr)) - eth_hw_addr_random(ndev); - else - ndev->addr_assign_type &= ~NET_ADDR_RANDOM; - - /* set up unicast MAC address filter set its mac address */ - mutex_lock(&lp->indirect_mutex); - temac_indirect_out32(lp, XTE_UAW0_OFFSET, - (ndev->dev_addr[0]) | - (ndev->dev_addr[1] << 8) | - (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 */ - temac_indirect_out32(lp, XTE_UAW1_OFFSET, - (ndev->dev_addr[4] & 0x000000ff) | - (ndev->dev_addr[5] << 8)); - mutex_unlock(&lp->indirect_mutex); - - return 0; -} - -static int netdev_set_mac_address(struct net_device *ndev, void *p) -{ - struct sockaddr *addr = p; - - return temac_set_mac_address(ndev, addr->sa_data); -} - -static void temac_set_multicast_list(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - u32 multi_addr_msw, multi_addr_lsw, val; - int i; - - mutex_lock(&lp->indirect_mutex); - if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) || - netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM) { - /* - * We must make the kernel realise we had to move - * into promisc mode or we start all out war on - * the cable. If it was a promisc request the - * flag is already set. If not we assert it. - */ - ndev->flags |= IFF_PROMISC; - temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK); - dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); - } else if (!netdev_mc_empty(ndev)) { - struct netdev_hw_addr *ha; - - i = 0; - netdev_for_each_mc_addr(ha, ndev) { - if (i >= MULTICAST_CAM_TABLE_NUM) - break; - multi_addr_msw = ((ha->addr[3] << 24) | - (ha->addr[2] << 16) | - (ha->addr[1] << 8) | - (ha->addr[0])); - temac_indirect_out32(lp, XTE_MAW0_OFFSET, - multi_addr_msw); - multi_addr_lsw = ((ha->addr[5] << 8) | - (ha->addr[4]) | (i << 16)); - temac_indirect_out32(lp, XTE_MAW1_OFFSET, - multi_addr_lsw); - i++; - } - } else { - val = temac_indirect_in32(lp, XTE_AFM_OFFSET); - temac_indirect_out32(lp, XTE_AFM_OFFSET, - val & ~XTE_AFM_EPPRM_MASK); - temac_indirect_out32(lp, XTE_MAW0_OFFSET, 0); - temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0); - dev_info(&ndev->dev, "Promiscuous mode disabled.\n"); - } - mutex_unlock(&lp->indirect_mutex); -} - -struct temac_option { - int flg; - u32 opt; - u32 reg; - u32 m_or; - u32 m_and; -} temac_options[] = { - /* Turn on jumbo packet support for both Rx and Tx */ - { - .opt = XTE_OPTION_JUMBO, - .reg = XTE_TXC_OFFSET, - .m_or = XTE_TXC_TXJMBO_MASK, - }, - { - .opt = XTE_OPTION_JUMBO, - .reg = XTE_RXC1_OFFSET, - .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, - }, - { - .opt = XTE_OPTION_VLAN, - .reg = XTE_RXC1_OFFSET, - .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, - }, - /* Turn on FCS insertion on transmit packets */ - { - .opt = XTE_OPTION_FCS_INSERT, - .reg = XTE_TXC_OFFSET, - .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, - }, - /* Turn on flow control */ - { - .opt = XTE_OPTION_FLOW_CONTROL, - .reg = XTE_FCC_OFFSET, - .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, - }, - /* Turn on promiscuous frame filtering (all frames are received ) */ - { - .opt = XTE_OPTION_PROMISC, - .reg = XTE_AFM_OFFSET, - .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, - }, - /* Enable receiver? */ - { - .opt = XTE_OPTION_RXEN, - .reg = XTE_RXC1_OFFSET, - .m_or =XTE_RXC1_RXEN_MASK, - }, - {} -}; - -/** - * temac_setoptions - */ -static u32 temac_setoptions(struct net_device *ndev, u32 options) -{ - struct temac_local *lp = netdev_priv(ndev); - struct temac_option *tp = &temac_options[0]; - int reg; - - mutex_lock(&lp->indirect_mutex); - while (tp->opt) { - reg = temac_indirect_in32(lp, tp->reg) & ~tp->m_or; - if (options & tp->opt) - reg |= tp->m_or; - temac_indirect_out32(lp, tp->reg, reg); - tp++; - } - lp->options |= options; - mutex_unlock(&lp->indirect_mutex); - - return 0; -} - -/* Initialize temac */ -static void temac_device_reset(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - u32 timeout; - u32 val; - - /* Perform a software reset */ - - /* 0x300 host enable bit ? */ - /* reset PHY through control register ?:1 */ - - dev_dbg(&ndev->dev, "%s()\n", __func__); - - mutex_lock(&lp->indirect_mutex); - /* Reset the receiver and wait for it to finish reset */ - temac_indirect_out32(lp, XTE_RXC1_OFFSET, XTE_RXC1_RXRST_MASK); - timeout = 1000; - while (temac_indirect_in32(lp, XTE_RXC1_OFFSET) & XTE_RXC1_RXRST_MASK) { - udelay(1); - if (--timeout == 0) { - dev_err(&ndev->dev, - "temac_device_reset RX reset timeout!!\n"); - break; - } - } - - /* Reset the transmitter and wait for it to finish reset */ - temac_indirect_out32(lp, XTE_TXC_OFFSET, XTE_TXC_TXRST_MASK); - timeout = 1000; - while (temac_indirect_in32(lp, XTE_TXC_OFFSET) & XTE_TXC_TXRST_MASK) { - udelay(1); - if (--timeout == 0) { - dev_err(&ndev->dev, - "temac_device_reset TX reset timeout!!\n"); - break; - } - } - - /* Disable the receiver */ - val = temac_indirect_in32(lp, XTE_RXC1_OFFSET); - temac_indirect_out32(lp, XTE_RXC1_OFFSET, val & ~XTE_RXC1_RXEN_MASK); - - /* Reset Local Link (DMA) */ - lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); - timeout = 1000; - while (lp->dma_in(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) { - udelay(1); - if (--timeout == 0) { - dev_err(&ndev->dev, - "temac_device_reset DMA reset timeout!!\n"); - break; - } - } - lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE); - - if (temac_dma_bd_init(ndev)) { - dev_err(&ndev->dev, - "temac_device_reset descriptor allocation failed\n"); - } - - temac_indirect_out32(lp, XTE_RXC0_OFFSET, 0); - temac_indirect_out32(lp, XTE_RXC1_OFFSET, 0); - temac_indirect_out32(lp, XTE_TXC_OFFSET, 0); - temac_indirect_out32(lp, XTE_FCC_OFFSET, XTE_FCC_RXFLO_MASK); - - mutex_unlock(&lp->indirect_mutex); - - /* Sync default options with HW - * but leave receiver and transmitter disabled. */ - temac_setoptions(ndev, - lp->options & ~(XTE_OPTION_TXEN | XTE_OPTION_RXEN)); - - temac_set_mac_address(ndev, NULL); - - /* Set address filter table */ - temac_set_multicast_list(ndev); - if (temac_setoptions(ndev, lp->options)) - dev_err(&ndev->dev, "Error setting TEMAC options\n"); - - /* Init Driver variable */ - ndev->trans_start = jiffies; /* prevent tx timeout */ -} - -void temac_adjust_link(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - struct phy_device *phy = lp->phy_dev; - u32 mii_speed; - int link_state; - - /* hash together the state values to decide if something has changed */ - link_state = phy->speed | (phy->duplex << 1) | phy->link; - - mutex_lock(&lp->indirect_mutex); - if (lp->last_link != link_state) { - mii_speed = temac_indirect_in32(lp, XTE_EMCFG_OFFSET); - 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; - } - - /* Write new speed setting out to TEMAC */ - temac_indirect_out32(lp, XTE_EMCFG_OFFSET, mii_speed); - lp->last_link = link_state; - phy_print_status(phy); - } - mutex_unlock(&lp->indirect_mutex); -} - -static void temac_start_xmit_done(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - struct cdmac_bd *cur_p; - unsigned int stat = 0; - - cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; - stat = cur_p->app0; - - while (stat & STS_CTRL_APP0_CMPLT) { - dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len, - DMA_TO_DEVICE); - if (cur_p->app4) - dev_kfree_skb_irq((struct sk_buff *)cur_p->app4); - cur_p->app0 = 0; - cur_p->app1 = 0; - cur_p->app2 = 0; - cur_p->app3 = 0; - cur_p->app4 = 0; - - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += cur_p->len; - - lp->tx_bd_ci++; - if (lp->tx_bd_ci >= TX_BD_NUM) - lp->tx_bd_ci = 0; - - cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; - stat = cur_p->app0; - } - - netif_wake_queue(ndev); -} - -static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag) -{ - struct cdmac_bd *cur_p; - int tail; - - tail = lp->tx_bd_tail; - cur_p = &lp->tx_bd_v[tail]; - - do { - if (cur_p->app0) - return NETDEV_TX_BUSY; - - tail++; - if (tail >= TX_BD_NUM) - tail = 0; - - cur_p = &lp->tx_bd_v[tail]; - num_frag--; - } while (num_frag >= 0); - - return 0; -} - -static int 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; - 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)) { - if (!netif_queue_stopped(ndev)) { - netif_stop_queue(ndev); - return NETDEV_TX_BUSY; - } - return NETDEV_TX_BUSY; - } - - cur_p->app0 = 0; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - unsigned int csum_start_off = skb_checksum_start_offset(skb); - unsigned int csum_index_off = csum_start_off + skb->csum_offset; - - cur_p->app0 |= 1; /* TX Checksum Enabled */ - cur_p->app1 = (csum_start_off << 16) | csum_index_off; - cur_p->app2 = 0; /* initial checksum seed */ - } - - cur_p->app0 |= STS_CTRL_APP0_SOP; - cur_p->len = skb_headlen(skb); - cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len, - DMA_TO_DEVICE); - cur_p->app4 = (unsigned long)skb; - - for (ii = 0; ii < num_frag; ii++) { - lp->tx_bd_tail++; - if (lp->tx_bd_tail >= TX_BD_NUM) - lp->tx_bd_tail = 0; - - cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; - cur_p->phys = dma_map_single(ndev->dev.parent, - skb_frag_address(frag), - skb_frag_size(frag), DMA_TO_DEVICE); - cur_p->len = skb_frag_size(frag); - cur_p->app0 = 0; - frag++; - } - cur_p->app0 |= STS_CTRL_APP0_EOP; - - 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) - lp->tx_bd_tail = 0; - - skb_tx_timestamp(skb); - - /* Kick off the transfer */ - lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ - - return NETDEV_TX_OK; -} - - -static void ll_temac_recv(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - struct sk_buff *skb, *new_skb; - unsigned int bdstat; - struct cdmac_bd *cur_p; - dma_addr_t tail_p; - int length; - unsigned long flags; - - spin_lock_irqsave(&lp->rx_lock, flags); - - tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; - cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; - - bdstat = cur_p->app0; - while ((bdstat & STS_CTRL_APP0_CMPLT)) { - - skb = lp->rx_skb[lp->rx_bd_ci]; - length = cur_p->app4 & 0x3FFF; - - dma_unmap_single(ndev->dev.parent, cur_p->phys, length, - DMA_FROM_DEVICE); - - skb_put(skb, length); - skb->dev = ndev; - skb->protocol = eth_type_trans(skb, ndev); - skb_checksum_none_assert(skb); - - /* if we're doing rx csum offload, set it up */ - if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) && - (skb->protocol == __constant_htons(ETH_P_IP)) && - (skb->len > 64)) { - - skb->csum = cur_p->app3 & 0xFFFF; - skb->ip_summed = CHECKSUM_COMPLETE; - } - - if (!skb_defer_rx_timestamp(skb)) - netif_rx(skb); - - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += length; - - new_skb = netdev_alloc_skb_ip_align(ndev, - XTE_MAX_JUMBO_FRAME_SIZE); - - if (new_skb == 0) { - dev_err(&ndev->dev, "no memory for new sk_buff\n"); - spin_unlock_irqrestore(&lp->rx_lock, flags); - return; - } - - cur_p->app0 = STS_CTRL_APP0_IRQONEND; - cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data, - XTE_MAX_JUMBO_FRAME_SIZE, - DMA_FROM_DEVICE); - cur_p->len = XTE_MAX_JUMBO_FRAME_SIZE; - lp->rx_skb[lp->rx_bd_ci] = new_skb; - - lp->rx_bd_ci++; - if (lp->rx_bd_ci >= RX_BD_NUM) - lp->rx_bd_ci = 0; - - cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; - bdstat = cur_p->app0; - } - lp->dma_out(lp, RX_TAILDESC_PTR, tail_p); - - spin_unlock_irqrestore(&lp->rx_lock, flags); -} - -static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev) -{ - struct net_device *ndev = _ndev; - struct temac_local *lp = netdev_priv(ndev); - unsigned int status; - - status = lp->dma_in(lp, TX_IRQ_REG); - lp->dma_out(lp, TX_IRQ_REG, status); - - if (status & (IRQ_COAL | IRQ_DLY)) - temac_start_xmit_done(lp->ndev); - if (status & 0x080) - dev_err(&ndev->dev, "DMA error 0x%x\n", status); - - return IRQ_HANDLED; -} - -static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev) -{ - struct net_device *ndev = _ndev; - struct temac_local *lp = netdev_priv(ndev); - unsigned int status; - - /* Read and clear the status registers */ - status = lp->dma_in(lp, RX_IRQ_REG); - lp->dma_out(lp, RX_IRQ_REG, status); - - if (status & (IRQ_COAL | IRQ_DLY)) - ll_temac_recv(lp->ndev); - - return IRQ_HANDLED; -} - -static int temac_open(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - int rc; - - dev_dbg(&ndev->dev, "temac_open()\n"); - - if (lp->phy_node) { - lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node, - temac_adjust_link, 0, 0); - if (!lp->phy_dev) { - dev_err(lp->dev, "of_phy_connect() failed\n"); - return -ENODEV; - } - - phy_start(lp->phy_dev); - } - - temac_device_reset(ndev); - - rc = request_irq(lp->tx_irq, ll_temac_tx_irq, 0, ndev->name, ndev); - if (rc) - goto err_tx_irq; - rc = request_irq(lp->rx_irq, ll_temac_rx_irq, 0, ndev->name, ndev); - if (rc) - goto err_rx_irq; - - return 0; - - err_rx_irq: - free_irq(lp->tx_irq, ndev); - err_tx_irq: - if (lp->phy_dev) - phy_disconnect(lp->phy_dev); - lp->phy_dev = NULL; - dev_err(lp->dev, "request_irq() failed\n"); - return rc; -} - -static int temac_stop(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - - dev_dbg(&ndev->dev, "temac_close()\n"); - - free_irq(lp->tx_irq, ndev); - free_irq(lp->rx_irq, ndev); - - if (lp->phy_dev) - phy_disconnect(lp->phy_dev); - lp->phy_dev = NULL; - - temac_dma_bd_release(ndev); - - return 0; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void -temac_poll_controller(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - - disable_irq(lp->tx_irq); - disable_irq(lp->rx_irq); - - ll_temac_rx_irq(lp->tx_irq, ndev); - ll_temac_tx_irq(lp->rx_irq, ndev); - - enable_irq(lp->tx_irq); - enable_irq(lp->rx_irq); -} -#endif - -static int temac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) -{ - struct temac_local *lp = netdev_priv(ndev); - - if (!netif_running(ndev)) - return -EINVAL; - - if (!lp->phy_dev) - return -EINVAL; - - return phy_mii_ioctl(lp->phy_dev, rq, cmd); -} - -static const struct net_device_ops temac_netdev_ops = { - .ndo_open = temac_open, - .ndo_stop = temac_stop, - .ndo_start_xmit = temac_start_xmit, - .ndo_set_mac_address = netdev_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = temac_ioctl, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = temac_poll_controller, -#endif -}; - -/* --------------------------------------------------------------------- - * SYSFS device attributes - */ -static ssize_t temac_show_llink_regs(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct temac_local *lp = netdev_priv(ndev); - int i, len = 0; - - for (i = 0; i < 0x11; i++) - len += sprintf(buf + len, "%.8x%s", lp->dma_in(lp, i), - (i % 8) == 7 ? "\n" : " "); - len += sprintf(buf + len, "\n"); - - return len; -} - -static DEVICE_ATTR(llink_regs, 0440, temac_show_llink_regs, NULL); - -static struct attribute *temac_device_attrs[] = { - &dev_attr_llink_regs.attr, - NULL, -}; - -static const struct attribute_group temac_attr_group = { - .attrs = temac_device_attrs, -}; - -/* ethtool support */ -static int temac_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) -{ - struct temac_local *lp = netdev_priv(ndev); - return phy_ethtool_gset(lp->phy_dev, cmd); -} - -static int temac_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) -{ - struct temac_local *lp = netdev_priv(ndev); - return phy_ethtool_sset(lp->phy_dev, cmd); -} - -static int temac_nway_reset(struct net_device *ndev) -{ - struct temac_local *lp = netdev_priv(ndev); - return phy_start_aneg(lp->phy_dev); -} - -static const struct ethtool_ops temac_ethtool_ops = { - .get_settings = temac_get_settings, - .set_settings = temac_set_settings, - .nway_reset = temac_nway_reset, - .get_link = ethtool_op_get_link, -}; - -static int __devinit temac_of_probe(struct platform_device *op) -{ - struct device_node *np; - struct temac_local *lp; - struct net_device *ndev; - const void *addr; - __be32 *p; - int size, rc = 0; - - /* Init network device structure */ - ndev = alloc_etherdev(sizeof(*lp)); - if (!ndev) - return -ENOMEM; - - ether_setup(ndev); - dev_set_drvdata(&op->dev, ndev); - SET_NETDEV_DEV(ndev, &op->dev); - ndev->flags &= ~IFF_MULTICAST; /* clear multicast */ - ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST; - ndev->netdev_ops = &temac_netdev_ops; - ndev->ethtool_ops = &temac_ethtool_ops; -#if 0 - ndev->features |= NETIF_F_IP_CSUM; /* Can checksum TCP/UDP over IPv4. */ - ndev->features |= NETIF_F_HW_CSUM; /* Can checksum all the packets. */ - ndev->features |= NETIF_F_IPV6_CSUM; /* Can checksum IPV6 TCP/UDP */ - ndev->features |= NETIF_F_HIGHDMA; /* Can DMA to high memory. */ - ndev->features |= NETIF_F_HW_VLAN_TX; /* Transmit VLAN hw accel */ - ndev->features |= NETIF_F_HW_VLAN_RX; /* Receive VLAN hw acceleration */ - ndev->features |= NETIF_F_HW_VLAN_FILTER; /* Receive VLAN filtering */ - ndev->features |= NETIF_F_VLAN_CHALLENGED; /* cannot handle VLAN pkts */ - ndev->features |= NETIF_F_GSO; /* Enable software GSO. */ - ndev->features |= NETIF_F_MULTI_QUEUE; /* Has multiple TX/RX queues */ - ndev->features |= NETIF_F_LRO; /* large receive offload */ -#endif - - /* setup temac private info structure */ - lp = netdev_priv(ndev); - lp->ndev = ndev; - lp->dev = &op->dev; - lp->options = XTE_OPTION_DEFAULTS; - spin_lock_init(&lp->rx_lock); - mutex_init(&lp->indirect_mutex); - - /* map device registers */ - lp->regs = of_iomap(op->dev.of_node, 0); - if (!lp->regs) { - dev_err(&op->dev, "could not map temac regs.\n"); - goto nodev; - } - - /* Setup checksum offload, but default to off if not specified */ - lp->temac_features = 0; - p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,txcsum", NULL); - if (p && be32_to_cpu(*p)) { - lp->temac_features |= TEMAC_FEATURE_TX_CSUM; - /* Can checksum TCP/UDP over IPv4. */ - ndev->features |= NETIF_F_IP_CSUM; - } - p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL); - if (p && be32_to_cpu(*p)) - lp->temac_features |= TEMAC_FEATURE_RX_CSUM; - - /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ - np = of_parse_phandle(op->dev.of_node, "llink-connected", 0); - if (!np) { - dev_err(&op->dev, "could not find DMA node\n"); - goto err_iounmap; - } - - /* Setup the DMA register accesses, could be DCR or memory mapped */ - if (temac_dcr_setup(lp, op, np)) { - - /* no DCR in the device tree, try non-DCR */ - lp->sdma_regs = of_iomap(np, 0); - if (lp->sdma_regs) { - lp->dma_in = temac_dma_in32; - lp->dma_out = temac_dma_out32; - dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs); - } else { - dev_err(&op->dev, "unable to map DMA registers\n"); - of_node_put(np); - goto err_iounmap; - } - } - - lp->rx_irq = irq_of_parse_and_map(np, 0); - lp->tx_irq = irq_of_parse_and_map(np, 1); - - of_node_put(np); /* Finished with the DMA node; drop the reference */ - - if (!lp->rx_irq || !lp->tx_irq) { - dev_err(&op->dev, "could not determine irqs\n"); - rc = -ENOMEM; - goto err_iounmap_2; - } - - - /* Retrieve the MAC address */ - addr = of_get_property(op->dev.of_node, "local-mac-address", &size); - if ((!addr) || (size != 6)) { - dev_err(&op->dev, "could not find MAC address\n"); - rc = -ENODEV; - goto err_iounmap_2; - } - temac_set_mac_address(ndev, (void *)addr); - - rc = temac_mdio_setup(lp, op->dev.of_node); - if (rc) - dev_warn(&op->dev, "error registering MDIO bus\n"); - - lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0); - if (lp->phy_node) - dev_dbg(lp->dev, "using PHY node %s (%p)\n", np->full_name, np); - - /* Add the device attributes */ - rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group); - if (rc) { - dev_err(lp->dev, "Error creating sysfs files\n"); - goto err_iounmap_2; - } - - rc = register_netdev(lp->ndev); - if (rc) { - dev_err(lp->dev, "register_netdev() error (%i)\n", rc); - goto err_register_ndev; - } - - return 0; - - err_register_ndev: - sysfs_remove_group(&lp->dev->kobj, &temac_attr_group); - err_iounmap_2: - if (lp->sdma_regs) - iounmap(lp->sdma_regs); - err_iounmap: - iounmap(lp->regs); - nodev: - free_netdev(ndev); - ndev = NULL; - return rc; -} - -static int __devexit temac_of_remove(struct platform_device *op) -{ - struct net_device *ndev = dev_get_drvdata(&op->dev); - struct temac_local *lp = netdev_priv(ndev); - - temac_mdio_teardown(lp); - unregister_netdev(ndev); - sysfs_remove_group(&lp->dev->kobj, &temac_attr_group); - if (lp->phy_node) - of_node_put(lp->phy_node); - lp->phy_node = NULL; - dev_set_drvdata(&op->dev, NULL); - iounmap(lp->regs); - if (lp->sdma_regs) - iounmap(lp->sdma_regs); - free_netdev(ndev); - return 0; -} - -static struct of_device_id temac_of_match[] __devinitdata = { - { .compatible = "xlnx,xps-ll-temac-1.01.b", }, - { .compatible = "xlnx,xps-ll-temac-2.00.a", }, - { .compatible = "xlnx,xps-ll-temac-2.02.a", }, - { .compatible = "xlnx,xps-ll-temac-2.03.a", }, - {}, -}; -MODULE_DEVICE_TABLE(of, temac_of_match); - -static struct platform_driver temac_of_driver = { - .probe = temac_of_probe, - .remove = __devexit_p(temac_of_remove), - .driver = { - .owner = THIS_MODULE, - .name = "xilinx_temac", - .of_match_table = temac_of_match, - }, -}; - -module_platform_driver(temac_of_driver); - -MODULE_DESCRIPTION("Xilinx LL_TEMAC Ethernet driver"); -MODULE_AUTHOR("Yoshio Kashiwagi"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/ANDROID_3.4.5/drivers/net/ethernet/xilinx/ll_temac_mdio.c deleted file mode 100644 index 8cf9d4f5..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/ll_temac_mdio.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * MDIO bus driver for the Xilinx TEMAC device - * - * Copyright (c) 2009 Secret Lab Technologies, Ltd. - */ - -#include <linux/io.h> -#include <linux/netdevice.h> -#include <linux/mutex.h> -#include <linux/phy.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_address.h> -#include <linux/slab.h> -#include <linux/of_mdio.h> - -#include "ll_temac.h" - -/* --------------------------------------------------------------------- - * MDIO Bus functions - */ -static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg) -{ - struct temac_local *lp = bus->priv; - u32 rc; - - /* Write the PHY address to the MIIM Access Initiator register. - * When the transfer completes, the PHY register value will appear - * in the LSW0 register */ - mutex_lock(&lp->indirect_mutex); - temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg); - rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET); - mutex_unlock(&lp->indirect_mutex); - - dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n", - phy_id, reg, rc); - - return rc; -} - -static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) -{ - struct temac_local *lp = bus->priv; - - dev_dbg(lp->dev, "temac_mdio_write(phy_id=%i, reg=%x, val=%x)\n", - phy_id, reg, val); - - /* First write the desired value into the write data register - * and then write the address into the access initiator register - */ - mutex_lock(&lp->indirect_mutex); - temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val); - temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg); - mutex_unlock(&lp->indirect_mutex); - - return 0; -} - -int temac_mdio_setup(struct temac_local *lp, struct device_node *np) -{ - struct mii_bus *bus; - const u32 *bus_hz; - int clk_div; - int rc, size; - struct resource res; - - /* Calculate a reasonable divisor for the clock rate */ - clk_div = 0x3f; /* worst-case default setting */ - bus_hz = of_get_property(np, "clock-frequency", &size); - if (bus_hz && size >= sizeof(*bus_hz)) { - clk_div = (*bus_hz) / (2500 * 1000 * 2) - 1; - if (clk_div < 1) - clk_div = 1; - if (clk_div > 0x3f) - clk_div = 0x3f; - } - - /* Enable the MDIO bus by asserting the enable bit and writing - * in the clock config */ - mutex_lock(&lp->indirect_mutex); - temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div); - mutex_unlock(&lp->indirect_mutex); - - bus = mdiobus_alloc(); - if (!bus) - return -ENOMEM; - - of_address_to_resource(np, 0, &res); - snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx", - (unsigned long long)res.start); - bus->priv = lp; - bus->name = "Xilinx TEMAC MDIO"; - bus->read = temac_mdio_read; - bus->write = temac_mdio_write; - bus->parent = lp->dev; - bus->irq = lp->mdio_irqs; /* preallocated IRQ table */ - - lp->mii_bus = bus; - - rc = of_mdiobus_register(bus, np); - if (rc) - goto err_register; - - mutex_lock(&lp->indirect_mutex); - dev_dbg(lp->dev, "MDIO bus registered; MC:%x\n", - temac_indirect_in32(lp, XTE_MC_OFFSET)); - mutex_unlock(&lp->indirect_mutex); - return 0; - - err_register: - mdiobus_free(bus); - return rc; -} - -void temac_mdio_teardown(struct temac_local *lp) -{ - mdiobus_unregister(lp->mii_bus); - kfree(lp->mii_bus->irq); - mdiobus_free(lp->mii_bus); - lp->mii_bus = NULL; -} - diff --git a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_axienet.h b/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_axienet.h deleted file mode 100644 index 44b8d2ba..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_axienet.h +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Definitions for Xilinx Axi Ethernet device driver. - * - * Copyright (c) 2009 Secret Lab Technologies, Ltd. - * Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved. - */ - -#ifndef XILINX_AXIENET_H -#define XILINX_AXIENET_H - -#include <linux/netdevice.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> - -/* Packet size info */ -#define XAE_HDR_SIZE 14 /* Size of Ethernet header */ -#define XAE_HDR_VLAN_SIZE 18 /* Size of an Ethernet hdr + VLAN */ -#define XAE_TRL_SIZE 4 /* Size of Ethernet trailer (FCS) */ -#define XAE_MTU 1500 /* Max MTU of an Ethernet frame */ -#define XAE_JUMBO_MTU 9000 /* Max MTU of a jumbo Eth. frame */ - -#define XAE_MAX_FRAME_SIZE (XAE_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE) -#define XAE_MAX_VLAN_FRAME_SIZE (XAE_MTU + XAE_HDR_VLAN_SIZE + XAE_TRL_SIZE) -#define XAE_MAX_JUMBO_FRAME_SIZE (XAE_JUMBO_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE) - -/* Configuration options */ - -/* Accept all incoming packets. Default: disabled (cleared) */ -#define XAE_OPTION_PROMISC (1 << 0) - -/* Jumbo frame support for Tx & Rx. Default: disabled (cleared) */ -#define XAE_OPTION_JUMBO (1 << 1) - -/* VLAN Rx & Tx frame support. Default: disabled (cleared) */ -#define XAE_OPTION_VLAN (1 << 2) - -/* Enable recognition of flow control frames on Rx. Default: enabled (set) */ -#define XAE_OPTION_FLOW_CONTROL (1 << 4) - -/* Strip FCS and PAD from incoming frames. Note: PAD from VLAN frames is not - * stripped. Default: disabled (set) */ -#define XAE_OPTION_FCS_STRIP (1 << 5) - -/* Generate FCS field and add PAD automatically for outgoing frames. - * Default: enabled (set) */ -#define XAE_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 XAE_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. Default: enabled (set) */ -#define XAE_OPTION_LENTYPE_ERR (1 << 7) - -/* Enable the transmitter. Default: enabled (set) */ -#define XAE_OPTION_TXEN (1 << 11) - -/* Enable the receiver. Default: enabled (set) */ -#define XAE_OPTION_RXEN (1 << 12) - -/* Default options set when device is initialized or reset */ -#define XAE_OPTION_DEFAULTS \ - (XAE_OPTION_TXEN | \ - XAE_OPTION_FLOW_CONTROL | \ - XAE_OPTION_RXEN) - -/* Axi DMA Register definitions */ - -#define XAXIDMA_TX_CR_OFFSET 0x00000000 /* Channel control */ -#define XAXIDMA_TX_SR_OFFSET 0x00000004 /* Status */ -#define XAXIDMA_TX_CDESC_OFFSET 0x00000008 /* Current descriptor pointer */ -#define XAXIDMA_TX_TDESC_OFFSET 0x00000010 /* Tail descriptor pointer */ - -#define XAXIDMA_RX_CR_OFFSET 0x00000030 /* Channel control */ -#define XAXIDMA_RX_SR_OFFSET 0x00000034 /* Status */ -#define XAXIDMA_RX_CDESC_OFFSET 0x00000038 /* Current descriptor pointer */ -#define XAXIDMA_RX_TDESC_OFFSET 0x00000040 /* Tail descriptor pointer */ - -#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 /* Start/stop DMA channel */ -#define XAXIDMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */ - -#define XAXIDMA_BD_NDESC_OFFSET 0x00 /* Next descriptor pointer */ -#define XAXIDMA_BD_BUFA_OFFSET 0x08 /* Buffer address */ -#define XAXIDMA_BD_CTRL_LEN_OFFSET 0x18 /* Control/buffer length */ -#define XAXIDMA_BD_STS_OFFSET 0x1C /* Status */ -#define XAXIDMA_BD_USR0_OFFSET 0x20 /* User IP specific word0 */ -#define XAXIDMA_BD_USR1_OFFSET 0x24 /* User IP specific word1 */ -#define XAXIDMA_BD_USR2_OFFSET 0x28 /* User IP specific word2 */ -#define XAXIDMA_BD_USR3_OFFSET 0x2C /* User IP specific word3 */ -#define XAXIDMA_BD_USR4_OFFSET 0x30 /* User IP specific word4 */ -#define XAXIDMA_BD_ID_OFFSET 0x34 /* Sw ID */ -#define XAXIDMA_BD_HAS_STSCNTRL_OFFSET 0x38 /* Whether has stscntrl strm */ -#define XAXIDMA_BD_HAS_DRE_OFFSET 0x3C /* Whether has DRE */ - -#define XAXIDMA_BD_HAS_DRE_SHIFT 8 /* Whether has DRE shift */ -#define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */ -#define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */ - -#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */ -#define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */ -#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */ -#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */ - -#define XAXIDMA_DELAY_MASK 0xFF000000 /* Delay timeout counter */ -#define XAXIDMA_COALESCE_MASK 0x00FF0000 /* Coalesce counter */ - -#define XAXIDMA_DELAY_SHIFT 24 -#define XAXIDMA_COALESCE_SHIFT 16 - -#define XAXIDMA_IRQ_IOC_MASK 0x00001000 /* Completion intr */ -#define XAXIDMA_IRQ_DELAY_MASK 0x00002000 /* Delay interrupt */ -#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 */ -#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_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */ -#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */ -#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */ - -#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */ -#define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */ -#define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */ -#define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */ -#define XAXIDMA_BD_STS_INT_ERR_MASK 0x10000000 /* Internal err */ -#define XAXIDMA_BD_STS_ALL_ERR_MASK 0x70000000 /* All errors */ -#define XAXIDMA_BD_STS_RXSOF_MASK 0x08000000 /* First rx pkt */ -#define XAXIDMA_BD_STS_RXEOF_MASK 0x04000000 /* Last rx pkt */ -#define XAXIDMA_BD_STS_ALL_MASK 0xFC000000 /* All status bits */ - -#define XAXIDMA_BD_MINIMUM_ALIGNMENT 0x40 - -/* Axi Ethernet registers definition */ -#define XAE_RAF_OFFSET 0x00000000 /* Reset and Address filter */ -#define XAE_TPF_OFFSET 0x00000004 /* Tx Pause Frame */ -#define XAE_IFGP_OFFSET 0x00000008 /* Tx Inter-frame gap adjustment*/ -#define XAE_IS_OFFSET 0x0000000C /* Interrupt status */ -#define XAE_IP_OFFSET 0x00000010 /* Interrupt pending */ -#define XAE_IE_OFFSET 0x00000014 /* Interrupt enable */ -#define XAE_TTAG_OFFSET 0x00000018 /* Tx VLAN TAG */ -#define XAE_RTAG_OFFSET 0x0000001C /* Rx VLAN TAG */ -#define XAE_UAWL_OFFSET 0x00000020 /* Unicast address word lower */ -#define XAE_UAWU_OFFSET 0x00000024 /* Unicast address word upper */ -#define XAE_TPID0_OFFSET 0x00000028 /* VLAN TPID0 register */ -#define XAE_TPID1_OFFSET 0x0000002C /* VLAN TPID1 register */ -#define XAE_PPST_OFFSET 0x00000030 /* PCS PMA Soft Temac Status Reg */ -#define XAE_RCW0_OFFSET 0x00000400 /* Rx Configuration Word 0 */ -#define XAE_RCW1_OFFSET 0x00000404 /* Rx Configuration Word 1 */ -#define XAE_TC_OFFSET 0x00000408 /* Tx Configuration */ -#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_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 */ -#define XAE_MDIO_MIP_OFFSET 0x00000620 /* MII Mgmt Interrupt Pending - * register offset */ -#define XAE_MDIO_MIE_OFFSET 0x00000640 /* MII Management Interrupt Enable - * register offset */ -#define XAE_MDIO_MIC_OFFSET 0x00000660 /* MII Management Interrupt Clear - * register offset. */ -#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 */ -#define XAE_AF0_OFFSET 0x00000710 /* Address Filter 0 */ -#define XAE_AF1_OFFSET 0x00000714 /* Address Filter 1 */ - -#define XAE_TX_VLAN_DATA_OFFSET 0x00004000 /* TX VLAN data table address */ -#define XAE_RX_VLAN_DATA_OFFSET 0x00008000 /* RX VLAN data table address */ -#define XAE_MCAST_TABLE_OFFSET 0x00020000 /* Multicast table address */ - -/* Bit Masks for Axi Ethernet RAF register */ -#define XAE_RAF_MCSTREJ_MASK 0x00000002 /* Reject receive multicast - * destination address */ -#define XAE_RAF_BCSTREJ_MASK 0x00000004 /* Reject receive broadcast - * destination address */ -#define XAE_RAF_TXVTAGMODE_MASK 0x00000018 /* Tx VLAN TAG mode */ -#define XAE_RAF_RXVTAGMODE_MASK 0x00000060 /* Rx VLAN TAG mode */ -#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 */ -#define XAE_RAF_EMULTIFLTRENBL_MASK 0x00001000 /* Exteneded Multicast - * Filtering mode - */ -#define XAE_RAF_STATSRST_MASK 0x00002000 /* Stats. Counter Reset */ -#define XAE_RAF_RXBADFRMEN_MASK 0x00004000 /* Recv Bad Frame Enable */ -#define XAE_RAF_TXVTAGMODE_SHIFT 3 /* Tx Tag mode shift bits */ -#define XAE_RAF_RXVTAGMODE_SHIFT 5 /* Rx Tag mode shift bits */ -#define XAE_RAF_TXVSTRPMODE_SHIFT 7 /* Tx strip mode shift bits*/ -#define XAE_RAF_RXVSTRPMODE_SHIFT 9 /* Rx Strip mode shift bits*/ - -/* Bit Masks for Axi Ethernet TPF and IFGP registers */ -#define XAE_TPF_TPFV_MASK 0x0000FFFF /* Tx pause frame value */ -#define XAE_IFGP0_IFGP_MASK 0x0000007F /* Transmit inter-frame - * gap adjustment value */ - -/* Bit Masks for Axi Ethernet IS, IE and IP registers, Same masks apply - * for all 3 registers. */ -#define XAE_INT_HARDACSCMPLT_MASK 0x00000001 /* Hard register access - * complete */ -#define XAE_INT_AUTONEG_MASK 0x00000002 /* Auto negotiation - * complete */ -#define XAE_INT_RXCMPIT_MASK 0x00000004 /* Rx complete */ -#define XAE_INT_RXRJECT_MASK 0x00000008 /* Rx frame rejected */ -#define XAE_INT_RXFIFOOVR_MASK 0x00000010 /* Rx fifo overrun */ -#define XAE_INT_TXCMPIT_MASK 0x00000020 /* Tx complete */ -#define XAE_INT_RXDCMLOCK_MASK 0x00000040 /* Rx Dcm Lock */ -#define XAE_INT_MGTRDY_MASK 0x00000080 /* MGT clock Lock */ -#define XAE_INT_PHYRSTCMPLT_MASK 0x00000100 /* Phy Reset complete */ -#define XAE_INT_ALL_MASK 0x0000003F /* All the ints */ - -#define XAE_INT_RECV_ERROR_MASK \ - (XAE_INT_RXRJECT_MASK | XAE_INT_RXFIFOOVR_MASK) /* INT bits that - * indicate receive - * errors */ - -/* Bit masks for Axi Ethernet VLAN TPID Word 0 register */ -#define XAE_TPID_0_MASK 0x0000FFFF /* TPID 0 */ -#define XAE_TPID_1_MASK 0xFFFF0000 /* TPID 1 */ - -/* Bit masks for Axi Ethernet VLAN TPID Word 1 register */ -#define XAE_TPID_2_MASK 0x0000FFFF /* TPID 0 */ -#define XAE_TPID_3_MASK 0xFFFF0000 /* TPID 1 */ - -/* Bit masks for Axi Ethernet RCW1 register */ -#define XAE_RCW1_RST_MASK 0x80000000 /* Reset */ -#define XAE_RCW1_JUM_MASK 0x40000000 /* Jumbo frame enable */ -#define XAE_RCW1_FCS_MASK 0x20000000 /* In-Band FCS enable - * (FCS not stripped) */ -#define XAE_RCW1_RX_MASK 0x10000000 /* Receiver enable */ -#define XAE_RCW1_VLAN_MASK 0x08000000 /* VLAN frame enable */ -#define XAE_RCW1_LT_DIS_MASK 0x02000000 /* Length/type field valid check - * disable */ -#define XAE_RCW1_CL_DIS_MASK 0x01000000 /* Control frame Length check - * disable */ -#define XAE_RCW1_PAUSEADDR_MASK 0x0000FFFF /* Pause frame source address - * bits [47:32]. Bits [31:0] are - * stored in register RCW0 */ - -/* Bit masks for Axi Ethernet TC register */ -#define XAE_TC_RST_MASK 0x80000000 /* Reset */ -#define XAE_TC_JUM_MASK 0x40000000 /* Jumbo frame enable */ -#define XAE_TC_FCS_MASK 0x20000000 /* In-Band FCS enable - * (FCS not generated) */ -#define XAE_TC_TX_MASK 0x10000000 /* Transmitter enable */ -#define XAE_TC_VLAN_MASK 0x08000000 /* VLAN frame enable */ -#define XAE_TC_IFG_MASK 0x02000000 /* Inter-frame gap adjustment - * enable */ - -/* Bit masks for Axi Ethernet FCC register */ -#define XAE_FCC_FCRX_MASK 0x20000000 /* Rx flow control enable */ -#define XAE_FCC_FCTX_MASK 0x40000000 /* Tx flow control enable */ - -/* Bit masks for Axi Ethernet EMMC register */ -#define XAE_EMMC_LINKSPEED_MASK 0xC0000000 /* Link speed */ -#define XAE_EMMC_RGMII_MASK 0x20000000 /* RGMII mode enable */ -#define XAE_EMMC_SGMII_MASK 0x10000000 /* SGMII mode enable */ -#define XAE_EMMC_GPCS_MASK 0x08000000 /* 1000BaseX mode enable */ -#define XAE_EMMC_HOST_MASK 0x04000000 /* Host interface enable */ -#define XAE_EMMC_TX16BIT 0x02000000 /* 16 bit Tx client enable */ -#define XAE_EMMC_RX16BIT 0x01000000 /* 16 bit Rx client enable */ -#define XAE_EMMC_LINKSPD_10 0x00000000 /* Link Speed mask for 10 Mbit */ -#define XAE_EMMC_LINKSPD_100 0x40000000 /* Link Speed mask for 100 Mbit */ -#define XAE_EMMC_LINKSPD_1000 0x80000000 /* Link Speed mask for 1000 Mbit */ - -/* Bit masks for Axi Ethernet PHYC register */ -#define XAE_PHYC_SGMIILINKSPEED_MASK 0xC0000000 /* SGMII link speed mask*/ -#define XAE_PHYC_RGMIILINKSPEED_MASK 0x0000000C /* RGMII link speed */ -#define XAE_PHYC_RGMIIHD_MASK 0x00000002 /* RGMII Half-duplex */ -#define XAE_PHYC_RGMIILINK_MASK 0x00000001 /* RGMII link status */ -#define XAE_PHYC_RGLINKSPD_10 0x00000000 /* RGMII link 10 Mbit */ -#define XAE_PHYC_RGLINKSPD_100 0x00000004 /* RGMII link 100 Mbit */ -#define XAE_PHYC_RGLINKSPD_1000 0x00000008 /* RGMII link 1000 Mbit */ -#define XAE_PHYC_SGLINKSPD_10 0x00000000 /* SGMII link 10 Mbit */ -#define XAE_PHYC_SGLINKSPD_100 0x40000000 /* SGMII link 100 Mbit */ -#define XAE_PHYC_SGLINKSPD_1000 0x80000000 /* SGMII link 1000 Mbit */ - -/* Bit masks for Axi Ethernet MDIO interface MC register */ -#define XAE_MDIO_MC_MDIOEN_MASK 0x00000040 /* MII management enable */ -#define XAE_MDIO_MC_CLOCK_DIVIDE_MAX 0x3F /* Maximum MDIO divisor */ - -/* Bit masks for Axi Ethernet MDIO interface MCR register */ -#define XAE_MDIO_MCR_PHYAD_MASK 0x1F000000 /* Phy Address Mask */ -#define XAE_MDIO_MCR_PHYAD_SHIFT 24 /* Phy Address Shift */ -#define XAE_MDIO_MCR_REGAD_MASK 0x001F0000 /* Reg Address Mask */ -#define XAE_MDIO_MCR_REGAD_SHIFT 16 /* Reg Address Shift */ -#define XAE_MDIO_MCR_OP_MASK 0x0000C000 /* Operation Code Mask */ -#define XAE_MDIO_MCR_OP_SHIFT 13 /* Operation Code Shift */ -#define XAE_MDIO_MCR_OP_READ_MASK 0x00008000 /* Op Code Read Mask */ -#define XAE_MDIO_MCR_OP_WRITE_MASK 0x00004000 /* Op Code Write Mask */ -#define XAE_MDIO_MCR_INITIATE_MASK 0x00000800 /* Ready Mask */ -#define XAE_MDIO_MCR_READY_MASK 0x00000080 /* Ready Mask */ - -/* Bit masks for Axi Ethernet MDIO interface MIS, MIP, MIE, MIC registers */ -#define XAE_MDIO_INT_MIIM_RDY_MASK 0x00000001 /* MIIM Interrupt */ - -/* Bit masks for Axi Ethernet UAW1 register */ -#define XAE_UAW1_UNICASTADDR_MASK 0x0000FFFF /* Station address bits - * [47:32]; Station address - * bits [31:0] are stored in - * register UAW0 */ - -/* Bit masks for Axi Ethernet FMI register */ -#define XAE_FMI_PM_MASK 0x80000000 /* Promis. mode enable */ -#define XAE_FMI_IND_MASK 0x00000003 /* Index Mask */ - -#define XAE_MDIO_DIV_DFT 29 /* Default MDIO clock divisor */ - -/* Defines for different options for C_PHY_TYPE parameter in Axi Ethernet IP */ -#define XAE_PHY_TYPE_MII 0 -#define XAE_PHY_TYPE_GMII 1 -#define XAE_PHY_TYPE_RGMII_1_3 2 -#define XAE_PHY_TYPE_RGMII_2_0 3 -#define XAE_PHY_TYPE_SGMII 4 -#define XAE_PHY_TYPE_1000BASE_X 5 - -#define XAE_MULTICAST_CAM_TABLE_NUM 4 /* Total number of entries in the - * hardware multicast table. */ - -/* Axi Ethernet Synthesis features */ -#define XAE_FEATURE_PARTIAL_RX_CSUM (1 << 0) -#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_NO_CSUM_OFFLOAD 0 - -#define XAE_FULL_CSUM_STATUS_MASK 0x00000038 -#define XAE_IP_UDP_CSUM_VALIDATED 0x00000003 -#define XAE_IP_TCP_CSUM_VALIDATED 0x00000002 - -#define DELAY_OF_ONE_MILLISEC 1000 - -/** - * struct axidma_bd - Axi Dma buffer descriptor layout - * @next: MM2S/S2MM Next Descriptor Pointer - * @reserved1: Reserved and not used - * @phys: MM2S/S2MM Buffer Address - * @reserved2: Reserved and not used - * @reserved3: Reserved and not used - * @reserved4: Reserved and not used - * @cntrl: MM2S/S2MM Control value - * @status: MM2S/S2MM Status value - * @app0: MM2S/S2MM User Application Field 0. - * @app1: MM2S/S2MM User Application Field 1. - * @app2: MM2S/S2MM User Application Field 2. - * @app3: MM2S/S2MM User Application Field 3. - * @app4: MM2S/S2MM User Application Field 4. - * @sw_id_offset: MM2S/S2MM Sw ID - * @reserved5: Reserved and not used - * @reserved6: Reserved and not used - */ -struct axidma_bd { - u32 next; /* Physical address of next buffer descriptor */ - u32 reserved1; - u32 phys; - u32 reserved2; - u32 reserved3; - u32 reserved4; - u32 cntrl; - u32 status; - u32 app0; - u32 app1; /* TX start << 16 | insert */ - u32 app2; /* TX csum seed */ - u32 app3; - u32 app4; - u32 sw_id_offset; - u32 reserved5; - u32 reserved6; -}; - -/** - * 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_dev: Pointer to PHY device structure attached to the axienet_local - * @phy_node: Pointer to device node structure - * @mii_bus: Pointer to MII bus structure - * @mdio_irqs: IRQs table for MDIO bus required in mii_bus structure - * @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 - * @tx_irq: Axidma TX IRQ number - * @rx_irq: Axidma RX IRQ number - * @temac_type: axienet type to identify between soft and hard temac - * @phy_type: 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 - * 1522 bytes (assuming support for basic VLAN) - * @jumbo_support: Stores hardware configuration for jumbo support. If hardware - * can handle jumbo packets, this entry will be 1, else 0. - */ -struct axienet_local { - struct net_device *ndev; - struct device *dev; - - /* Connection to PHY device */ - struct phy_device *phy_dev; /* Pointer to PHY device */ - struct device_node *phy_node; - - /* MDIO bus data */ - struct mii_bus *mii_bus; /* MII bus reference */ - int mdio_irqs[PHY_MAX_ADDR]; /* IRQs table for MDIO bus */ - - /* IO registers, dma functions and IRQs */ - void __iomem *regs; - void __iomem *dma_regs; - - struct tasklet_struct dma_err_tasklet; - - int tx_irq; - int rx_irq; - u32 temac_type; - u32 phy_type; - - u32 options; /* Current options word */ - u32 last_link; - u32 features; - - /* Buffer descriptors */ - struct axidma_bd *tx_bd_v; - dma_addr_t tx_bd_p; - struct axidma_bd *rx_bd_v; - dma_addr_t rx_bd_p; - u32 tx_bd_ci; - u32 tx_bd_tail; - u32 rx_bd_ci; - - u32 max_frm_size; - u32 jumbo_support; - - int csum_offload_on_tx_path; - int csum_offload_on_rx_path; - - u32 coalesce_count_rx; - u32 coalesce_count_tx; -}; - -/** - * struct axiethernet_option - Used to set axi ethernet hardware options - * @opt: Option to be set. - * @reg: Register offset to be written for setting the option - * @m_or: Mask to be ORed for setting the option in the register - */ -struct axienet_option { - u32 opt; - u32 reg; - u32 m_or; -}; - -/** - * axienet_ior - Memory mapped Axi Ethernet register read - * @lp: Pointer to axienet local structure - * @offset: Address offset from the base address of Axi Ethernet core - * - * returns: The contents of the Axi Ethernet register - * - * This function returns the contents of the corresponding register. - */ -static inline u32 axienet_ior(struct axienet_local *lp, off_t offset) -{ - return in_be32(lp->regs + offset); -} - -/** - * axienet_iow - Memory mapped Axi Ethernet register write - * @lp: Pointer to axienet local structure - * @offset: Address offset from the base address of Axi Ethernet core - * @value: Value to be written into the Axi Ethernet register - * - * This function writes the desired value into the corresponding Axi Ethernet - * register. - */ -static inline void axienet_iow(struct axienet_local *lp, off_t offset, - u32 value) -{ - out_be32((lp->regs + offset), value); -} - -/* Function prototypes visible in xilinx_axienet_mdio.c for other files */ -int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np); -int axienet_mdio_wait_until_ready(struct axienet_local *lp); -void axienet_mdio_teardown(struct axienet_local *lp); - -#endif /* XILINX_AXI_ENET_H */ diff --git a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_axienet_main.c deleted file mode 100644 index 9c365e19..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ /dev/null @@ -1,1669 +0,0 @@ -/* - * Xilinx Axi Ethernet device driver - * - * Copyright (c) 2008 Nissin Systems Co., Ltd., Yoshio Kashiwagi - * Copyright (c) 2005-2008 DLA Systems, David H. Lynch Jr. <dhlii@dlasys.net> - * Copyright (c) 2008-2009 Secret Lab Technologies Ltd. - * Copyright (c) 2010 - 2011 Michal Simek <monstr@monstr.eu> - * Copyright (c) 2010 - 2011 PetaLogix - * Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved. - * - * This is a driver for the Xilinx Axi Ethernet which is used in the Virtex6 - * and Spartan6. - * - * TODO: - * - Add Axi Fifo support. - * - Factor out Axi DMA code into separate driver. - * - Test and fix basic multicast filtering. - * - Add support for extended multicast filtering. - * - Test basic VLAN support. - * - Add support for extended VLAN support. - */ - -#include <linux/delay.h> -#include <linux/etherdevice.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/of_mdio.h> -#include <linux/of_platform.h> -#include <linux/of_address.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/phy.h> -#include <linux/mii.h> -#include <linux/ethtool.h> - -#include "xilinx_axienet.h" - -/* Descriptors defines for Tx and Rx DMA - 2^n for the best performance */ -#define TX_BD_NUM 64 -#define RX_BD_NUM 128 - -/* Must be shorter than length of ethtool_drvinfo.driver field to fit */ -#define DRIVER_NAME "xaxienet" -#define DRIVER_DESCRIPTION "Xilinx Axi Ethernet driver" -#define DRIVER_VERSION "1.00a" - -#define AXIENET_REGS_N 32 - -/* Match table for of_platform binding */ -static struct of_device_id axienet_of_match[] __devinitdata = { - { .compatible = "xlnx,axi-ethernet-1.00.a", }, - { .compatible = "xlnx,axi-ethernet-1.01.a", }, - { .compatible = "xlnx,axi-ethernet-2.01.a", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, axienet_of_match); - -/* Option table for setting up Axi Ethernet hardware options */ -static struct axienet_option axienet_options[] = { - /* Turn on jumbo packet support for both Rx and Tx */ - { - .opt = XAE_OPTION_JUMBO, - .reg = XAE_TC_OFFSET, - .m_or = XAE_TC_JUM_MASK, - }, { - .opt = XAE_OPTION_JUMBO, - .reg = XAE_RCW1_OFFSET, - .m_or = XAE_RCW1_JUM_MASK, - }, { /* Turn on VLAN packet support for both Rx and Tx */ - .opt = XAE_OPTION_VLAN, - .reg = XAE_TC_OFFSET, - .m_or = XAE_TC_VLAN_MASK, - }, { - .opt = XAE_OPTION_VLAN, - .reg = XAE_RCW1_OFFSET, - .m_or = XAE_RCW1_VLAN_MASK, - }, { /* Turn on FCS stripping on receive packets */ - .opt = XAE_OPTION_FCS_STRIP, - .reg = XAE_RCW1_OFFSET, - .m_or = XAE_RCW1_FCS_MASK, - }, { /* Turn on FCS insertion on transmit packets */ - .opt = XAE_OPTION_FCS_INSERT, - .reg = XAE_TC_OFFSET, - .m_or = XAE_TC_FCS_MASK, - }, { /* Turn off length/type field checking on receive packets */ - .opt = XAE_OPTION_LENTYPE_ERR, - .reg = XAE_RCW1_OFFSET, - .m_or = XAE_RCW1_LT_DIS_MASK, - }, { /* Turn on Rx flow control */ - .opt = XAE_OPTION_FLOW_CONTROL, - .reg = XAE_FCC_OFFSET, - .m_or = XAE_FCC_FCRX_MASK, - }, { /* Turn on Tx flow control */ - .opt = XAE_OPTION_FLOW_CONTROL, - .reg = XAE_FCC_OFFSET, - .m_or = XAE_FCC_FCTX_MASK, - }, { /* Turn on promiscuous frame filtering */ - .opt = XAE_OPTION_PROMISC, - .reg = XAE_FMI_OFFSET, - .m_or = XAE_FMI_PM_MASK, - }, { /* Enable transmitter */ - .opt = XAE_OPTION_TXEN, - .reg = XAE_TC_OFFSET, - .m_or = XAE_TC_TX_MASK, - }, { /* Enable receiver */ - .opt = XAE_OPTION_RXEN, - .reg = XAE_RCW1_OFFSET, - .m_or = XAE_RCW1_RX_MASK, - }, - {} -}; - -/** - * axienet_dma_in32 - Memory mapped Axi DMA register read - * @lp: Pointer to axienet local structure - * @reg: Address offset from the base address of the Axi DMA core - * - * returns: The contents of the Axi DMA register - * - * This function returns the contents of the corresponding Axi DMA register. - */ -static inline u32 axienet_dma_in32(struct axienet_local *lp, off_t reg) -{ - return in_be32(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) -{ - out_be32((lp->dma_regs + reg), value); -} - -/** - * axienet_dma_bd_release - Release buffer descriptor rings - * @ndev: Pointer to the net_device structure - * - * This function is used to release the descriptors allocated in - * axienet_dma_bd_init. axienet_dma_bd_release is called when Axi Ethernet - * driver stop api is called. - */ -static void axienet_dma_bd_release(struct net_device *ndev) -{ - int i; - struct axienet_local *lp = netdev_priv(ndev); - - for (i = 0; i < RX_BD_NUM; i++) { - dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys, - lp->max_frm_size, DMA_FROM_DEVICE); - dev_kfree_skb((struct sk_buff *) - (lp->rx_bd_v[i].sw_id_offset)); - } - - 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); - } - 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); - } -} - -/** - * axienet_dma_bd_init - Setup buffer descriptor rings for Axi DMA - * @ndev: Pointer to the net_device structure - * - * returns: 0, on success - * -ENOMEM, on failure - * - * This function is called to initialize the Rx and Tx DMA descriptor - * rings. This initializes the descriptors with required default values - * and is called when Axi Ethernet driver reset is called. - */ -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); - - /* Reset the indexes which are used for accessing the BDs */ - lp->tx_bd_ci = 0; - lp->tx_bd_tail = 0; - lp->rx_bd_ci = 0; - - /* - * Allocate the Tx and Rx buffer descriptors. - */ - lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, - sizeof(*lp->tx_bd_v) * TX_BD_NUM, - &lp->tx_bd_p, - GFP_KERNEL); - if (!lp->tx_bd_v) { - dev_err(&ndev->dev, "unable to allocate DMA Tx buffer " - "descriptors"); - goto out; - } - - lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, - sizeof(*lp->rx_bd_v) * RX_BD_NUM, - &lp->rx_bd_p, - GFP_KERNEL); - if (!lp->rx_bd_v) { - dev_err(&ndev->dev, "unable to allocate DMA Rx buffer " - "descriptors"); - goto out; - } - - memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM); - for (i = 0; i < TX_BD_NUM; i++) { - lp->tx_bd_v[i].next = lp->tx_bd_p + - sizeof(*lp->tx_bd_v) * - ((i + 1) % TX_BD_NUM); - } - - memset(lp->rx_bd_v, 0, sizeof(*lp->rx_bd_v) * RX_BD_NUM); - for (i = 0; i < RX_BD_NUM; i++) { - lp->rx_bd_v[i].next = lp->rx_bd_p + - sizeof(*lp->rx_bd_v) * - ((i + 1) % RX_BD_NUM); - - skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size); - if (!skb) { - dev_err(&ndev->dev, "alloc_skb error %d\n", i); - goto out; - } - - lp->rx_bd_v[i].sw_id_offset = (u32) skb; - lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent, - skb->data, - lp->max_frm_size, - DMA_FROM_DEVICE); - 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) * (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); - - return 0; -out: - axienet_dma_bd_release(ndev); - return -ENOMEM; -} - -/** - * axienet_set_mac_address - Write the MAC address - * @ndev: Pointer to the net_device structure - * @address: 6 byte Address to be written as MAC address - * - * This function is called to initialize the MAC address of the Axi Ethernet - * core. It writes to the UAW0 and UAW1 registers of the core. - */ -static void axienet_set_mac_address(struct net_device *ndev, void *address) -{ - struct axienet_local *lp = netdev_priv(ndev); - - if (address) - memcpy(ndev->dev_addr, address, ETH_ALEN); - if (!is_valid_ether_addr(ndev->dev_addr)) - random_ether_addr(ndev->dev_addr); - - /* Set up unicast MAC address filter set its mac address */ - axienet_iow(lp, XAE_UAW0_OFFSET, - (ndev->dev_addr[0]) | - (ndev->dev_addr[1] << 8) | - (ndev->dev_addr[2] << 16) | - (ndev->dev_addr[3] << 24)); - axienet_iow(lp, XAE_UAW1_OFFSET, - (((axienet_ior(lp, XAE_UAW1_OFFSET)) & - ~XAE_UAW1_UNICASTADDR_MASK) | - (ndev->dev_addr[4] | - (ndev->dev_addr[5] << 8)))); -} - -/** - * netdev_set_mac_address - Write the MAC address (from outside the driver) - * @ndev: Pointer to the net_device structure - * @p: 6 byte Address to be written as MAC address - * - * returns: 0 for all conditions. Presently, there is no failure case. - * - * This function is called to initialize the MAC address of the Axi Ethernet - * core. It calls the core specific axienet_set_mac_address. This is the - * function that goes into net_device_ops structure entry ndo_set_mac_address. - */ -static int netdev_set_mac_address(struct net_device *ndev, void *p) -{ - struct sockaddr *addr = p; - axienet_set_mac_address(ndev, addr->sa_data); - return 0; -} - -/** - * axienet_set_multicast_list - Prepare the multicast table - * @ndev: Pointer to the net_device structure - * - * This function is called to initialize the multicast table during - * initialization. The Axi Ethernet basic multicast support has a four-entry - * multicast table which is initialized here. Additionally this function - * goes into the net_device_ops structure entry ndo_set_multicast_list. This - * means whenever the multicast table entries need to be updated this - * function gets called. - */ -static void axienet_set_multicast_list(struct net_device *ndev) -{ - int i; - u32 reg, af0reg, af1reg; - struct axienet_local *lp = netdev_priv(ndev); - - if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) || - netdev_mc_count(ndev) > XAE_MULTICAST_CAM_TABLE_NUM) { - /* We must make the kernel realize we had to move into - * promiscuous mode. If it was a promiscuous mode request - * the flag is already set. If not we set it. */ - ndev->flags |= IFF_PROMISC; - reg = axienet_ior(lp, XAE_FMI_OFFSET); - reg |= XAE_FMI_PM_MASK; - axienet_iow(lp, XAE_FMI_OFFSET, reg); - dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); - } else if (!netdev_mc_empty(ndev)) { - struct netdev_hw_addr *ha; - - i = 0; - netdev_for_each_mc_addr(ha, ndev) { - if (i >= XAE_MULTICAST_CAM_TABLE_NUM) - break; - - af0reg = (ha->addr[0]); - af0reg |= (ha->addr[1] << 8); - af0reg |= (ha->addr[2] << 16); - af0reg |= (ha->addr[3] << 24); - - af1reg = (ha->addr[4]); - af1reg |= (ha->addr[5] << 8); - - reg = axienet_ior(lp, XAE_FMI_OFFSET) & 0xFFFFFF00; - reg |= i; - - axienet_iow(lp, XAE_FMI_OFFSET, reg); - axienet_iow(lp, XAE_AF0_OFFSET, af0reg); - axienet_iow(lp, XAE_AF1_OFFSET, af1reg); - i++; - } - } else { - reg = axienet_ior(lp, XAE_FMI_OFFSET); - reg &= ~XAE_FMI_PM_MASK; - - axienet_iow(lp, XAE_FMI_OFFSET, reg); - - for (i = 0; i < XAE_MULTICAST_CAM_TABLE_NUM; i++) { - reg = axienet_ior(lp, XAE_FMI_OFFSET) & 0xFFFFFF00; - reg |= i; - - axienet_iow(lp, XAE_FMI_OFFSET, reg); - axienet_iow(lp, XAE_AF0_OFFSET, 0); - axienet_iow(lp, XAE_AF1_OFFSET, 0); - } - - dev_info(&ndev->dev, "Promiscuous mode disabled.\n"); - } -} - -/** - * axienet_setoptions - Set an Axi Ethernet option - * @ndev: Pointer to the net_device structure - * @options: Option to be enabled/disabled - * - * The Axi Ethernet core has multiple features which can be selectively turned - * on or off. The typical options could be jumbo frame option, basic VLAN - * option, promiscuous mode option etc. This function is used to set or clear - * these options in the Axi Ethernet hardware. This is done through - * axienet_option structure . - */ -static void axienet_setoptions(struct net_device *ndev, u32 options) -{ - int reg; - struct axienet_local *lp = netdev_priv(ndev); - struct axienet_option *tp = &axienet_options[0]; - - while (tp->opt) { - reg = ((axienet_ior(lp, tp->reg)) & ~(tp->m_or)); - if (options & tp->opt) - reg |= tp->m_or; - axienet_iow(lp, tp->reg, reg); - tp++; - } - - lp->options |= options; -} - -static void __axienet_device_reset(struct axienet_local *lp, - struct device *dev, off_t offset) -{ - u32 timeout; - /* 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 - * reset process. */ - axienet_dma_out32(lp, offset, XAXIDMA_CR_RESET_MASK); - timeout = DELAY_OF_ONE_MILLISEC; - while (axienet_dma_in32(lp, offset) & XAXIDMA_CR_RESET_MASK) { - udelay(1); - if (--timeout == 0) { - dev_err(dev, "axienet_device_reset DMA " - "reset timeout!\n"); - break; - } - } -} - -/** - * axienet_device_reset - Reset and initialize the Axi Ethernet hardware. - * @ndev: Pointer to the net_device structure - * - * 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 - * Ethernet core. No separate hardware reset is done for the Axi Ethernet - * core. - */ -static void axienet_device_reset(struct net_device *ndev) -{ - u32 axienet_status; - struct axienet_local *lp = netdev_priv(ndev); - - __axienet_device_reset(lp, &ndev->dev, XAXIDMA_TX_CR_OFFSET); - __axienet_device_reset(lp, &ndev->dev, XAXIDMA_RX_CR_OFFSET); - - lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE; - lp->options &= (~XAE_OPTION_JUMBO); - - if ((ndev->mtu > XAE_MTU) && - (ndev->mtu <= XAE_JUMBO_MTU) && - (lp->jumbo_support)) { - lp->max_frm_size = ndev->mtu + XAE_HDR_VLAN_SIZE + - XAE_TRL_SIZE; - lp->options |= XAE_OPTION_JUMBO; - } - - if (axienet_dma_bd_init(ndev)) { - dev_err(&ndev->dev, "axienet_device_reset descriptor " - "allocation failed\n"); - } - - axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET); - axienet_status &= ~XAE_RCW1_RX_MASK; - axienet_iow(lp, XAE_RCW1_OFFSET, axienet_status); - - axienet_status = axienet_ior(lp, XAE_IP_OFFSET); - if (axienet_status & XAE_INT_RXRJECT_MASK) - axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK); - - axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK); - - /* Sync default options with HW but leave receiver and - * transmitter disabled.*/ - axienet_setoptions(ndev, lp->options & - ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); - axienet_set_mac_address(ndev, NULL); - axienet_set_multicast_list(ndev); - axienet_setoptions(ndev, lp->options); - - ndev->trans_start = jiffies; -} - -/** - * axienet_adjust_link - Adjust the PHY link speed/duplex. - * @ndev: Pointer to the net_device structure - * - * This function is called to change the speed and duplex setting after - * auto negotiation is done by the PHY. This is the function that gets - * registered with the PHY interface through the "of_phy_connect" call. - */ -static void axienet_adjust_link(struct net_device *ndev) -{ - u32 emmc_reg; - u32 link_state; - u32 setspeed = 1; - struct axienet_local *lp = netdev_priv(ndev); - struct phy_device *phy = lp->phy_dev; - - link_state = phy->speed | (phy->duplex << 1) | phy->link; - if (lp->last_link != link_state) { - if ((phy->speed == SPEED_10) || (phy->speed == SPEED_100)) { - if (lp->phy_type == XAE_PHY_TYPE_1000BASE_X) - setspeed = 0; - } else { - if ((phy->speed == SPEED_1000) && - (lp->phy_type == XAE_PHY_TYPE_MII)) - setspeed = 0; - } - - if (setspeed == 1) { - emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET); - emmc_reg &= ~XAE_EMMC_LINKSPEED_MASK; - - switch (phy->speed) { - case SPEED_1000: - emmc_reg |= XAE_EMMC_LINKSPD_1000; - break; - case SPEED_100: - emmc_reg |= XAE_EMMC_LINKSPD_100; - break; - case SPEED_10: - emmc_reg |= XAE_EMMC_LINKSPD_10; - break; - default: - dev_err(&ndev->dev, "Speed other than 10, 100 " - "or 1Gbps is not supported\n"); - break; - } - - axienet_iow(lp, XAE_EMMC_OFFSET, emmc_reg); - lp->last_link = link_state; - phy_print_status(phy); - } else { - dev_err(&ndev->dev, "Error setting Axi Ethernet " - "mac speed\n"); - } - } -} - -/** - * axienet_start_xmit_done - Invoked once a transmit is completed by the - * Axi DMA Tx channel. - * @ndev: Pointer to the net_device structure - * - * 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. - */ -static void axienet_start_xmit_done(struct net_device *ndev) -{ - 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->app4) - dev_kfree_skb_irq((struct sk_buff *)cur_p->app4); - /*cur_p->phys = 0;*/ - cur_p->app0 = 0; - cur_p->app1 = 0; - cur_p->app2 = 0; - cur_p->app4 = 0; - cur_p->status = 0; - - size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; - packets++; - - lp->tx_bd_ci = ++lp->tx_bd_ci % TX_BD_NUM; - cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; - status = cur_p->status; - } - - ndev->stats.tx_packets += packets; - ndev->stats.tx_bytes += size; - netif_wake_queue(ndev); -} - -/** - * axienet_check_tx_bd_space - Checks if a BD/group of BDs are currently busy - * @lp: Pointer to the axienet_local structure - * @num_frag: The number of BDs to check for - * - * returns: 0, on success - * NETDEV_TX_BUSY, if any of the descriptors are not free - * - * 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. - */ -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) % TX_BD_NUM]; - if (cur_p->status & XAXIDMA_BD_STS_ALL_MASK) - return NETDEV_TX_BUSY; - return 0; -} - -/** - * axienet_start_xmit - Starts the transmission. - * @skb: sk_buff pointer that contains data to be Txed. - * @ndev: Pointer to net_device structure. - * - * returns: NETDEV_TX_OK, on success - * NETDEV_TX_BUSY, if any of the descriptors are not free - * - * This function is invoked from upper layers to initiate transmission. The - * function uses the next available free BDs and populates their fields to - * start the transmission. Additionally if checksum offloading is supported, - * it populates AXI Stream Control fields with appropriate values. - */ -static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - u32 ii; - u32 num_frag; - u32 csum_start_off; - u32 csum_index_off; - skb_frag_t *frag; - dma_addr_t tail_p; - 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]; - - if (axienet_check_tx_bd_space(lp, num_frag)) { - if (!netif_queue_stopped(ndev)) - netif_stop_queue(ndev); - return NETDEV_TX_BUSY; - } - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (lp->features & XAE_FEATURE_FULL_TX_CSUM) { - /* Tx Full Checksum Offload Enabled */ - cur_p->app0 |= 2; - } else if (lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) { - csum_start_off = skb_transport_offset(skb); - csum_index_off = csum_start_off + skb->csum_offset; - /* Tx Partial Checksum Offload Enabled */ - cur_p->app0 |= 1; - cur_p->app1 = (csum_start_off << 16) | csum_index_off; - } - } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { - cur_p->app0 |= 2; /* Tx Full Checksum Offload Enabled */ - } - - 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++) { - lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM; - cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; - 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); - cur_p->cntrl = skb_frag_size(frag); - } - - cur_p->cntrl |= XAXIDMA_BD_CTRL_TXEOF_MASK; - cur_p->app4 = (unsigned long)skb; - - tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; - /* Start the transfer */ - axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p); - lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM; - - 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. - * - * 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. - */ -static void axienet_recv(struct net_device *ndev) -{ - u32 length; - u32 csumstatus; - u32 size = 0; - u32 packets = 0; - dma_addr_t tail_p; - struct axienet_local *lp = netdev_priv(ndev); - struct sk_buff *skb, *new_skb; - struct axidma_bd *cur_p; - - tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; - cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; - - while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) { - skb = (struct sk_buff *) (cur_p->sw_id_offset); - length = cur_p->app4 & 0x0000FFFF; - - dma_unmap_single(ndev->dev.parent, cur_p->phys, - lp->max_frm_size, - DMA_FROM_DEVICE); - - 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; - } - } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 && - skb->protocol == __constant_htons(ETH_P_IP) && - skb->len > 64) { - skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF); - skb->ip_summed = CHECKSUM_COMPLETE; - } - - netif_rx(skb); - - size += length; - packets++; - - new_skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size); - if (!new_skb) { - dev_err(&ndev->dev, "no memory for new sk_buff\n"); - return; - } - 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->sw_id_offset = (u32) new_skb; - - lp->rx_bd_ci = ++lp->rx_bd_ci % RX_BD_NUM; - cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; - } - - ndev->stats.rx_packets += packets; - ndev->stats.rx_bytes += size; - - axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p); -} - -/** - * axienet_tx_irq - Tx Done Isr. - * @irq: irq number - * @_ndev: net_device pointer - * - * returns: IRQ_HANDLED for all cases. - * - * This is the Axi DMA Tx done Isr. It invokes "axienet_start_xmit_done" - * to complete the 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_start_xmit_done(lp->ndev); - goto out; - } - if (!(status & XAXIDMA_IRQ_ALL_MASK)) - dev_err(&ndev->dev, "No interrupts asserted in Tx path"); - 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); - - tasklet_schedule(&lp->dma_err_tasklet); - } -out: - axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status); - return IRQ_HANDLED; -} - -/** - * axienet_rx_irq - Rx Isr. - * @irq: irq number - * @_ndev: net_device pointer - * - * returns: IRQ_HANDLED for all cases. - * - * This is the Axi DMA Rx Isr. It invokes "axienet_recv" to complete the 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_recv(lp->ndev); - goto out; - } - if (!(status & XAXIDMA_IRQ_ALL_MASK)) - dev_err(&ndev->dev, "No interrupts asserted in Rx path"); - 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_CR_OFFSET, cr); - - tasklet_schedule(&lp->dma_err_tasklet); - } -out: - axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status); - return IRQ_HANDLED; -} - -/** - * axienet_open - Driver open routine. - * @ndev: Pointer to net_device structure - * - * returns: 0, on success. - * -ENODEV, if PHY cannot be connected to - * non-zero error value on failure - * - * This is the driver open routine. It calls phy_start to start the PHY device. - * It also allocates interrupt service routines, enables the interrupt lines - * and ISR handling. Axi Ethernet core is reset through Axi DMA core. Buffer - * descriptors are initialized. - */ -static int axienet_open(struct net_device *ndev) -{ - int ret, mdio_mcreg; - struct axienet_local *lp = netdev_priv(ndev); - - dev_dbg(&ndev->dev, "axienet_open()\n"); - - mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET); - ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) - return ret; - /* 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. If MDIO is not disabled when the reset - * process is started, MDIO will be broken afterwards. */ - axienet_iow(lp, XAE_MDIO_MC_OFFSET, - (mdio_mcreg & (~XAE_MDIO_MC_MDIOEN_MASK))); - axienet_device_reset(ndev); - /* Enable the MDIO */ - axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg); - ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) - return ret; - - if (lp->phy_node) { - lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node, - axienet_adjust_link, 0, - PHY_INTERFACE_MODE_GMII); - if (!lp->phy_dev) { - dev_err(lp->dev, "of_phy_connect() failed\n"); - return -ENODEV; - } - phy_start(lp->phy_dev); - } - - /* Enable interrupts for Axi DMA Tx */ - ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev); - if (ret) - goto err_tx_irq; - /* Enable interrupts for Axi DMA Rx */ - ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev); - if (ret) - goto err_rx_irq; - /* Enable tasklets for Axi DMA error handling */ - tasklet_enable(&lp->dma_err_tasklet); - return 0; - -err_rx_irq: - free_irq(lp->tx_irq, ndev); -err_tx_irq: - if (lp->phy_dev) - phy_disconnect(lp->phy_dev); - lp->phy_dev = NULL; - dev_err(lp->dev, "request_irq() failed\n"); - return ret; -} - -/** - * axienet_stop - Driver stop routine. - * @ndev: Pointer to net_device structure - * - * returns: 0, on success. - * - * This is the driver stop routine. It calls phy_disconnect to stop the PHY - * device. It also removes the interrupt handlers and disables the interrupts. - * The Axi DMA Tx/Rx BDs are released. - */ -static int axienet_stop(struct net_device *ndev) -{ - u32 cr; - struct axienet_local *lp = netdev_priv(ndev); - - dev_dbg(&ndev->dev, "axienet_close()\n"); - - cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET); - axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, - cr & (~XAXIDMA_CR_RUNSTOP_MASK)); - cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET); - axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, - cr & (~XAXIDMA_CR_RUNSTOP_MASK)); - axienet_setoptions(ndev, lp->options & - ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); - - tasklet_disable(&lp->dma_err_tasklet); - - free_irq(lp->tx_irq, ndev); - free_irq(lp->rx_irq, ndev); - - if (lp->phy_dev) - phy_disconnect(lp->phy_dev); - lp->phy_dev = NULL; - - axienet_dma_bd_release(ndev); - return 0; -} - -/** - * axienet_change_mtu - Driver change mtu routine. - * @ndev: Pointer to net_device structure - * @new_mtu: New mtu value to be applied - * - * returns: Always returns 0 (success). - * - * This is the change mtu driver routine. It checks if the Axi Ethernet - * hardware supports jumbo frames before changing the mtu. This can be - * called only when the device is not up. - */ -static int axienet_change_mtu(struct net_device *ndev, int new_mtu) -{ - struct axienet_local *lp = netdev_priv(ndev); - - if (netif_running(ndev)) - return -EBUSY; - if (lp->jumbo_support) { - if ((new_mtu > XAE_JUMBO_MTU) || (new_mtu < 64)) - return -EINVAL; - ndev->mtu = new_mtu; - } else { - if ((new_mtu > XAE_MTU) || (new_mtu < 64)) - return -EINVAL; - ndev->mtu = new_mtu; - } - - return 0; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -/** - * axienet_poll_controller - Axi Ethernet poll mechanism. - * @ndev: Pointer to net_device structure - * - * This implements Rx/Tx ISR poll mechanisms. The interrupts are disabled prior - * to polling the ISRs and are enabled back after the polling is done. - */ -static void axienet_poll_controller(struct net_device *ndev) -{ - struct axienet_local *lp = netdev_priv(ndev); - disable_irq(lp->tx_irq); - disable_irq(lp->rx_irq); - axienet_rx_irq(lp->tx_irq, ndev); - axienet_tx_irq(lp->rx_irq, ndev); - enable_irq(lp->tx_irq); - enable_irq(lp->rx_irq); -} -#endif - -static const struct net_device_ops axienet_netdev_ops = { - .ndo_open = axienet_open, - .ndo_stop = axienet_stop, - .ndo_start_xmit = axienet_start_xmit, - .ndo_change_mtu = axienet_change_mtu, - .ndo_set_mac_address = netdev_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = axienet_set_multicast_list, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = axienet_poll_controller, -#endif -}; - -/** - * axienet_ethtools_get_settings - Get Axi Ethernet settings related to PHY. - * @ndev: Pointer to net_device structure - * @ecmd: Pointer to ethtool_cmd structure - * - * This implements ethtool command for getting PHY settings. If PHY could - * not be found, the function returns -ENODEV. This function calls the - * relevant PHY ethtool API to get the PHY settings. - * Issue "ethtool ethX" under linux prompt to execute this function. - */ -static int axienet_ethtools_get_settings(struct net_device *ndev, - struct ethtool_cmd *ecmd) -{ - struct axienet_local *lp = netdev_priv(ndev); - struct phy_device *phydev = lp->phy_dev; - if (!phydev) - return -ENODEV; - return phy_ethtool_gset(phydev, ecmd); -} - -/** - * axienet_ethtools_set_settings - Set PHY settings as passed in the argument. - * @ndev: Pointer to net_device structure - * @ecmd: Pointer to ethtool_cmd structure - * - * This implements ethtool command for setting various PHY settings. If PHY - * could not be found, the function returns -ENODEV. This function calls the - * relevant PHY ethtool API to set the PHY. - * Issue e.g. "ethtool -s ethX speed 1000" under linux prompt to execute this - * function. - */ -static int axienet_ethtools_set_settings(struct net_device *ndev, - struct ethtool_cmd *ecmd) -{ - struct axienet_local *lp = netdev_priv(ndev); - struct phy_device *phydev = lp->phy_dev; - if (!phydev) - return -ENODEV; - return phy_ethtool_sset(phydev, ecmd); -} - -/** - * axienet_ethtools_get_drvinfo - Get various Axi Ethernet driver information. - * @ndev: Pointer to net_device structure - * @ed: Pointer to ethtool_drvinfo structure - * - * This implements ethtool command for getting the driver information. - * Issue "ethtool -i ethX" under linux prompt to execute this function. - */ -static void axienet_ethtools_get_drvinfo(struct net_device *ndev, - struct ethtool_drvinfo *ed) -{ - memset(ed, 0, sizeof(struct ethtool_drvinfo)); - strcpy(ed->driver, DRIVER_NAME); - strcpy(ed->version, DRIVER_VERSION); - ed->regdump_len = sizeof(u32) * AXIENET_REGS_N; -} - -/** - * axienet_ethtools_get_regs_len - Get the total regs length present in the - * AxiEthernet core. - * @ndev: Pointer to net_device structure - * - * This implements ethtool command for getting the total register length - * information. - */ -static int axienet_ethtools_get_regs_len(struct net_device *ndev) -{ - return sizeof(u32) * AXIENET_REGS_N; -} - -/** - * axienet_ethtools_get_regs - Dump the contents of all registers present - * in AxiEthernet core. - * @ndev: Pointer to net_device structure - * @regs: Pointer to ethtool_regs structure - * @ret: Void pointer used to return the contents of the registers. - * - * This implements ethtool command for getting the Axi Ethernet register dump. - * Issue "ethtool -d ethX" to execute this function. - */ -static void axienet_ethtools_get_regs(struct net_device *ndev, - struct ethtool_regs *regs, void *ret) -{ - u32 *data = (u32 *) ret; - size_t len = sizeof(u32) * AXIENET_REGS_N; - struct axienet_local *lp = netdev_priv(ndev); - - regs->version = 0; - regs->len = len; - - memset(data, 0, len); - data[0] = axienet_ior(lp, XAE_RAF_OFFSET); - data[1] = axienet_ior(lp, XAE_TPF_OFFSET); - data[2] = axienet_ior(lp, XAE_IFGP_OFFSET); - data[3] = axienet_ior(lp, XAE_IS_OFFSET); - data[4] = axienet_ior(lp, XAE_IP_OFFSET); - data[5] = axienet_ior(lp, XAE_IE_OFFSET); - data[6] = axienet_ior(lp, XAE_TTAG_OFFSET); - data[7] = axienet_ior(lp, XAE_RTAG_OFFSET); - data[8] = axienet_ior(lp, XAE_UAWL_OFFSET); - data[9] = axienet_ior(lp, XAE_UAWU_OFFSET); - data[10] = axienet_ior(lp, XAE_TPID0_OFFSET); - data[11] = axienet_ior(lp, XAE_TPID1_OFFSET); - data[12] = axienet_ior(lp, XAE_PPST_OFFSET); - data[13] = axienet_ior(lp, XAE_RCW0_OFFSET); - data[14] = axienet_ior(lp, XAE_RCW1_OFFSET); - data[15] = axienet_ior(lp, XAE_TC_OFFSET); - data[16] = axienet_ior(lp, XAE_FCC_OFFSET); - data[17] = axienet_ior(lp, XAE_EMMC_OFFSET); - data[18] = axienet_ior(lp, XAE_PHYC_OFFSET); - data[19] = axienet_ior(lp, XAE_MDIO_MC_OFFSET); - 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); - data[30] = axienet_ior(lp, XAE_AF0_OFFSET); - data[31] = axienet_ior(lp, XAE_AF1_OFFSET); -} - -/** - * axienet_ethtools_get_pauseparam - Get the pause parameter setting for - * Tx and Rx paths. - * @ndev: Pointer to net_device structure - * @epauseparm: Pointer to ethtool_pauseparam structure. - * - * This implements ethtool command for getting axi ethernet pause frame - * setting. Issue "ethtool -a ethX" to execute this function. - */ -static void -axienet_ethtools_get_pauseparam(struct net_device *ndev, - struct ethtool_pauseparam *epauseparm) -{ - u32 regval; - struct axienet_local *lp = netdev_priv(ndev); - epauseparm->autoneg = 0; - regval = axienet_ior(lp, XAE_FCC_OFFSET); - epauseparm->tx_pause = regval & XAE_FCC_FCTX_MASK; - epauseparm->rx_pause = regval & XAE_FCC_FCRX_MASK; -} - -/** - * axienet_ethtools_set_pauseparam - Set device pause parameter(flow control) - * settings. - * @ndev: Pointer to net_device structure - * @epauseparam:Pointer to ethtool_pauseparam structure - * - * This implements ethtool command for enabling flow control on Rx and Tx - * paths. Issue "ethtool -A ethX tx on|off" under linux prompt to execute this - * function. - */ -static int -axienet_ethtools_set_pauseparam(struct net_device *ndev, - struct ethtool_pauseparam *epauseparm) -{ - u32 regval = 0; - struct axienet_local *lp = netdev_priv(ndev); - - if (netif_running(ndev)) { - printk(KERN_ERR "%s: Please stop netif before applying " - "configruation\n", ndev->name); - return -EFAULT; - } - - regval = axienet_ior(lp, XAE_FCC_OFFSET); - if (epauseparm->tx_pause) - regval |= XAE_FCC_FCTX_MASK; - else - regval &= ~XAE_FCC_FCTX_MASK; - if (epauseparm->rx_pause) - regval |= XAE_FCC_FCRX_MASK; - else - regval &= ~XAE_FCC_FCRX_MASK; - axienet_iow(lp, XAE_FCC_OFFSET, regval); - - return 0; -} - -/** - * axienet_ethtools_get_coalesce - Get DMA interrupt coalescing count. - * @ndev: Pointer to net_device structure - * @ecoalesce: Pointer to ethtool_coalesce structure - * - * This implements ethtool command for getting the DMA interrupt coalescing - * count on Tx and Rx paths. Issue "ethtool -c ethX" under linux prompt to - * execute this function. - */ -static int axienet_ethtools_get_coalesce(struct net_device *ndev, - struct ethtool_coalesce *ecoalesce) -{ - 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; - return 0; -} - -/** - * axienet_ethtools_set_coalesce - Set DMA interrupt coalescing count. - * @ndev: Pointer to net_device structure - * @ecoalesce: Pointer to ethtool_coalesce structure - * - * 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 - * prompt to execute this function. - */ -static int axienet_ethtools_set_coalesce(struct net_device *ndev, - struct ethtool_coalesce *ecoalesce) -{ - struct axienet_local *lp = netdev_priv(ndev); - - if (netif_running(ndev)) { - printk(KERN_ERR "%s: Please stop netif before applying " - "configruation\n", ndev->name); - 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->tx_max_coalesced_frames) - lp->coalesce_count_tx = ecoalesce->tx_max_coalesced_frames; - - return 0; -} - -static struct ethtool_ops axienet_ethtool_ops = { - .get_settings = axienet_ethtools_get_settings, - .set_settings = axienet_ethtools_set_settings, - .get_drvinfo = axienet_ethtools_get_drvinfo, - .get_regs_len = axienet_ethtools_get_regs_len, - .get_regs = axienet_ethtools_get_regs, - .get_link = ethtool_op_get_link, - .get_pauseparam = axienet_ethtools_get_pauseparam, - .set_pauseparam = axienet_ethtools_set_pauseparam, - .get_coalesce = axienet_ethtools_get_coalesce, - .set_coalesce = axienet_ethtools_set_coalesce, -}; - -/** - * axienet_dma_err_handler - Tasklet handler for Axi DMA Error - * @data: Data passed - * - * Resets the Axi DMA and Axi Ethernet devices, and reconfigures the - * Tx/Rx BDs. - */ -static void axienet_dma_err_handler(unsigned long data) -{ - u32 axienet_status; - u32 cr, i; - int mdio_mcreg; - struct axienet_local *lp = (struct axienet_local *) data; - struct net_device *ndev = lp->ndev; - struct axidma_bd *cur_p; - - axienet_setoptions(ndev, lp->options & - ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); - mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET); - axienet_mdio_wait_until_ready(lp); - /* 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. So if MDIO is not disabled when the reset - * process is started, MDIO will be broken afterwards. */ - axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg & - ~XAE_MDIO_MC_MDIOEN_MASK)); - - __axienet_device_reset(lp, &ndev->dev, XAXIDMA_TX_CR_OFFSET); - __axienet_device_reset(lp, &ndev->dev, XAXIDMA_RX_CR_OFFSET); - - axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg); - axienet_mdio_wait_until_ready(lp); - - for (i = 0; i < TX_BD_NUM; i++) { - cur_p = &lp->tx_bd_v[i]; - if (cur_p->phys) - dma_unmap_single(ndev->dev.parent, cur_p->phys, - (cur_p->cntrl & - XAXIDMA_BD_CTRL_LENGTH_MASK), - DMA_TO_DEVICE); - if (cur_p->app4) - dev_kfree_skb_irq((struct sk_buff *) cur_p->app4); - cur_p->phys = 0; - cur_p->cntrl = 0; - cur_p->status = 0; - cur_p->app0 = 0; - cur_p->app1 = 0; - cur_p->app2 = 0; - cur_p->app3 = 0; - cur_p->app4 = 0; - cur_p->sw_id_offset = 0; - } - - for (i = 0; i < RX_BD_NUM; i++) { - cur_p = &lp->rx_bd_v[i]; - cur_p->status = 0; - cur_p->app0 = 0; - cur_p->app1 = 0; - cur_p->app2 = 0; - cur_p->app3 = 0; - cur_p->app4 = 0; - } - - lp->tx_bd_ci = 0; - 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) * (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_status = axienet_ior(lp, XAE_RCW1_OFFSET); - axienet_status &= ~XAE_RCW1_RX_MASK; - axienet_iow(lp, XAE_RCW1_OFFSET, axienet_status); - - axienet_status = axienet_ior(lp, XAE_IP_OFFSET); - if (axienet_status & XAE_INT_RXRJECT_MASK) - axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK); - axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK); - - /* Sync default options with HW but leave receiver and - * transmitter disabled.*/ - axienet_setoptions(ndev, lp->options & - ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); - axienet_set_mac_address(ndev, NULL); - axienet_set_multicast_list(ndev); - axienet_setoptions(ndev, lp->options); -} - -/** - * axienet_of_probe - Axi Ethernet probe function. - * @op: Pointer to platform device structure. - * @match: Pointer to device id structure - * - * returns: 0, on success - * Non-zero error value on failure. - * - * This is the probe routine for Axi Ethernet driver. This is called before - * any other driver routines are invoked. It allocates and sets up the Ethernet - * device. Parses through device tree and populates fields of - * axienet_local. It registers the Ethernet device. - */ -static int __devinit axienet_of_probe(struct platform_device *op) -{ - __be32 *p; - int size, ret = 0; - struct device_node *np; - struct axienet_local *lp; - struct net_device *ndev; - const void *addr; - - ndev = alloc_etherdev(sizeof(*lp)); - if (!ndev) - return -ENOMEM; - - ether_setup(ndev); - dev_set_drvdata(&op->dev, ndev); - - SET_NETDEV_DEV(ndev, &op->dev); - ndev->flags &= ~IFF_MULTICAST; /* clear multicast */ - ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST; - ndev->netdev_ops = &axienet_netdev_ops; - ndev->ethtool_ops = &axienet_ethtool_ops; - - lp = netdev_priv(ndev); - lp->ndev = ndev; - lp->dev = &op->dev; - lp->options = XAE_OPTION_DEFAULTS; - /* Map device registers */ - lp->regs = of_iomap(op->dev.of_node, 0); - if (!lp->regs) { - dev_err(&op->dev, "could not map Axi Ethernet regs.\n"); - goto nodev; - } - /* Setup checksum offload, but default to off if not specified */ - lp->features = 0; - - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,txcsum", NULL); - if (p) { - switch (be32_to_cpup(p)) { - case 1: - lp->csum_offload_on_tx_path = - XAE_FEATURE_PARTIAL_TX_CSUM; - lp->features |= XAE_FEATURE_PARTIAL_TX_CSUM; - /* Can checksum TCP/UDP over IPv4. */ - ndev->features |= NETIF_F_IP_CSUM; - break; - case 2: - lp->csum_offload_on_tx_path = - XAE_FEATURE_FULL_TX_CSUM; - lp->features |= XAE_FEATURE_FULL_TX_CSUM; - /* Can checksum TCP/UDP over IPv4. */ - ndev->features |= NETIF_F_IP_CSUM; - break; - default: - lp->csum_offload_on_tx_path = XAE_NO_CSUM_OFFLOAD; - } - } - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL); - if (p) { - switch (be32_to_cpup(p)) { - case 1: - lp->csum_offload_on_rx_path = - XAE_FEATURE_PARTIAL_RX_CSUM; - lp->features |= XAE_FEATURE_PARTIAL_RX_CSUM; - break; - case 2: - lp->csum_offload_on_rx_path = - XAE_FEATURE_FULL_RX_CSUM; - lp->features |= XAE_FEATURE_FULL_RX_CSUM; - break; - default: - lp->csum_offload_on_rx_path = XAE_NO_CSUM_OFFLOAD; - } - } - /* For supporting jumbo frames, the Axi Ethernet hardware must have - * a larger Rx/Tx Memory. Typically, the size must be more than or - * equal to 16384 bytes, so that we can enable jumbo option and start - * supporting jumbo frames. Here we check for memory allocated for - * Rx/Tx in the hardware from the device-tree and accordingly set - * flags. */ - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,rxmem", NULL); - if (p) { - if ((be32_to_cpup(p)) >= 0x4000) - lp->jumbo_support = 1; - } - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,temac-type", - NULL); - if (p) - lp->temac_type = be32_to_cpup(p); - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,phy-type", NULL); - if (p) - lp->phy_type = be32_to_cpup(p); - - /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ - np = of_parse_phandle(op->dev.of_node, "axistream-connected", 0); - if (!np) { - dev_err(&op->dev, "could not find DMA node\n"); - goto err_iounmap; - } - lp->dma_regs = of_iomap(np, 0); - if (lp->dma_regs) { - dev_dbg(&op->dev, "MEM base: %p\n", lp->dma_regs); - } else { - dev_err(&op->dev, "unable to map DMA registers\n"); - of_node_put(np); - } - lp->rx_irq = irq_of_parse_and_map(np, 1); - lp->tx_irq = irq_of_parse_and_map(np, 0); - of_node_put(np); - if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) { - dev_err(&op->dev, "could not determine irqs\n"); - ret = -ENOMEM; - goto err_iounmap_2; - } - - /* Retrieve the MAC address */ - addr = of_get_property(op->dev.of_node, "local-mac-address", &size); - if ((!addr) || (size != 6)) { - dev_err(&op->dev, "could not find MAC address\n"); - ret = -ENODEV; - goto err_iounmap_2; - } - axienet_set_mac_address(ndev, (void *) addr); - - lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD; - lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD; - - lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0); - ret = axienet_mdio_setup(lp, op->dev.of_node); - if (ret) - dev_warn(&op->dev, "error registering MDIO bus\n"); - - ret = register_netdev(lp->ndev); - if (ret) { - dev_err(lp->dev, "register_netdev() error (%i)\n", ret); - goto err_iounmap_2; - } - - tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler, - (unsigned long) lp); - tasklet_disable(&lp->dma_err_tasklet); - - return 0; - -err_iounmap_2: - if (lp->dma_regs) - iounmap(lp->dma_regs); -err_iounmap: - iounmap(lp->regs); -nodev: - free_netdev(ndev); - ndev = NULL; - return ret; -} - -static int __devexit axienet_of_remove(struct platform_device *op) -{ - struct net_device *ndev = dev_get_drvdata(&op->dev); - struct axienet_local *lp = netdev_priv(ndev); - - axienet_mdio_teardown(lp); - unregister_netdev(ndev); - - if (lp->phy_node) - of_node_put(lp->phy_node); - lp->phy_node = NULL; - - dev_set_drvdata(&op->dev, NULL); - - iounmap(lp->regs); - if (lp->dma_regs) - iounmap(lp->dma_regs); - free_netdev(ndev); - - return 0; -} - -static struct platform_driver axienet_of_driver = { - .probe = axienet_of_probe, - .remove = __devexit_p(axienet_of_remove), - .driver = { - .owner = THIS_MODULE, - .name = "xilinx_axienet", - .of_match_table = axienet_of_match, - }, -}; - -module_platform_driver(axienet_of_driver); - -MODULE_DESCRIPTION("Xilinx Axi Ethernet driver"); -MODULE_AUTHOR("Xilinx"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c deleted file mode 100644 index e90e1f46..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * MDIO bus driver for the Xilinx Axi Ethernet device - * - * Copyright (c) 2009 Secret Lab Technologies, Ltd. - * Copyright (c) 2010 - 2011 Michal Simek <monstr@monstr.eu> - * Copyright (c) 2010 - 2011 PetaLogix - * Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved. - */ - -#include <linux/of_address.h> -#include <linux/of_mdio.h> -#include <linux/jiffies.h> - -#include "xilinx_axienet.h" - -#define MAX_MDIO_FREQ 2500000 /* 2.5 MHz */ -#define DEFAULT_CLOCK_DIVISOR XAE_MDIO_DIV_DFT - -/* Wait till MDIO interface is ready to accept a new transaction.*/ -int axienet_mdio_wait_until_ready(struct axienet_local *lp) -{ - long end = jiffies + 2; - while (!(axienet_ior(lp, XAE_MDIO_MCR_OFFSET) & - XAE_MDIO_MCR_READY_MASK)) { - if (end - jiffies <= 0) { - WARN_ON(1); - return -ETIMEDOUT; - } - udelay(1); - } - return 0; -} - -/** - * axienet_mdio_read - MDIO interface read function - * @bus: Pointer to mii bus structure - * @phy_id: Address of the PHY device - * @reg: PHY register to read - * - * returns: The register contents on success, -ETIMEDOUT on a timeout - * - * Reads the contents of the requested register from the requested PHY - * address by first writing the details into MCR register. After a while - * the register MRD is read to obtain the PHY register content. - */ -static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg) -{ - u32 rc; - int ret; - struct axienet_local *lp = bus->priv; - - ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) - return ret; - - axienet_iow(lp, XAE_MDIO_MCR_OFFSET, - (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) & - XAE_MDIO_MCR_PHYAD_MASK) | - ((reg << XAE_MDIO_MCR_REGAD_SHIFT) & - XAE_MDIO_MCR_REGAD_MASK) | - XAE_MDIO_MCR_INITIATE_MASK | - XAE_MDIO_MCR_OP_READ_MASK)); - - ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) - 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); - - return rc; -} - -/** - * axienet_mdio_write - MDIO interface write function - * @bus: Pointer to mii bus structure - * @phy_id: Address of the PHY device - * @reg: PHY register to write to - * @val: Value to be written into the register - * - * returns: 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 - * to finish the write operation. - */ -static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg, - u16 val) -{ - int ret; - struct axienet_local *lp = bus->priv; - - dev_dbg(lp->dev, "axienet_mdio_write(phy_id=%i, reg=%x, val=%x)\n", - phy_id, reg, val); - - ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) - return ret; - - 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) | - ((reg << XAE_MDIO_MCR_REGAD_SHIFT) & - XAE_MDIO_MCR_REGAD_MASK) | - XAE_MDIO_MCR_INITIATE_MASK | - XAE_MDIO_MCR_OP_WRITE_MASK)); - - ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) - return ret; - return 0; -} - -/** - * axienet_mdio_setup - MDIO setup function - * @lp: Pointer to axienet local data structure. - * @np: Pointer to device node - * - * returns: 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. - **/ -int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np) -{ - int ret; - u32 clk_div, host_clock; - u32 *property_p; - struct mii_bus *bus; - struct resource res; - struct device_node *np1; - - /* clk_div can be calculated by deriving it from the equation: - * fMDIO = fHOST / ((1 + clk_div) * 2) - * - * Where fMDIO <= 2500000, so we get: - * fHOST / ((1 + clk_div) * 2) <= 2500000 - * - * Then we get: - * 1 / ((1 + clk_div) * 2) <= (2500000 / fHOST) - * - * Then we get: - * 1 / (1 + clk_div) <= ((2500000 * 2) / fHOST) - * - * Then we get: - * 1 / (1 + clk_div) <= (5000000 / fHOST) - * - * So: - * (1 + clk_div) >= (fHOST / 5000000) - * - * And finally: - * clk_div >= (fHOST / 5000000) - 1 - * - * fHOST can be read from the flattened device tree as property - * "clock-frequency" from the CPU - */ - - np1 = of_find_node_by_name(NULL, "cpu"); - if (!np1) { - printk(KERN_WARNING "%s(): Could not find CPU device node.", - __func__); - printk(KERN_WARNING "Setting MDIO clock divisor to " - "default %d\n", DEFAULT_CLOCK_DIVISOR); - clk_div = DEFAULT_CLOCK_DIVISOR; - goto issue; - } - property_p = (u32 *) of_get_property(np1, "clock-frequency", NULL); - if (!property_p) { - printk(KERN_WARNING "%s(): Could not find CPU property: " - "clock-frequency.", __func__); - printk(KERN_WARNING "Setting MDIO clock divisor to " - "default %d\n", DEFAULT_CLOCK_DIVISOR); - clk_div = DEFAULT_CLOCK_DIVISOR; - goto issue; - } - - host_clock = be32_to_cpup(property_p); - 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++; - - printk(KERN_DEBUG "%s(): Setting MDIO clock divisor to %u based " - "on %u Hz host clock.\n", __func__, clk_div, host_clock); - - of_node_put(np1); -issue: - axienet_iow(lp, XAE_MDIO_MC_OFFSET, - (((u32) clk_div) | XAE_MDIO_MC_MDIOEN_MASK)); - - ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) - return ret; - - bus = mdiobus_alloc(); - if (!bus) - return -ENOMEM; - - np1 = of_get_parent(lp->phy_node); - of_address_to_resource(np1, 0, &res); - snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx", - (unsigned long long) res.start); - - bus->priv = lp; - bus->name = "Xilinx Axi Ethernet MDIO"; - bus->read = axienet_mdio_read; - bus->write = axienet_mdio_write; - bus->parent = lp->dev; - bus->irq = lp->mdio_irqs; /* preallocated IRQ table */ - lp->mii_bus = bus; - - ret = of_mdiobus_register(bus, np1); - if (ret) { - mdiobus_free(bus); - return ret; - } - return 0; -} - -/** - * axienet_mdio_teardown - MDIO remove function - * @lp: Pointer to axienet local data structure. - * - * Unregisters the MDIO and frees any associate memory for mii bus. - */ -void axienet_mdio_teardown(struct axienet_local *lp) -{ - mdiobus_unregister(lp->mii_bus); - kfree(lp->mii_bus->irq); - mdiobus_free(lp->mii_bus); - lp->mii_bus = NULL; -} diff --git a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_emaclite.c deleted file mode 100644 index 77cfe511..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ /dev/null @@ -1,1308 +0,0 @@ -/* - * 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@petalogix.com>. - * - * 2007-2009 (c) Xilinx, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <linux/module.h> -#include <linux/uaccess.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/of_address.h> -#include <linux/of_device.h> -#include <linux/of_platform.h> -#include <linux/of_mdio.h> -#include <linux/of_net.h> -#include <linux/phy.h> -#include <linux/interrupt.h> - -#define DRIVER_NAME "xilinx_emaclite" - -/* Register offsets for the EmacLite Core */ -#define XEL_TXBUFF_OFFSET 0x0 /* Transmit Buffer */ -#define XEL_MDIOADDR_OFFSET 0x07E4 /* MDIO Address Register */ -#define XEL_MDIOWR_OFFSET 0x07E8 /* MDIO Write Data Register */ -#define XEL_MDIORD_OFFSET 0x07EC /* MDIO Read Data Register */ -#define XEL_MDIOCTRL_OFFSET 0x07F0 /* MDIO Control Register */ -#define XEL_GIER_OFFSET 0x07F8 /* GIE Register */ -#define XEL_TSR_OFFSET 0x07FC /* Tx status */ -#define XEL_TPLR_OFFSET 0x07F4 /* Tx packet length */ - -#define XEL_RXBUFF_OFFSET 0x1000 /* Receive Buffer */ -#define XEL_RPLR_OFFSET 0x100C /* Rx packet length */ -#define XEL_RSR_OFFSET 0x17FC /* Rx status */ - -#define XEL_BUFFER_OFFSET 0x0800 /* Next Tx/Rx buffer's offset */ - -/* MDIO Address Register Bit Masks */ -#define XEL_MDIOADDR_REGADR_MASK 0x0000001F /* Register Address */ -#define XEL_MDIOADDR_PHYADR_MASK 0x000003E0 /* PHY Address */ -#define XEL_MDIOADDR_PHYADR_SHIFT 5 -#define XEL_MDIOADDR_OP_MASK 0x00000400 /* RD/WR Operation */ - -/* MDIO Write Data Register Bit Masks */ -#define XEL_MDIOWR_WRDATA_MASK 0x0000FFFF /* Data to be Written */ - -/* MDIO Read Data Register Bit Masks */ -#define XEL_MDIORD_RDDATA_MASK 0x0000FFFF /* Data to be Read */ - -/* MDIO Control Register Bit Masks */ -#define XEL_MDIOCTRL_MDIOSTS_MASK 0x00000001 /* MDIO Status Mask */ -#define XEL_MDIOCTRL_MDIOEN_MASK 0x00000008 /* MDIO Enable */ - -/* Global Interrupt Enable Register (GIER) Bit Masks */ -#define XEL_GIER_GIE_MASK 0x80000000 /* Global Enable */ - -/* Transmit Status Register (TSR) Bit Masks */ -#define XEL_TSR_XMIT_BUSY_MASK 0x00000001 /* Tx complete */ -#define XEL_TSR_PROGRAM_MASK 0x00000002 /* Program the MAC address */ -#define XEL_TSR_XMIT_IE_MASK 0x00000008 /* Tx interrupt enable bit */ -#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000 /* Buffer is active, SW bit - * only. This is not documented - * in the HW spec */ - -/* Define for programming the MAC address into the EmacLite */ -#define XEL_TSR_PROG_MAC_ADDR (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK) - -/* Receive Status Register (RSR) */ -#define XEL_RSR_RECV_DONE_MASK 0x00000001 /* Rx complete */ -#define XEL_RSR_RECV_IE_MASK 0x00000008 /* Rx interrupt enable bit */ - -/* Transmit Packet Length Register (TPLR) */ -#define XEL_TPLR_LENGTH_MASK 0x0000FFFF /* Tx packet length */ - -/* Receive Packet Length Register (RPLR) */ -#define XEL_RPLR_LENGTH_MASK 0x0000FFFF /* Rx packet length */ - -#define XEL_HEADER_OFFSET 12 /* Offset to length field */ -#define XEL_HEADER_SHIFT 16 /* Shift value for length */ - -/* General Ethernet Definitions */ -#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) - -/** - * struct net_local - Our private per device data - * @ndev: instance of the network device - * @tx_ping_pong: indicates whether Tx Pong buffer is configured in HW - * @rx_ping_pong: indicates whether Rx Pong buffer is configured in HW - * @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 - * @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 - * @phy_node: pointer to the PHY device node - * @mii_bus: pointer to the MII bus - * @mdio_irqs: IRQs table for MDIO bus - * @last_link: last link status - * @has_mdio: indicates whether MDIO is included in the HW - */ -struct net_local { - - struct net_device *ndev; - - bool tx_ping_pong; - bool rx_ping_pong; - u32 next_tx_buf_to_use; - u32 next_rx_buf_to_use; - void __iomem *base_addr; - - spinlock_t reset_lock; - struct sk_buff *deferred_skb; - - struct phy_device *phy_dev; - struct device_node *phy_node; - - struct mii_bus *mii_bus; - int mdio_irqs[PHY_MAX_ADDR]; - - int last_link; - bool has_mdio; -}; - - -/*************************/ -/* EmacLite driver calls */ -/*************************/ - -/** - * xemaclite_enable_interrupts - Enable the interrupts for the EmacLite device - * @drvdata: Pointer to the Emaclite device private data - * - * This function enables the Tx and Rx interrupts for the Emaclite device along - * with the Global Interrupt Enable. - */ -static void xemaclite_enable_interrupts(struct net_local *drvdata) -{ - u32 reg_data; - - /* Enable the Tx interrupts for the first Buffer */ - reg_data = in_be32(drvdata->base_addr + XEL_TSR_OFFSET); - out_be32(drvdata->base_addr + XEL_TSR_OFFSET, - reg_data | XEL_TSR_XMIT_IE_MASK); - - /* Enable the Tx interrupts for the second Buffer if - * configured in HW */ - if (drvdata->tx_ping_pong != 0) { - reg_data = in_be32(drvdata->base_addr + - XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); - out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_TSR_OFFSET, - reg_data | XEL_TSR_XMIT_IE_MASK); - } - - /* Enable the Rx interrupts for the first buffer */ - out_be32(drvdata->base_addr + XEL_RSR_OFFSET, - XEL_RSR_RECV_IE_MASK); - - /* Enable the Rx interrupts for the second Buffer if - * configured in HW */ - if (drvdata->rx_ping_pong != 0) { - out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_RSR_OFFSET, - XEL_RSR_RECV_IE_MASK); - } - - /* Enable the Global Interrupt Enable */ - out_be32(drvdata->base_addr + XEL_GIER_OFFSET, XEL_GIER_GIE_MASK); -} - -/** - * xemaclite_disable_interrupts - Disable the interrupts for the EmacLite device - * @drvdata: Pointer to the Emaclite device private data - * - * This function disables the Tx and Rx interrupts for the Emaclite device, - * along with the Global Interrupt Enable. - */ -static void xemaclite_disable_interrupts(struct net_local *drvdata) -{ - u32 reg_data; - - /* Disable the Global Interrupt Enable */ - out_be32(drvdata->base_addr + XEL_GIER_OFFSET, XEL_GIER_GIE_MASK); - - /* Disable the Tx interrupts for the first buffer */ - reg_data = in_be32(drvdata->base_addr + XEL_TSR_OFFSET); - out_be32(drvdata->base_addr + XEL_TSR_OFFSET, - reg_data & (~XEL_TSR_XMIT_IE_MASK)); - - /* Disable the Tx interrupts for the second Buffer - * if configured in HW */ - if (drvdata->tx_ping_pong != 0) { - reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_TSR_OFFSET); - out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_TSR_OFFSET, - reg_data & (~XEL_TSR_XMIT_IE_MASK)); - } - - /* Disable the Rx interrupts for the first buffer */ - reg_data = in_be32(drvdata->base_addr + XEL_RSR_OFFSET); - out_be32(drvdata->base_addr + XEL_RSR_OFFSET, - reg_data & (~XEL_RSR_RECV_IE_MASK)); - - /* Disable the Rx interrupts for the second buffer - * if configured in HW */ - if (drvdata->rx_ping_pong != 0) { - - reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_RSR_OFFSET); - out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + - XEL_RSR_OFFSET, - reg_data & (~XEL_RSR_RECV_IE_MASK)); - } -} - -/** - * xemaclite_aligned_write - Write from 16-bit aligned to 32-bit aligned address - * @src_ptr: Void pointer to the 16-bit aligned source address - * @dest_ptr: Pointer to the 32-bit aligned destination address - * @length: Number bytes to write from source to destination - * - * 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) -{ - u32 align_buffer; - u32 *to_u32_ptr; - u16 *from_u16_ptr, *to_u16_ptr; - - to_u32_ptr = dest_ptr; - from_u16_ptr = src_ptr; - align_buffer = 0; - - for (; length > 3; length -= 4) { - to_u16_ptr = (u16 *)&align_buffer; - *to_u16_ptr++ = *from_u16_ptr++; - *to_u16_ptr++ = *from_u16_ptr++; - - /* Output a word */ - *to_u32_ptr++ = align_buffer; - } - if (length) { - u8 *from_u8_ptr, *to_u8_ptr; - - /* Set up to output the remaining data */ - align_buffer = 0; - to_u8_ptr = (u8 *) &align_buffer; - from_u8_ptr = (u8 *) from_u16_ptr; - - /* Output the remaining data */ - for (; length > 0; length--) - *to_u8_ptr++ = *from_u8_ptr++; - - *to_u32_ptr = align_buffer; - } -} - -/** - * xemaclite_aligned_read - Read from 32-bit aligned to 16-bit aligned buffer - * @src_ptr: Pointer to the 32-bit aligned source address - * @dest_ptr: Pointer to the 16-bit aligned destination address - * @length: Number bytes to read from source to destination - * - * This function reads data from a 32-bit aligned address in the EmacLite device - * to a 16-bit aligned buffer. - */ -static void xemaclite_aligned_read(u32 *src_ptr, u8 *dest_ptr, - unsigned length) -{ - u16 *to_u16_ptr, *from_u16_ptr; - u32 *from_u32_ptr; - u32 align_buffer; - - from_u32_ptr = src_ptr; - to_u16_ptr = (u16 *) dest_ptr; - - for (; length > 3; length -= 4) { - /* Copy each word into the temporary buffer */ - align_buffer = *from_u32_ptr++; - from_u16_ptr = (u16 *)&align_buffer; - - /* Read data from source */ - *to_u16_ptr++ = *from_u16_ptr++; - *to_u16_ptr++ = *from_u16_ptr++; - } - - if (length) { - u8 *to_u8_ptr, *from_u8_ptr; - - /* Set up to read the remaining data */ - to_u8_ptr = (u8 *) to_u16_ptr; - align_buffer = *from_u32_ptr++; - from_u8_ptr = (u8 *) &align_buffer; - - /* Read the remaining data */ - for (; length > 0; length--) - *to_u8_ptr = *from_u8_ptr; - } -} - -/** - * xemaclite_send_data - Send an Ethernet frame - * @drvdata: Pointer to the Emaclite device private data - * @data: Pointer to the data to be sent - * @byte_count: Total frame size, including header - * - * This function checks if the Tx buffer of the Emaclite device is free to send - * data. If so, it fills the Tx buffer with data for transmission. Otherwise, it - * returns an error. - * - * Return: 0 upon success or -1 if the buffer(s) are full. - * - * Note: The maximum Tx packet size can not be more than Ethernet header - * (14 Bytes) + Maximum MTU (1500 bytes). This is excluding FCS. - */ -static int xemaclite_send_data(struct net_local *drvdata, u8 *data, - unsigned int byte_count) -{ - u32 reg_data; - void __iomem *addr; - - /* Determine the expected Tx buffer address */ - addr = drvdata->base_addr + drvdata->next_tx_buf_to_use; - - /* If the length is too large, truncate it */ - if (byte_count > ETH_FRAME_LEN) - byte_count = ETH_FRAME_LEN; - - /* Check if the expected buffer is available */ - reg_data = in_be32(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; - } else if (drvdata->tx_ping_pong != 0) { - /* If the expected buffer is full, try the other buffer, - * if it is configured in HW */ - - addr = (void __iomem __force *)((u32 __force)addr ^ - XEL_BUFFER_OFFSET); - reg_data = in_be32(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 - return -1; /* Buffer was full, return failure */ - - /* Write the frame to the buffer */ - xemaclite_aligned_write(data, (u32 __force *) addr, byte_count); - - out_be32(addr + XEL_TPLR_OFFSET, (byte_count & XEL_TPLR_LENGTH_MASK)); - - /* Update the Tx Status Register to indicate that there is a - * frame to send. Set the XEL_TSR_XMIT_ACTIVE_MASK flag which - * is used by the interrupt handler to check whether a frame - * has been transmitted */ - reg_data = in_be32(addr + XEL_TSR_OFFSET); - reg_data |= (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK); - out_be32(addr + XEL_TSR_OFFSET, reg_data); - - return 0; -} - -/** - * xemaclite_recv_data - Receive a frame - * @drvdata: Pointer to the Emaclite device private data - * @data: Address where the data is to be received - * - * This function is intended to be called from the interrupt context or - * with a wrapper which waits for the receive frame to be available. - * - * Return: Total number of bytes received - */ -static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) -{ - void __iomem *addr; - u16 length, proto_type; - u32 reg_data; - - /* Determine the expected buffer address */ - addr = (drvdata->base_addr + drvdata->next_rx_buf_to_use); - - /* Verify which buffer has valid data */ - reg_data = in_be32(addr + XEL_RSR_OFFSET); - - if ((reg_data & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { - if (drvdata->rx_ping_pong != 0) - drvdata->next_rx_buf_to_use ^= XEL_BUFFER_OFFSET; - } else { - /* The instance is out of sync, try other buffer if other - * buffer is configured, return 0 otherwise. If the instance is - * out of sync, do not update the 'next_rx_buf_to_use' since it - * will correct on subsequent calls */ - if (drvdata->rx_ping_pong != 0) - addr = (void __iomem __force *)((u32 __force)addr ^ - XEL_BUFFER_OFFSET); - else - return 0; /* No data was available */ - - /* Verify that buffer has valid data */ - reg_data = in_be32(addr + XEL_RSR_OFFSET); - if ((reg_data & XEL_RSR_RECV_DONE_MASK) != - XEL_RSR_RECV_DONE_MASK) - return 0; /* No data was available */ - } - - /* Get the protocol type of the ethernet frame that arrived */ - proto_type = ((ntohl(in_be32(addr + XEL_HEADER_OFFSET + - XEL_RXBUFF_OFFSET)) >> XEL_HEADER_SHIFT) & - XEL_RPLR_LENGTH_MASK); - - /* Check if received ethernet frame is a raw ethernet frame - * or an IP packet or an ARP packet */ - if (proto_type > (ETH_FRAME_LEN + ETH_FCS_LEN)) { - - if (proto_type == ETH_P_IP) { - length = ((ntohl(in_be32(addr + - XEL_HEADER_IP_LENGTH_OFFSET + - XEL_RXBUFF_OFFSET)) >> - XEL_HEADER_SHIFT) & - XEL_RPLR_LENGTH_MASK); - length += ETH_HLEN + ETH_FCS_LEN; - - } else if (proto_type == ETH_P_ARP) - length = XEL_ARP_PACKET_SIZE + ETH_HLEN + ETH_FCS_LEN; - 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 - /* Use the length in the frame, plus the header and trailer */ - length = proto_type + ETH_HLEN + ETH_FCS_LEN; - - /* Read from the EmacLite device */ - xemaclite_aligned_read((u32 __force *) (addr + XEL_RXBUFF_OFFSET), - data, length); - - /* Acknowledge the frame */ - reg_data = in_be32(addr + XEL_RSR_OFFSET); - reg_data &= ~XEL_RSR_RECV_DONE_MASK; - out_be32(addr + XEL_RSR_OFFSET, reg_data); - - return length; -} - -/** - * xemaclite_update_address - Update the MAC address in the device - * @drvdata: Pointer to the Emaclite device private data - * @address_ptr:Pointer to the MAC address (MAC address is a 48-bit value) - * - * Tx must be idle and Rx should be idle for deterministic results. - * It is recommended that this function should be called after the - * initialization and before transmission of any packets from the device. - * The MAC address can be programmed using any of the two transmit - * buffers (if configured). - */ -static void xemaclite_update_address(struct net_local *drvdata, - u8 *address_ptr) -{ - void __iomem *addr; - u32 reg_data; - - /* Determine the expected Tx buffer address */ - addr = drvdata->base_addr + drvdata->next_tx_buf_to_use; - - xemaclite_aligned_write(address_ptr, (u32 __force *) addr, ETH_ALEN); - - out_be32(addr + XEL_TPLR_OFFSET, ETH_ALEN); - - /* Update the MAC address in the EmacLite */ - reg_data = in_be32(addr + XEL_TSR_OFFSET); - out_be32(addr + XEL_TSR_OFFSET, reg_data | XEL_TSR_PROG_MAC_ADDR); - - /* Wait for EmacLite to finish with the MAC address update */ - while ((in_be32(addr + XEL_TSR_OFFSET) & - XEL_TSR_PROG_MAC_ADDR) != 0) - ; -} - -/** - * xemaclite_set_mac_address - Set the MAC address for this device - * @dev: Pointer to the network device instance - * @addr: Void pointer to the sockaddr structure - * - * This function copies the HW address from the sockaddr strucutre 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 - * successfully - */ -static int xemaclite_set_mac_address(struct net_device *dev, void *address) -{ - struct net_local *lp = netdev_priv(dev); - struct sockaddr *addr = address; - - if (netif_running(dev)) - return -EBUSY; - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - xemaclite_update_address(lp, dev->dev_addr); - return 0; -} - -/** - * xemaclite_tx_timeout - Callback for Tx Timeout - * @dev: Pointer to the network device - * - * This function is called when Tx time out occurs for Emaclite device. - */ -static void xemaclite_tx_timeout(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - unsigned long flags; - - dev_err(&lp->ndev->dev, "Exceeded transmit timeout of %lu ms\n", - TX_TIMEOUT * 1000UL / HZ); - - dev->stats.tx_errors++; - - /* Reset the device */ - spin_lock_irqsave(&lp->reset_lock, flags); - - /* Shouldn't really be necessary, but shouldn't hurt */ - netif_stop_queue(dev); - - xemaclite_disable_interrupts(lp); - xemaclite_enable_interrupts(lp); - - if (lp->deferred_skb) { - dev_kfree_skb(lp->deferred_skb); - lp->deferred_skb = NULL; - dev->stats.tx_errors++; - } - - /* To exclude tx timeout */ - dev->trans_start = jiffies; /* prevent tx timeout */ - - /* We're all ready to go. Start the queue */ - netif_wake_queue(dev); - spin_unlock_irqrestore(&lp->reset_lock, flags); -} - -/**********************/ -/* Interrupt Handlers */ -/**********************/ - -/** - * xemaclite_tx_handler - Interrupt handler for frames sent - * @dev: Pointer to the network device - * - * This function updates the number of packets transmitted and handles the - * deferred skb, if there is one. - */ -static void xemaclite_tx_handler(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - dev->stats.tx_packets++; - if (lp->deferred_skb) { - if (xemaclite_send_data(lp, - (u8 *) lp->deferred_skb->data, - lp->deferred_skb->len) != 0) - return; - else { - dev->stats.tx_bytes += lp->deferred_skb->len; - dev_kfree_skb_irq(lp->deferred_skb); - lp->deferred_skb = NULL; - dev->trans_start = jiffies; /* prevent tx timeout */ - netif_wake_queue(dev); - } - } -} - -/** - * xemaclite_rx_handler- Interrupt handler for frames received - * @dev: Pointer to the network device - * - * This function allocates memory for a socket buffer, fills it with data - * received and hands it over to the TCP/IP stack. - */ -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); - if (!skb) { - /* Couldn't get memory. */ - dev->stats.rx_dropped++; - dev_err(&lp->ndev->dev, "Could not allocate receive buffer\n"); - 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); - - len = xemaclite_recv_data(lp, (u8 *) skb->data); - - if (!len) { - dev->stats.rx_errors++; - dev_kfree_skb_irq(skb); - return; - } - - skb_put(skb, len); /* Tell the skb how much data we got */ - - skb->protocol = eth_type_trans(skb, dev); - skb_checksum_none_assert(skb); - - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; - - if (!skb_defer_rx_timestamp(skb)) - netif_rx(skb); /* Send the packet upstream */ -} - -/** - * xemaclite_interrupt - Interrupt handler for this driver - * @irq: Irq of the Emaclite device - * @dev_id: Void pointer to the network device instance used as callback - * reference - * - * This function handles the Tx and Rx interrupts of the EmacLite device. - */ -static irqreturn_t xemaclite_interrupt(int irq, void *dev_id) -{ - bool tx_complete = false; - struct net_device *dev = dev_id; - struct net_local *lp = netdev_priv(dev); - void __iomem *base_addr = lp->base_addr; - u32 tx_status; - - /* Check if there is Rx Data available */ - if ((in_be32(base_addr + XEL_RSR_OFFSET) & XEL_RSR_RECV_DONE_MASK) || - (in_be32(base_addr + XEL_BUFFER_OFFSET + XEL_RSR_OFFSET) - & XEL_RSR_RECV_DONE_MASK)) - - xemaclite_rx_handler(dev); - - /* Check if the Transmission for the first buffer is completed */ - tx_status = in_be32(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; - out_be32(base_addr + XEL_TSR_OFFSET, tx_status); - - tx_complete = true; - } - - /* Check if the Transmission for the second buffer is completed */ - tx_status = in_be32(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; - out_be32(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, - tx_status); - - tx_complete = true; - } - - /* If there was a Tx interrupt, call the Tx Handler */ - if (tx_complete != 0) - xemaclite_tx_handler(dev); - - return IRQ_HANDLED; -} - -/**********************/ -/* MDIO Bus functions */ -/**********************/ - -/** - * xemaclite_mdio_wait - Wait for the MDIO to be ready to use - * @lp: Pointer to the Emaclite device private data - * - * This function waits till the device is ready to accept a new MDIO - * request. - * - * Return: 0 for success or ETIMEDOUT for a timeout - */ - -static int xemaclite_mdio_wait(struct net_local *lp) -{ - long end = jiffies + 2; - - /* wait for the MDIO interface to not be busy or timeout - after some time. - */ - while (in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET) & - XEL_MDIOCTRL_MDIOSTS_MASK) { - if (end - jiffies <= 0) { - WARN_ON(1); - return -ETIMEDOUT; - } - msleep(1); - } - return 0; -} - -/** - * xemaclite_mdio_read - Read from a given MII management register - * @bus: the mii_bus struct - * @phy_id: the phy address - * @reg: register number to read from - * - * This function waits till the device is ready to accept a new MDIO - * request and then writes the phy address to the MDIO Address register - * and reads data from MDIO Read Data register, when its available. - * - * Return: Value read from the MII management register - */ -static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int reg) -{ - struct net_local *lp = bus->priv; - u32 ctrl_reg; - u32 rc; - - if (xemaclite_mdio_wait(lp)) - return -ETIMEDOUT; - - /* Write the PHY address, register number and set the OP bit in the - * MDIO Address register. Set the Status bit in the MDIO Control - * register to start a MDIO read transaction. - */ - ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET); - out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET, - XEL_MDIOADDR_OP_MASK | - ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg)); - out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET, - ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK); - - if (xemaclite_mdio_wait(lp)) - return -ETIMEDOUT; - - rc = in_be32(lp->base_addr + XEL_MDIORD_OFFSET); - - dev_dbg(&lp->ndev->dev, - "xemaclite_mdio_read(phy_id=%i, reg=%x) == %x\n", - phy_id, reg, rc); - - return rc; -} - -/** - * xemaclite_mdio_write - Write to a given MII management register - * @bus: the mii_bus struct - * @phy_id: the phy address - * @reg: register number to write to - * @val: value to write to the register number specified by reg - * - * This function waits till the device is ready to accept a new MDIO - * request and then writes the val to the MDIO Write Data register. - */ -static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg, - u16 val) -{ - struct net_local *lp = bus->priv; - u32 ctrl_reg; - - dev_dbg(&lp->ndev->dev, - "xemaclite_mdio_write(phy_id=%i, reg=%x, val=%x)\n", - phy_id, reg, val); - - if (xemaclite_mdio_wait(lp)) - return -ETIMEDOUT; - - /* Write the PHY address, register number and clear the OP bit in the - * MDIO Address register and then write the value into the MDIO Write - * Data register. Finally, set the Status bit in the MDIO Control - * register to start a MDIO write transaction. - */ - ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET); - out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET, - ~XEL_MDIOADDR_OP_MASK & - ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg)); - out_be32(lp->base_addr + XEL_MDIOWR_OFFSET, val); - out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET, - ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK); - - return 0; -} - -/** - * xemaclite_mdio_reset - Reset the mdio bus. - * @bus: Pointer to the MII bus - * - * This function is required(?) as per Documentation/networking/phy.txt. - * There is no reset in this device; this function always returns 0. - */ -static int xemaclite_mdio_reset(struct mii_bus *bus) -{ - return 0; -} - -/** - * xemaclite_mdio_setup - Register mii_bus for the Emaclite device - * @lp: Pointer to the Emaclite device private data - * @ofdev: Pointer to OF device structure - * - * This function enables MDIO bus in the Emaclite device and registers a - * mii_bus. - * - * Return: 0 upon success or a negative error upon failure - */ -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); - - /* Don't register the MDIO bus if the phy_node or its parent node - * can't be found. - */ - if (!np) - return -ENODEV; - - /* Enable the MDIO bus by asserting the enable bit in MDIO Control - * register. - */ - out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET, - XEL_MDIOCTRL_MDIOEN_MASK); - - bus = mdiobus_alloc(); - if (!bus) - return -ENOMEM; - - of_address_to_resource(np, 0, &res); - snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx", - (unsigned long long)res.start); - bus->priv = lp; - bus->name = "Xilinx Emaclite MDIO"; - bus->read = xemaclite_mdio_read; - bus->write = xemaclite_mdio_write; - bus->reset = xemaclite_mdio_reset; - bus->parent = dev; - bus->irq = lp->mdio_irqs; /* preallocated IRQ table */ - - lp->mii_bus = bus; - - rc = of_mdiobus_register(bus, np); - if (rc) - goto err_register; - - return 0; - -err_register: - mdiobus_free(bus); - return rc; -} - -/** - * xemaclite_adjust_link - Link state callback for the Emaclite device - * @ndev: pointer to net_device struct - * - * There's nothing in the Emaclite device to be configured when the link - * state changes. We just print the status. - */ -void xemaclite_adjust_link(struct net_device *ndev) -{ - struct net_local *lp = netdev_priv(ndev); - struct phy_device *phy = lp->phy_dev; - int link_state; - - /* hash together the state values to decide if something has changed */ - link_state = phy->speed | (phy->duplex << 1) | phy->link; - - if (lp->last_link != link_state) { - lp->last_link = link_state; - phy_print_status(phy); - } -} - -/** - * xemaclite_open - Open the network device - * @dev: Pointer to the network device - * - * This function sets the MAC address, requests an IRQ and enables interrupts - * for the Emaclite device and starts the Tx queue. - * It also connects to the phy device, if MDIO is included in Emaclite device. - */ -static int xemaclite_open(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - int retval; - - /* Just to be safe, stop the device first */ - 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); - if (!lp->phy_dev) { - dev_err(&lp->ndev->dev, "of_phy_connect() failed\n"); - return -ENODEV; - } - - /* EmacLite doesn't support giga-bit speeds */ - lp->phy_dev->supported &= (PHY_BASIC_FEATURES); - lp->phy_dev->advertising = lp->phy_dev->supported; - - /* 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); - - /* 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); - } - - /* Set the MAC address each time opened */ - xemaclite_update_address(lp, dev->dev_addr); - - /* Grab the IRQ */ - retval = request_irq(dev->irq, xemaclite_interrupt, 0, dev->name, dev); - if (retval) { - dev_err(&lp->ndev->dev, "Could not allocate interrupt %d\n", - dev->irq); - if (lp->phy_dev) - phy_disconnect(lp->phy_dev); - lp->phy_dev = NULL; - - return retval; - } - - /* Enable Interrupts */ - xemaclite_enable_interrupts(lp); - - /* We're ready to go */ - netif_start_queue(dev); - - return 0; -} - -/** - * xemaclite_close - Close the network device - * @dev: Pointer to the network device - * - * This function stops the Tx queue, disables interrupts and frees the IRQ for - * the Emaclite device. - * It also disconnects the phy device associated with the Emaclite device. - */ -static int xemaclite_close(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - netif_stop_queue(dev); - xemaclite_disable_interrupts(lp); - free_irq(dev->irq, dev); - - if (lp->phy_dev) - phy_disconnect(lp->phy_dev); - lp->phy_dev = NULL; - - return 0; -} - -/** - * xemaclite_send - Transmit a frame - * @orig_skb: Pointer to the socket buffer to be transmitted - * @dev: Pointer to the network device - * - * This function checks if the Tx buffer of the Emaclite device is free to send - * data. If so, it fills the Tx buffer with data from socket buffer data, - * updates the stats and frees the socket buffer. The Tx completion is signaled - * by an interrupt. If the Tx buffer isn't free, then the socket buffer is - * deferred and the Tx queue is stopped so that the deferred socket buffer can - * be transmitted when the Emaclite device is free to transmit data. - * - * Return: 0, always. - */ -static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - struct sk_buff *new_skb; - unsigned int len; - unsigned long flags; - - len = orig_skb->len; - - new_skb = orig_skb; - - spin_lock_irqsave(&lp->reset_lock, flags); - if (xemaclite_send_data(lp, (u8 *) new_skb->data, len) != 0) { - /* If the Emaclite Tx buffer is busy, stop the Tx queue and - * defer the skb for transmission during the ISR, after the - * current transmission is complete */ - netif_stop_queue(dev); - lp->deferred_skb = new_skb; - /* Take the time stamp now, since we can't do this in an ISR. */ - skb_tx_timestamp(new_skb); - spin_unlock_irqrestore(&lp->reset_lock, flags); - return 0; - } - spin_unlock_irqrestore(&lp->reset_lock, flags); - - skb_tx_timestamp(new_skb); - - dev->stats.tx_bytes += len; - dev_kfree_skb(new_skb); - - return 0; -} - -/** - * xemaclite_remove_ndev - Free the network device - * @ndev: Pointer to the network device to be freed - * - * This function un maps the IO region of the Emaclite device and frees the net - * device. - */ -static void xemaclite_remove_ndev(struct net_device *ndev) -{ - if (ndev) { - struct net_local *lp = netdev_priv(ndev); - - if (lp->base_addr) - iounmap((void __iomem __force *) (lp->base_addr)); - free_netdev(ndev); - } -} - -/** - * get_bool - Get a parameter from the OF device - * @ofdev: Pointer to OF device structure - * @s: Property to be retrieved - * - * This function looks for a property in the device node and returns the value - * of the property if its found or 0 if the property is not found. - * - * Return: Value of the parameter if the parameter is found, or 0 otherwise - */ -static bool get_bool(struct platform_device *ofdev, const char *s) -{ - u32 *p = (u32 *)of_get_property(ofdev->dev.of_node, s, NULL); - - if (p) { - return (bool)*p; - } else { - dev_warn(&ofdev->dev, "Parameter %s not found," - "defaulting to false\n", s); - return 0; - } -} - -static struct net_device_ops xemaclite_netdev_ops; - -/** - * xemaclite_of_probe - Probe method for the Emaclite device. - * @ofdev: Pointer to OF device structure - * @match: Pointer to the structure used for matching a device - * - * This function probes for the Emaclite device in the device tree. - * It initializes the driver data structure and the hardware, sets the MAC - * address and registers the network device. - * It also registers a mii_bus for the Emaclite device, if MDIO is included - * in the device. - * - * Return: 0, if the driver is bound to the Emaclite device, or - * a negative error if there is failure. - */ -static int __devinit xemaclite_of_probe(struct platform_device *ofdev) -{ - struct resource r_irq; /* Interrupt resources */ - struct resource r_mem; /* IO mem resources */ - struct net_device *ndev = NULL; - struct net_local *lp = NULL; - struct device *dev = &ofdev->dev; - const void *mac_address; - - int rc = 0; - - dev_info(dev, "Device Tree Probing\n"); - - /* Get iospace for the device */ - rc = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem); - if (rc) { - dev_err(dev, "invalid address\n"); - return rc; - } - - /* Get IRQ for the device */ - rc = of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq); - if (!rc) { - dev_err(dev, "no IRQ found\n"); - return rc; - } - - /* Create an ethernet device instance */ - ndev = alloc_etherdev(sizeof(struct net_local)); - if (!ndev) - return -ENOMEM; - - dev_set_drvdata(dev, ndev); - SET_NETDEV_DEV(ndev, &ofdev->dev); - - ndev->irq = r_irq.start; - ndev->mem_start = r_mem.start; - ndev->mem_end = r_mem.end; - - lp = netdev_priv(ndev); - lp->ndev = ndev; - - if (!request_mem_region(ndev->mem_start, - ndev->mem_end - ndev->mem_start + 1, - DRIVER_NAME)) { - dev_err(dev, "Couldn't lock memory region at %p\n", - (void *)ndev->mem_start); - rc = -EBUSY; - goto error2; - } - - /* Get the virtual base address for the device */ - lp->base_addr = ioremap(r_mem.start, resource_size(&r_mem)); - if (NULL == lp->base_addr) { - dev_err(dev, "EmacLite: Could not allocate iomem\n"); - rc = -EIO; - goto error1; - } - - spin_lock_init(&lp->reset_lock); - lp->next_tx_buf_to_use = 0x0; - 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 (mac_address) - /* Set the MAC address. */ - memcpy(ndev->dev_addr, mac_address, 6); - else - dev_warn(dev, "No MAC address found\n"); - - /* Clear the Tx CSR's in case this is a restart */ - out_be32(lp->base_addr + XEL_TSR_OFFSET, 0); - out_be32(lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, 0); - - /* Set the MAC address in the EmacLite device */ - xemaclite_update_address(lp, ndev->dev_addr); - - lp->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0); - rc = xemaclite_mdio_setup(lp, &ofdev->dev); - if (rc) - dev_warn(&ofdev->dev, "error registering MDIO bus\n"); - - dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr); - - ndev->netdev_ops = &xemaclite_netdev_ops; - ndev->flags &= ~IFF_MULTICAST; - ndev->watchdog_timeo = TX_TIMEOUT; - - /* Finally, register the device */ - rc = register_netdev(ndev); - if (rc) { - dev_err(dev, - "Cannot register network device, aborting\n"); - goto error1; - } - - 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); - return 0; - -error1: - release_mem_region(ndev->mem_start, resource_size(&r_mem)); - -error2: - xemaclite_remove_ndev(ndev); - return rc; -} - -/** - * xemaclite_of_remove - Unbind the driver from the Emaclite device. - * @of_dev: Pointer to OF device structure - * - * This function is called if a device is physically removed from the system or - * if the driver module is being unloaded. It frees any resources allocated to - * the device. - * - * Return: 0, always. - */ -static int __devexit xemaclite_of_remove(struct platform_device *of_dev) -{ - struct device *dev = &of_dev->dev; - struct net_device *ndev = dev_get_drvdata(dev); - - struct net_local *lp = netdev_priv(ndev); - - /* Un-register the mii_bus, if configured */ - if (lp->has_mdio) { - mdiobus_unregister(lp->mii_bus); - kfree(lp->mii_bus->irq); - mdiobus_free(lp->mii_bus); - lp->mii_bus = NULL; - } - - unregister_netdev(ndev); - - if (lp->phy_node) - of_node_put(lp->phy_node); - lp->phy_node = NULL; - - release_mem_region(ndev->mem_start, ndev->mem_end-ndev->mem_start + 1); - - xemaclite_remove_ndev(ndev); - dev_set_drvdata(dev, NULL); - - return 0; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void -xemaclite_poll_controller(struct net_device *ndev) -{ - disable_irq(ndev->irq); - xemaclite_interrupt(ndev->irq, ndev); - enable_irq(ndev->irq); -} -#endif - -static struct net_device_ops xemaclite_netdev_ops = { - .ndo_open = xemaclite_open, - .ndo_stop = xemaclite_close, - .ndo_start_xmit = xemaclite_send, - .ndo_set_mac_address = xemaclite_set_mac_address, - .ndo_tx_timeout = xemaclite_tx_timeout, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = xemaclite_poll_controller, -#endif -}; - -/* Match table for OF platform binding */ -static struct of_device_id xemaclite_of_match[] __devinitdata = { - { .compatible = "xlnx,opb-ethernetlite-1.01.a", }, - { .compatible = "xlnx,opb-ethernetlite-1.01.b", }, - { .compatible = "xlnx,xps-ethernetlite-1.00.a", }, - { .compatible = "xlnx,xps-ethernetlite-2.00.a", }, - { .compatible = "xlnx,xps-ethernetlite-2.01.a", }, - { .compatible = "xlnx,xps-ethernetlite-3.00.a", }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(of, xemaclite_of_match); - -static struct platform_driver xemaclite_of_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = xemaclite_of_match, - }, - .probe = xemaclite_of_probe, - .remove = __devexit_p(xemaclite_of_remove), -}; - -module_platform_driver(xemaclite_of_driver); - -MODULE_AUTHOR("Xilinx, Inc."); -MODULE_DESCRIPTION("Xilinx Ethernet MAC Lite driver"); -MODULE_LICENSE("GPL"); |