📄 hamachi.c
字号:
err_out: return ret;}static int __init read_eeprom(long ioaddr, int location){ int bogus_cnt = 1000; /* We should check busy first - per docs -KDU */ while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); writew(location, ioaddr + EEAddr); writeb(0x02, ioaddr + EECmdStatus); bogus_cnt = 1000; while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); if (hamachi_debug > 5) printk(" EEPROM status is %2.2x after %d ticks.\n", (int)readb(ioaddr + EECmdStatus), 1000- bogus_cnt); return readb(ioaddr + EEData);}/* MII Managemen Data I/O accesses. These routines assume the MDIO controller is idle, and do not exit until the command is finished. */static int mdio_read(long ioaddr, int phy_id, int location){ int i; /* We should check busy first - per docs -KDU */ for (i = 10000; i >= 0; i--) if ((readw(ioaddr + MII_Status) & 1) == 0) break; writew((phy_id<<8) + location, ioaddr + MII_Addr); writew(0x0001, ioaddr + MII_Cmd); for (i = 10000; i >= 0; i--) if ((readw(ioaddr + MII_Status) & 1) == 0) break; return readw(ioaddr + MII_Rd_Data);}static void mdio_write(long ioaddr, int phy_id, int location, int value){ int i; /* We should check busy first - per docs -KDU */ for (i = 10000; i >= 0; i--) if ((readw(ioaddr + MII_Status) & 1) == 0) break; writew((phy_id<<8) + location, ioaddr + MII_Addr); writew(value, ioaddr + MII_Wr_Data); /* Wait for the command to finish. */ for (i = 10000; i >= 0; i--) if ((readw(ioaddr + MII_Status) & 1) == 0) break; return;}static int hamachi_open(struct net_device *dev){ struct hamachi_private *hmp = dev->priv; long ioaddr = dev->base_addr; int i; u32 rx_int_var, tx_int_var; u16 fifo_info; i = request_irq(dev->irq, &hamachi_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; if (hamachi_debug > 1) printk(KERN_DEBUG "%s: hamachi_open() irq %d.\n", dev->name, dev->irq); hamachi_init_ring(dev);#if ADDRLEN == 64 /* writellll anyone ? */ writel(cpu_to_le64(hmp->rx_ring_dma), ioaddr + RxPtr); writel(cpu_to_le64(hmp->rx_ring_dma) >> 32, ioaddr + RxPtr + 4); writel(cpu_to_le64(hmp->tx_ring_dma), ioaddr + TxPtr); writel(cpu_to_le64(hmp->tx_ring_dma) >> 32, ioaddr + TxPtr + 4);#else writel(cpu_to_le32(hmp->rx_ring_dma), ioaddr + RxPtr); writel(cpu_to_le32(hmp->tx_ring_dma), ioaddr + TxPtr);#endif /* TODO: It would make sense to organize this as words since the card * documentation does. -KDU */ for (i = 0; i < 6; i++) writeb(dev->dev_addr[i], ioaddr + StationAddr + i); /* Initialize other registers: with so many this eventually this will converted to an offset/value list. */ /* Configure the FIFO */ fifo_info = (readw(ioaddr + GPIO) & 0x00C0) >> 6; switch (fifo_info){ case 0 : /* No FIFO */ writew(0x0000, ioaddr + FIFOcfg); break; case 1 : /* Configure the FIFO for 512K external, 16K used for Tx. */ writew(0x0028, ioaddr + FIFOcfg); break; case 2 : /* Configure the FIFO for 1024 external, 32K used for Tx. */ writew(0x004C, ioaddr + FIFOcfg); break; case 3 : /* Configure the FIFO for 2048 external, 32K used for Tx. */ writew(0x006C, ioaddr + FIFOcfg); break; default : printk(KERN_WARNING "%s: Unsupported external memory config!\n", dev->name); /* Default to no FIFO */ writew(0x0000, ioaddr + FIFOcfg); break; } if (dev->if_port == 0) dev->if_port = hmp->default_port; /* Setting the Rx mode will start the Rx process. */ /* If someone didn't choose a duplex, default to full-duplex */ if (hmp->duplex_lock != 1) hmp->full_duplex = 1; /* always 1, takes no more time to do it */ writew(0x0001, ioaddr + RxChecksum);#ifdef TX_CHECKSUM writew(0x0001, ioaddr + TxChecksum);#else writew(0x0000, ioaddr + TxChecksum);#endif writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */ writew(0x215F, ioaddr + MACCnfg); writew(0x000C, ioaddr + FrameGap0); /* WHAT?!?!? Why isn't this documented somewhere? -KDU */ writew(0x1018, ioaddr + FrameGap1); /* Why do we enable receives/transmits here? -KDU */ writew(0x0780, ioaddr + MACCnfg2); /* Upper 16 bits control LEDs. */ /* Enable automatic generation of flow control frames, period 0xffff. */ writel(0x0030FFFF, ioaddr + FlowCtrl); writew(MAX_FRAME_SIZE, ioaddr + MaxFrameSize); /* dev->mtu+14 ??? */ /* Enable legacy links. */ writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ /* Initial Link LED to blinking red. */ writeb(0x03, ioaddr + LEDCtrl); /* Configure interrupt mitigation. This has a great effect on performance, so systems tuning should start here!. */ rx_int_var = hmp->rx_int_var; tx_int_var = hmp->tx_int_var; if (hamachi_debug > 1) { printk("max_tx_latency: %d, max_tx_gap: %d, min_tx_pkt: %d\n", tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8, (tx_int_var & 0x00ff0000) >> 16); printk("max_rx_latency: %d, max_rx_gap: %d, min_rx_pkt: %d\n", rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8, (rx_int_var & 0x00ff0000) >> 16); printk("rx_int_var: %x, tx_int_var: %x\n", rx_int_var, tx_int_var); } writel(tx_int_var, ioaddr + TxIntrCtrl); writel(rx_int_var, ioaddr + RxIntrCtrl); set_rx_mode(dev); netif_start_queue(dev); /* Enable interrupts by setting the interrupt mask. */ writel(0x80878787, ioaddr + InterruptEnable); writew(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ /* Configure and start the DMA channels. */ /* Burst sizes are in the low three bits: size = 4<<(val&7) */#if ADDRLEN == 64 writew(0x005D, ioaddr + RxDMACtrl); /* 128 dword bursts */ writew(0x005D, ioaddr + TxDMACtrl);#else writew(0x001D, ioaddr + RxDMACtrl); writew(0x001D, ioaddr + TxDMACtrl);#endif writew(0x0001, dev->base_addr + RxCmd); if (hamachi_debug > 2) { printk(KERN_DEBUG "%s: Done hamachi_open(), status: Rx %x Tx %x.\n", dev->name, readw(ioaddr + RxStatus), readw(ioaddr + TxStatus)); } /* Set the timer to check for link beat. */ init_timer(&hmp->timer); hmp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ hmp->timer.data = (unsigned long)dev; hmp->timer.function = &hamachi_timer; /* timer handler */ add_timer(&hmp->timer); return 0;}static inline int hamachi_tx(struct net_device *dev){ struct hamachi_private *hmp = dev->priv; /* Update the dirty pointer until we find an entry that is still owned by the card */ for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++) { int entry = hmp->dirty_tx % TX_RING_SIZE; struct sk_buff *skb; if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) break; /* Free the original skb. */ skb = hmp->tx_skbuff[entry]; if (skb != 0) { pci_unmap_single(hmp->pci_dev, hmp->tx_ring[entry].addr, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); hmp->tx_skbuff[entry] = 0; } hmp->tx_ring[entry].status_n_length = 0; if (entry >= TX_RING_SIZE-1) hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); hmp->stats.tx_packets++; } return 0;}static void hamachi_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct hamachi_private *hmp = dev->priv; long ioaddr = dev->base_addr; int next_tick = 10*HZ; if (hamachi_debug > 2) { printk(KERN_INFO "%s: Hamachi Autonegotiation status %4.4x, LPA " "%4.4x.\n", dev->name, readw(ioaddr + ANStatus), readw(ioaddr + ANLinkPartnerAbility)); printk(KERN_INFO "%s: Autonegotiation regs %4.4x %4.4x %4.4x " "%4.4x %4.4x %4.4x.\n", dev->name, readw(ioaddr + 0x0e0), readw(ioaddr + 0x0e2), readw(ioaddr + 0x0e4), readw(ioaddr + 0x0e6), readw(ioaddr + 0x0e8), readw(ioaddr + 0x0eA)); } /* We could do something here... nah. */ hmp->timer.expires = RUN_AT(next_tick); add_timer(&hmp->timer);}static void hamachi_tx_timeout(struct net_device *dev){ int i; struct hamachi_private *hmp = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x," " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus)); { int i; printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length); printk("\n"KERN_DEBUG" Tx ring %p: ", hmp->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) printk(" %4.4x", hmp->tx_ring[i].status_n_length); printk("\n"); } /* Reinit the hardware and make sure the Rx and Tx processes are up and running. */ dev->if_port = 0; /* The right way to do Reset. -KDU * -Clear OWN bit in all Rx/Tx descriptors * -Wait 50 uS for channels to go idle * -Turn off MAC receiver * -Issue Reset */ for (i = 0; i < RX_RING_SIZE; i++) hmp->rx_ring[i].status_n_length &= cpu_to_le32(~DescOwn); /* Presume that all packets in the Tx queue are gone if we have to * re-init the hardware. */ for (i = 0; i < TX_RING_SIZE; i++){ struct sk_buff *skb; if (i >= TX_RING_SIZE - 1) hmp->tx_ring[i].status_n_length = cpu_to_le32( DescEndRing | (hmp->tx_ring[i].status_n_length & 0x0000FFFF)); else hmp->tx_ring[i].status_n_length &= 0x0000ffff; skb = hmp->tx_skbuff[i]; if (skb){ pci_unmap_single(hmp->pci_dev, hmp->tx_ring[i].addr, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); hmp->tx_skbuff[i] = 0; } } udelay(60); /* Sleep 60 us just for safety sake */ writew(0x0002, dev->base_addr + RxCmd); /* STOP Rx */ writeb(0x01, ioaddr + ChipReset); /* Reinit the hardware */ hmp->tx_full = 0; hmp->cur_rx = hmp->cur_tx = 0; hmp->dirty_rx = hmp->dirty_tx = 0; /* Rx packets are also presumed lost; however, we need to make sure a * ring of buffers is in tact. -KDU */ for (i = 0; i < RX_RING_SIZE; i++){ struct sk_buff *skb = hmp->rx_skbuff[i]; if (skb){ pci_unmap_single(hmp->pci_dev, hmp->rx_ring[i].addr, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); hmp->rx_skbuff[i] = 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(hmp->rx_buf_sz); hmp->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. */ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2)); } hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as wrapping the ring. */ hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); /* Trigger an immediate transmit demand. */ dev->trans_start = jiffies; hmp->stats.tx_errors++; /* Restart the chip's Tx/Rx processes . */ writew(0x0002, dev->base_addr + TxCmd); /* STOP Tx */ writew(0x0001, dev->base_addr + TxCmd); /* START Tx */ writew(0x0001, dev->base_addr + RxCmd); /* START Rx */ netif_wake_queue(dev);}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void hamachi_init_ring(struct net_device *dev){ struct hamachi_private *hmp = dev->priv; int i; hmp->tx_full = 0; hmp->cur_rx = hmp->cur_tx = 0; hmp->dirty_rx = hmp->dirty_tx = 0;#if 0 /* This is wrong. I'm not sure what the original plan was, but this * is wrong. An MTU of 1 gets you a buffer of 1536, while an MTU * of 1501 gets a buffer of 1533? -KDU */ hmp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);#endif /* My attempt at a reasonable correction */ /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the * card needs room to do 8 byte alignment, +2 so we can reserve * the first 2 bytes, and +16 gets room for the status word from the * card. -KDU
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -