📄 3c359.c
字号:
temp_ring_loc++ ; temp_ring_loc &= (XL_RX_RING_SIZE-1) ; } frame_length = xl_priv->xl_rx_ring[temp_ring_loc].framestatus & 0x7FFF ; skb = dev_alloc_skb(frame_length) ; if (skb==NULL) { /* No memory for frame, still need to roll forward the rx ring */ printk(KERN_WARNING "%s: dev_alloc_skb failed - multi buffer !\n", dev->name) ; while (xl_priv->rx_ring_tail != temp_ring_loc) adv_rx_ring(dev) ; adv_rx_ring(dev) ; /* One more time just for luck :) */ xl_priv->xl_stats.rx_dropped++ ; writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; return ; } skb->dev = dev ; while (xl_priv->rx_ring_tail != temp_ring_loc) { copy_len = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen & 0x7FFF ; frame_length -= copy_len ; pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, copy_len) ; pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; adv_rx_ring(dev) ; } /* Now we have found the last fragment */ pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, frame_length) ; /* memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */ pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; adv_rx_ring(dev) ; skb->protocol = tr_type_trans(skb,dev) ; netif_rx(skb) ; } else { /* Single Descriptor Used, simply swap buffers over, fast path */ frame_length = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & 0x7FFF ; skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; if (skb==NULL) { /* Still need to fix the rx ring */ printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer \n",dev->name) ; adv_rx_ring(dev) ; xl_priv->xl_stats.rx_dropped++ ; writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; return ; } skb->dev = dev ; skb2 = xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] ; pci_unmap_single(xl_priv->pdev, xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr, xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; skb_put(skb2, frame_length) ; skb2->protocol = tr_type_trans(skb2,dev) ; xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] = skb ; xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr = pci_map_single(xl_priv->pdev,skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen = xl_priv->pkt_buf_sz | RXUPLASTFRAG ; adv_rx_ring(dev) ; xl_priv->xl_stats.rx_packets++ ; xl_priv->xl_stats.rx_bytes += frame_length ; netif_rx(skb2) ; } /* if multiple buffers */ dev->last_rx = jiffies ; } /* while packet to do */ /* Clear the updComplete interrupt */ writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; return ; }/* * This is ruthless, it doesn't care what state the card is in it will * completely reset the adapter. */static void xl_reset(struct net_device *dev) { struct xl_private *xl_priv=(struct xl_private *)dev->priv; u8 __iomem * xl_mmio = xl_priv->xl_mmio ; unsigned long t; writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; /* * Must wait for cmdInProgress bit (12) to clear before continuing with * card configuration. */ t=jiffies; while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { if(jiffies-t > 40*HZ) { printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); break ; } } }static void xl_freemem(struct net_device *dev) { struct xl_private *xl_priv=(struct xl_private *)dev->priv ; int i ; for (i=0;i<XL_RX_RING_SIZE;i++) { dev_kfree_skb_irq(xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]) ; pci_unmap_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; xl_priv->rx_ring_tail++ ; xl_priv->rx_ring_tail &= XL_RX_RING_SIZE-1; } /* unmap ring */ pci_unmap_single(xl_priv->pdev,xl_priv->rx_ring_dma_addr, sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE, PCI_DMA_FROMDEVICE) ; pci_unmap_single(xl_priv->pdev,xl_priv->tx_ring_dma_addr, sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE, PCI_DMA_TODEVICE) ; kfree(xl_priv->xl_rx_ring) ; kfree(xl_priv->xl_tx_ring) ; return ; }static irqreturn_t xl_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; struct xl_private *xl_priv =(struct xl_private *)dev->priv; u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u16 intstatus, macstatus ; if (!dev) { printk(KERN_WARNING "Device structure dead, aaahhhh !\n") ; return IRQ_NONE; } intstatus = readw(xl_mmio + MMIO_INTSTATUS) ; if (!(intstatus & 1)) /* We didn't generate the interrupt */ return IRQ_NONE; spin_lock(&xl_priv->xl_lock) ; /* * Process the interrupt */ /* * Something fishy going on here, we shouldn't get 0001 ints, not fatal though. */ if (intstatus == 0x0001) { writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; printk(KERN_INFO "%s: 00001 int received \n",dev->name) ; } else { if (intstatus & (HOSTERRINT | SRBRINT | ARBCINT | UPCOMPINT | DNCOMPINT | HARDERRINT | (1<<8) | TXUNDERRUN | ASBFINT)) { /* * Host Error. * It may be possible to recover from this, but usually it means something * is seriously fubar, so we just close the adapter. */ if (intstatus & HOSTERRINT) { printk(KERN_WARNING "%s: Host Error, performing global reset, intstatus = %04x \n",dev->name,intstatus) ; writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); netif_stop_queue(dev) ; xl_freemem(dev) ; free_irq(dev->irq,dev); xl_reset(dev) ; writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; spin_unlock(&xl_priv->xl_lock) ; return IRQ_HANDLED; } /* Host Error */ if (intstatus & SRBRINT ) { /* Srbc interrupt */ writel(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; if (xl_priv->srb_queued) xl_srb_bh(dev) ; } /* SRBR Interrupt */ if (intstatus & TXUNDERRUN) { /* Issue DnReset command */ writel(DNRESET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { /* Wait for command to run */ /* !!! FIX-ME !!!! Must put a timeout check here ! */ /* Empty Loop */ } printk(KERN_WARNING "%s: TX Underrun received \n",dev->name) ; writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; } /* TxUnderRun */ if (intstatus & ARBCINT ) { /* Arbc interrupt */ xl_arb_cmd(dev) ; } /* Arbc */ if (intstatus & ASBFINT) { if (xl_priv->asb_queued == 1) { xl_asb_cmd(dev) ; } else if (xl_priv->asb_queued == 2) { xl_asb_bh(dev) ; } else { writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; } } /* Asbf */ if (intstatus & UPCOMPINT ) /* UpComplete */ xl_rx(dev) ; if (intstatus & DNCOMPINT ) /* DnComplete */ xl_dn_comp(dev) ; if (intstatus & HARDERRINT ) { /* Hardware error */ writel(MMIO_WORD_READ | MACSTATUS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; macstatus = readw(xl_mmio + MMIO_MACDATA) ; printk(KERN_WARNING "%s: MacStatusError, details: ", dev->name); if (macstatus & (1<<14)) printk(KERN_WARNING "tchk error: Unrecoverable error \n") ; if (macstatus & (1<<3)) printk(KERN_WARNING "eint error: Internal watchdog timer expired \n") ; if (macstatus & (1<<2)) printk(KERN_WARNING "aint error: Host tried to perform invalid operation \n") ; printk(KERN_WARNING "Instatus = %02x, macstatus = %02x\n",intstatus,macstatus) ; printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); netif_stop_queue(dev) ; xl_freemem(dev) ; free_irq(dev->irq,dev); unregister_netdev(dev) ; free_netdev(dev) ; xl_reset(dev) ; writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; spin_unlock(&xl_priv->xl_lock) ; return IRQ_HANDLED; } } else { printk(KERN_WARNING "%s: Received Unknown interrupt : %04x \n", dev->name, intstatus) ; writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; } } /* Turn interrupts back on */ writel( SETINDENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; writel( SETINTENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; spin_unlock(&xl_priv->xl_lock) ; return IRQ_HANDLED;} /* * Tx - Polling configuration */ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) { struct xl_private *xl_priv=(struct xl_private *)dev->priv; struct xl_tx_desc *txd ; int tx_head, tx_tail, tx_prev ; unsigned long flags ; spin_lock_irqsave(&xl_priv->xl_lock,flags) ; netif_stop_queue(dev) ; if (xl_priv->free_ring_entries > 1 ) { /* * Set up the descriptor for the packet */ tx_head = xl_priv->tx_ring_head ; tx_tail = xl_priv->tx_ring_tail ; txd = &(xl_priv->xl_tx_ring[tx_head]) ; txd->dnnextptr = 0 ; txd->framestartheader = skb->len | TXDNINDICATE ; txd->buffer = pci_map_single(xl_priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE) ; txd->buffer_length = skb->len | TXDNFRAGLAST ; xl_priv->tx_ring_skb[tx_head] = skb ; xl_priv->xl_stats.tx_packets++ ; xl_priv->xl_stats.tx_bytes += skb->len ; /* * Set the nextptr of the previous descriptor equal to this descriptor, add XL_TX_RING_SIZE -1 * to ensure no negative numbers in unsigned locations. */ tx_prev = (xl_priv->tx_ring_head + XL_TX_RING_SIZE - 1) & (XL_TX_RING_SIZE - 1) ; xl_priv->tx_ring_head++ ; xl_priv->tx_ring_head &= (XL_TX_RING_SIZE - 1) ; xl_priv->free_ring_entries-- ; xl_priv->xl_tx_ring[tx_prev].dnnextptr = xl_priv->tx_ring_dma_addr + (sizeof (struct xl_tx_desc) * tx_head) ; /* Sneaky, by doing a read on DnListPtr we can force the card to poll on the DnNextPtr */ /* readl(xl_mmio + MMIO_DNLISTPTR) ; */ netif_wake_queue(dev) ; spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; return 0; } else { spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; return 1; }} /* * The NIC has told us that a packet has been downloaded onto the card, we must * find out which packet it has done, clear the skb and information for the packet * then advance around the ring for all tranmitted packets */static void xl_dn_comp(struct net_device *dev) { struct xl_private *xl_priv=(struct xl_private *)dev->priv; u8 __iomem * xl_mmio = xl_priv->xl_mmio ; struct xl_tx_desc *txd ; if (xl_priv->tx_ring_tail == 255) {/* First time */ xl_priv->xl_tx_ring[0].framestartheader = 0 ; xl_priv->xl_tx_ring[0].dnnextptr = 0 ; xl_priv->tx_ring_tail = 1 ; } while (xl_priv->xl_tx_ring[xl_priv->tx_ring_tail].framestartheader & TXDNCOMPLETE ) { txd = &(xl_priv->xl_tx_ring[xl_priv->tx_ring_tail]) ; pci_unmap_single(xl_priv->pdev,txd->buffer, xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]->len, PCI_DMA_TODEVICE) ; txd->framestartheader = 0 ; txd->buffer = 0xdeadbeef ; txd->buffer_length = 0 ; dev_kfree_skb_irq(xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]) ; xl_priv->tx_ring_tail++ ; xl_priv->tx_ring_tail &= (XL_TX_RING_SIZE - 1) ; xl_priv->free_ring_entries++ ; } netif_wake_queue(dev) ; writel(ACK_INTERRUPT | DNCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; }/* * Close the adapter properly. * This srb reply cannot be handled from interrupt context as we have * to free the interrupt from the driver. */static int xl_close(struct net_device *dev) { struct xl_private *xl_priv = (struct xl_private *) dev->priv ; u8 __iomem * xl_mmio = xl_priv->xl_mmio ; unsigned long t ; netif_stop_queue(dev) ; /* * Close the adapter, need to stall the rx and tx queues. */ writew(DNSTALL, xl_mmio + MMIO_COMMAND) ; t=jiffies; while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { schedule(); if(jiffies-t > 10*HZ) { printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNSTALL not responding.\n", dev->name); break ; } } writew(DNDISABLE, xl_mmio + MMIO_COMMAND) ; t=jiffies; while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { schedule(); if(jiffies-t > 10*HZ) { printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNDISABLE not responding.\n", dev->name); break ; } } writew(UPSTALL, xl_mmio + MMIO_COMMAND) ; t=jiffies; while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { schedule(); if(jiffies-t > 10*HZ) { printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPSTALL not responding.\n", dev->name); break ; } } /* Turn off interrupts, we will still get the indication though * so we can trap it */ writel(SETINTENABLE, xl_mmio + MMIO_COMMAND) ; xl_srb_cmd(dev,CLOSE_NIC) ; t=jiffies; while (!(readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_SRB)) { schedule(); if(jiffies-t > 10*HZ) { printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-CLOSENIC not responding.\n", dev->name); break ; } } /* Read the srb response from the adapter */ writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD); if (readb(xl_mmio + MMIO_MACDATA) != CLOSE_NIC) { printk(KERN_INFO "%s: CLOSE_NIC did not get a CLOSE_NIC response \n",dev->name) ; } else { writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; if (readb(xl_mmio + MMIO_MACDATA)==0) { printk(KERN_INFO "%s: Adapter has been closed \n",dev->name) ; writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; xl_freemem(dev) ; free_irq(dev->irq,dev) ; } else { printk(KERN_INFO "%s: Close nic command returned error code %02x\n",dev->name, readb(xl_mmio + MMIO_MACDATA)) ; } } /* Reset the upload and download logic */ writew(UPRESET, xl_mmio + MMIO_COMMAND) ; t=jiffies; while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { schedule(); if(jiffies-t > 10*HZ) { printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPRESET not responding.\n", dev->name); break ; } } writew(DNRESET, xl_mmio + MMIO_COMMAND) ; t=jiffies; while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { schedule(); if(jiffies-t > 10*HZ) { printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNRESET not responding.\n", dev->name); break ; } } xl_hw_reset(dev) ; return 0 ;}static void xl_set_rx_mode(struct net_device *dev) { struct xl_private *xl_priv = (struct xl_private *) dev->priv ; struct dev_mc_list *dmi ; unsigned char dev_mc_address[4] ; u16 options ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -