📄 winbond-840.c
字号:
/* Reset the chip to erase previous misconfiguration. No hold time required! */ writel(0x00000001, ioaddr + PCIBusCfg); dev->base_addr = ioaddr; dev->irq = irq; np = dev->priv; np->pci_dev = pdev; np->chip_id = chip_idx; np->drv_flags = pci_id_tbl[chip_idx].drv_flags; spin_lock_init(&np->lock); np->mii_if.dev = dev; np->mii_if.mdio_read = mdio_read; np->mii_if.mdio_write = mdio_write; pci_set_drvdata(pdev, dev); if (dev->mem_start) option = dev->mem_start; /* The lower four bits are the media type. */ if (option > 0) { if (option & 0x200) np->mii_if.full_duplex = 1; if (option & 15) printk(KERN_INFO "%s: ignoring user supplied media type %d", dev->name, option & 15); } if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) np->mii_if.full_duplex = 1; if (np->mii_if.full_duplex) np->mii_if.force_media = 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 = &netdev_ioctl; dev->ethtool_ops = &netdev_ethtool_ops; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; i = register_netdev(dev); if (i) goto err_out_cleardev; printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, MII_BMSR); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); np->mii = (mdio_read(dev, phy, MII_PHYSID1) << 16)+ mdio_read(dev, phy, MII_PHYSID2); printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status " "0x%4.4x advertising %4.4x.\n", dev->name, np->mii, phy, mii_status, np->mii_if.advertising); } } np->mii_cnt = phy_idx; np->mii_if.phy_id = np->phys[0]; if (phy_idx == 0) { printk(KERN_WARNING "%s: MII PHY not found -- this device may " "not operate correctly.\n", dev->name); } } find_cnt++; return 0;err_out_cleardev: pci_set_drvdata(pdev, NULL);#ifndef USE_IO_OPS iounmap((void *)ioaddr);err_out_free_res:#endif pci_release_regions(pdev);err_out_netdev: free_netdev (dev); return -ENODEV;}/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. These are often serial bit streams generated by the host processor. The example below is for the common 93c46 EEPROM, 64 16 bit words. *//* 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=0x02, EE_Write0=0x801, EE_Write1=0x805, EE_ChipSelect=0x801, EE_DataIn=0x08,};/* 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; long ee_addr = addr + EECtrl; int read_cmd = location | EE_ReadCmd; writel(EE_ChipSelect, 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 = 16; i > 0; i--) { writel(EE_ChipSelect | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0); writel(EE_ChipSelect, ee_addr); eeprom_delay(ee_addr); } /* Terminate the EEPROM access. */ writel(0, ee_addr); return retval;}/* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet for details. The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back 33Mhz PCI cycles. */#define mdio_delay(mdio_addr) readl(mdio_addr)/* Set iff a MII transceiver on any interface requires mdio preamble. This only set with older transceivers, so the extra code size of a per-interface flag is not worthwhile. */static char mii_preamble_required = 1;#define MDIO_WRITE0 (MDIO_EnbOutput)#define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)/* Generate the preamble required for initial synchronization and a few older transceivers. */static void mdio_sync(long mdio_addr){ int bits = 32; /* Establish sync by sending at least 32 logic ones. */ while (--bits >= 0) { writel(MDIO_WRITE1, mdio_addr); mdio_delay(mdio_addr); writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); }}static int mdio_read(struct net_device *dev, int phy_id, int location){ long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int i, retval = 0; if (mii_preamble_required) mdio_sync(mdio_addr); /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; writel(dataval, mdio_addr); mdio_delay(mdio_addr); writel(dataval | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 20; i > 0; i--) { writel(MDIO_EnbIn, mdio_addr); mdio_delay(mdio_addr); retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0); writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } return (retval>>1) & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){ struct netdev_private *np = dev->priv; long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; if (location == 4 && phy_id == np->phys[0]) np->mii_if.advertising = value; if (mii_preamble_required) mdio_sync(mdio_addr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; writel(dataval, mdio_addr); mdio_delay(mdio_addr); writel(dataval | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { writel(MDIO_EnbIn, mdio_addr); mdio_delay(mdio_addr); writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } return;}static int netdev_open(struct net_device *dev){ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; writel(0x00000001, ioaddr + PCIBusCfg); /* Reset */ netif_device_detach(dev); i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i) goto out_err; if (debug > 1) printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n", dev->name, dev->irq); if((i=alloc_ringdesc(dev))) goto out_err; spin_lock_irq(&np->lock); netif_device_attach(dev); init_registers(dev); spin_unlock_irq(&np->lock); netif_start_queue(dev); if (debug > 2) printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); /* Set the timer to check for link beat. */ init_timer(&np->timer); np->timer.expires = jiffies + 1*HZ; np->timer.data = (unsigned long)dev; np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); return 0;out_err: netif_device_attach(dev); return i;}#define MII_DAVICOM_DM9101 0x0181b800static int update_link(struct net_device *dev){ struct netdev_private *np = dev->priv; int duplex, fasteth, result, mii_reg; /* BSMR */ mii_reg = mdio_read(dev, np->phys[0], MII_BMSR); if (mii_reg == 0xffff) return np->csr6; /* reread: the link status bit is sticky */ mii_reg = mdio_read(dev, np->phys[0], MII_BMSR); if (!(mii_reg & 0x4)) { if (netif_carrier_ok(dev)) { if (debug) printk(KERN_INFO "%s: MII #%d reports no link. Disabling watchdog.\n", dev->name, np->phys[0]); netif_carrier_off(dev); } return np->csr6; } if (!netif_carrier_ok(dev)) { if (debug) printk(KERN_INFO "%s: MII #%d link is back. Enabling watchdog.\n", dev->name, np->phys[0]); netif_carrier_on(dev); } if ((np->mii & ~0xf) == MII_DAVICOM_DM9101) { /* If the link partner doesn't support autonegotiation * the MII detects it's abilities with the "parallel detection". * Some MIIs update the LPA register to the result of the parallel * detection, some don't. * The Davicom PHY [at least 0181b800] doesn't. * Instead bit 9 and 13 of the BMCR are updated to the result * of the negotiation.. */ mii_reg = mdio_read(dev, np->phys[0], MII_BMCR); duplex = mii_reg & BMCR_FULLDPLX; fasteth = mii_reg & BMCR_SPEED100; } else { int negotiated; mii_reg = mdio_read(dev, np->phys[0], MII_LPA); negotiated = mii_reg & np->mii_if.advertising; duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL); fasteth = negotiated & 0x380; } duplex |= np->mii_if.force_media; /* remove fastether and fullduplex */ result = np->csr6 & ~0x20000200; if (duplex) result |= 0x200; if (fasteth) result |= 0x20000000; if (result != np->csr6 && debug) printk(KERN_INFO "%s: Setting %dMBit-%s-duplex based on MII#%d\n", dev->name, fasteth ? 100 : 10, duplex ? "full" : "half", np->phys[0]); return result;}#define RXTX_TIMEOUT 2000static inline void update_csr6(struct net_device *dev, int new){ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int limit = RXTX_TIMEOUT; if (!netif_device_present(dev)) new = 0; if (new==np->csr6) return; /* stop both Tx and Rx processes */ writel(np->csr6 & ~0x2002, ioaddr + NetworkConfig); /* wait until they have really stopped */ for (;;) { int csr5 = readl(ioaddr + IntrStatus); int t; t = (csr5 >> 17) & 0x07; if (t==0||t==1) { /* rx stopped */ t = (csr5 >> 20) & 0x07; if (t==0||t==1) break; } limit--; if(!limit) { printk(KERN_INFO "%s: couldn't stop rxtx, IntrStatus %xh.\n", dev->name, csr5); break; } udelay(1); } np->csr6 = new; /* and restart them with the new configuration */ writel(np->csr6, ioaddr + NetworkConfig); if (new & 0x200) np->mii_if.full_duplex = 1;}static void netdev_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; if (debug > 2) printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " "config %8.8x.\n", dev->name, (int)readl(ioaddr + IntrStatus), (int)readl(ioaddr + NetworkConfig)); spin_lock_irq(&np->lock); update_csr6(dev, update_link(dev)); spin_unlock_irq(&np->lock); np->timer.expires = jiffies + 10*HZ; add_timer(&np->timer);}static void init_rxtx_rings(struct net_device *dev){ struct netdev_private *np = dev->priv; int i; np->rx_head_desc = &np->rx_ring[0]; np->tx_ring = (struct w840_tx_desc*)&np->rx_ring[RX_RING_SIZE]; /* Initial all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].length = np->rx_buf_sz; np->rx_ring[i].status = 0; np->rx_skbuff[i] = NULL; } /* Mark the last entry as wrapping the ring. */ np->rx_ring[i-1].length |= DescEndRing; /* 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_addr[i] = pci_map_single(np->pci_dev,skb->tail,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -