📄 acenic_np.c
字号:
RX_MINI_RING_ENTRIES)))); info->rx_return_ctrl.flags = 0; info->rx_return_ctrl.max_len = RX_RETURN_RING_ENTRIES; memset(ap->rx_return_ring, 0, RX_RETURN_RING_ENTRIES * sizeof(struct rx_desc)); set_aceaddr(&info->rx_ret_prd_ptr, ap->rx_ret_prd_dma); *(ap->rx_ret_prd) = 0; writel(TX_RING_BASE, ®s->WinBase); memset(ap->tx_ring, 0, TX_RING_ENTRIES * sizeof(struct tx_desc)); set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma); info->tx_ctrl.max_len = TX_RING_ENTRIES; tmp = 0;#if TX_COAL_INTS_ONLY tmp |= RCB_FLG_COAL_INT_ONLY;#endif tmp |= RCB_FLG_TX_HOST_RING; info->tx_ctrl.flags = tmp; set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma); /* * Potential item for tuning parameter */ writel(DMA_THRESH_8W, ®s->DmaReadCfg); writel(DMA_THRESH_8W, ®s->DmaWriteCfg); writel(0, ®s->MaskInt); writel(1, ®s->IfIdx); writel(1, ®s->AssistState); writel(DEF_STAT, ®s->TuneStatTicks); writel(DEF_TRACE, ®s->TuneTrace); ace_set_rxtx_parms(dev, 0); if (board_idx == BOARD_IDX_OVERFLOW) { printk(KERN_WARNING "%s: more then %i NICs detected, " "ignoring module parameters!\n", dev->name, ACE_MAX_MOD_PARMS); } else if (board_idx >= 0) { if (tx_coal_tick[board_idx]) writel(tx_coal_tick[board_idx], ®s->TuneTxCoalTicks); if (max_tx_desc[board_idx]) writel(max_tx_desc[board_idx], ®s->TuneMaxTxDesc); if (rx_coal_tick[board_idx]) writel(rx_coal_tick[board_idx], ®s->TuneRxCoalTicks); if (max_rx_desc[board_idx]) writel(max_rx_desc[board_idx], ®s->TuneMaxRxDesc); if (trace[board_idx]) writel(trace[board_idx], ®s->TuneTrace); if ((tx_ratio[board_idx] >= 0) && (tx_ratio[board_idx] < 64)) writel(tx_ratio[board_idx], ®s->TxBufRat); } /* * Default link parameters */ tmp = LNK_ENABLE | LNK_FULL_DUPLEX | LNK_1000MB | LNK_100MB | LNK_10MB | LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL | LNK_NEGOTIATE; if(ap->version >= 2) tmp |= LNK_TX_FLOW_CTL_Y; /* * Override link default parameters */ if ((board_idx >= 0) && link[board_idx]) { int option = link[board_idx]; tmp = LNK_ENABLE; if (option & 0x01) { printk(KERN_INFO "%s: Setting half duplex link\n", dev->name); tmp &= ~LNK_FULL_DUPLEX; } if (option & 0x02) tmp &= ~LNK_NEGOTIATE; if (option & 0x10) tmp |= LNK_10MB; if (option & 0x20) tmp |= LNK_100MB; if (option & 0x40) tmp |= LNK_1000MB; if ((option & 0x70) == 0) { printk(KERN_WARNING "%s: No media speed specified, " "forcing auto negotiation\n", dev->name); tmp |= LNK_NEGOTIATE | LNK_1000MB | LNK_100MB | LNK_10MB; } if ((option & 0x100) == 0) tmp |= LNK_NEG_FCTL; else printk(KERN_INFO "%s: Disabling flow control " "negotiation\n", dev->name); if (option & 0x200) tmp |= LNK_RX_FLOW_CTL_Y; if ((option & 0x400) && (ap->version >= 2)) { printk(KERN_INFO "%s: Enabling TX flow control\n", dev->name); tmp |= LNK_TX_FLOW_CTL_Y; } } ap->link = tmp; writel(tmp, ®s->TuneLink); if (ap->version >= 2) writel(tmp, ®s->TuneFastLink); if (ACE_IS_TIGON_I(ap)) writel(tigonFwStartAddr, ®s->Pc); if (ap->version == 2) writel(tigon2FwStartAddr, ®s->Pc); writel(0, ®s->Mb0Lo); /* * Set tx_csm before we start receiving interrupts, otherwise * the interrupt handler might think it is supposed to process * tx ints before we are up and running, which may cause a null * pointer access in the int handler. */ ap->tx_full = 0; ap->cur_rx = 0; ap->tx_prd = *(ap->tx_csm) = ap->tx_ret_csm = 0; wmb(); ace_set_txprd(regs, ap, 0); writel(0, ®s->RxRetCsm); /* * Start the NIC CPU */ writel(readl(®s->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), ®s->CpuCtrl); /* * Wait for the firmware to spin up - max 3 seconds. */ myjif = jiffies + 3 * HZ; while (time_before(jiffies, myjif) && !ap->fw_running); if (!ap->fw_running) { printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name); ace_dump_trace(ap); writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); /* aman@sgi.com - account for badly behaving firmware/NIC: * - have observed that the NIC may continue to generate * interrupts for some reason; attempt to stop it - halt * second CPU for Tigon II cards, and also clear Mb0 * - if we're a module, we'll fail to load if this was * the only GbE card in the system => if the kernel does * see an interrupt from the NIC, code to handle it is * gone and OOps! - so free_irq also */ if (ap->version >= 2) writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); writel(0, ®s->Mb0Lo); ecode = -EBUSY; goto init_error; } /* * We load the ring here as there seem to be no way to tell the * firmware to wipe the ring without re-initializing it. */ if (!test_and_set_bit(0, &ap->std_refill_busy)) ace_load_std_rx_ring(ap, RX_RING_SIZE); else printk(KERN_ERR "%s: Someone is busy refilling the RX ring\n", dev->name); if (ap->version >= 2) { if (!test_and_set_bit(0, &ap->mini_refill_busy)) ace_load_mini_rx_ring(ap, RX_MINI_SIZE); else printk(KERN_ERR "%s: Someone is busy refilling " "the RX mini ring\n", dev->name); } return 0; init_error: ace_init_cleanup(dev); return ecode;}static void ace_set_rxtx_parms(struct net_device *dev, int jumbo){ struct ace_private *ap; struct ace_regs *regs; int board_idx; ap = dev->priv; regs = ap->regs; board_idx = ap->board_idx; if (board_idx >= 0) { if (!jumbo) { if (!tx_coal_tick[board_idx]) writel(DEF_TX_COAL, ®s->TuneTxCoalTicks); if (!max_tx_desc[board_idx]) writel(DEF_TX_MAX_DESC, ®s->TuneMaxTxDesc); if (!rx_coal_tick[board_idx]) writel(DEF_RX_COAL, ®s->TuneRxCoalTicks); if (!max_rx_desc[board_idx]) writel(DEF_RX_MAX_DESC, ®s->TuneMaxRxDesc); if (!tx_ratio[board_idx]) writel(DEF_TX_RATIO, ®s->TxBufRat); } else { if (!tx_coal_tick[board_idx]) writel(DEF_JUMBO_TX_COAL, ®s->TuneTxCoalTicks); if (!max_tx_desc[board_idx]) writel(DEF_JUMBO_TX_MAX_DESC, ®s->TuneMaxTxDesc); if (!rx_coal_tick[board_idx]) writel(DEF_JUMBO_RX_COAL, ®s->TuneRxCoalTicks); if (!max_rx_desc[board_idx]) writel(DEF_JUMBO_RX_MAX_DESC, ®s->TuneMaxRxDesc); if (!tx_ratio[board_idx]) writel(DEF_JUMBO_TX_RATIO, ®s->TxBufRat); } }}/* * Monitor the card to detect hangs. */static void ace_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; /* * We haven't received a stats update event for more than 2.5 * seconds and there is data in the transmit queue, thus we * asume the card is stuck. */ if (*ap->tx_csm != ap->tx_ret_csm) { printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n", dev->name, (unsigned int)readl(®s->HostCtrl)); } ap->timer.expires = jiffies + (5/2*HZ); add_timer(&ap->timer);}static void ace_tasklet(unsigned long dev){ struct ace_private *ap = ((struct net_device *)dev)->priv; int cur_size; cur_size = atomic_read(&ap->cur_rx_bufs); if ((cur_size < RX_LOW_STD_THRES) && !test_and_set_bit(0, &ap->std_refill_busy)) {#if DEBUG printk("refilling buffers (current %i)\n", cur_size);#endif ace_load_std_rx_ring(ap, RX_RING_SIZE - cur_size); } if (ap->version >= 2) { cur_size = atomic_read(&ap->cur_mini_bufs); if ((cur_size < RX_LOW_MINI_THRES) && !test_and_set_bit(0, &ap->mini_refill_busy)) {#if DEBUG printk("refilling mini buffers (current %i)\n", cur_size);#endif ace_load_mini_rx_ring(ap, RX_MINI_SIZE - cur_size); } } cur_size = atomic_read(&ap->cur_jumbo_bufs); if (ap->jumbo && (cur_size < RX_LOW_JUMBO_THRES) && !test_and_set_bit(0, &ap->jumbo_refill_busy)) {#if DEBUG printk("refilling jumbo buffers (current %i)\n", >cur_size);#endif ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE - cur_size); } ap->tasklet_pending = 0;}/* * Copy the contents of the NIC's trace buffer to kernel memory. */static void ace_dump_trace(struct ace_private *ap){#if 0 if (!ap->trace_buf) if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL))) return;#endif}/* * Load the standard rx ring. * * Loading rings is safe without holding the spin lock since this is * done only before the device is enabled, thus no interrupts are * generated and by the interrupt handler/tasklet handler. */static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs){ struct ace_regs *regs; short i, idx; regs = ap->regs; idx = ap->rx_std_skbprd; for (i = 0; i < nr_bufs; i++) { struct sk_buff *skb; struct rx_desc *rd; dma_addr_t mapping; skb = NP_dev_alloc_skb(ACE_STD_BUFSIZE); if (!skb) break; /* * Make sure IP header starts on a fresh cache line. */ skb_reserve(skb, 2 + 16); mapping = pci_map_single(ap->pdev, skb->data, ACE_STD_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_std_skbuff[idx].skb = skb; ap->skb->rx_std_skbuff[idx].mapping = mapping; rd = &ap->rx_std_ring[idx]; set_aceaddr(&rd->addr, mapping); rd->size = ACE_STD_MTU + ETH_HLEN + 4; rd->idx = idx; idx = (idx + 1) % RX_STD_RING_ENTRIES; } if (!i) goto error_out; atomic_add(i, &ap->cur_rx_bufs); ap->rx_std_skbprd = idx; if (ACE_IS_TIGON_I(ap)) { struct cmd cmd; cmd.evt = C_SET_RX_PRD_IDX; cmd.code = 0; cmd.idx = ap->rx_std_skbprd; ace_issue_cmd(regs, &cmd); } else { writel(idx, ®s->RxStdPrd); wmb(); } out: clear_bit(0, &ap->std_refill_busy); return; error_out: if( xtime.tv_sec > ap->lastmsgtime ) { printk(KERN_INFO "Out of memory when allocating " "receive buffers\n"); ap->lastmsgtime = xtime.tv_sec; } goto out;}static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs){ struct ace_regs *regs; short i, idx; regs = ap->regs; idx = ap->rx_mini_skbprd; for (i = 0; i < nr_bufs; i++) { struct sk_buff *skb; struct rx_desc *rd; dma_addr_t mapping; // skb = NP_dev_alloc_skb(ACE_MINI_BUFSIZE, GFP_ATOMIC); skb = NP_dev_alloc_skb(ACE_MINI_BUFSIZE); if (!skb) break; /* * Make sure the IP header ends up on a fresh cache line */ skb_reserve(skb, 2 + 16); mapping = pci_map_single(ap->pdev, skb->data, ACE_MINI_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_mini_skbuff[idx].skb = skb; ap->skb->rx_mini_skbuff[idx].mapping = mapping; rd = &ap->rx_mini_ring[idx]; set_aceaddr(&rd->addr, mapping); rd->size = ACE_MINI_SIZE; rd->idx = idx; idx = (idx + 1) % RX_MINI_RING_ENTRIES; } if (!i) goto error_out; atomic_add(i, &ap->cur_mini_bufs); ap->rx_mini_skbprd = idx; writel(idx, ®s->RxMiniPrd); wmb(); out: clear_bit(0, &ap->mini_refill_busy); return; error_out: if( xtime.tv_sec > ap->lastmsgtime ) { printk(KERN_INFO "Out of memory when allocating " "receive buffers\n"); ap->lastmsgtime = xtime.tv_sec; } goto out;}/* * Load the jumbo rx ring, this may happen at any time if the MTU * is changed to a value > 1500. */static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs){ struct ace_regs *regs; short i, idx; regs = ap->regs; idx = ap->rx_jumbo_skbprd; for (i = 0; i < nr_bufs; i++) { struct sk_buff *skb; struct rx_desc *rd; dma_addr_t mapping;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -