ioc3-eth.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,595 行 · 第 1/3 页

C
1,595
字号
/* * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card. * * Copyright (C) 1999, 2000, 2001, 2003 Ralf Baechle * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc. * * References: *  o IOC3 ASIC specification 4.51, 1996-04-18 *  o IEEE 802.3 specification, 2000 edition *  o DP38840A Specification, National Semiconductor, March 1997 * * To do: * *  o Handle allocation failures in ioc3_alloc_skb() more gracefully. *  o Handle allocation failures in ioc3_init_rings(). *  o Use prefetching for large packets.  What is a good lower limit for *    prefetching? *  o We're probably allocating a bit too much memory. *  o Use hardware checksums. *  o Convert to using a IOC3 meta driver. *  o Which PHYs might possibly be attached to the IOC3 in real live, *    which workarounds are required for them?  Do we ever have Lucent's? *  o For the 2.5 branch kill the mii-tool ioctls. */#define IOC3_NAME	"ioc3-eth"#define IOC3_VERSION	"2.6.3-3"#include <linux/config.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/crc32.h>#include <linux/mii.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/udp.h>#ifdef CONFIG_SERIAL_8250#include <linux/serial.h>#include <asm/serial.h>#define IOC3_BAUD (22000000 / (3*16))#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)#endif#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <linux/skbuff.h>#include <linux/dp83840.h>#include <net/ip.h>#include <asm/byteorder.h>#include <asm/checksum.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/uaccess.h>#include <asm/sn/types.h>#include <asm/sn/sn0/addrs.h>#include <asm/sn/sn0/hubni.h>#include <asm/sn/sn0/hubio.h>#include <asm/sn/klconfig.h>#include <asm/sn/ioc3.h>#include <asm/sn/sn0/ip27.h>#include <asm/pci/bridge.h>/* * 64 RX buffers.  This is tunable in the range of 16 <= x < 512.  The * value must be a power of two. */#define RX_BUFFS 64#define ETCSR_FD	((17<<ETCSR_IPGR2_SHIFT) | (11<<ETCSR_IPGR1_SHIFT) | 21)#define ETCSR_HD	((21<<ETCSR_IPGR2_SHIFT) | (21<<ETCSR_IPGR1_SHIFT) | 21)/* Private per NIC data of the driver.  */struct ioc3_private {	struct ioc3 *regs;	unsigned long *rxr;		/* pointer to receiver ring */	struct ioc3_etxd *txr;	struct sk_buff *rx_skbs[512];	struct sk_buff *tx_skbs[128];	struct net_device_stats stats;	int rx_ci;			/* RX consumer index */	int rx_pi;			/* RX producer index */	int tx_ci;			/* TX consumer index */	int tx_pi;			/* TX producer index */	int txqlen;	u32 emcr, ehar_h, ehar_l;	spinlock_t ioc3_lock;	struct mii_if_info mii;	struct pci_dev *pdev;	/* Members used by autonegotiation  */	struct timer_list ioc3_timer;};static inline struct net_device *priv_netdev(struct ioc3_private *dev){	return (void *)dev - ((sizeof(struct net_device) + 31) & ~31);}static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static void ioc3_set_multicast_list(struct net_device *dev);static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev);static void ioc3_timeout(struct net_device *dev);static inline unsigned int ioc3_hash(const unsigned char *addr);static inline void ioc3_stop(struct ioc3_private *ip);static void ioc3_init(struct net_device *dev);static const char ioc3_str[] = "IOC3 Ethernet";static struct ethtool_ops ioc3_ethtool_ops;/* We use this to acquire receive skb's that we can DMA directly into. */#define IOC3_CACHELINE	128ULstatic inline unsigned long aligned_rx_skb_addr(unsigned long addr){	return (~addr + 1) & (IOC3_CACHELINE - 1UL);}static inline struct sk_buff * ioc3_alloc_skb(unsigned long length,	unsigned int gfp_mask){	struct sk_buff *skb;	skb = alloc_skb(length + IOC3_CACHELINE - 1, gfp_mask);	if (likely(skb)) {		int offset = aligned_rx_skb_addr((unsigned long) skb->data);		if (offset)			skb_reserve(skb, offset);	}	return skb;}static inline unsigned long ioc3_map(void *ptr, unsigned long vdev){#ifdef CONFIG_SGI_IP27	vdev <<= 58;   /* Shift to PCI64_ATTR_VIRTUAL */	return vdev | (0xaUL << PCI64_ATTR_TARG_SHFT) | PCI64_ATTR_PREF |	       ((unsigned long)ptr & TO_PHYS_MASK);#else	return virt_to_bus(ptr);#endif}/* BEWARE: The IOC3 documentation documents the size of rx buffers as   1644 while it's actually 1664.  This one was nasty to track down ...  */#define RX_OFFSET		10#define RX_BUF_ALLOC_SIZE	(1664 + RX_OFFSET + IOC3_CACHELINE)/* DMA barrier to separate cached and uncached accesses.  */#define BARRIER()							\	__asm__("sync" ::: "memory")#define IOC3_SIZE 0x100000/* * IOC3 is a big endian device * * Unorthodox but makes the users of these macros more readable - the pointer * to the IOC3's memory mapped registers is expected as struct ioc3 * ioc3 * in the environment. */#define ioc3_r_mcr()		be32_to_cpu(ioc3->mcr)#define ioc3_w_mcr(v)		do { ioc3->mcr = cpu_to_be32(v); } while (0)#define ioc3_w_gpcr_s(v)	do { ioc3->gpcr_s = cpu_to_be32(v); } while (0)#define ioc3_r_emcr()		be32_to_cpu(ioc3->emcr)#define ioc3_w_emcr(v)		do { ioc3->emcr = cpu_to_be32(v); } while (0)#define ioc3_r_eisr()		be32_to_cpu(ioc3->eisr)#define ioc3_w_eisr(v)		do { ioc3->eisr = cpu_to_be32(v); } while (0)#define ioc3_r_eier()		be32_to_cpu(ioc3->eier)#define ioc3_w_eier(v)		do { ioc3->eier = cpu_to_be32(v); } while (0)#define ioc3_r_ercsr()		be32_to_cpu(ioc3->ercsr)#define ioc3_w_ercsr(v)		do { ioc3->ercsr = cpu_to_be32(v); } while (0)#define ioc3_r_erbr_h()		be32_to_cpu(ioc3->erbr_h)#define ioc3_w_erbr_h(v)	do { ioc3->erbr_h = cpu_to_be32(v); } while (0)#define ioc3_r_erbr_l()		be32_to_cpu(ioc3->erbr_l)#define ioc3_w_erbr_l(v)	do { ioc3->erbr_l = cpu_to_be32(v); } while (0)#define ioc3_r_erbar()		be32_to_cpu(ioc3->erbar)#define ioc3_w_erbar(v)		do { ioc3->erbar = cpu_to_be32(v); } while (0)#define ioc3_r_ercir()		be32_to_cpu(ioc3->ercir)#define ioc3_w_ercir(v)		do { ioc3->ercir = cpu_to_be32(v); } while (0)#define ioc3_r_erpir()		be32_to_cpu(ioc3->erpir)#define ioc3_w_erpir(v)		do { ioc3->erpir = cpu_to_be32(v); } while (0)#define ioc3_r_ertr()		be32_to_cpu(ioc3->ertr)#define ioc3_w_ertr(v)		do { ioc3->ertr = cpu_to_be32(v); } while (0)#define ioc3_r_etcsr()		be32_to_cpu(ioc3->etcsr)#define ioc3_w_etcsr(v)		do { ioc3->etcsr = cpu_to_be32(v); } while (0)#define ioc3_r_ersr()		be32_to_cpu(ioc3->ersr)#define ioc3_w_ersr(v)		do { ioc3->ersr = cpu_to_be32(v); } while (0)#define ioc3_r_etcdc()		be32_to_cpu(ioc3->etcdc)#define ioc3_w_etcdc(v)		do { ioc3->etcdc = cpu_to_be32(v); } while (0)#define ioc3_r_ebir()		be32_to_cpu(ioc3->ebir)#define ioc3_w_ebir(v)		do { ioc3->ebir = cpu_to_be32(v); } while (0)#define ioc3_r_etbr_h()		be32_to_cpu(ioc3->etbr_h)#define ioc3_w_etbr_h(v)	do { ioc3->etbr_h = cpu_to_be32(v); } while (0)#define ioc3_r_etbr_l()		be32_to_cpu(ioc3->etbr_l)#define ioc3_w_etbr_l(v)	do { ioc3->etbr_l = cpu_to_be32(v); } while (0)#define ioc3_r_etcir()		be32_to_cpu(ioc3->etcir)#define ioc3_w_etcir(v)		do { ioc3->etcir = cpu_to_be32(v); } while (0)#define ioc3_r_etpir()		be32_to_cpu(ioc3->etpir)#define ioc3_w_etpir(v)		do { ioc3->etpir = cpu_to_be32(v); } while (0)#define ioc3_r_emar_h()		be32_to_cpu(ioc3->emar_h)#define ioc3_w_emar_h(v)	do { ioc3->emar_h = cpu_to_be32(v); } while (0)#define ioc3_r_emar_l()		be32_to_cpu(ioc3->emar_l)#define ioc3_w_emar_l(v)	do { ioc3->emar_l = cpu_to_be32(v); } while (0)#define ioc3_r_ehar_h()		be32_to_cpu(ioc3->ehar_h)#define ioc3_w_ehar_h(v)	do { ioc3->ehar_h = cpu_to_be32(v); } while (0)#define ioc3_r_ehar_l()		be32_to_cpu(ioc3->ehar_l)#define ioc3_w_ehar_l(v)	do { ioc3->ehar_l = cpu_to_be32(v); } while (0)#define ioc3_r_micr()		be32_to_cpu(ioc3->micr)#define ioc3_w_micr(v)		do { ioc3->micr = cpu_to_be32(v); } while (0)#define ioc3_r_midr_r()		be32_to_cpu(ioc3->midr_r)#define ioc3_w_midr_r(v)	do { ioc3->midr_r = cpu_to_be32(v); } while (0)#define ioc3_r_midr_w()		be32_to_cpu(ioc3->midr_w)#define ioc3_w_midr_w(v)	do { ioc3->midr_w = cpu_to_be32(v); } while (0)static inline u32 mcr_pack(u32 pulse, u32 sample){	return (pulse << 10) | (sample << 2);}static int nic_wait(struct ioc3 *ioc3){	u32 mcr;        do {                mcr = ioc3_r_mcr();        } while (!(mcr & 2));        return mcr & 1;}static int nic_reset(struct ioc3 *ioc3){        int presence;	ioc3_w_mcr(mcr_pack(500, 65));	presence = nic_wait(ioc3);	ioc3_w_mcr(mcr_pack(0, 500));	nic_wait(ioc3);        return presence;}static inline int nic_read_bit(struct ioc3 *ioc3){	int result;	ioc3_w_mcr(mcr_pack(6, 13));	result = nic_wait(ioc3);	ioc3_w_mcr(mcr_pack(0, 100));	nic_wait(ioc3);	return result;}static inline void nic_write_bit(struct ioc3 *ioc3, int bit){	if (bit)		ioc3_w_mcr(mcr_pack(6, 110));	else		ioc3_w_mcr(mcr_pack(80, 30));	nic_wait(ioc3);}/* * Read a byte from an iButton device */static u32 nic_read_byte(struct ioc3 *ioc3){	u32 result = 0;	int i;	for (i = 0; i < 8; i++)		result = (result >> 1) | (nic_read_bit(ioc3) << 7);	return result;}/* * Write a byte to an iButton device */static void nic_write_byte(struct ioc3 *ioc3, int byte){	int i, bit;	for (i = 8; i; i--) {		bit = byte & 1;		byte >>= 1;		nic_write_bit(ioc3, bit);	}}static u64 nic_find(struct ioc3 *ioc3, int *last){	int a, b, index, disc;	u64 address = 0;	nic_reset(ioc3);	/* Search ROM.  */	nic_write_byte(ioc3, 0xf0);	/* Algorithm from ``Book of iButton Standards''.  */	for (index = 0, disc = 0; index < 64; index++) {		a = nic_read_bit(ioc3);		b = nic_read_bit(ioc3);		if (a && b) {			printk("NIC search failed (not fatal).\n");			*last = 0;			return 0;		}		if (!a && !b) {			if (index == *last) {				address |= 1UL << index;			} else if (index > *last) {				address &= ~(1UL << index);				disc = index;			} else if ((address & (1UL << index)) == 0)				disc = index;			nic_write_bit(ioc3, address & (1UL << index));			continue;		} else {			if (a)				address |= 1UL << index;			else				address &= ~(1UL << index);			nic_write_bit(ioc3, a);			continue;		}	}	*last = disc;	return address;}static int nic_init(struct ioc3 *ioc3){	const char *type;	u8 crc;	u8 serial[6];	int save = 0, i;	type = "unknown";	while (1) {		u64 reg;		reg = nic_find(ioc3, &save);		switch (reg & 0xff) {		case 0x91:			type = "DS1981U";			break;		default:			if (save == 0) {				/* Let the caller try again.  */				return -1;			}			continue;		}		nic_reset(ioc3);		/* Match ROM.  */		nic_write_byte(ioc3, 0x55);		for (i = 0; i < 8; i++)			nic_write_byte(ioc3, (reg >> (i << 3)) & 0xff);		reg >>= 8; /* Shift out type.  */		for (i = 0; i < 6; i++) {			serial[i] = reg & 0xff;			reg >>= 8;		}		crc = reg & 0xff;		break;	}	printk("Found %s NIC", type);	if (type != "unknown") {		printk (" registration number %02x:%02x:%02x:%02x:%02x:%02x,"			" CRC %02x", serial[0], serial[1], serial[2],			serial[3], serial[4], serial[5], crc);	}	printk(".\n");	return 0;}/* * Read the NIC (Number-In-a-Can) device used to store the MAC address on * SN0 / SN00 nodeboards and PCI cards. */static void ioc3_get_eaddr_nic(struct ioc3_private *ip){	struct ioc3 *ioc3 = ip->regs;	u8 nic[14];	int tries = 2; /* There may be some problem with the battery?  */	int i;	ioc3_w_gpcr_s(1 << 21);	while (tries--) {		if (!nic_init(ioc3))			break;		udelay(500);	}	if (tries < 0) {		printk("Failed to read MAC address\n");		return;	}	/* Read Memory.  */	nic_write_byte(ioc3, 0xf0);	nic_write_byte(ioc3, 0x00);	nic_write_byte(ioc3, 0x00);	for (i = 13; i >= 0; i--)		nic[i] = nic_read_byte(ioc3);	for (i = 2; i < 8; i++)		priv_netdev(ip)->dev_addr[i - 2] = nic[i];}/* * Ok, this is hosed by design.  It's necessary to know what machine the * NIC is in in order to know how to read the NIC address.  We also have * to know if it's a PCI card or a NIC in on the node board ... */static void ioc3_get_eaddr(struct ioc3_private *ip){	int i;	ioc3_get_eaddr_nic(ip);	printk("Ethernet address is ");	for (i = 0; i < 6; i++) {		printk("%02x", priv_netdev(ip)->dev_addr[i]);		if (i < 5)			printk(":");	}	printk(".\n");}/* * Caller must hold the ioc3_lock ever for MII readers.  This is also * used to protect the transmitter side but it's low contention. */static int ioc3_mdio_read(struct net_device *dev, int phy, int reg){	struct ioc3_private *ip = netdev_priv(dev);	struct ioc3 *ioc3 = ip->regs;	while (ioc3_r_micr() & MICR_BUSY);	ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG);	while (ioc3_r_micr() & MICR_BUSY);	return ioc3_r_micr() & MIDR_DATA_MASK;}static void ioc3_mdio_write(struct net_device *dev, int phy, int reg, int data){	struct ioc3_private *ip = netdev_priv(dev);	struct ioc3 *ioc3 = ip->regs;	while (ioc3_r_micr() & MICR_BUSY);	ioc3_w_midr_w(data);	ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg);	while (ioc3_r_micr() & MICR_BUSY);}static int ioc3_mii_init(struct ioc3_private *ip);static struct net_device_stats *ioc3_get_stats(struct net_device *dev){	struct ioc3_private *ip = netdev_priv(dev);	struct ioc3 *ioc3 = ip->regs;	ip->stats.collisions += (ioc3_r_etcdc() & ETCDC_COLLCNT_MASK);	return &ip->stats;}#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUMstatic void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len){	struct ethhdr *eh = eth_hdr(skb);	uint32_t csum, ehsum;	unsigned int proto;	struct iphdr *ih;	uint16_t *ew;	unsigned char *cp;	/*	 * Did hardware handle the checksum at all?  The cases we can handle	 * are:	 *	 * - TCP and UDP checksums of IPv4 only.	 * - IPv6 would be doable but we keep that for later ...	 * - Only unfragmented packets.  Did somebody already tell you	 *   fragmentation is evil?	 * - don't care about packet size.  Worst case when processing a	 *   malformed packet we'll try to access the packet at ip header +	 *   64 bytes which is still inside the skb.  Even in the unlikely	 *   case where the checksum is right the higher layers will still	 *   drop the packet as appropriate.	 */	if (eh->h_proto != ntohs(ETH_P_IP))		return;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?