📄 via-velocity.c
字号:
* Scan the queues looking for transmitted packets that * we can complete and clean up. Update any statistics as * neccessary/ */ static int velocity_tx_srv(struct velocity_info *vptr, u32 status){ struct tx_desc *td; int qnum; int full = 0; int idx; int works = 0; struct velocity_td_info *tdinfo; struct net_device_stats *stats = &vptr->stats; for (qnum = 0; qnum < vptr->num_txq; qnum++) { for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0; idx = (idx + 1) % vptr->options.numtx) { /* * Get Tx Descriptor */ td = &(vptr->td_rings[qnum][idx]); tdinfo = &(vptr->td_infos[qnum][idx]); if (td->tdesc0.owner == OWNED_BY_NIC) break; if ((works++ > 15)) break; if (td->tdesc0.TSR & TSR0_TERR) { stats->tx_errors++; stats->tx_dropped++; if (td->tdesc0.TSR & TSR0_CDH) stats->tx_heartbeat_errors++; if (td->tdesc0.TSR & TSR0_CRS) stats->tx_carrier_errors++; if (td->tdesc0.TSR & TSR0_ABT) stats->tx_aborted_errors++; if (td->tdesc0.TSR & TSR0_OWC) stats->tx_window_errors++; } else { stats->tx_packets++; stats->tx_bytes += tdinfo->skb->len; } velocity_free_tx_buf(vptr, tdinfo); vptr->td_used[qnum]--; } vptr->td_tail[qnum] = idx; if (AVAIL_TD(vptr, qnum) < 1) { full = 1; } } /* * Look to see if we should kick the transmit network * layer for more work. */ if (netif_queue_stopped(vptr->dev) && (full == 0) && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) { netif_wake_queue(vptr->dev); } return works;}/** * velocity_print_link_status - link status reporting * @vptr: velocity to report on * * Turn the link status of the velocity card into a kernel log * description of the new link state, detailing speed and duplex * status */static void velocity_print_link_status(struct velocity_info *vptr){ if (vptr->mii_status & VELOCITY_LINK_FAIL) { VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name); } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) { VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link autonegation", vptr->dev->name); if (vptr->mii_status & VELOCITY_SPEED_1000) VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps"); else if (vptr->mii_status & VELOCITY_SPEED_100) VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps"); else VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps"); if (vptr->mii_status & VELOCITY_DUPLEX_FULL) VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n"); else VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n"); } else { VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name); switch (vptr->options.spd_dpx) { case SPD_DPX_100_HALF: VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n"); break; case SPD_DPX_100_FULL: VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n"); break; case SPD_DPX_10_HALF: VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n"); break; case SPD_DPX_10_FULL: VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n"); break; default: break; } }}/** * velocity_error - handle error from controller * @vptr: velocity * @status: card status * * Process an error report from the hardware and attempt to recover * the card itself. At the moment we cannot recover from some * theoretically impossible errors but this could be fixed using * the pci_device_failed logic to bounce the hardware * */ static void velocity_error(struct velocity_info *vptr, int status){ if (status & ISR_TXSTLI) { struct mac_regs * regs = vptr->mac_regs; printk(KERN_ERR "TD structure errror TDindex=%hx\n", readw(®s->TDIdx[0])); BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR); writew(TRDCSR_RUN, ®s->TDCSRClr); netif_stop_queue(vptr->dev); /* FIXME: port over the pci_device_failed code and use it here */ } if (status & ISR_SRCI) { struct mac_regs * regs = vptr->mac_regs; int linked; if (vptr->options.spd_dpx == SPD_DPX_AUTO) { vptr->mii_status = check_connection_type(regs); /* * If it is a 3119, disable frame bursting in * halfduplex mode and enable it in fullduplex * mode */ if (vptr->rev_id < REV_ID_VT3216_A0) { if (vptr->mii_status | VELOCITY_DUPLEX_FULL) BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); else BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); } /* * Only enable CD heart beat counter in 10HD mode */ if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) { BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); } else { BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); } } /* * Get link status from PHYSR0 */ linked = readb(®s->PHYSR0) & PHYSR0_LINKGD; if (linked) { vptr->mii_status &= ~VELOCITY_LINK_FAIL; } else { vptr->mii_status |= VELOCITY_LINK_FAIL; } velocity_print_link_status(vptr); enable_flow_control_ability(vptr); /* * Re-enable auto-polling because SRCI will disable * auto-polling */ enable_mii_autopoll(regs); if (vptr->mii_status & VELOCITY_LINK_FAIL) netif_stop_queue(vptr->dev); else netif_wake_queue(vptr->dev); }; if (status & ISR_MIBFI) velocity_update_hw_mibs(vptr); if (status & ISR_LSTEI) mac_rx_queue_wake(vptr->mac_regs);}/** * velocity_free_tx_buf - free transmit buffer * @vptr: velocity * @tdinfo: buffer * * Release an transmit buffer. If the buffer was preallocated then * recycle it, if not then unmap the buffer. */ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo){ struct sk_buff *skb = tdinfo->skb; int i; /* * Don't unmap the pre-allocated tx_bufs */ if (tdinfo->skb_dma && (tdinfo->skb_dma[0] != tdinfo->buf_dma)) { for (i = 0; i < tdinfo->nskb_dma; i++) {#ifdef VELOCITY_ZERO_COPY_SUPPORT pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], td->tdesc1.len, PCI_DMA_TODEVICE);#else pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], skb->len, PCI_DMA_TODEVICE);#endif tdinfo->skb_dma[i] = 0; } } dev_kfree_skb_irq(skb); tdinfo->skb = NULL;}/** * velocity_open - interface activation callback * @dev: network layer device to open * * Called when the network layer brings the interface up. Returns * a negative posix error code on failure, or zero on success. * * All the ring allocation and set up is done on open for this * adapter to minimise memory usage when inactive */ static int velocity_open(struct net_device *dev){ struct velocity_info *vptr = dev->priv; int ret; vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32); ret = velocity_init_rings(vptr); if (ret < 0) goto out; ret = velocity_init_rd_ring(vptr); if (ret < 0) goto err_free_desc_rings; ret = velocity_init_td_ring(vptr); if (ret < 0) goto err_free_rd_ring; /* Ensure chip is running */ pci_set_power_state(vptr->pdev, 0); velocity_init_registers(vptr, VELOCITY_INIT_COLD); ret = request_irq(vptr->pdev->irq, &velocity_intr, SA_SHIRQ, dev->name, dev); if (ret < 0) { /* Power down the chip */ pci_set_power_state(vptr->pdev, 3); goto err_free_td_ring; } mac_enable_int(vptr->mac_regs); netif_start_queue(dev); vptr->flags |= VELOCITY_FLAGS_OPENED;out: return ret;err_free_td_ring: velocity_free_td_ring(vptr);err_free_rd_ring: velocity_free_rd_ring(vptr);err_free_desc_rings: velocity_free_rings(vptr); goto out;}/** * velocity_change_mtu - MTU change callback * @dev: network device * @new_mtu: desired MTU * * Handle requests from the networking layer for MTU change on * this interface. It gets called on a change by the network layer. * Return zero for success or negative posix error code. */ static int velocity_change_mtu(struct net_device *dev, int new_mtu){ struct velocity_info *vptr = dev->priv; unsigned long flags; int oldmtu = dev->mtu; int ret = 0; if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) { VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n", vptr->dev->name); return -EINVAL; } if (new_mtu != oldmtu) { spin_lock_irqsave(&vptr->lock, flags); netif_stop_queue(dev); velocity_shutdown(vptr); velocity_free_td_ring(vptr); velocity_free_rd_ring(vptr); dev->mtu = new_mtu; if (new_mtu > 8192) vptr->rx_buf_sz = 9 * 1024; else if (new_mtu > 4096) vptr->rx_buf_sz = 8192; else vptr->rx_buf_sz = 4 * 1024; ret = velocity_init_rd_ring(vptr); if (ret < 0) goto out_unlock; ret = velocity_init_td_ring(vptr); if (ret < 0) goto out_unlock; velocity_init_registers(vptr, VELOCITY_INIT_COLD); mac_enable_int(vptr->mac_regs); netif_start_queue(dev);out_unlock: spin_unlock_irqrestore(&vptr->lock, flags); } return ret;}/** * velocity_shutdown - shut down the chip * @vptr: velocity to deactivate * * Shuts down the internal operations of the velocity and * disables interrupts, autopolling, transmit and receive */ static void velocity_shutdown(struct velocity_info *vptr){ struct mac_regs * regs = vptr->mac_regs; mac_disable_int(regs); writel(CR0_STOP, ®s->CR0Set); writew(0xFFFF, ®s->TDCSRClr); writeb(0xFF, ®s->RDCSRClr); safe_disable_mii_autopoll(regs); mac_clear_isr(regs);}/** * velocity_close - close adapter callback * @dev: network device * * Callback from the network layer when the velocity is being * deactivated by the network layer */static int velocity_close(struct net_device *dev){ struct velocity_info *vptr = dev->priv; netif_stop_queue(dev); velocity_shutdown(vptr); if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) velocity_get_ip(vptr); if (dev->irq != 0) free_irq(dev->irq, dev); /* Power down the chip */ pci_set_power_state(vptr->pdev, 3); /* Free the resources */ velocity_free_td_ring(vptr); velocity_free_rd_ring(vptr); velocity_free_rings(vptr); vptr->flags &= (~VELOCITY_FLAGS_OPENED); return 0;}/** * velocity_xmit - transmit packet callback * @skb: buffer to transmit * @dev: network device * * Called by the networ layer to request a packet is queued to * the velocity. Returns zero on success. */ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev){ struct velocity_info *vptr = dev->priv; int qnum = 0; struct tx_desc *td_ptr; struct velocity_td_info *tdinfo; unsigned long flags; int index; int pktlen = skb->len; spin_lock_irqsave(&vptr->lock, flags); index = vptr->td_curr[qnum]; td_ptr = &(vptr->td_rings[qnum][index]); tdinfo = &(vptr->td_infos[qnum][index]); td_ptr->tdesc1.TCPLS = TCPLS_NORMAL; td_ptr->tdesc1.TCR = TCR0_TIC; td_ptr->td_buf[0].queue = 0; /* * Pad short frames. */ if (pktlen < ETH_ZLEN) { /* Cannot occur until ZC support */ if(skb_linearize(skb, GFP_ATOMIC)) return 0; pktlen = ETH_ZLEN; memcpy(tdinfo->buf, skb->data, skb->len); memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len); tdinfo->skb = skb; tdinfo->skb_dma[0] = tdinfo->buf_dma; td_ptr->tdesc0.pktsize = pktlen; td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); td_ptr->td_buf[0].pa_high = 0; td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize; tdinfo->nskb_dma = 1; td_ptr->tdesc1.CMDZ = 2; } else#ifdef VELOCITY_ZERO_COPY_SUPPORT if (skb_shinfo(skb)->nr_frags > 0) { int nfrags = skb_shinfo(skb)->nr_frags; tdinfo->skb = skb; if (nfrags > 6) { skb_linearize(skb, GFP_ATOMIC); memcpy(tdinfo->buf, skb->data, skb->len); tdinfo->skb_dma[0] = tdinfo->buf_dma; td_ptr->tdesc0.pktsize = td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); td_ptr->td_buf[0].pa_high = 0; td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize; tdinfo->nskb_dma = 1; td_ptr->tdesc1.CMDZ = 2; } else { int i = 0; tdinfo->nskb_dma = 0; tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data, skb->len - skb->data_len, PCI_DMA_TODEVICE); td_ptr->tdesc0.pktsize = pktlen; /* FIXME: support 48bit DMA later */ td_ptr->td_buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma); td_ptr->td_buf[i].pa_high = 0; td_ptr->td_buf[i].bufsize = skb->len->skb->data_len; for (i = 0; i < nfrags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; void *addr = ((void *) page_address(frag->page + frag->page_offset)); tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE); td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]); td_ptr->td_buf[i + 1].pa_high = 0; td_ptr->td_buf[i + 1].bufsize = frag->size; } tdinfo->nskb_dma = i - 1; td_ptr->tdesc1.CMDZ = i; } } else#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -