📄 via-rhine.c
字号:
struct sk_buff *tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; /* Tx bounce buffers */ unsigned char *tx_buf[TX_RING_SIZE]; unsigned char *tx_bufs; dma_addr_t tx_bufs_dma; struct pci_dev *pdev; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ int chip_id, drv_flags; struct rx_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ u16 chip_cmd; /* Current setting for ChipCmd */ /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; unsigned int default_port:4; /* Last dev->if_port value. */ u8 tx_thresh, rx_thresh; /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */ unsigned char phys[MAX_MII_CNT]; /* MII device addresses. */ unsigned int mii_cnt; /* number of MIIs found, but only the first one is used */ u16 mii_status; /* last read MII status */ struct mii_if_info mii_if;};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 via_rhine_open(struct net_device *dev);static void via_rhine_check_duplex(struct net_device *dev);static void via_rhine_timer(unsigned long data);static void via_rhine_tx_timeout(struct net_device *dev);static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev);static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static void via_rhine_tx(struct net_device *dev);static void via_rhine_rx(struct net_device *dev);static void via_rhine_error(struct net_device *dev, int intr_status);static void via_rhine_set_rx_mode(struct net_device *dev);static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int via_rhine_close(struct net_device *dev);static inline void clear_tally_counters(long ioaddr);static void wait_for_reset(struct net_device *dev, char *name){ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int chip_id = np->chip_id; int i; /* 3043 may need long delay after reset (dlink) */ if (chip_id == VT3043 || chip_id == VT86C100A) udelay(100); i = 0; do { udelay(5); i++; if(i > 2000) { printk(KERN_ERR "%s: reset did not complete in 10 ms.\n", name); break; } } while(readw(ioaddr + ChipCmd) & CmdReset); if (debug > 1) printk(KERN_INFO "%s: reset finished after %d microseconds.\n", name, 5*i);}#ifdef USE_MEMstatic void __devinit enable_mmio(long ioaddr, int chip_id){ int n; if (chip_id == VT3043 || chip_id == VT86C100A) { /* More recent docs say that this bit is reserved ... */ n = inb(ioaddr + ConfigA) | 0x20; outb(n, ioaddr + ConfigA); } else if (chip_id == VT6102) { n = inb(ioaddr + ConfigD) | 0x80; outb(n, ioaddr + ConfigD); }}#endifstatic void __devinit reload_eeprom(long ioaddr){ int i; outb(0x20, ioaddr + MACRegEEcsr); /* Typically 2 cycles to reload. */ for (i = 0; i < 150; i++) if (! (inb(ioaddr + MACRegEEcsr) & 0x20)) break;}static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *dev; struct netdev_private *np; int i, option; int chip_id = (int) ent->driver_data; static int card_idx = -1; long ioaddr; long memaddr; int io_size; int pci_flags;#ifdef USE_MEM long ioaddr0;#endif /* when built into the kernel, we only print version if device is found */#ifndef MODULE static int printed_version; if (!printed_version++) printk(version);#endif card_idx++; option = card_idx < MAX_UNITS ? options[card_idx] : 0; io_size = via_rhine_chip_info[chip_id].io_size; pci_flags = via_rhine_chip_info[chip_id].pci_flags; if (pci_enable_device (pdev)) goto err_out; /* this should always be supported */ if (pci_set_dma_mask(pdev, 0xffffffff)) { printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n"); goto err_out; } /* sanity check */ if ((pci_resource_len (pdev, 0) < io_size) || (pci_resource_len (pdev, 1) < io_size)) { printk (KERN_ERR "Insufficient PCI resources, aborting\n"); goto err_out; } ioaddr = pci_resource_start (pdev, 0); memaddr = pci_resource_start (pdev, 1); if (pci_flags & PCI_USES_MASTER) pci_set_master (pdev); dev = alloc_etherdev(sizeof(*np)); if (dev == NULL) { printk (KERN_ERR "init_ethernet failed for card #%d\n", card_idx); goto err_out; } SET_MODULE_OWNER(dev); if (pci_request_regions(pdev, shortname)) goto err_out_free_netdev;#ifdef USE_MEM ioaddr0 = ioaddr; enable_mmio(ioaddr0, chip_id); ioaddr = (long) ioremap (memaddr, io_size); if (!ioaddr) { printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%lX\n", pdev->slot_name, io_size, memaddr); goto err_out_free_res; } /* Check that selected MMIO registers match the PIO ones */ i = 0; while (mmio_verify_registers[i]) { int reg = mmio_verify_registers[i++]; unsigned char a = inb(ioaddr0+reg); unsigned char b = readb(ioaddr+reg); if (a != b) { printk (KERN_ERR "MMIO do not match PIO [%02x] (%02x != %02x)\n", reg, a, b); goto err_out_unmap; } }#endif /* D-Link provided reset code (with comment additions) */ if (via_rhine_chip_info[chip_id].drv_flags & HasWOL) { unsigned char byOrgValue; /* clear sticky bit before reset & read ethernet address */ byOrgValue = readb(ioaddr + StickyHW); byOrgValue = byOrgValue & 0xFC; writeb(byOrgValue, ioaddr + StickyHW); /* (bits written are cleared?) */ /* disable force PME-enable */ writeb(0x80, ioaddr + WOLcgClr); /* disable power-event config bit */ writeb(0xFF, ioaddr + WOLcrClr); /* clear power status (undocumented in vt6102 docs?) */ writeb(0xFF, ioaddr + PwrcsrClr); } /* Reset the chip to erase previous misconfiguration. */ writew(CmdReset, ioaddr + ChipCmd); dev->base_addr = ioaddr; wait_for_reset(dev, shortname); /* Reload the station address from the EEPROM. */#ifdef USE_IO reload_eeprom(ioaddr);#else reload_eeprom(ioaddr0); /* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO. If reload_eeprom() was done first this could be avoided, but it is not known if that still works with the "win98-reboot" problem. */ enable_mmio(ioaddr0, chip_id);#endif for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); if (!is_valid_ether_addr(dev->dev_addr)) { printk(KERN_ERR "Invalid MAC address for card #%d\n", card_idx); goto err_out_unmap; } if (chip_id == VT6102) { /* * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA * turned on. it makes MAC receive magic packet * automatically. So, we turn it off. (D-Link) */ writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); } dev->irq = pdev->irq; np = dev->priv; spin_lock_init (&np->lock); np->chip_id = chip_id; np->drv_flags = via_rhine_chip_info[chip_id].drv_flags; np->pdev = pdev; np->mii_if.dev = dev; np->mii_if.mdio_read = mdio_read; np->mii_if.mdio_write = mdio_write; 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; np->default_port = option & 15; } if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) np->mii_if.full_duplex = 1; if (np->mii_if.full_duplex) { printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation" " disabled.\n", dev->name); np->mii_if.duplex_lock = 1; } /* The chip-specific entries in the device structure. */ dev->open = via_rhine_open; dev->hard_start_xmit = via_rhine_start_tx; dev->stop = via_rhine_close; dev->get_stats = via_rhine_get_stats; dev->set_multicast_list = via_rhine_set_rx_mode; dev->do_ioctl = via_rhine_ioctl; dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (np->drv_flags & ReqTxAlign) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; i = register_netdev(dev); if (i) goto err_out_unmap; printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, via_rhine_chip_info[chip_id].name, (pci_flags & PCI_USES_IO) ? ioaddr : memaddr); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); pci_set_drvdata(pdev, dev); if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; np->phys[0] = 1; /* Standard for this chip. */ for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; np->mii_if.advertising = mdio_read(dev, phy, 4); printk(KERN_INFO "%s: MII PHY found at address %d, status " "0x%4.4x advertising %4.4x Link %4.4x.\n", dev->name, phy, mii_status, np->mii_if.advertising, mdio_read(dev, phy, 5)); /* set IFF_RUNNING */ if (mii_status & MIILink) netif_carrier_on(dev); else netif_carrier_off(dev); } } np->mii_cnt = phy_idx; np->mii_if.phy_id = np->phys[0]; } /* Allow forcing the media type. */ if (option > 0) { if (option & 0x220) np->mii_if.full_duplex = 1; np->default_port = option & 0x3ff; if (np->default_port & 0x330) { /* FIXME: shouldn't someone check this variable? */ /* np->medialock = 1; */ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", (option & 0x300 ? 100 : 10), (option & 0x220 ? "full" : "half")); if (np->mii_cnt) mdio_write(dev, np->phys[0], 0, ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */ ((option & 0x220) ? 0x0100 : 0)); /* Full duplex? */ } } return 0;err_out_unmap:#ifdef USE_MEM iounmap((void *)ioaddr);err_out_free_res:#endif pci_release_regions(pdev);err_out_free_netdev: kfree (dev);err_out: return -ENODEV;}static int alloc_ring(struct net_device* dev){ struct netdev_private *np = dev->priv; void *ring; dma_addr_t ring_dma; ring = pci_alloc_consistent(np->pdev, RX_RING_SIZE * sizeof(struct rx_desc) + TX_RING_SIZE * sizeof(struct tx_desc), &ring_dma); if (!ring) { printk(KERN_ERR "Could not allocate DMA memory.\n"); return -ENOMEM; } if (np->drv_flags & ReqTxAlign) { np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, &np->tx_bufs_dma); if (np->tx_bufs == NULL) { pci_free_consistent(np->pdev, RX_RING_SIZE * sizeof(struct rx_desc) + TX_RING_SIZE * sizeof(struct tx_desc), ring, ring_dma); return -ENOMEM; } } np->rx_ring = ring; np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc); np->rx_ring_dma = ring_dma; np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc); return 0;}void free_ring(struct net_device* dev){ struct netdev_private *np = dev->priv; pci_free_consistent(np->pdev, RX_RING_SIZE * sizeof(struct rx_desc) + TX_RING_SIZE * sizeof(struct tx_desc), np->rx_ring, np->rx_ring_dma); np->tx_ring = NULL; if (np->tx_bufs) pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, np->tx_bufs, np->tx_bufs_dma); np->tx_bufs = NULL;}static void alloc_rbufs(struct net_device *dev){ struct netdev_private *np = dev->priv; dma_addr_t next; int i; np->dirty_rx = np->cur_rx = 0; np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); np->rx_head_desc = &np->rx_ring[0]; next = np->rx_ring_dma; /* Init the ring entries */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].rx_status = 0; np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); next += sizeof(struct rx_desc); np->rx_ring[i].next_desc = cpu_to_le32(next); np->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma); /* 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_skbuff_dma[i] = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]); np->rx_ring[i].rx_status = cpu_to_le32(DescOwn); } np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);}static void free_rbufs(struct net_device* dev){ struct netdev_private *np = dev->priv; int i; /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].rx_status = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -