📄 epic100.c
字号:
ep->advertising = mdio_read(ioaddr, phy, 4); printk( KERN_INFO "%s: Autonegotiation advertising %4.4x link " "partner %4.4x.\n", dev->name, ep->advertising, mdio_read(ioaddr, phy, 5)); } else if ( ! (ep->chip_flags & NO_MII)) { printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n", dev->name); /* Use the known PHY address of the EPII. */ ep->phys[0] = 3; } } /* 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. */ ep->force_fd = duplex; dev->if_port = ep->default_port = option; if (ep->default_port) ep->medialock = 1; /* 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 = &mii_ioctl; dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; return 0;#ifndef USE_IO_OPSerr_out_free_mmio: release_mem_region (pci_resource_start (pdev, 1), pci_resource_len (pdev, 1));#endiferr_out_free_pio: release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0));err_out_free_netdev: unregister_netdev(dev); kfree(dev); return -ENODEV;}/* 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. No extra delay is needed with 33Mhz PCI, but 66Mhz is untested. */#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 int 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(long ioaddr, int phy_id, int location){ int i; outl((phy_id << 9) | (location << 4) | MII_READOP, ioaddr + MIICtrl); /* Typical operation takes < 50 ticks. */ for (i = 4000; i > 0; i--) if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) return inw(ioaddr + MIIData); return 0xffff;}static void mdio_write(long ioaddr, int phy_id, int location, int value){ int i; outw(value, ioaddr + MIIData); outl((phy_id << 9) | (location << 4) | MII_WRITEOP, ioaddr + MIICtrl); for (i = 10000; i > 0; i--) { if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0) break; } return;}static int epic_open(struct net_device *dev){ struct epic_private *ep = (struct epic_private *)dev->priv; long ioaddr = dev->base_addr; int i; int retval; ep->full_duplex = ep->force_fd; /* Soft reset the chip. */ outl(0x4001, ioaddr + GENCTL); MOD_INC_USE_COUNT; if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev))) { MOD_DEC_USE_COUNT; return retval; } epic_init_ring(dev); outl(0x4000, ioaddr + GENCTL); /* This next magic! line by Ken Yamaguchi.. ?? */ 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. */ outl(0x12, ioaddr + MIICfg); 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 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(ioaddr, ep->phys[0], 0, 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(ioaddr, ep->phys[0], 1)); outl(0x13, ioaddr + MIICfg); } } else { int mii_reg5 = mdio_read(ioaddr, ep->phys[0], 5); if (mii_reg5 != 0xffff) { if ((mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040) ep->full_duplex = 1; else if (! (mii_reg5 & 0x4000)) mdio_write(ioaddr, ep->phys[0], 0, 0x1200); if (debug > 1) printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d" " register read of %4.4x.\n", dev->name, ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5); } } outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); outl(virt_to_bus(ep->rx_ring), ioaddr + PRxCDAR); outl(virt_to_bus(ep->tx_ring), 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 | TxDone | TxEmpty | RxError | RxOverflow | RxFull | RxHeader | RxDone, 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->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 = (struct epic_private *)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); } /* Remove the packets on the Rx queue. */ epic_rx(dev);}static void epic_restart(struct net_device *dev){ long ioaddr = dev->base_addr; struct epic_private *ep = (struct epic_private *)dev->priv; int i; printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n", dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx); /* Soft reset the chip. */ outl(0x0001, ioaddr + GENCTL); udelay(1); /* Duplicate code from epic_open(). */ outl(0x0008, ioaddr + TEST1);#if defined(__powerpc__) || defined(__sparc__) /* Big endian */ outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);#else outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);#endif outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); if (ep->chip_flags & MII_PWRDWN) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); 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); outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); outl(virt_to_bus(&ep->rx_ring[ep->cur_rx%RX_RING_SIZE]), ioaddr + PRxCDAR); outl(virt_to_bus(&ep->tx_ring[ep->dirty_tx%TX_RING_SIZE]), ioaddr + PTxCDAR); /* Start the chip's Rx process. */ set_rx_mode(dev); outl(StartRx | RxQueued, ioaddr + COMMAND); /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) | CntFull | TxUnderrun | TxDone | TxEmpty | RxError | RxOverflow | RxFull | RxHeader | RxDone, ioaddr + INTMASK); printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), (int)inl(ioaddr + INTSTAT)); return;}static void epic_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct epic_private *ep = (struct epic_private *)dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; int mii_reg5 = ep->mii_phy_cnt ? mdio_read(ioaddr, ep->phys[0], 5) : 0; int negotiated = mii_reg5 & ep->advertising; int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; if (debug > 3) { printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n", dev->name, (int)inl(ioaddr + TxSTAT)); printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x " "IntStatus %4.4x RxStatus %4.4x.\n", dev->name, (int)inl(ioaddr + INTMASK), (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT)); } if (! ep->force_fd) { if (ep->full_duplex != duplex) { ep->full_duplex = duplex; printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" " partner capability of %4.4x.\n", dev->name, ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5); outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); } } ep->timer.expires = jiffies + next_tick; add_timer(&ep->timer);}static void epic_tx_timeout(struct net_device *dev){ struct epic_private *ep = (struct epic_private *)dev->priv; long ioaddr = dev->base_addr; if (debug > 0) { printk(KERN_WARNING "%s: Transmit timeout using MII device, " "Tx status %4.4x.\n", dev->name, (int)inw(ioaddr + TxSTAT)); if (debug > 1) { printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n", dev->name, ep->dirty_tx, ep->cur_tx); } } if (inw(ioaddr + TxSTAT) & 0x10) { /* Tx FIFO underflow. */ ep->stats.tx_fifo_errors++; outl(RestartTx, ioaddr + COMMAND); } else { epic_restart(dev); outl(TxQueued, dev->base_addr + COMMAND); } dev->trans_start = jiffies; ep->stats.tx_errors++; return;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void epic_init_ring(struct net_device *dev){ struct epic_private *ep = (struct epic_private *)dev->priv; int i; ep->tx_full = 0; ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; ep->dirty_tx = ep->cur_tx = 0; ep->cur_rx = ep->dirty_rx = 0; ep->last_rx_time = jiffies; ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); /* Initialize all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { ep->rx_ring[i].rxstatus = 0; ep->rx_ring[i].buflength = cpu_to_le32(ep->rx_buf_sz); ep->rx_ring[i].next = virt_to_le32desc(&ep->rx_ring[i+1]); ep->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ ep->rx_ring[i-1].next = virt_to_le32desc(&ep->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(ep->rx_buf_sz); ep->rx_skbuff[i] = skb; if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ ep->rx_ring[i].bufaddr = virt_to_le32desc(skb->tail); ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn); } ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* The Tx buffer descriptor is filled in as needed, but we do need to clear the ownership bit. */ for (i = 0; i < TX_RING_SIZE; i++) { ep->tx_skbuff[i] = 0; ep->tx_ring[i].txstatus = 0x0000; ep->tx_ring[i].next = virt_to_le32desc(&ep->tx_ring[i+1]); } ep->tx_ring[i-1].next = virt_to_le32desc(&ep->tx_ring[0]); return;}static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct epic_private *ep = (struct epic_private *)dev->priv; int entry, free_count; u32 ctrl_word; /* Caution: the write order is important here, set the field with the "ownership" bit last. */ spin_lock_irq(&ep->lock); /* Calculate the next Tx descriptor entry. */ free_count = ep->cur_tx - ep->dirty_tx; entry = ep->cur_tx % TX_RING_SIZE; ep->tx_skbuff[entry] = skb; ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data); if (free_count < TX_QUEUE_LEN/2) {/* Typical path */ ctrl_word = cpu_to_le32(0x100000); /* No interrupt */ } else if (free_count == TX_QUEUE_LEN/2) { ctrl_word = cpu_to_le32(0x140000); /* Tx-done intr. */ } else if (free_count < TX_QUEUE_LEN - 1) { ctrl_word = cpu_to_le32(0x100000); /* No Tx-done intr. */ } else { /* Leave room for an additional entry. */ ctrl_word = cpu_to_le32(0x140000); /* Tx-done intr. */ ep->tx_full = 1; } ep->tx_ring[entry].buflength = ctrl_word | cpu_to_le32(skb->len); ep->tx_ring[entry].txstatus = ((skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN) << 16) | cpu_to_le32(DescOwn); ep->cur_tx++; if (ep->tx_full) netif_stop_queue(dev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -