ipg.c
来自「linux 内核源代码」· C语言 代码 · 共 2,341 行 · 第 1/5 页
C
2,341 行
rxfd = sp->rxd + entry; if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb) break; /* Get received frame length. */ framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; /* Check for jumbo frame arrival with too small * RXFRAG_SIZE. */ if (framelen > IPG_RXFRAG_SIZE) { IPG_DEBUG_MSG ("RFS FrameLen > allocated fragment size.\n"); framelen = IPG_RXFRAG_SIZE; } if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) { IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n", (unsigned long int) rxfd->rfs); /* Increment general receive error statistic. */ sp->stats.rx_errors++; /* Increment detailed receive error statistics. */ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { IPG_DEBUG_MSG("RX FIFO overrun occured.\n"); sp->stats.rx_fifo_errors++; } if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { IPG_DEBUG_MSG("RX runt occured.\n"); sp->stats.rx_length_errors++; } if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXOVERSIZEDFRAME) ; /* Do nothing, error count handled by a IPG * statistic register. */ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { IPG_DEBUG_MSG("RX alignment error occured.\n"); sp->stats.rx_frame_errors++; } if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFCSERROR) ; /* Do nothing, error count handled by a IPG * statistic register. */ /* Free the memory associated with the RX * buffer since it is erroneous and we will * not pass it to higher layer processes. */ if (skb) { __le64 info = rxfd->frag_info; pci_unmap_single(sp->pdev, le64_to_cpu(info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); IPG_DEV_KFREE_SKB(skb); } } else { /* Adjust the new buffer length to accomodate the size * of the received frame. */ skb_put(skb, framelen); /* Set the buffer's protocol field to Ethernet. */ skb->protocol = eth_type_trans(skb, dev); /* If the frame contains an IP/TCP/UDP frame, * determine if upper layer must check IP/TCP/UDP * checksums. * * NOTE: DO NOT RELY ON THE TCP/UDP CHECKSUM * VERIFICATION FOR SILICON REVISIONS B3 * AND EARLIER! * if ((le64_to_cpu(rxfd->rfs & (IPG_RFS_TCPDETECTED | IPG_RFS_UDPDETECTED | IPG_RFS_IPDETECTED))) && !(le64_to_cpu(rxfd->rfs & (IPG_RFS_TCPERROR | IPG_RFS_UDPERROR | IPG_RFS_IPERROR)))) { * Indicate IP checksums were performed * by the IPG. * skb->ip_summed = CHECKSUM_UNNECESSARY; } else */ { /* The IPG encountered an error with (or * there were no) IP/TCP/UDP checksums. * This may or may not indicate an invalid * IP/TCP/UDP frame was received. Let the * upper layer decide. */ skb->ip_summed = CHECKSUM_NONE; } /* Hand off frame for higher layer processing. * The function netif_rx() releases the sk_buff * when processing completes. */ netif_rx(skb); /* Record frame receive time (jiffies = Linux * kernel current time stamp). */ dev->last_rx = jiffies; } /* Assure RX buffer is not reused by IPG. */ sp->RxBuff[entry] = NULL; } /* * If there are more RFDs to proces and the allocated amount of RFD * processing time has expired, assert Interrupt Requested to make * sure we come back to process the remaining RFDs. */ if (i == IPG_MAXRFDPROCESS_COUNT) ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);#ifdef IPG_DEBUG /* Check if the RFD list contained no receive frame data. */ if (!i) sp->EmptyRFDListCount++;#endif while ((le64_to_cpu(rxfd->rfs) & IPG_RFS_RFDDONE) && !((le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) && (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND))) { unsigned int entry = curr++ % IPG_RFDLIST_LENGTH; rxfd = sp->rxd + entry; IPG_DEBUG_MSG("Frame requires multiple RFDs.\n"); /* An unexpected event, additional code needed to handle * properly. So for the time being, just disregard the * frame. */ /* Free the memory associated with the RX * buffer since it is erroneous and we will * not pass it to higher layer processes. */ if (sp->RxBuff[entry]) { pci_unmap_single(sp->pdev, le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); } /* Assure RX buffer is not reused by IPG. */ sp->RxBuff[entry] = NULL; } sp->rx_current = curr; /* Check to see if there are a minimum number of used * RFDs before restoring any (should improve performance.) */ if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE) ipg_nic_rxrestore(dev); return 0;}#endifstatic void ipg_reset_after_host_error(struct work_struct *work){ struct ipg_nic_private *sp = container_of(work, struct ipg_nic_private, task.work); struct net_device *dev = sp->dev; IPG_DDEBUG_MSG("DMACtrl = %8.8x\n", ioread32(sp->ioaddr + IPG_DMACTRL)); /* * Acknowledge HostError interrupt by resetting * IPG DMA and HOST. */ ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA); init_rfdlist(dev); init_tfdlist(dev); if (ipg_io_config(dev) < 0) { printk(KERN_INFO "%s: Cannot recover from PCI error.\n", dev->name); schedule_delayed_work(&sp->task, HZ); }}static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst){ struct net_device *dev = dev_inst; struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; unsigned int handled = 0; u16 status; IPG_DEBUG_MSG("_interrupt_handler\n");#ifdef JUMBO_FRAME ipg_nic_rxrestore(dev);#endif spin_lock(&sp->lock); /* Get interrupt source information, and acknowledge * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly, * IntRequested, MacControlFrame, LinkEvent) interrupts * if issued. Also, all IPG interrupts are disabled by * reading IntStatusAck. */ status = ipg_r16(INT_STATUS_ACK); IPG_DEBUG_MSG("IntStatusAck = %4.4x\n", status); /* Shared IRQ of remove event. */ if (!(status & IPG_IS_RSVD_MASK)) goto out_enable; handled = 1; if (unlikely(!netif_running(dev))) goto out_unlock; /* If RFDListEnd interrupt, restore all used RFDs. */ if (status & IPG_IS_RFD_LIST_END) { IPG_DEBUG_MSG("RFDListEnd Interrupt.\n"); /* The RFD list end indicates an RFD was encountered * with a 0 NextPtr, or with an RFDDone bit set to 1 * (indicating the RFD is not read for use by the * IPG.) Try to restore all RFDs. */ ipg_nic_rxrestore(dev);#ifdef IPG_DEBUG /* Increment the RFDlistendCount counter. */ sp->RFDlistendCount++;#endif } /* If RFDListEnd, RxDMAPriority, RxDMAComplete, or * IntRequested interrupt, process received frames. */ if ((status & IPG_IS_RX_DMA_PRIORITY) || (status & IPG_IS_RFD_LIST_END) || (status & IPG_IS_RX_DMA_COMPLETE) || (status & IPG_IS_INT_REQUESTED)) {#ifdef IPG_DEBUG /* Increment the RFD list checked counter if interrupted * only to check the RFD list. */ if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END | IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) & (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE | IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE | IPG_IS_UPDATE_STATS))) sp->RFDListCheckedCount++;#endif ipg_nic_rx(dev); } /* If TxDMAComplete interrupt, free used TFDs. */ if (status & IPG_IS_TX_DMA_COMPLETE) ipg_nic_txfree(dev); /* TxComplete interrupts indicate one of numerous actions. * Determine what action to take based on TXSTATUS register. */ if (status & IPG_IS_TX_COMPLETE) ipg_nic_txcleanup(dev); /* If UpdateStats interrupt, update Linux Ethernet statistics */ if (status & IPG_IS_UPDATE_STATS) ipg_nic_get_stats(dev); /* If HostError interrupt, reset IPG. */ if (status & IPG_IS_HOST_ERROR) { IPG_DDEBUG_MSG("HostError Interrupt\n"); schedule_delayed_work(&sp->task, 0); } /* If LinkEvent interrupt, resolve autonegotiation. */ if (status & IPG_IS_LINK_EVENT) { if (ipg_config_autoneg(dev) < 0) printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name); } /* If MACCtrlFrame interrupt, do nothing. */ if (status & IPG_IS_MAC_CTRL_FRAME) IPG_DEBUG_MSG("MACCtrlFrame interrupt.\n"); /* If RxComplete interrupt, do nothing. */ if (status & IPG_IS_RX_COMPLETE) IPG_DEBUG_MSG("RxComplete interrupt.\n"); /* If RxEarly interrupt, do nothing. */ if (status & IPG_IS_RX_EARLY) IPG_DEBUG_MSG("RxEarly interrupt.\n");out_enable: /* Re-enable IPG interrupts. */ ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE | IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE | IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE);out_unlock: spin_unlock(&sp->lock); return IRQ_RETVAL(handled);}static void ipg_rx_clear(struct ipg_nic_private *sp){ unsigned int i; for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { if (sp->RxBuff[i]) { struct ipg_rx *rxfd = sp->rxd + i; IPG_DEV_KFREE_SKB(sp->RxBuff[i]); sp->RxBuff[i] = NULL; pci_unmap_single(sp->pdev, le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); } }}static void ipg_tx_clear(struct ipg_nic_private *sp){ unsigned int i; for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { if (sp->TxBuff[i]) { struct ipg_tx *txfd = sp->txd + i; pci_unmap_single(sp->pdev, le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN, sp->TxBuff[i]->len, PCI_DMA_TODEVICE); IPG_DEV_KFREE_SKB(sp->TxBuff[i]); sp->TxBuff[i] = NULL; } }}static int ipg_nic_open(struct net_device *dev){ struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; struct pci_dev *pdev = sp->pdev; int rc; IPG_DEBUG_MSG("_nic_open\n"); sp->rx_buf_sz = IPG_RXSUPPORT_SIZE; /* Check for interrupt line conflicts, and request interrupt * line for IPG. * * IMPORTANT: Disable IPG interrupts prior to registering * IRQ. */ ipg_w16(0x0000, INT_ENABLE); /* Register the interrupt line to be used by the IPG within * the Linux system. */ rc = request_irq(pdev->irq, &ipg_interrupt_handler, IRQF_SHARED, dev->name, dev); if (rc < 0) { printk(KERN_INFO "%s: Error when requesting interrupt.\n", dev->name); goto out; } dev->irq = pdev->irq; rc = -ENOMEM; sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES, &sp->rxd_map, GFP_KERNEL); if (!sp->rxd) goto err_free_irq_0; sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES, &sp->txd_map, GFP_KERNEL); if (!sp->txd) goto err_free_rx_1; rc = init_rfdlist(dev); if (rc < 0) { printk(KERN_INFO "%s: Error during configuration.\n", dev->name); goto err_free_tx_2; } init_tfdlist(dev); rc = ipg_io_config(dev); if (rc < 0) { printk(KERN_INFO "%s: Error during configuration.\n", dev->name); goto err_release_tfdlist_3; } /* Resolve autonegotiation. */ if (ipg_config_autoneg(dev) < 0) printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name);#ifdef JUMBO_FRAME /* initialize JUMBO Frame control variable */ sp->Jumbo.FoundStart = 0; sp->Jumbo.CurrentSize = 0; sp->Jumbo.skb = 0; dev->mtu = IPG_TXFRAG_SIZE;#endif /* Enable transmit and receive operation of the IPG. */ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK, MAC_CTRL); netif_start_queue(dev);out: return rc;err_release_tfdlist_3: ipg_tx_clear(sp); ipg_rx_clear(sp);err_free_tx_2: dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);err_free_rx_1: dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);err_free_irq_0: free_irq(pdev->irq, dev); goto out;}static int ipg_nic_stop(struct net_device *dev){ struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; struct pci_dev *pdev = sp->pdev; IPG_DEBUG_MSG("_nic_stop\n"); netif_stop_queue(dev); IPG_DDEBUG_MSG("RFDlistendCount = %i\n", sp->RFDlistendCount); IPG_DDEBUG_MSG("RFDListCheckedCount = %i\n", sp->rxdCheckedCount); IPG_DDEBUG_MSG("EmptyRFDListCount = %i\n", sp->EmptyRFDListCount); IPG_DUMPTFDLIST(dev); do {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?