📄 natsemi.c
字号:
static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 data){ struct netdev_private *np = dev->priv; if (phy_id == 1 && reg < 32) { writew(data, dev->base_addr+BasicControl+(reg<<2)); switch (reg) { case MII_ADVERTISE: np->advertising = data; break; } }}/* CFG bits [13:16] [18:23] */#define CFG_RESET_SAVE 0xfde000/* WCSR bits [0:4] [9:10] */#define WCSR_RESET_SAVE 0x61f/* RFCR bits [20] [22] [27:31] */#define RFCR_RESET_SAVE 0xf8500000;static void natsemi_reset(struct net_device *dev){ int i; u32 cfg; u32 wcsr; u32 rfcr; u16 pmatch[3]; u16 sopass[3]; struct netdev_private *np = dev->priv; /* * Resetting the chip causes some registers to be lost. * Natsemi suggests NOT reloading the EEPROM while live, so instead * we save the state that would have been loaded from EEPROM * on a normal power-up (see the spec EEPROM map). This assumes * whoever calls this will follow up with init_registers() eventually. */ /* CFG */ cfg = readl(dev->base_addr + ChipConfig) & CFG_RESET_SAVE; /* WCSR */ wcsr = readl(dev->base_addr + WOLCmd) & WCSR_RESET_SAVE; /* RFCR */ rfcr = readl(dev->base_addr + RxFilterAddr) & RFCR_RESET_SAVE; /* PMATCH */ for (i = 0; i < 3; i++) { writel(i*2, dev->base_addr + RxFilterAddr); pmatch[i] = readw(dev->base_addr + RxFilterData); } /* SOPAS */ for (i = 0; i < 3; i++) { writel(0xa+(i*2), dev->base_addr + RxFilterAddr); sopass[i] = readw(dev->base_addr + RxFilterData); } /* now whack the chip */ writel(ChipReset, dev->base_addr + ChipCmd); for (i=0;i<NATSEMI_HW_TIMEOUT;i++) { if (!(readl(dev->base_addr + ChipCmd) & ChipReset)) break; udelay(5); } if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: reset did not complete in %d usec.\n", dev->name, i*5); } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: reset completed in %d usec.\n", dev->name, i*5); } /* restore CFG */ cfg |= readl(dev->base_addr + ChipConfig) & ~CFG_RESET_SAVE; writel(cfg, dev->base_addr + ChipConfig); /* restore WCSR */ wcsr |= readl(dev->base_addr + WOLCmd) & ~WCSR_RESET_SAVE; writel(wcsr, dev->base_addr + WOLCmd); /* read RFCR */ rfcr |= readl(dev->base_addr + RxFilterAddr) & ~RFCR_RESET_SAVE; /* restore PMATCH */ for (i = 0; i < 3; i++) { writel(i*2, dev->base_addr + RxFilterAddr); writew(pmatch[i], dev->base_addr + RxFilterData); } for (i = 0; i < 3; i++) { writel(0xa+(i*2), dev->base_addr + RxFilterAddr); writew(sopass[i], dev->base_addr + RxFilterData); } /* restore RFCR */ writel(rfcr, dev->base_addr + RxFilterAddr); }static void natsemi_reload_eeprom(struct net_device *dev){ struct netdev_private *np = dev->priv; int i; writel(EepromReload, dev->base_addr + PCIBusCfg); for (i=0;i<NATSEMI_HW_TIMEOUT;i++) { if (!(readl(dev->base_addr + PCIBusCfg) & EepromReload)) break; udelay(5); } if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: EEPROM did not reload in %d usec.\n", dev->name, i*5); } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n", dev->name, i*5); }}static void natsemi_stop_rxtx(struct net_device *dev){ long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; int i; writel(RxOff | TxOff, ioaddr + ChipCmd); for(i=0;i< NATSEMI_HW_TIMEOUT;i++) { if ((readl(ioaddr + ChipCmd) & (TxOn|RxOn)) == 0) break; udelay(5); } if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n", dev->name, i*5); } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n", dev->name, i*5); }}static int netdev_open(struct net_device *dev){ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; /* Reset the chip, just in case. */ natsemi_reset(dev); i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i) return i; if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); i = alloc_ring(dev); if (i < 0) { free_irq(dev->irq, dev); return i; } init_ring(dev); spin_lock_irq(&np->lock); init_registers(dev); spin_unlock_irq(&np->lock); netif_start_queue(dev); if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: Done netdev_open(), status: %#08x.\n", dev->name, (int)readl(ioaddr + ChipCmd)); /* Set the timer to check for link beat. */ init_timer(&np->timer); np->timer.expires = jiffies + NATSEMI_TIMER_FREQ; np->timer.data = (unsigned long)dev; np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); return 0;}static void check_link(struct net_device *dev){ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int duplex; int chipcfg = readl(ioaddr + ChipConfig); if (!(chipcfg & CfgLink)) { if (netif_carrier_ok(dev)) { if (netif_msg_link(np)) printk(KERN_NOTICE "%s: link down.\n", dev->name); netif_carrier_off(dev); } return; } if (!netif_carrier_ok(dev)) { if (netif_msg_link(np)) printk(KERN_NOTICE "%s: link up.\n", dev->name); netif_carrier_on(dev); } duplex = np->full_duplex || (chipcfg & CfgFullDuplex ? 1 : 0); /* if duplex is set then bit 28 must be set, too */ if (duplex ^ !!(np->rx_config & RxAcceptTx)) { if (netif_msg_link(np)) printk(KERN_INFO "%s: Setting %s-duplex based on negotiated " "link capability.\n", dev->name, duplex ? "full" : "half"); if (duplex) { np->rx_config |= RxAcceptTx; np->tx_config |= TxCarrierIgn | TxHeartIgn; } else { np->rx_config &= ~RxAcceptTx; np->tx_config &= ~(TxCarrierIgn | TxHeartIgn); } writel(np->tx_config, ioaddr + TxConfig); writel(np->rx_config, ioaddr + RxConfig); }}static void init_registers(struct net_device *dev){ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; for (i=0;i<NATSEMI_HW_TIMEOUT;i++) { if (readl(dev->base_addr + ChipConfig) & CfgAnegDone) break; udelay(10); } if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) { printk(KERN_INFO "%s: autonegotiation did not complete in %d usec.\n", dev->name, i*10); } /* On page 78 of the spec, they recommend some settings for "optimum performance" to be done in sequence. These settings optimize some of the 100Mbit autodetection circuitry. They say we only want to do this for rev C of the chip, but engineers at NSC (Bradley Kennedy) recommends always setting them. If you don't, you get errors on some autonegotiations that make the device unusable. */ writew(1, ioaddr + PGSEL); writew(PMDCSR_VAL, ioaddr + PMDCSR); writew(TSTDAT_VAL, ioaddr + TSTDAT); writew(DSPCFG_VAL, ioaddr + DSPCFG); writew(SDCFG_VAL, ioaddr + SDCFG); writew(0, ioaddr + PGSEL); /* Enable PHY Specific event based interrupts. Link state change and Auto-Negotiation Completion are among the affected. Read the intr status to clear it (needed for wake events). */ readw(ioaddr + MIntrStatus); writew(MICRIntEn, ioaddr + MIntrCtrl); /* clear any interrupts that are pending, such as wake events */ readl(ioaddr + IntrStatus); writel(np->ring_dma, ioaddr + RxRingPtr); writel(np->ring_dma + RX_RING_SIZE * sizeof(struct netdev_desc), ioaddr + TxRingPtr); /* Initialize other registers. * Configure the PCI bus bursts and FIFO thresholds. * Configure for standard, in-spec Ethernet. * Start with half-duplex. check_link will update * to the correct settings. */ /* DRTH: 2: start tx if 64 bytes are in the fifo * FLTH: 0x10: refill with next packet if 512 bytes are free * MXDMA: 0: up to 256 byte bursts. * MXDMA must be <= FLTH * ECRETRY=1 * ATP=1 */ np->tx_config = TxAutoPad | TxCollRetry | TxMxdma_256 | (0x1002); writel(np->tx_config, ioaddr + TxConfig); /* DRTH 0x10: start copying to memory if 128 bytes are in the fifo * MXDMA 0: up to 256 byte bursts */ np->rx_config = RxMxdma_256 | 0x20; writel(np->rx_config, ioaddr + RxConfig); /* Disable PME: * The PME bit is initialized from the EEPROM contents. * PCI cards probably have PME disabled, but motherboard * implementations may have PME set to enable WakeOnLan. * With PME set the chip will scan incoming packets but * nothing will be written to memory. */ np->SavedClkRun = readl(ioaddr + ClkRun); writel(np->SavedClkRun & ~PMEEnable, ioaddr + ClkRun); if (np->SavedClkRun & PMEStatus && netif_msg_wol(np)) { printk(KERN_NOTICE "%s: Wake-up event %#08x\n", dev->name, readl(ioaddr + WOLCmd)); } check_link(dev); __set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. */ writel(DEFAULT_INTR, ioaddr + IntrMask); writel(1, ioaddr + IntrEnable); writel(RxOn | TxOn, ioaddr + ChipCmd); writel(StatsClear, ioaddr + StatsCtrl); /* Clear Stats */}/* * The frequency on this has been increased because of a nasty little problem. * It seems that a reference set for this chip went out with incorrect info, * and there exist boards that aren't quite right. An unexpected voltage drop * can cause the PHY to get itself in a weird state (basically reset..). * NOTE: this only seems to affect revC chips. */static void netdev_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct netdev_private *np = dev->priv; int next_tick = 5*HZ; long ioaddr = dev->base_addr; u16 dspcfg; if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, * a read clears any pending interrupts. */ printk(KERN_DEBUG "%s: Media selection timer tick.\n", dev->name); } /* check for a nasty random phy-reset - use dspcfg as a flag */ writew(1, ioaddr+PGSEL); dspcfg = readw(ioaddr+DSPCFG); writew(0, ioaddr+PGSEL); if (dspcfg != DSPCFG_VAL) { if (!netif_queue_stopped(dev)) { if (netif_msg_hw(np)) printk(KERN_NOTICE "%s: possible phy reset: " "re-initializing\n", dev->name); disable_irq(dev->irq); spin_lock_irq(&np->lock); init_registers(dev); spin_unlock_irq(&np->lock); enable_irq(dev->irq); } else { /* hurry back */ next_tick = HZ; } } else { /* init_registers() calls check_link() for the above case */ spin_lock_irq(&np->lock); check_link(dev); spin_unlock_irq(&np->lock); } mod_timer(&np->timer, jiffies + next_tick);}static void dump_ring(struct net_device *dev){ struct netdev_private *np = dev->priv; if (netif_msg_pktdata(np)) { int i; printk(KERN_DEBUG " Tx ring at %p:\n", np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) { printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->tx_ring[i].next_desc, np->tx_ring[i].cmd_status, np->tx_ring[i].addr); } printk(KERN_DEBUG " Rx ring %p:\n", np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) { printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->rx_ring[i].next_desc, np->rx_ring[i].cmd_status, np->rx_ring[i].addr); } }}static void tx_timeout(struct net_device *dev){ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; disable_irq(dev->irq); spin_lock_irq(&np->lock); if (netif_device_present(dev)) { if (netif_msg_tx_err(np)) printk(KERN_WARNING "%s: Transmit timed out, status %#08x," " resetting...\n", dev->name, readl(ioaddr + IntrStatus)); dump_ring(dev); natsemi_reset(dev); drain_ring(dev); init_ring(dev); init_registers(dev); } else { printk(KERN_WARNING "%s: tx_timeout while in suspended state?\n", dev->name); } spin_unlock_irq(&np->lock); enable_irq(dev->irq); dev->trans_start = jiffies; np->stats.tx_errors++; netif_wake_queue(dev);}static int alloc_ring(struct net_device *dev){ struct netdev_private *np = dev->priv; np->rx_ring = pci_alloc_consistent(np->pci_dev, sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE), &np->ring_dma); if (!np->rx_ring) return -ENOMEM; np->tx_ring = &np->rx_ring[RX_RING_SIZE]; return 0;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void init_ring(struct net_device *dev){ struct netdev_private *np = dev->priv; int i; 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]; /* Please be carefull before changing this loop - at least gcc-2.95.1 * miscompiles it otherwise. */ /* Initialize all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].next_desc = cpu_to_le32(np->ring_dma +sizeof(struct netdev_desc) *((i+1)%RX_RING_SIZE)); np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn); np->rx_skbuff[i] = NULL; } /* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -