sb1250-mac.c
来自「linux 内核源代码」· C语言 代码 · 共 2,649 行 · 第 1/5 页
C
2,649 行
/* * Copyright (C) 2001,2002,2003,2004 Broadcom Corporation * Copyright (c) 2006, 2007 Maciej W. Rozycki * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * This driver is designed for the Broadcom SiByte SOC built-in * Ethernet controllers. Written by Mitch Lichtenberg at Broadcom Corp. * * Updated to the driver model and the PHY abstraction layer * by Maciej W. Rozycki. */#include <linux/bug.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/bitops.h>#include <linux/err.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/phy.h>#include <linux/platform_device.h>#include <asm/cache.h>#include <asm/io.h>#include <asm/processor.h> /* Processor type for cache alignment. *//* This is only here until the firmware is ready. In that case, the firmware leaves the ethernet address in the register for us. */#ifdef CONFIG_SIBYTE_STANDALONE#define SBMAC_ETH0_HWADDR "40:00:00:00:01:00"#define SBMAC_ETH1_HWADDR "40:00:00:00:01:01"#define SBMAC_ETH2_HWADDR "40:00:00:00:01:02"#define SBMAC_ETH3_HWADDR "40:00:00:00:01:03"#endif/* These identify the driver base version and may not be removed. */#if 0static char version1[] __initdata ="sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n";#endif/* Operational parameters that usually are not changed. */#define CONFIG_SBMAC_COALESCE/* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT (2*HZ)MODULE_AUTHOR("Mitch Lichtenberg (Broadcom Corp.)");MODULE_DESCRIPTION("Broadcom SiByte SOC GB Ethernet driver");/* A few user-configurable values which may be modified when a driver module is loaded. *//* 1 normal messages, 0 quiet .. 7 verbose. */static int debug = 1;module_param(debug, int, S_IRUGO);MODULE_PARM_DESC(debug, "Debug messages");#ifdef CONFIG_SBMAC_COALESCEstatic int int_pktcnt_tx = 255;module_param(int_pktcnt_tx, int, S_IRUGO);MODULE_PARM_DESC(int_pktcnt_tx, "TX packet count");static int int_timeout_tx = 255;module_param(int_timeout_tx, int, S_IRUGO);MODULE_PARM_DESC(int_timeout_tx, "TX timeout value");static int int_pktcnt_rx = 64;module_param(int_pktcnt_rx, int, S_IRUGO);MODULE_PARM_DESC(int_pktcnt_rx, "RX packet count");static int int_timeout_rx = 64;module_param(int_timeout_rx, int, S_IRUGO);MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");#endif#include <asm/sibyte/board.h>#include <asm/sibyte/sb1250.h>#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)#include <asm/sibyte/bcm1480_regs.h>#include <asm/sibyte/bcm1480_int.h>#define R_MAC_DMA_OODPKTLOST_RX R_MAC_DMA_OODPKTLOST#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)#include <asm/sibyte/sb1250_regs.h>#include <asm/sibyte/sb1250_int.h>#else#error invalid SiByte MAC configuation#endif#include <asm/sibyte/sb1250_scd.h>#include <asm/sibyte/sb1250_mac.h>#include <asm/sibyte/sb1250_dma.h>#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)#define UNIT_INT(n) (K_BCM1480_INT_MAC_0 + ((n) * 2))#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)#define UNIT_INT(n) (K_INT_MAC_0 + (n))#else#error invalid SiByte MAC configuation#endif#ifdef K_INT_PHY#define SBMAC_PHY_INT K_INT_PHY#else#define SBMAC_PHY_INT PHY_POLL#endif/********************************************************************** * Simple types ********************************************************************* */enum sbmac_speed { sbmac_speed_none = 0, sbmac_speed_10 = SPEED_10, sbmac_speed_100 = SPEED_100, sbmac_speed_1000 = SPEED_1000,};enum sbmac_duplex { sbmac_duplex_none = -1, sbmac_duplex_half = DUPLEX_HALF, sbmac_duplex_full = DUPLEX_FULL,};enum sbmac_fc { sbmac_fc_none, sbmac_fc_disabled, sbmac_fc_frame, sbmac_fc_collision, sbmac_fc_carrier,};enum sbmac_state { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, sbmac_state_broken,};/********************************************************************** * Macros ********************************************************************* */#define SBDMA_NEXTBUF(d,f) ((((d)->f+1) == (d)->sbdma_dscrtable_end) ? \ (d)->sbdma_dscrtable : (d)->f+1)#define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)#define SBMAC_MAX_TXDESCR 256#define SBMAC_MAX_RXDESCR 256#define ETHER_ALIGN 2#define ETHER_ADDR_LEN 6#define ENET_PACKET_SIZE 1518/*#define ENET_PACKET_SIZE 9216 *//********************************************************************** * DMA Descriptor structure ********************************************************************* */struct sbdmadscr { uint64_t dscr_a; uint64_t dscr_b;};/********************************************************************** * DMA Controller structure ********************************************************************* */struct sbmacdma { /* * This stuff is used to identify the channel and the registers * associated with it. */ struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ int sbdma_channel; /* channel number */ int sbdma_txdir; /* direction (1=transmit) */ int sbdma_maxdescr; /* total # of descriptors in ring */#ifdef CONFIG_SBMAC_COALESCE int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt */ int sbdma_int_timeout; /* # usec rx/tx interrupt */#endif void __iomem *sbdma_config0; /* DMA config register 0 */ void __iomem *sbdma_config1; /* DMA config register 1 */ void __iomem *sbdma_dscrbase; /* descriptor base address */ void __iomem *sbdma_dscrcnt; /* descriptor count register */ void __iomem *sbdma_curdscr; /* current descriptor address */ void __iomem *sbdma_oodpktlost; /* pkt drop (rx only) */ /* * This stuff is for maintenance of the ring */ void *sbdma_dscrtable_unaligned; struct sbdmadscr *sbdma_dscrtable; /* base of descriptor table */ struct sbdmadscr *sbdma_dscrtable_end; /* end of descriptor table */ struct sk_buff **sbdma_ctxtable; /* context table, one per descr */ dma_addr_t sbdma_dscrtable_phys; /* and also the phys addr */ struct sbdmadscr *sbdma_addptr; /* next dscr for sw to add */ struct sbdmadscr *sbdma_remptr; /* next dscr for sw to remove */};/********************************************************************** * Ethernet softc structure ********************************************************************* */struct sbmac_softc { /* * Linux-specific things */ struct net_device *sbm_dev; /* pointer to linux device */ struct napi_struct napi; struct phy_device *phy_dev; /* the associated PHY device */ struct mii_bus mii_bus; /* the MII bus */ int phy_irq[PHY_MAX_ADDR]; spinlock_t sbm_lock; /* spin lock */ int sbm_devflags; /* current device flags */ int sbm_buffersize; /* * Controller-specific things */ void __iomem *sbm_base; /* MAC's base address */ enum sbmac_state sbm_state; /* current state */ void __iomem *sbm_macenable; /* MAC Enable Register */ void __iomem *sbm_maccfg; /* MAC Config Register */ void __iomem *sbm_fifocfg; /* FIFO Config Register */ void __iomem *sbm_framecfg; /* Frame Config Register */ void __iomem *sbm_rxfilter; /* Receive Filter Register */ void __iomem *sbm_isr; /* Interrupt Status Register */ void __iomem *sbm_imr; /* Interrupt Mask Register */ void __iomem *sbm_mdio; /* MDIO Register */ enum sbmac_speed sbm_speed; /* current speed */ enum sbmac_duplex sbm_duplex; /* current duplex */ enum sbmac_fc sbm_fc; /* cur. flow control setting */ int sbm_pause; /* current pause setting */ int sbm_link; /* current link state */ unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; struct sbmacdma sbm_txdma; /* only channel 0 for now */ struct sbmacdma sbm_rxdma; int rx_hw_checksum; int sbe_idx;};/********************************************************************** * Externs ********************************************************************* *//********************************************************************** * Prototypes ********************************************************************* */static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan, int txrx, int maxdescr);static void sbdma_channel_start(struct sbmacdma *d, int rxtx);static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *m);static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *m);static void sbdma_emptyring(struct sbmacdma *d);static void sbdma_fillring(struct sbmacdma *d);static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d, int work_to_do, int poll);static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d, int poll);static int sbmac_initctx(struct sbmac_softc *s);static void sbmac_channel_start(struct sbmac_softc *s);static void sbmac_channel_stop(struct sbmac_softc *s);static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *, enum sbmac_state);static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff);static uint64_t sbmac_addr2reg(unsigned char *ptr);static irqreturn_t sbmac_intr(int irq, void *dev_instance);static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);static void sbmac_setmulti(struct sbmac_softc *sc);static int sbmac_init(struct platform_device *pldev, long long base);static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed);static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, enum sbmac_fc fc);static int sbmac_open(struct net_device *dev);static void sbmac_tx_timeout (struct net_device *dev);static void sbmac_set_rx_mode(struct net_device *dev);static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int sbmac_close(struct net_device *dev);static int sbmac_poll(struct napi_struct *napi, int budget);static void sbmac_mii_poll(struct net_device *dev);static int sbmac_mii_probe(struct net_device *dev);static void sbmac_mii_sync(void __iomem *sbm_mdio);static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data, int bitcnt);static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx);static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx, u16 val);/********************************************************************** * Globals ********************************************************************* */static char sbmac_string[] = "sb1250-mac";static char sbmac_pretty[] = "SB1250 MAC";static char sbmac_mdio_string[] = "sb1250-mac-mdio";/********************************************************************** * MDIO constants ********************************************************************* */#define MII_COMMAND_START 0x01#define MII_COMMAND_READ 0x02#define MII_COMMAND_WRITE 0x01#define MII_COMMAND_ACK 0x02#define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */#define ENABLE 1#define DISABLE 0/********************************************************************** * SBMAC_MII_SYNC(sbm_mdio) * * Synchronize with the MII - send a pattern of bits to the MII * that will guarantee that it is ready to accept a command. * * Input parameters: * sbm_mdio - address of the MAC's MDIO register * * Return value: * nothing ********************************************************************* */static void sbmac_mii_sync(void __iomem *sbm_mdio){ int cnt; uint64_t bits; int mac_mdio_genc; mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; __raw_writeq(bits | mac_mdio_genc, sbm_mdio); for (cnt = 0; cnt < 32; cnt++) { __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio); __raw_writeq(bits | mac_mdio_genc, sbm_mdio); }}/********************************************************************** * SBMAC_MII_SENDDATA(sbm_mdio, data, bitcnt) * * Send some bits to the MII. The bits to be sent are right- * justified in the 'data' parameter. * * Input parameters: * sbm_mdio - address of the MAC's MDIO register * data - data to send * bitcnt - number of bits to send ********************************************************************* */static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data, int bitcnt){ int i; uint64_t bits; unsigned int curmask; int mac_mdio_genc; mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT; __raw_writeq(bits | mac_mdio_genc, sbm_mdio); curmask = 1 << (bitcnt - 1); for (i = 0; i < bitcnt; i++) { if (data & curmask) bits |= M_MAC_MDIO_OUT; else bits &= ~M_MAC_MDIO_OUT; __raw_writeq(bits | mac_mdio_genc, sbm_mdio); __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio); __raw_writeq(bits | mac_mdio_genc, sbm_mdio); curmask >>= 1; }}/********************************************************************** * SBMAC_MII_READ(bus, phyaddr, regidx) * Read a PHY register. * * Input parameters: * bus - MDIO bus handle * phyaddr - PHY's address * regnum - index of register to read * * Return value: * value read, or 0xffff if an error occurred. ********************************************************************* */static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx){ struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv; void __iomem *sbm_mdio = sc->sbm_mdio; int idx; int error; int regval; int mac_mdio_genc; /* * Synchronize ourselves so that the PHY knows the next * thing coming down is a command */ sbmac_mii_sync(sbm_mdio); /* * Send the data to the PHY. The sequence is * a "start" command (2 bits) * a "read" command (2 bits) * the PHY addr (5 bits) * the register index (5 bits) */ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2); sbmac_mii_senddata(sbm_mdio, MII_COMMAND_READ, 2); sbmac_mii_senddata(sbm_mdio, phyaddr, 5); sbmac_mii_senddata(sbm_mdio, regidx, 5); mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; /* * Switch the port around without a clock transition. */ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); /* * Send out a clock pulse to signal we want the status */ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, sbm_mdio); __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); /* * If an error occurred, the PHY will signal '1' back */ error = __raw_readq(sbm_mdio) & M_MAC_MDIO_IN; /* * Issue an 'idle' clock pulse, but keep the direction * the same. */ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, sbm_mdio); __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); regval = 0; for (idx = 0; idx < 16; idx++) { regval <<= 1; if (error == 0) { if (__raw_readq(sbm_mdio) & M_MAC_MDIO_IN) regval |= 1; } __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, sbm_mdio); __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); } /* Switch back to output */ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio); if (error == 0) return regval;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?