epic100.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,688 行 · 第 1/4 页
C
1,688 行
SET_NETDEV_DEV(dev, &pdev->dev);#ifdef USE_IO_OPS ioaddr = pci_resource_start (pdev, 0);#else ioaddr = pci_resource_start (pdev, 1); ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx); goto err_out_free_netdev; }#endif pci_set_drvdata(pdev, dev); ep = dev->priv; ep->mii.dev = dev; ep->mii.mdio_read = mdio_read; ep->mii.mdio_write = mdio_write; ep->mii.phy_id_mask = 0x1f; ep->mii.reg_num_mask = 0x1f; ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); if (!ring_space) goto err_out_iounmap; ep->tx_ring = (struct epic_tx_desc *)ring_space; ep->tx_ring_dma = ring_dma; ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); if (!ring_space) goto err_out_unmap_tx; ep->rx_ring = (struct epic_rx_desc *)ring_space; ep->rx_ring_dma = ring_dma; if (dev->mem_start) { option = dev->mem_start; duplex = (dev->mem_start & 16) ? 1 : 0; } else if (card_idx >= 0 && card_idx < MAX_UNITS) { if (options[card_idx] >= 0) option = options[card_idx]; if (full_duplex[card_idx] >= 0) duplex = full_duplex[card_idx]; } dev->base_addr = ioaddr; dev->irq = irq; spin_lock_init(&ep->lock); spin_lock_init(&ep->napi_lock); ep->reschedule_in_poll = 0; /* Bring the chip out of low-power mode. */ outl(0x4200, ioaddr + GENCTL); /* Magic?! If we don't set this bit the MII interface won't work. */ /* This magic is documented in SMSC app note 7.15 */ for (i = 16; i > 0; i--) outl(0x0008, ioaddr + TEST1); /* Turn on the MII transceiver. */ outl(0x12, ioaddr + MIICfg); if (chip_idx == 1) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); outl(0x0200, ioaddr + GENCTL); /* Note: the '175 does not have a serial EEPROM. */ for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4)); if (debug > 2) { printk(KERN_DEBUG DRV_NAME "(%s): EEPROM contents\n", pci_name(pdev)); for (i = 0; i < 64; i++) printk(" %4.4x%s", read_eeprom(ioaddr, i), i % 16 == 15 ? "\n" : ""); } ep->pci_dev = pdev; ep->chip_id = chip_idx; ep->chip_flags = pci_id_tbl[chip_idx].drv_flags; ep->irq_mask = (ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) | CntFull | TxUnderrun | EpicNapiEvent; /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes much time and no cards have external MII. */ { int phy, phy_idx = 0; for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) { int mii_status = mdio_read(dev, phy, MII_BMSR); if (mii_status != 0xffff && mii_status != 0x0000) { ep->phys[phy_idx++] = phy; printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control " "%4.4x status %4.4x.\n", pci_name(pdev), phy, mdio_read(dev, phy, 0), mii_status); } } ep->mii_phy_cnt = phy_idx; if (phy_idx != 0) { phy = ep->phys[0]; ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE); printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link " "partner %4.4x.\n", pci_name(pdev), ep->mii.advertising, mdio_read(dev, phy, 5)); } else if ( ! (ep->chip_flags & NO_MII)) { printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n", pci_name(pdev)); /* Use the known PHY address of the EPII. */ ep->phys[0] = 3; } ep->mii.phy_id = ep->phys[0]; } /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */ if (ep->chip_flags & MII_PWRDWN) outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL); outl(0x0008, ioaddr + GENCTL); /* The lower four bits are the media type. */ if (duplex) { ep->mii.force_media = ep->mii.full_duplex = 1; printk(KERN_INFO DRV_NAME "(%s): Forced full duplex operation requested.\n", pci_name(pdev)); } dev->if_port = ep->default_port = option; /* The Epic-specific entries in the device structure. */ dev->open = &epic_open; dev->hard_start_xmit = &epic_start_xmit; dev->stop = &epic_close; dev->get_stats = &epic_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &netdev_ioctl; dev->ethtool_ops = &netdev_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; dev->poll = epic_poll; dev->weight = 64; ret = register_netdev(dev); if (ret < 0) goto err_out_unmap_rx; printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x.\n", dev->dev_addr[i]);out: return ret;err_out_unmap_rx: pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);err_out_unmap_tx: pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);err_out_iounmap:#ifndef USE_IO_OPS iounmap(ioaddr);err_out_free_netdev:#endif free_netdev(dev);err_out_free_res: pci_release_regions(pdev);err_out_disable: pci_disable_device(pdev); goto out;}/* Serial EEPROM section. *//* EEPROM_Ctrl bits. */#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */#define EE_CS 0x02 /* EEPROM chip select. */#define EE_DATA_WRITE 0x08 /* EEPROM chip data in. */#define EE_WRITE_0 0x01#define EE_WRITE_1 0x09#define EE_DATA_READ 0x10 /* EEPROM chip data out. */#define EE_ENB (0x0001 | EE_CS)/* Delay between EEPROM clock transitions. This serves to flush the operation to the PCI bus. */#define eeprom_delay() inl(ee_addr)/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD (5 << 6)#define EE_READ64_CMD (6 << 6)#define EE_READ256_CMD (6 << 8)#define EE_ERASE_CMD (7 << 6)static void epic_disable_int(struct net_device *dev, struct epic_private *ep){ long ioaddr = dev->base_addr; outl(0x00000000, ioaddr + INTMASK);}static inline void __epic_pci_commit(long ioaddr){#ifndef USE_IO_OPS inl(ioaddr + INTMASK);#endif}static inline void epic_napi_irq_off(struct net_device *dev, struct epic_private *ep){ long ioaddr = dev->base_addr; outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK); __epic_pci_commit(ioaddr);}static inline void epic_napi_irq_on(struct net_device *dev, struct epic_private *ep){ long ioaddr = dev->base_addr; /* No need to commit possible posted write */ outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK);}static int __devinit read_eeprom(long ioaddr, int location){ int i; int retval = 0; long ee_addr = ioaddr + EECTL; int read_cmd = location | (inl(ee_addr) & 0x40 ? EE_READ64_CMD : EE_READ256_CMD); outl(EE_ENB & ~EE_CS, ee_addr); outl(EE_ENB, ee_addr); /* Shift the read command bits out. */ for (i = 12; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_WRITE_1 : EE_WRITE_0; outl(EE_ENB | dataval, ee_addr); eeprom_delay(); outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); } outl(EE_ENB, ee_addr); for (i = 16; i > 0; i--) { outl(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); outl(EE_ENB, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ outl(EE_ENB & ~EE_CS, ee_addr); return retval;}#define MII_READOP 1#define MII_WRITEOP 2static int mdio_read(struct net_device *dev, int phy_id, int location){ long ioaddr = dev->base_addr; int read_cmd = (phy_id << 9) | (location << 4) | MII_READOP; int i; outl(read_cmd, ioaddr + MIICtrl); /* Typical operation takes 25 loops. */ for (i = 400; i > 0; i--) { barrier(); if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) { /* Work around read failure bug. */ if (phy_id == 1 && location < 6 && inw(ioaddr + MIIData) == 0xffff) { outl(read_cmd, ioaddr + MIICtrl); continue; } return inw(ioaddr + MIIData); } } return 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int loc, int value){ long ioaddr = dev->base_addr; int i; outw(value, ioaddr + MIIData); outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl); for (i = 10000; i > 0; i--) { barrier(); if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0) break; } return;}static int epic_open(struct net_device *dev){ struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; int i; int retval; /* Soft reset the chip. */ outl(0x4001, ioaddr + GENCTL); if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev))) return retval; epic_init_ring(dev); outl(0x4000, ioaddr + GENCTL); /* This magic is documented in SMSC app note 7.15 */ for (i = 16; i > 0; i--) outl(0x0008, ioaddr + TEST1); /* Pull the chip out of low-power mode, enable interrupts, and set for PCI read multiple. The MIIcfg setting and strange write order are required by the details of which bits are reset and the transceiver wiring on the Ositech CardBus card. */#if 0 outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);#endif if (ep->chip_flags & MII_PWRDWN) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);#if defined(__powerpc__) || defined(__sparc__) /* Big endian */ outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); inl(ioaddr + GENCTL); outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);#else outl(0x4412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); inl(ioaddr + GENCTL); outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);#endif udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */ for (i = 0; i < 3; i++) outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4); ep->tx_threshold = TX_FIFO_THRESH; outl(ep->tx_threshold, ioaddr + TxThresh); if (media2miictl[dev->if_port & 15]) { if (ep->mii_phy_cnt) mdio_write(dev, ep->phys[0], MII_BMCR, media2miictl[dev->if_port&15]); if (dev->if_port == 1) { if (debug > 1) printk(KERN_INFO "%s: Using the 10base2 transceiver, MII " "status %4.4x.\n", dev->name, mdio_read(dev, ep->phys[0], MII_BMSR)); } } else { int mii_lpa = mdio_read(dev, ep->phys[0], MII_LPA); if (mii_lpa != 0xffff) { if ((mii_lpa & LPA_100FULL) || (mii_lpa & 0x01C0) == LPA_10FULL) ep->mii.full_duplex = 1; else if (! (mii_lpa & LPA_LPACK)) mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART); if (debug > 1) printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d" " register read of %4.4x.\n", dev->name, ep->mii.full_duplex ? "full" : "half", ep->phys[0], mii_lpa); } } outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); outl(ep->rx_ring_dma, ioaddr + PRxCDAR); outl(ep->tx_ring_dma, ioaddr + PTxCDAR); /* Start the chip's Rx process. */ set_rx_mode(dev); outl(StartRx | RxQueued, ioaddr + COMMAND); netif_start_queue(dev); /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) | CntFull | TxUnderrun | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); if (debug > 1) printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " "%s-duplex.\n", dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL), ep->mii.full_duplex ? "full" : "half"); /* Set the timer to switch to check for link beat and perhaps switch to an alternate media type. */ init_timer(&ep->timer); ep->timer.expires = jiffies + 3*HZ; ep->timer.data = (unsigned long)dev; ep->timer.function = &epic_timer; /* timer handler */ add_timer(&ep->timer); return 0;}/* Reset the chip to recover from a PCI transaction error. This may occur at interrupt time. */static void epic_pause(struct net_device *dev){ long ioaddr = dev->base_addr; struct epic_private *ep = dev->priv; netif_stop_queue (dev); /* Disable interrupts by clearing the interrupt mask. */ outl(0x00000000, ioaddr + INTMASK); /* Stop the chip's Tx and Rx DMA processes. */ outw(StopRx | StopTxDMA | StopRxDMA, ioaddr + COMMAND); /* Update the error counts. */ if (inw(ioaddr + COMMAND) != 0xffff) { ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?