📄 natsemi.c
字号:
printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, natsemi_pci_info[chip_idx].name, ioaddr); for (i = 0; i < ETH_ALEN/2; i++) { /* weird organization */ unsigned short a; a = (le16_to_cpu(eeprom_read(ioaddr, i + 6)) >> 15) + (le16_to_cpu(eeprom_read(ioaddr, i + 7)) << 1); ((u16 *)dev->dev_addr)[i] = a; } for (i = 0; i < ETH_ALEN-1; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);#if ! defined(final_version) /* Dump the EEPROM contents during development. */ if (debug > 4) for (i = 0; i < 64; i++) printk("%4.4x%s", eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n");#endif /* Reset the chip to erase previous misconfiguration. */ writel(ChipReset, ioaddr + ChipCmd); dev->base_addr = ioaddr; dev->irq = irq; np = dev->priv; np->pci_dev = pdev; pdev->driver_data = dev; np->iosize = iosize; spin_lock_init(&np->lock); if (dev->mem_start) option = dev->mem_start; /* The lower four bits are the media type. */ if (option > 0) { if (option & 0x200) np->full_duplex = 1; np->default_port = option & 15; if (np->default_port) np->medialock = 1; } if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) np->full_duplex = 1; if (np->full_duplex) 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; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) dev->mtu = mtu; np->advertising = readl(ioaddr + 0x90); printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", dev->name, (int)readl(ioaddr + 0x84), np->advertising); return 0;}/* 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. *//* Delay between EEPROM clock transitions. No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that made udelay() unreliable. The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is depricated.*/#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 alway-set leading bit. */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; int 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); for (i = 16; i > 0; i--) { writel(EE_ChipSelect | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); /* data bits are LSB first */ retval = (retval >> 1) | ((readl(ee_addr) & EE_DataOut) ? 0x8000 : 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 transceiver, and 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 readl(dev->base_addr + 0x80 + (location<<2)) & 0xffff; 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 + 0x80 + (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; /* Do we need to reset the chip??? */ i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i) return i; if (debug > 1) 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 < ETH_ALEN; i += 2) { writel(i, ioaddr + RxFilterAddr); writew(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8), ioaddr + RxFilterData); } /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. */ /* Configure for standard, in-spec Ethernet. */ np->tx_config = (1<<28) + /* Automatic transmit padding */ (1<<23) + /* Excessive collision retry */ (0x0<<20) + /* Max DMA burst = 512 byte */ (8<<8) + /* fill threshold = 256 byte */ 2; /* drain threshold = 64 byte */ writel(np->tx_config, ioaddr + TxConfig); np->rx_config = (0x0<<20) /* Max DMA burst = 512 byte */ + (0x8<<1); /* Drain Threshold = 64 byte */ writel(np->rx_config, ioaddr + RxConfig); if (dev->if_port == 0) dev->if_port = np->default_port; /* Disable PME */ np->SavedClkRun = readl(ioaddr + ClkRun); writel(np->SavedClkRun & ~0x100, ioaddr + ClkRun); netif_start_queue(dev); check_duplex(dev); set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. * We don't listen for TxDone interrupts and rely on TxIdle. */ writel(IntrAbnormalSummary | IntrTxIdle | IntrRxIdle | IntrRxDone, ioaddr + IntrMask); writel(1, ioaddr + IntrEnable); writel(RxOn | TxOn, ioaddr + ChipCmd); writel(4, ioaddr + StatsCtrl); /* Clear Stats */ if (debug > 2) 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) { np->full_duplex = duplex; if (debug) printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link" " capability.\n", dev->name, duplex ? "full" : "half"); if (duplex) { np->rx_config |= 0x10000000; np->tx_config |= 0xC0000000; } else { np->rx_config &= ~0x10000000; np->tx_config &= ~0xC0000000; } writel(np->tx_config, ioaddr + TxConfig); writel(np->rx_config, ioaddr + RxConfig); }}static void netdev_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; if (debug > 3) printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", dev->name, (int)readl(ioaddr + IntrStatus)); check_duplex(dev); np->timer.expires = jiffies + next_tick; add_timer(&np->timer);}static void tx_timeout(struct net_device *dev){ struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr));#ifndef __alpha__ { int i; printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status); printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) printk(" %4.4x", np->tx_ring[i].cmd_status); printk("\n"); }#endif /* Perhaps we should reinitialize the hardware here. */ dev->if_port = 0; /* Stop and restart the chip's Tx processes . */ /* Trigger an immediate transmit demand. */ dev->trans_start = jiffies; np->stats.tx_errors++; return;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void init_ring(struct net_device *dev){ struct netdev_private *np = (struct netdev_private *)dev->priv; int i; np->tx_full = 0; np->cur_rx = np->cur_tx = 0; np->dirty_rx = np->dirty_tx = 0; np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); np->rx_head_desc = &np->rx_ring[0]; /* Initialize all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]); np->rx_ring[i].cmd_status = DescOwn; np->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]); /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); np->rx_skbuff[i] = skb; if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ np->rx_ring[i].addr = virt_to_le32desc(skb->tail); np->rx_ring[i].cmd_status = cpu_to_le32(np->rx_buf_sz); } np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]); np->tx_ring[i].cmd_status = 0; } np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]); return;}static int start_tx(struct sk_buff *skb, struct net_device *dev){ struct netdev_private *np = (struct netdev_private *)dev->priv; unsigned entry; /* Note: Ordering is important here, set the field with the "ownership" bit last, and only then increment cur_tx. */ /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; np->tx_skbuff[entry] = skb; np->tx_ring[entry].addr = virt_to_le32desc(skb->data); np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len); np->cur_tx++; /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */ if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) { np->tx_full = 1; netif_stop_queue(dev); } /* Wake the potentially-idle transmit channel. */ writel(TxOn, dev->base_addr + ChipCmd); dev->trans_start = jiffies; if (debug > 4) { printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } return 0;}/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs){ struct net_device *dev = (struct net_device *)dev_instance; struct netdev_private *np; long ioaddr; int boguscnt = max_interrupt_work;#ifndef final_version /* Can never occur. */ if (dev == NULL) { printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown " "device.\n", irq); return; }#endif ioaddr = dev->base_addr; np = (struct netdev_private *)dev->priv; spin_lock(&np->lock); do { u32 intr_status = readl(ioaddr + IntrStatus); /* Acknowledge all of the current interrupt sources ASAP. */ writel(intr_status & 0x000ffff, ioaddr + IntrStatus); if (debug > 4) printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", dev->name, intr_status);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -