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 + -
显示快捷键?