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