📄 natsemi.c
字号:
struct netdev_desc rx_ring[RX_RING_SIZE]; struct netdev_desc tx_ring[TX_RING_SIZE]; struct net_device *next_module; /* Link for devices of this type. */ void *priv_addr; /* Unaligned address for kfree */ const char *product_name; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for later free(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ int msg_level; int chip_id, drv_flags; struct pci_dev *pci_dev; long in_interrupt; /* Word-long for SMP locks. */ int max_interrupt_work; int intr_enable; unsigned int restore_intr_enable:1; /* Set if temporarily masked. */ unsigned int rx_q_empty:1; /* Set out-of-skbuffs. */ struct netdev_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ int rx_copybreak; unsigned int cur_tx, dirty_tx; unsigned int tx_full:1; /* The Tx queue is full. */ /* These values keep track of the transceiver/media in use. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; unsigned int medialock:1; /* Do not sense media. */ unsigned int default_port; /* Last dev->if_port value. */ /* Rx filter. */ u32 cur_rx_mode; u16 rx_filter[32]; int multicast_filter_limit; /* FIFO and PCI burst thresholds. */ int tx_config, rx_config; /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */};static int eeprom_read(long ioaddr, int location);static int mdio_read(struct net_device *dev, int phy_id, int location);static void mdio_write(struct net_device *dev, int phy_id, int location, int value);static int netdev_open(struct net_device *dev);static void check_duplex(struct net_device *dev);static void netdev_timer(unsigned long data);static void tx_timeout(struct net_device *dev);static int rx_ring_fill(struct net_device *dev);static void init_ring(struct net_device *dev);static int start_tx(struct sk_buff *skb, struct net_device *dev);static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);static void netdev_error(struct net_device *dev, int intr_status);static int netdev_rx(struct net_device *dev);static void netdev_error(struct net_device *dev, int intr_status);static void set_rx_mode(struct net_device *dev);static struct net_device_stats *get_stats(struct net_device *dev);static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int netdev_close(struct net_device *dev);/* A list of our installed devices, for removing the driver module. */static struct net_device *root_net_dev = NULL;#ifndef MODULEint natsemi_probe(struct net_device *dev){ if (pci_drv_register(&natsemi_drv_id, dev) < 0) return -ENODEV; printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); return 0;}#endifstatic void *natsemi_probe1(struct pci_dev *pdev, void *init_dev, long ioaddr, int irq, int chip_idx, int card_idx){ struct net_device *dev; struct netdev_private *np; void *priv_mem; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; int prev_eedata; dev = init_etherdev(init_dev, 0); if (!dev) return NULL; /* Perhaps NETIF_MSG_PROBE */ printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr); /* Work around the dropped serial bit. */ prev_eedata = eeprom_read(ioaddr, 6); for (i = 0; i < 3; i++) { int eedata = eeprom_read(ioaddr, i + 7); dev->dev_addr[i*2] = (eedata << 1) + (prev_eedata >> 15); dev->dev_addr[i*2+1] = eedata >> 7; prev_eedata = eedata; } for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); /* Reset the chip to erase previous misconfiguration. */ writel(ChipReset, ioaddr + ChipCmd); /* Make certain elements e.g. descriptor lists are aligned. */ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL); /* Check for the very unlikely case of no memory. */ if (priv_mem == NULL) return NULL; dev->base_addr = ioaddr; dev->irq = irq; dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN); memset(np, 0, sizeof(*np)); np->priv_addr = priv_mem; np->next_module = root_net_dev; root_net_dev = dev; np->pci_dev = pdev; np->chip_id = chip_idx; np->drv_flags = pci_id_tbl[chip_idx].drv_flags; np->msg_level = (1 << debug) - 1; np->rx_copybreak = rx_copybreak; np->max_interrupt_work = max_interrupt_work; np->multicast_filter_limit = multicast_filter_limit; if (dev->mem_start) option = dev->mem_start; /* 0x10/0x20/0x100/0x200 set forced speed&duplex modes. */ if (option > 0) { if (option & 0x220) np->full_duplex = 1; np->default_port = option & 0x3ff; if (np->default_port & 0x330) { np->medialock = 1; if (np->msg_level & NETIF_MSG_PROBE) printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", (option & 0x300 ? 100 : 10), (np->full_duplex ? "full" : "half")); writew(((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */ (np->full_duplex ? 0x0100 : 0), /* Full duplex? */ ioaddr + NS_MII_BMCR); } } if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) np->full_duplex = 1; if (np->full_duplex) { if (np->msg_level & NETIF_MSG_PROBE) printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation" " disabled.\n", dev->name); np->duplex_lock = 1; } /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; dev->hard_start_xmit = &start_tx; dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; /* Override the PME enable from the EEPROM. */ writel(0x8000, ioaddr + ClkRunCtrl); if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) { u32 chip_config = readl(ioaddr + ChipConfig); if (np->msg_level & NETIF_MSG_PROBE) printk(KERN_INFO "%s: Transceiver default autonegotiation %s " "10%s %s duplex.\n", dev->name, chip_config & 0x2000 ? "enabled, advertise" : "disabled, force", chip_config & 0x4000 ? "0" : "", chip_config & 0x8000 ? "full" : "half"); } if (np->msg_level & NETIF_MSG_PROBE) printk(KERN_INFO "%s: Transceiver status 0x%4.4x partner %4.4x.\n", dev->name, (int)readl(ioaddr + NS_MII_BMSR), (int)readl(ioaddr + NS_MIILinkPartner)); return dev;}/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. Update to the code in other drivers for 8/10 bit addresses.*//* Delay between EEPROM clock transitions. This "delay" forces out buffered PCI writes, which is sufficient to meet the timing requirements of most EEPROMs.*/#define eeprom_delay(ee_addr) readl(ee_addr)enum EEPROM_Ctrl_Bits { EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02,};#define EE_Write0 (EE_ChipSelect)#define EE_Write1 (EE_ChipSelect | EE_DataIn)/* The EEPROM commands include the preamble. */enum EEPROM_Cmds { EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),};static int eeprom_read(long addr, int location){ int i; int retval = 0; long ee_addr = addr + EECtrl; int read_cmd = location | EE_ReadCmd; writel(EE_Write0, ee_addr); /* Shift the read command bits out. */ for (i = 10; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; writel(dataval, ee_addr); eeprom_delay(ee_addr); writel(dataval | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); } writel(EE_ChipSelect, ee_addr); eeprom_delay(ee_addr); for (i = 0; i < 16; i++) { writel(EE_ChipSelect | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval |= (readl(ee_addr) & EE_DataOut) ? 1 << i : 0; writel(EE_ChipSelect, ee_addr); eeprom_delay(ee_addr); } /* Terminate the EEPROM access. */ writel(EE_Write0, ee_addr); writel(0, ee_addr); return retval;}/* MII transceiver control section. The 83815 series has an internal, directly accessable transceiver. We present the management registers as if they were MII connected. */static int mdio_read(struct net_device *dev, int phy_id, int location){ if (phy_id == 1 && location < 32) return readw(dev->base_addr + NS_Xcvr_Mgmt + (location<<2)); else return 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){ if (phy_id == 1 && location < 32) writew(value, dev->base_addr + NS_Xcvr_Mgmt + (location<<2));}static int netdev_open(struct net_device *dev){ struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int i; /* We do not need to reset the '815 chip. */ MOD_INC_USE_COUNT; if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { MOD_DEC_USE_COUNT; return -EAGAIN; } if (np->msg_level & NETIF_MSG_IFUP) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); init_ring(dev); writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); for (i = 0; i < 6; i += 2) { writel(i, ioaddr + RxFilterAddr); writel(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8), ioaddr + RxFilterData); } /* Initialize other registers. */ /* See the datasheet for this correction. */ if (readl(ioaddr + ChipRevReg) == 0x0203) { writew(0x0001, ioaddr + 0xCC); writew(0x189C, ioaddr + 0xE4); writew(0x0000, ioaddr + 0xFC); writew(0x5040, ioaddr + 0xF4); writew(0x008C, ioaddr + 0xF8); } /* Configure the PCI bus bursts and FIFO thresholds. */ /* Configure for standard, in-spec Ethernet. */ if (readl(ioaddr + ChipConfig) & CfgFDX) { /* Full duplex */ np->tx_config = 0xD0801002; np->rx_config = 0x10000020; } else { np->tx_config = 0x10801002; np->rx_config = 0x0020; } if (dev->mtu > 1500) np->rx_config |= 0x08000000; writel(np->tx_config, ioaddr + TxConfig); writel(np->rx_config, ioaddr + RxConfig); if (dev->if_port == 0) dev->if_port = np->default_port; np->in_interrupt = 0; check_duplex(dev); set_rx_mode(dev); netif_start_tx_queue(dev); /* Enable interrupts by setting the interrupt mask. */ np->intr_enable = IntrNormalSummary | IntrAbnormalSummary | 0x1f; writel(np->intr_enable, ioaddr + IntrMask); writel(1, ioaddr + IntrEnable); writel(RxOn | TxOn, ioaddr + ChipCmd); writel(4, ioaddr + StatsCtrl); /* Clear Stats */ if (np->msg_level & NETIF_MSG_IFUP) printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n", dev->name, (int)readl(ioaddr + ChipCmd)); /* Set the timer to check for link beat. */ init_timer(&np->timer); np->timer.expires = jiffies + 3*HZ; np->timer.data = (unsigned long)dev; np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); return 0;}static void check_duplex(struct net_device *dev){ struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int duplex; if (np->duplex_lock) return; duplex = readl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0; if (np->full_duplex != duplex) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -