📄 acenic.c
字号:
memset(ap->info, 0, sizeof(struct ace_info)); memset(ap->skb, 0, sizeof(struct ace_skb)); ace_load_firmware(dev); ap->fw_running = 0; tmp_ptr = ap->info_dma; writel(tmp_ptr >> 32, ®s->InfoPtrHi); writel(tmp_ptr & 0xffffffff, ®s->InfoPtrLo); memset(ap->evt_ring, 0, EVT_RING_ENTRIES * sizeof(struct event)); set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring_dma); info->evt_ctrl.flags = 0; set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma); *(ap->evt_prd) = 0; wmb(); writel(0, ®s->EvtCsm); set_aceaddr(&info->cmd_ctrl.rngptr, 0x100); info->cmd_ctrl.flags = 0; info->cmd_ctrl.max_len = 0; for (i = 0; i < CMD_RING_ENTRIES; i++) writel(0, ®s->CmdRng[i]); writel(0, ®s->CmdPrd); writel(0, ®s->CmdCsm); tmp_ptr = ap->info_dma; tmp_ptr += (unsigned long) &(((struct ace_info *)0)->s.stats); set_aceaddr(&info->stats2_ptr, (dma_addr_t) tmp_ptr); set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma); info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4; info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; memset(ap->rx_std_ring, 0, RX_STD_RING_ENTRIES * sizeof(struct rx_desc)); for (i = 0; i < RX_STD_RING_ENTRIES; i++) ap->rx_std_ring[i].flags = BD_FLG_TCP_UDP_SUM; ap->rx_std_skbprd = 0; atomic_set(&ap->cur_rx_bufs, 0); set_aceaddr(&info->rx_jumbo_ctrl.rngptr, (ap->rx_ring_base_dma + (sizeof(struct rx_desc) * RX_STD_RING_ENTRIES))); info->rx_jumbo_ctrl.max_len = 0; info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; memset(ap->rx_jumbo_ring, 0, RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc)); for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) ap->rx_jumbo_ring[i].flags = BD_FLG_TCP_UDP_SUM | BD_FLG_JUMBO; ap->rx_jumbo_skbprd = 0; atomic_set(&ap->cur_jumbo_bufs, 0); memset(ap->rx_mini_ring, 0, RX_MINI_RING_ENTRIES * sizeof(struct rx_desc)); if (ap->version >= 2) { set_aceaddr(&info->rx_mini_ctrl.rngptr, (ap->rx_ring_base_dma + (sizeof(struct rx_desc) * (RX_STD_RING_ENTRIES + RX_JUMBO_RING_ENTRIES)))); info->rx_mini_ctrl.max_len = ACE_MINI_SIZE; info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; for (i = 0; i < RX_MINI_RING_ENTRIES; i++) ap->rx_mini_ring[i].flags = BD_FLG_TCP_UDP_SUM | BD_FLG_MINI; } else { set_aceaddr(&info->rx_mini_ctrl.rngptr, 0); info->rx_mini_ctrl.flags = RCB_FLG_RNG_DISABLE; info->rx_mini_ctrl.max_len = 0; } ap->rx_mini_skbprd = 0; atomic_set(&ap->cur_mini_bufs, 0); set_aceaddr(&info->rx_return_ctrl.rngptr, (ap->rx_ring_base_dma + (sizeof(struct rx_desc) * (RX_STD_RING_ENTRIES + RX_JUMBO_RING_ENTRIES + 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 = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|RCB_FLG_TX_HOST_RING;#if TX_COAL_INTS_ONLY tmp |= RCB_FLG_COAL_INT_ONLY;#endif info->tx_ctrl.flags = tmp; set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma); /* * Potential item for tuning parameter */#if 0 /* NO */ writel(DMA_THRESH_16W, ®s->DmaReadCfg); writel(DMA_THRESH_16W, ®s->DmaWriteCfg);#else writel(DMA_THRESH_8W, ®s->DmaReadCfg); writel(DMA_THRESH_8W, ®s->DmaWriteCfg);#endif 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->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); /* * Zero the stats before starting the interface */ memset(&ap->stats, 0, sizeof(ap->stats)); /* * 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); } }}static void ace_watchdog(struct net_device *data){ struct net_device *dev = 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)); /* This can happen due to ieee flow control. */ } else { printk(KERN_DEBUG "%s: BUG... transmitter died. Kicking it.\n", dev->name); netif_wake_queue(dev); }}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; prefetchw(&ap->cur_rx_bufs); 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 = alloc_skb(ACE_STD_BUFSIZE, GFP_ATOMIC); if (!skb) break; /* * Make sure IP header starts on a fresh cache line. */ skb_reserve(skb, 2 + 16); mapping = pci_map_page(ap->pdev, virt_to_page(skb->data), ((unsigned long)skb->data & ~PAGE_MASK), ACE_STD_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_std_skbuff[idx].skb = skb; pci_unmap_addr_set(&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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -