void pnic_do_nway(struct net_device *dev) { struct tulip_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->base_addr; u32 phy_reg = ioread32(ioaddr + 0xB8); u32 new_csr6 = tp->csr6 & ~0x40C40200; if (phy_reg & 0x78000000) { /* Ignore baseT4 */ if (phy_reg & 0x20000000) dev->if_port = 5; else if (phy_reg & 0x40000000) dev->if_port = 3; else if (phy_reg & 0x10000000) dev->if_port = 4; else if (phy_reg & 0x08000000) dev->if_port = 0; tp->nwayset = 1; new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000; iowrite32(0x32 | (dev->if_port & 1), ioaddr + CSR12); if (dev->if_port & 1) iowrite32(0x1F868, ioaddr + 0xB8); if (phy_reg & 0x30000000) { tp->full_duplex = 1; new_csr6 |= 0x00000200; } if (tulip_debug > 1) netdev_dbg(dev, "PNIC autonegotiated status %08x, %s\n", phy_reg, medianame[dev->if_port]); if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; /* Restart Tx */ tulip_restart_rxtx(tp); dev->trans_start = jiffies; } } }
/* Check the MII negotiated duplex, and change the CSR6 setting if required. Return 0 if everything is OK. Return < 0 if the transceiver is missing or has no link beat. */ int tulip_check_duplex(struct net_device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; int mii_reg1, mii_reg5, negotiated, duplex; if (tp->full_duplex_lock) return 0; mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5); if (tulip_debug > 1) printk(KERN_INFO "%s: MII status %4.4x, Link partner report " "%4.4x.\n", dev->name, mii_reg1, mii_reg5); if (mii_reg1 == 0xffff) return -2; if ((mii_reg1 & 0x0004) == 0) { int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); if ((new_reg1 & 0x0004) == 0) { if (tulip_debug > 1) printk(KERN_INFO "%s: No link beat on the MII interface," " status %4.4x.\n", dev->name, new_reg1); return -1; } } negotiated = mii_reg5 & tp->advertising[0]; duplex = ((negotiated & 0x0300) == 0x0100 || (negotiated & 0x00C0) == 0x0040); /* 100baseTx-FD or 10T-FD, but not 100-HD */ if (tp->full_duplex != duplex) { tp->full_duplex = duplex; if (negotiated & 0x038) /* 100mbps. */ tp->csr6 &= ~0x00400000; if (tp->full_duplex) tp->csr6 |= 0x0200; else tp->csr6 &= ~0x0200; tulip_restart_rxtx(tp, tp->csr6); if (tulip_debug > 0) printk(KERN_INFO "%s: Setting %s-duplex based on MII" "#%d link partner capability of %4.4x.\n", dev->name, tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); return 1; } return 0; }
void pnic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct tulip_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->base_addr; int next_tick = 60*HZ; if(!ioread32(ioaddr + CSR7)) { /* the timer was called due to a work overflow * in the interrupt handler. Skip the connection * checks, the nic is definitively speaking with * his link partner. */ goto too_good_connection; } if (tulip_media_cap[dev->if_port] & MediaIsMII) { spin_lock_irq(&tp->lock); if (tulip_check_duplex(dev) > 0) next_tick = 3*HZ; spin_unlock_irq(&tp->lock); } else { int csr12 = ioread32(ioaddr + CSR12); int new_csr6 = tp->csr6 & ~0x40C40200; int phy_reg = ioread32(ioaddr + 0xB8); int csr5 = ioread32(ioaddr + CSR5); if (tulip_debug > 1) netdev_dbg(dev, "PNIC timer PHY status %08x, %s CSR5 %08x\n", phy_reg, medianame[dev->if_port], csr5); if (phy_reg & 0x04000000) { /* Remote link fault */ iowrite32(0x0201F078, ioaddr + 0xB8); next_tick = 1*HZ; tp->nwayset = 0; } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */ pnic_do_nway(dev); next_tick = 60*HZ; } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ if (tulip_debug > 1) netdev_dbg(dev, "%s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n", medianame[dev->if_port], csr12, ioread32(ioaddr + CSR5), ioread32(ioaddr + 0xB8)); next_tick = 3*HZ; if (tp->medialock) { } else if (tp->nwayset && (dev->if_port & 1)) { next_tick = 1*HZ; } else if (dev->if_port == 0) { dev->if_port = 3; iowrite32(0x33, ioaddr + CSR12); new_csr6 = 0x01860000; iowrite32(0x1F868, ioaddr + 0xB8); } else { dev->if_port = 0; iowrite32(0x32, ioaddr + CSR12); new_csr6 = 0x00420000; iowrite32(0x1F078, ioaddr + 0xB8); } if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; /* Restart Tx */ tulip_restart_rxtx(tp); dev->trans_start = jiffies; if (tulip_debug > 1) dev_info(&dev->dev, "Changing PNIC configuration to %s %s-duplex, CSR6 %08x\n", medianame[dev->if_port], tp->full_duplex ? "full" : "half", new_csr6); } } } too_good_connection: mod_timer(&tp->timer, RUN_AT(next_tick)); if(!ioread32(ioaddr + CSR7)) { if (tulip_debug > 1) dev_info(&dev->dev, "sw timer wakeup\n"); disable_irq(dev->irq); tulip_refill_rx(dev); enable_irq(dev->irq); iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); } }
/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list of available transceivers. */ void t21142_media_task(struct work_struct *work) { struct tulip_private *tp = container_of(work, struct tulip_private, media_work); struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->base_addr; int csr12 = ioread32(ioaddr + CSR12); int next_tick = 60*HZ; int new_csr6 = 0; int csr14 = ioread32(ioaddr + CSR14); /* CSR12[LS10,LS100] are not reliable during autonegotiation */ if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000) csr12 |= 6; if (tulip_debug > 2) dev_info(&dev->dev, "21143 negotiation status %08x, %s\n", csr12, medianame[dev->if_port]); if (tulip_media_cap[dev->if_port] & MediaIsMII) { if (tulip_check_duplex(dev) < 0) { netif_carrier_off(dev); next_tick = 3*HZ; } else { netif_carrier_on(dev); next_tick = 60*HZ; } } else if (tp->nwayset) { /* Don't screw up a negotiated session! */ if (tulip_debug > 1) dev_info(&dev->dev, "Using NWay-set %s media, csr12 %08x\n", medianame[dev->if_port], csr12); } else if (tp->medialock) { ; } else if (dev->if_port == 3) { if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ if (tulip_debug > 1) dev_info(&dev->dev, "No 21143 100baseTx link beat, %08x, trying NWay\n", csr12); t21142_start_nway(dev); next_tick = 3*HZ; } } else if ((csr12 & 0x7000) != 0x5000) { /* Negotiation failed. Search media types. */ if (tulip_debug > 1) dev_info(&dev->dev, "21143 negotiation failed, status %08x\n", csr12); if (!(csr12 & 4)) { /* 10mbps link beat good. */ new_csr6 = 0x82420000; dev->if_port = 0; iowrite32(0, ioaddr + CSR13); iowrite32(0x0003FFFF, ioaddr + CSR14); iowrite16(t21142_csr15[dev->if_port], ioaddr + CSR15); iowrite32(t21142_csr13[dev->if_port], ioaddr + CSR13); } else { /* Select 100mbps port to check for link beat. */ new_csr6 = 0x83860000; dev->if_port = 3; iowrite32(0, ioaddr + CSR13); iowrite32(0x0003FFFF, ioaddr + CSR14); iowrite16(8, ioaddr + CSR15); iowrite32(1, ioaddr + CSR13); } if (tulip_debug > 1) dev_info(&dev->dev, "Testing new 21143 media %s\n", medianame[dev->if_port]); if (new_csr6 != (tp->csr6 & ~0x00D5)) { tp->csr6 &= 0x00D5; tp->csr6 |= new_csr6; iowrite32(0x0301, ioaddr + CSR12); tulip_restart_rxtx(tp); } next_tick = 3*HZ; } /* mod_timer synchronizes us with potential add_timer calls * from interrupts. */ mod_timer(&tp->timer, RUN_AT(next_tick)); }
static int tulip_rx(/*RTnet*/struct rtnet_device *rtdev, nanosecs_t *time_stamp) { struct tulip_private *tp = (struct tulip_private *)rtdev->priv; int entry = tp->cur_rx % RX_RING_SIZE; int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; int received = 0; if (tulip_debug > 4) /*RTnet*/rtdm_printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, tp->rx_ring[entry].status); /* If we own the next entry, it is a new packet. Send it up. */ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { s32 status = le32_to_cpu(tp->rx_ring[entry].status); if (tulip_debug > 5) /*RTnet*/rtdm_printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", rtdev->name, entry, status); if (--rx_work_limit < 0) break; if ((status & 0x38008300) != 0x0300) { if ((status & 0x38000300) != 0x0300) { /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { if (tulip_debug > 1) /*RTnet*/rtdm_printk(KERN_WARNING "%s: Oversized Ethernet frame " "spanned multiple buffers, status %8.8x!\n", rtdev->name, status); tp->stats.rx_length_errors++; } } else if (status & RxDescFatalErr) { /* There was a fatal error. */ if (tulip_debug > 2) /*RTnet*/rtdm_printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", rtdev->name, status); tp->stats.rx_errors++; /* end of a packet.*/ if (status & 0x0890) tp->stats.rx_length_errors++; if (status & 0x0004) tp->stats.rx_frame_errors++; if (status & 0x0002) tp->stats.rx_crc_errors++; if (status & 0x0001) tp->stats.rx_fifo_errors++; } } else { /* Omit the four octet CRC from the length. */ short pkt_len = ((status >> 16) & 0x7ff) - 4; struct /*RTnet*/rtskb *skb; #ifndef final_version if (pkt_len > 1518) { /*RTnet*/rtdm_printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", rtdev->name, pkt_len, pkt_len); pkt_len = 1518; tp->stats.rx_length_errors++; } #endif #if 0 /*RTnet*/ /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ if (pkt_len < tulip_rx_copybreak && (skb = /*RTnet*/dev_alloc_rtskb(pkt_len + 2)) != NULL) { skb->rtdev = rtdev; /*RTnet*/rtskb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single(tp->pdev, tp->rx_buffers[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) //eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, // pkt_len, 0); memcpy(rtskb_put(skb, pkt_len), tp->rx_buffers[entry].skb->tail, pkt_len); #else memcpy(/*RTnet*/rtskb_put(skb, pkt_len), tp->rx_buffers[entry].skb->tail, pkt_len); #endif } else { /* Pass up the skb already on the Rx ring. */ #endif /*RTnet*/ { char *temp = /*RTnet*/rtskb_put(skb = tp->rx_buffers[entry].skb, pkt_len); #ifndef final_version if (tp->rx_buffers[entry].mapping != le32_to_cpu(tp->rx_ring[entry].buffer1)) { /*RTnet*/rtdm_printk(KERN_ERR "%s: Internal fault: The skbuff addresses " "do not match in tulip_rx: %08x vs. %08x ? / %p.\n", rtdev->name, le32_to_cpu(tp->rx_ring[entry].buffer1), tp->rx_buffers[entry].mapping, temp);/*RTnet*/ } #endif pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); tp->rx_buffers[entry].skb = NULL; tp->rx_buffers[entry].mapping = 0; } skb->protocol = /*RTnet*/rt_eth_type_trans(skb, rtdev); skb->time_stamp = *time_stamp; /*RTnet*/rtnetif_rx(skb); tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; } received++; entry = (++tp->cur_rx) % RX_RING_SIZE; } return received; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ int tulip_interrupt(rtdm_irq_t *irq_handle) { nanosecs_t time_stamp = rtdm_clock_read();/*RTnet*/ struct rtnet_device *rtdev = rtdm_irq_get_arg(irq_handle, struct rtnet_device);/*RTnet*/ struct tulip_private *tp = (struct tulip_private *)rtdev->priv; long ioaddr = rtdev->base_addr; unsigned int csr5; int entry; int missed; int rx = 0; int tx = 0; int oi = 0; int maxrx = RX_RING_SIZE; int maxtx = TX_RING_SIZE; int maxoi = TX_RING_SIZE; unsigned int work_count = tulip_max_interrupt_work; /* Let's see whether the interrupt really is for us */ csr5 = inl(ioaddr + CSR5); if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) { rtdm_printk("%s: unexpected IRQ!\n",rtdev->name); return 0; } tp->nir++; do { /* Acknowledge all of the current interrupt sources ASAP. */ outl(csr5 & 0x0001ffff, ioaddr + CSR5); if (tulip_debug > 4) /*RTnet*/rtdm_printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", rtdev->name, csr5, inl(rtdev->base_addr + CSR5)); if (csr5 & (RxIntr | RxNoBuf)) { rx += tulip_rx(rtdev, &time_stamp); tulip_refill_rx(rtdev); } if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { unsigned int dirty_tx; rtdm_lock_get(&tp->lock); for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; dirty_tx++) { int entry = dirty_tx % TX_RING_SIZE; int status = le32_to_cpu(tp->tx_ring[entry].status); if (status < 0) break; /* It still has not been Txed */ /* Check for Rx filter setup frames. */ if (tp->tx_buffers[entry].skb == NULL) { /* test because dummy frames not mapped */ if (tp->tx_buffers[entry].mapping) pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, sizeof(tp->setup_frame), PCI_DMA_TODEVICE); continue; } if (status & 0x8000) { /* There was an major error, log it. */ #ifndef final_version if (tulip_debug > 1) /*RTnet*/rtdm_printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", rtdev->name, status); #endif tp->stats.tx_errors++; if (status & 0x4104) tp->stats.tx_aborted_errors++; if (status & 0x0C00) tp->stats.tx_carrier_errors++; if (status & 0x0200) tp->stats.tx_window_errors++; if (status & 0x0002) tp->stats.tx_fifo_errors++; if ((status & 0x0080) && tp->full_duplex == 0) tp->stats.tx_heartbeat_errors++; } else { tp->stats.tx_bytes += tp->tx_buffers[entry].skb->len; tp->stats.collisions += (status >> 3) & 15; tp->stats.tx_packets++; } pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, tp->tx_buffers[entry].skb->len, PCI_DMA_TODEVICE); /* Free the original skb. */ /*RTnet*/dev_kfree_rtskb(tp->tx_buffers[entry].skb); tp->tx_buffers[entry].skb = NULL; tp->tx_buffers[entry].mapping = 0; tx++; rtnetif_tx(rtdev); } #ifndef final_version if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { /*RTnet*/rtdm_printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d.\n", rtdev->name, dirty_tx, tp->cur_tx); dirty_tx += TX_RING_SIZE; } #endif if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) /*RTnet*/rtnetif_wake_queue(rtdev); tp->dirty_tx = dirty_tx; if (csr5 & TxDied) { if (tulip_debug > 2) /*RTnet*/rtdm_printk(KERN_WARNING "%s: The transmitter stopped." " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", rtdev->name, csr5, inl(ioaddr + CSR6), tp->csr6); tulip_restart_rxtx(tp); } rtdm_lock_put(&tp->lock); } /* Log errors. */ if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ if (csr5 == 0xffffffff) break; #if 0 /*RTnet*/ if (csr5 & TxJabber) tp->stats.tx_errors++; if (csr5 & TxFIFOUnderflow) { if ((tp->csr6 & 0xC000) != 0xC000) tp->csr6 += 0x4000; /* Bump up the Tx threshold */ else tp->csr6 |= 0x00200000; /* Store-n-forward. */ /* Restart the transmit process. */ tulip_restart_rxtx(tp); outl(0, ioaddr + CSR1); } if (csr5 & (RxDied | RxNoBuf)) { if (tp->flags & COMET_MAC_ADDR) { outl(tp->mc_filter[0], ioaddr + 0xAC); outl(tp->mc_filter[1], ioaddr + 0xB0); } } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; tp->stats.rx_errors++; tulip_start_rxtx(tp); } /* * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this * call is ever done under the spinlock */ if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { if (tp->link_change) (tp->link_change)(rtdev, csr5); } if (csr5 & SytemError) { int error = (csr5 >> 23) & 7; /* oops, we hit a PCI error. The code produced corresponds * to the reason: * 0 - parity error * 1 - master abort * 2 - target abort * Note that on parity error, we should do a software reset * of the chip to get it back into a sane state (according * to the 21142/3 docs that is). * -- rmk */ /*RTnet*/rtdm_printk(KERN_ERR "%s: (%lu) System Error occured (%d)\n", rtdev->name, tp->nir, error); } #endif /*RTnet*/ /*RTnet*/rtdm_printk(KERN_ERR "%s: Error detected, " "device may not work any more (csr5=%08x)!\n", rtdev->name, csr5); /* Clear all error sources, included undocumented ones! */ outl(0x0800f7ba, ioaddr + CSR5); oi++; }
/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list of available transceivers. */ void t21142_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; int csr12 = inl(ioaddr + CSR12); int next_tick = 60*HZ; int new_csr6 = 0; if (tulip_debug > 2) printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", dev->name, csr12, medianame[dev->if_port]); if (tulip_media_cap[dev->if_port] & MediaIsMII) { tulip_check_duplex(dev); next_tick = 60*HZ; } else if (tp->nwayset) { /* Don't screw up a negotiated session! */ if (tulip_debug > 1) printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", dev->name, medianame[dev->if_port], csr12); } else if (tp->medialock) { ; } else if (dev->if_port == 3) { if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ if (tulip_debug > 1) printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " "trying NWay.\n", dev->name, csr12); t21142_start_nway(dev); next_tick = 3*HZ; } } else if ((csr12 & 0x7000) != 0x5000) { /* Negotiation failed. Search media types. */ if (tulip_debug > 1) printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", dev->name, csr12); if (!(csr12 & 4)) { /* 10mbps link beat good. */ new_csr6 = 0x82420000; dev->if_port = 0; outl(0, ioaddr + CSR13); outl(0x0003FFFF, ioaddr + CSR14); outw(t21142_csr15[dev->if_port], ioaddr + CSR15); outl(t21142_csr13[dev->if_port], ioaddr + CSR13); } else { /* Select 100mbps port to check for link beat. */ new_csr6 = 0x83860000; dev->if_port = 3; outl(0, ioaddr + CSR13); outl(0x0003FF7F, ioaddr + CSR14); outw(8, ioaddr + CSR15); outl(1, ioaddr + CSR13); } if (tulip_debug > 1) printk(KERN_INFO"%s: Testing new 21143 media %s.\n", dev->name, medianame[dev->if_port]); if (new_csr6 != (tp->csr6 & ~0x00D5)) { tp->csr6 &= 0x00D5; tp->csr6 |= new_csr6; outl(0x0301, ioaddr + CSR12); tulip_restart_rxtx(tp); } next_tick = 3*HZ; } /* mod_timer synchronizes us with potential add_timer calls * from interrupts. */ mod_timer(&tp->timer, RUN_AT(next_tick)); }
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_instance; struct tulip_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->base_addr; int csr5; int missed; int rx = 0; int tx = 0; int oi = 0; int maxrx = RX_RING_SIZE; int maxtx = TX_RING_SIZE; int maxoi = TX_RING_SIZE; #ifdef CONFIG_TULIP_NAPI int rxd = 0; #else int entry; #endif unsigned int work_count = tulip_max_interrupt_work; unsigned int handled = 0; /* Let's see whether the interrupt really is for us */ csr5 = ioread32(ioaddr + CSR5); if (tp->flags & HAS_PHY_IRQ) handled = phy_interrupt (dev); if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) return IRQ_RETVAL(handled); tp->nir++; do { #ifdef CONFIG_TULIP_NAPI if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { rxd++; /* Mask RX intrs and add the device to poll list. */ iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); netif_rx_schedule(dev); if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) break; } /* Acknowledge the interrupt sources we handle here ASAP the poll function does Rx and RxNoBuf acking */ iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5); #else /* Acknowledge all of the current interrupt sources ASAP. */ iowrite32(csr5 & 0x0001ffff, ioaddr + CSR5); if (csr5 & (RxIntr | RxNoBuf)) { rx += tulip_rx(dev); tulip_refill_rx(dev); } #endif /* CONFIG_TULIP_NAPI */ if (tulip_debug > 4) printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", dev->name, csr5, ioread32(ioaddr + CSR5)); if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { unsigned int dirty_tx; spin_lock(&tp->lock); for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; dirty_tx++) { int entry = dirty_tx % TX_RING_SIZE; int status = le32_to_cpu(tp->tx_ring[entry].status); if (status < 0) break; /* It still has not been Txed */ /* Check for Rx filter setup frames. */ if (tp->tx_buffers[entry].skb == NULL) { /* test because dummy frames not mapped */ if (tp->tx_buffers[entry].mapping) pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, sizeof(tp->setup_frame), PCI_DMA_TODEVICE); continue; } if (status & 0x8000) { /* There was an major error, log it. */ #ifndef final_version if (tulip_debug > 1) printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", dev->name, status); #endif tp->stats.tx_errors++; if (status & 0x4104) tp->stats.tx_aborted_errors++; if (status & 0x0C00) tp->stats.tx_carrier_errors++; if (status & 0x0200) tp->stats.tx_window_errors++; if (status & 0x0002) tp->stats.tx_fifo_errors++; if ((status & 0x0080) && tp->full_duplex == 0) tp->stats.tx_heartbeat_errors++; } else { tp->stats.tx_bytes += tp->tx_buffers[entry].skb->len; tp->stats.collisions += (status >> 3) & 15; tp->stats.tx_packets++; } pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, tp->tx_buffers[entry].skb->len, PCI_DMA_TODEVICE); /* Free the original skb. */ dev_kfree_skb_irq(tp->tx_buffers[entry].skb); tp->tx_buffers[entry].skb = NULL; tp->tx_buffers[entry].mapping = 0; tx++; } #ifndef final_version if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d.\n", dev->name, dirty_tx, tp->cur_tx); dirty_tx += TX_RING_SIZE; } #endif if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) netif_wake_queue(dev); tp->dirty_tx = dirty_tx; if (csr5 & TxDied) { if (tulip_debug > 2) printk(KERN_WARNING "%s: The transmitter stopped." " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", dev->name, csr5, ioread32(ioaddr + CSR6), tp->csr6); tulip_restart_rxtx(tp); } spin_unlock(&tp->lock); } /* Log errors. */ if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ if (csr5 == 0xffffffff) break; if (csr5 & TxJabber) tp->stats.tx_errors++; if (csr5 & TxFIFOUnderflow) { if ((tp->csr6 & 0xC000) != 0xC000) tp->csr6 += 0x4000; /* Bump up the Tx threshold */ else tp->csr6 |= 0x00200000; /* Store-n-forward. */ /* Restart the transmit process. */ tulip_restart_rxtx(tp); iowrite32(0, ioaddr + CSR1); } if (csr5 & (RxDied | RxNoBuf)) { if (tp->flags & COMET_MAC_ADDR) { iowrite32(tp->mc_filter[0], ioaddr + 0xAC); iowrite32(tp->mc_filter[1], ioaddr + 0xB0); } } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff; tp->stats.rx_errors++; tulip_start_rxtx(tp); } /* * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this * call is ever done under the spinlock */ if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { if (tp->link_change) (tp->link_change)(dev, csr5); } if (csr5 & SytemError) { int error = (csr5 >> 23) & 7; /* oops, we hit a PCI error. The code produced corresponds * to the reason: * 0 - parity error * 1 - master abort * 2 - target abort * Note that on parity error, we should do a software reset * of the chip to get it back into a sane state (according * to the 21142/3 docs that is). * -- rmk */ printk(KERN_ERR "%s: (%lu) System Error occurred (%d)\n", dev->name, tp->nir, error); } /* Clear all error sources, included undocumented ones! */ iowrite32(0x0800f7ba, ioaddr + CSR5); oi++; }
void t21142_media_task(struct work_struct *work) { struct tulip_private *tp = container_of(work, struct tulip_private, media_work); struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->base_addr; int csr12 = ioread32(ioaddr + CSR12); int next_tick = 60*HZ; int new_csr6 = 0; int csr14 = ioread32(ioaddr + CSR14); /* */ if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000) csr12 |= 6; if (tulip_debug > 2) dev_info(&dev->dev, "21143 negotiation status %08x, %s\n", csr12, medianame[dev->if_port]); if (tulip_media_cap[dev->if_port] & MediaIsMII) { if (tulip_check_duplex(dev) < 0) { netif_carrier_off(dev); next_tick = 3*HZ; } else { netif_carrier_on(dev); next_tick = 60*HZ; } } else if (tp->nwayset) { /* */ if (tulip_debug > 1) dev_info(&dev->dev, "Using NWay-set %s media, csr12 %08x\n", medianame[dev->if_port], csr12); } else if (tp->medialock) { ; } else if (dev->if_port == 3) { if (csr12 & 2) { /* */ if (tulip_debug > 1) dev_info(&dev->dev, "No 21143 100baseTx link beat, %08x, trying NWay\n", csr12); t21142_start_nway(dev); next_tick = 3*HZ; } } else if ((csr12 & 0x7000) != 0x5000) { /* */ if (tulip_debug > 1) dev_info(&dev->dev, "21143 negotiation failed, status %08x\n", csr12); if (!(csr12 & 4)) { /* */ new_csr6 = 0x82420000; dev->if_port = 0; iowrite32(0, ioaddr + CSR13); iowrite32(0x0003FFFF, ioaddr + CSR14); iowrite16(t21142_csr15[dev->if_port], ioaddr + CSR15); iowrite32(t21142_csr13[dev->if_port], ioaddr + CSR13); } else { /* */ new_csr6 = 0x83860000; dev->if_port = 3; iowrite32(0, ioaddr + CSR13); iowrite32(0x0003FFFF, ioaddr + CSR14); iowrite16(8, ioaddr + CSR15); iowrite32(1, ioaddr + CSR13); } if (tulip_debug > 1) dev_info(&dev->dev, "Testing new 21143 media %s\n", medianame[dev->if_port]); if (new_csr6 != (tp->csr6 & ~0x00D5)) { tp->csr6 &= 0x00D5; tp->csr6 |= new_csr6; iowrite32(0x0301, ioaddr + CSR12); tulip_restart_rxtx(tp); } next_tick = 3*HZ; } /* */ mod_timer(&tp->timer, RUN_AT(next_tick)); }
void pnic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct tulip_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->base_addr; int next_tick = 60*HZ; if(!ioread32(ioaddr + CSR7)) { goto too_good_connection; } if (tulip_media_cap[dev->if_port] & MediaIsMII) { spin_lock_irq(&tp->lock); if (tulip_check_duplex(dev) > 0) next_tick = 3*HZ; spin_unlock_irq(&tp->lock); } else { int csr12 = ioread32(ioaddr + CSR12); int new_csr6 = tp->csr6 & ~0x40C40200; int phy_reg = ioread32(ioaddr + 0xB8); int csr5 = ioread32(ioaddr + CSR5); if (tulip_debug > 1) printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s " "CSR5 %8.8x.\n", dev->name, phy_reg, medianame[dev->if_port], csr5); if (phy_reg & 0x04000000) { iowrite32(0x0201F078, ioaddr + 0xB8); next_tick = 1*HZ; tp->nwayset = 0; } else if (phy_reg & 0x78000000) { pnic_do_nway(dev); next_tick = 60*HZ; } else if (csr5 & TPLnkFail) { if (tulip_debug > 1) printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " "CSR5 %8.8x, PHY %3.3x.\n", dev->name, medianame[dev->if_port], csr12, ioread32(ioaddr + CSR5), ioread32(ioaddr + 0xB8)); next_tick = 3*HZ; if (tp->medialock) { } else if (tp->nwayset && (dev->if_port & 1)) { next_tick = 1*HZ; } else if (dev->if_port == 0) { dev->if_port = 3; iowrite32(0x33, ioaddr + CSR12); new_csr6 = 0x01860000; iowrite32(0x1F868, ioaddr + 0xB8); } else { dev->if_port = 0; iowrite32(0x32, ioaddr + CSR12); new_csr6 = 0x00420000; iowrite32(0x1F078, ioaddr + 0xB8); } if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; tulip_restart_rxtx(tp); dev->trans_start = jiffies; if (tulip_debug > 1) printk(KERN_INFO "%s: Changing PNIC configuration to %s " "%s-duplex, CSR6 %8.8x.\n", dev->name, medianame[dev->if_port], tp->full_duplex ? "full" : "half", new_csr6); } } } too_good_connection: mod_timer(&tp->timer, RUN_AT(next_tick)); if(!ioread32(ioaddr + CSR7)) { if (tulip_debug > 1) printk(KERN_INFO "%s: sw timer wakeup.\n", dev->name); disable_irq(dev->irq); tulip_refill_rx(dev); enable_irq(dev->irq); iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); } }