📄 acenic.c
字号:
memset(ap->rx_jumbo_ring, 0, RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc)); info->rx_mini_ctrl.max_len = 0;#if 0 set_aceaddr(&info->rx_mini_ctrl.rngptr, ap->rx_mini_ring);#else set_aceaddr_bus(&info->rx_mini_ctrl.rngptr, 0);#endif info->rx_mini_ctrl.flags = FLG_RNG_DISABLED;#if 0 memset(ap->rx_mini_ring, 0, RX_MINI_RING_ENTRIES * sizeof(struct rx_desc));#endif set_aceaddr(&info->rx_return_ctrl.rngptr, ap->rx_return_ring); 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); writel(TX_RING_BASE, ®s->WinBase); ap->tx_ring = (struct tx_desc *)regs->Window; for (i = 0; i < (TX_RING_ENTRIES * sizeof(struct tx_desc) / 4); i++){ writel(0, (unsigned long)ap->tx_ring + i * 4); } info->tx_ctrl.max_len = TX_RING_ENTRIES; info->tx_ctrl.flags = 0; set_aceaddr_bus(&info->tx_ctrl.rngptr, (void *)TX_RING_BASE); set_aceaddr(&info->tx_csm_ptr, &ap->tx_csm); /* * 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_TX_COAL, ®s->TuneTxCoalTicks); writel(DEF_TX_MAX_DESC, ®s->TuneMaxTxDesc); writel(DEF_RX_COAL, ®s->TuneRxCoalTicks); writel(DEF_RX_MAX_DESC, ®s->TuneMaxRxDesc); writel(DEF_TRACE, ®s->TuneTrace); writel(DEF_TX_RATIO, ®s->TxBufRat); if (board_idx >= 8) { printk(KERN_WARNING "%s: more then 8 NICs detected, " "ignoring module parameters!\n", dev->name); board_idx = -1; } 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; } } writel(tmp, ®s->TuneLink); if (ap->version == 2) writel(tmp, ®s->TuneFastLink); if (ap->version == 1) writel(tigonFwStartAddr, ®s->Pc); else if (ap->version == 2) writel(tigon2FwStartAddr, ®s->Pc); writel(0, ®s->Mb0Lo); /* * 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); return -EBUSY; } /* * We load the ring here as there seem to be no way to tell the * firmware to wipe the ring without re-initializing it. */ ace_load_std_rx_ring(dev); return 0;}/* * Monitor the card to detect hangs. */static void ace_timer(unsigned long data){ struct device *dev = (struct device *)data; struct ace_private *ap = (struct ace_private *)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);}/* * 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. */static int ace_load_std_rx_ring(struct device *dev){ struct ace_private *ap; struct ace_regs *regs; struct ace_info *info; unsigned long flags; struct cmd cmd; short i; ap = (struct ace_private *)dev->priv; regs = ap->regs; info = ap->info; spin_lock_irqsave(&ap->lock, flags); /* * 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 = ap->dirty_rx = 0; ap->tx_prd = ap->tx_csm = ap->tx_ret_csm = 0; writel(0, ®s->RxRetCsm); for (i = 0; i < RX_RING_THRESH; i++) { struct sk_buff *skb; ap->rx_std_ring[i].flags = 0; skb = alloc_skb(ACE_STD_MTU + ETH_HLEN + 6, GFP_ATOMIC); ap->rx_std_skbuff[i] = skb; /* * Make sure the data contents end up on an aligned address */ skb_reserve(skb, 2); set_aceaddr(&ap->rx_std_ring[i].addr, skb->data); ap->rx_std_ring[i].size = ACE_STD_MTU + ETH_HLEN + 4; ap->rx_std_ring[i].flags = 0; ap->rx_std_ring[i].type = DESC_RX; ap->rx_std_ring[i].idx = i; } ap->rx_std_skbprd = i; /* * The last descriptor needs to be marked as being special. */ ap->rx_std_ring[i-1].type = DESC_END; cmd.evt = C_SET_RX_PRD_IDX; cmd.code = 0; cmd.idx = ap->rx_std_skbprd; ace_issue_cmd(regs, &cmd); spin_unlock_irqrestore(&ap->lock, flags); return 0;}/* * Load the jumbo rx ring, this may happen at any time if the MTU * is changed to a value > 1500. */static int ace_load_jumbo_rx_ring(struct device *dev){ struct ace_private *ap; struct ace_regs *regs; struct cmd cmd; unsigned long flags; short i; ap = (struct ace_private *)dev->priv; regs = ap->regs; spin_lock_irqsave(&ap->lock, flags); for (i = 0; i < RX_RING_JUMBO_THRESH; i++) { struct sk_buff *skb; ap->rx_jumbo_ring[i].flags = 0; skb = alloc_skb(ACE_JUMBO_MTU + ETH_HLEN + 6, GFP_ATOMIC); ap->rx_jumbo_skbuff[i] = skb; /* * Make sure the data contents end up on an aligned address */ skb_reserve(skb, 2); set_aceaddr(&ap->rx_jumbo_ring[i].addr, skb->data); ap->rx_jumbo_ring[i].size = ACE_JUMBO_MTU + ETH_HLEN + 4; ap->rx_jumbo_ring[i].flags = DFLG_RX_JUMBO; ap->rx_jumbo_ring[i].type = DESC_RX; ap->rx_jumbo_ring[i].idx = i; } ap->rx_jumbo_skbprd = i; /* * The last descriptor needs to be marked as being special. */ ap->rx_jumbo_ring[i-1].type = DESC_END; cmd.evt = C_SET_RX_JUMBO_PRD_IDX; cmd.code = 0; cmd.idx = ap->rx_jumbo_skbprd; ace_issue_cmd(regs, &cmd); spin_unlock_irqrestore(&ap->lock, flags); return 0;}/* * Tell the firmware not to accept jumbos and flush the jumbo ring. * This function must be called with the spinlock held. */static int ace_flush_jumbo_rx_ring(struct device *dev){ struct ace_private *ap; struct ace_regs *regs; struct cmd cmd; short i; ap = (struct ace_private *)dev->priv; regs = ap->regs; if (ap->jumbo){ cmd.evt = C_RESET_JUMBO_RNG; cmd.code = 0; cmd.idx = 0; ace_issue_cmd(regs, &cmd); for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { if (ap->rx_jumbo_skbuff[i]) { ap->rx_jumbo_ring[i].size = 0; set_aceaddr_bus(&ap->rx_jumbo_ring[i].addr, 0); dev_kfree_skb(ap->rx_jumbo_skbuff[i]); } } }else printk(KERN_ERR "%s: Trying to flush Jumbo ring without " "Jumbo support enabled\n", dev->name); return 0;}/* * All events are considered to be slow (RX/TX ints do not generate * events) and are handled here, outside the main interrupt handler, * to reduce the size of the handler. */static u32 ace_handle_event(struct device *dev, u32 evtcsm, u32 evtprd){ struct ace_private *ap; ap = (struct ace_private *)dev->priv; while (evtcsm != evtprd){ switch (ap->evt_ring[evtcsm].evt){ case E_FW_RUNNING: printk(KERN_INFO "%s: Firmware up and running\n", dev->name); ap->fw_running = 1; break; case E_STATS_UPDATED: break; case E_LNK_STATE: { u16 code = ap->evt_ring[evtcsm].code; if (code == E_C_LINK_UP){ printk("%s: Optical link UP\n", dev->name); } else if (code == E_C_LINK_DOWN) printk(KERN_INFO "%s: Optical link DOWN\n", dev->name); else printk(KERN_INFO "%s: Unknown optical link " "state %02x\n", dev->name, code); break; } case E_ERROR: switch(ap->evt_ring[evtcsm].code){ case E_C_ERR_INVAL_CMD: printk(KERN_ERR "%s: invalid command error\n", dev->name); break; case E_C_ERR_UNIMP_CMD: printk(KERN_ERR "%s: unimplemented command " "error\n", dev->name); break; case E_C_ERR_BAD_CFG: printk(KERN_ERR "%s: bad config error\n", dev->name); break; default: printk(KERN_ERR "%s: unknown error %02x\n", dev->name, ap->evt_ring[evtcsm].code); } break; case E_RESET_JUMBO_RNG: break; default: printk(KERN_ERR "%s: Unhandled event 0x%02x\n", dev->name, ap->evt_ring[evtcsm].evt); } evtcsm = (evtcsm + 1) % EVT_RING_ENTRIES; } return evtcsm;}static int ace_rx_int(struct device *dev, u32 rxretprd, u32 rxretcsm){ struct ace_private *ap = (struct ace_private *)dev->priv; struct ace_regs *regs = ap->regs; u32 idx, oldidx; idx = rxretcsm; while (idx != rxretprd){ struct sk_buff *skb, *newskb, *oldskb; struct rx_desc *newrxdesc, *oldrxdesc; u32 prdidx, size; void *addr; u16 csum; int jumbo; oldidx = ap->rx_return_ring[idx].idx; jumbo = ap->rx_return_ring[idx].flags & DFLG_RX_JUMBO; if (jumbo){ oldskb = ap->rx_jumbo_skbuff[oldidx]; prdidx = ap->rx_jumbo_skbprd; newrxdesc = &ap->rx_jumbo_ring[prdidx]; oldrxdesc = &ap->rx_jumbo_ring[oldidx]; }else{ oldskb = ap->rx_std_skbuff[oldidx]; prdidx = ap->rx_std_skbprd; newrxdesc = &ap->rx_std_ring[prdidx]; oldrxdesc = &ap->rx_std_ring[oldidx]; } size = oldrxdesc->size; if (size < PKT_COPY_THRESHOLD) { skb = alloc_skb(size + 2, GFP_ATOMIC); if (skb == NULL){ printk(KERN_ERR "%s: Out of memory\n", dev->name); goto error; } /* * Make sure the real data is aligned */ skb_reserve(skb, 2); memcpy(skb_put(skb, size), oldskb->data, size); addr = get_aceaddr_bus(&oldrxdesc->addr); newskb = oldskb; }else{ skb = oldskb; skb_put(skb, size); newskb = alloc_skb(size + 2, GFP_ATOMIC); if (newskb == NULL){ printk(KERN_ERR "%s: Out of memory\n", dev->name); goto error; } /* * Make sure we DMA directly into nicely * aligned receive buffers */ skb_reserve(newskb, 2); addr = (void *)virt_to_bus(newskb->data); } set_aceaddr_bus(&newrxdesc->addr, addr); newrxdesc->size = size; newrxdesc->flags = oldrxdesc->flags; newrxdesc->idx = prdidx; newrxdesc->type = DESC_RX;#if (BITS_PER_LONG == 32) newrxdesc->addr.addrhi = 0;#endif oldrxdesc->size = 0; set_aceaddr_bus(&oldrxdesc->addr, 0); if (jumbo){ ap->rx_jumbo_skbuff[oldidx] = NULL; ap->rx_jumbo_skbuff[prdidx] = newskb; prdidx = (prdidx + 1) % RX_JUMBO_RING_ENTRIES; ap->rx_jumbo_skbprd = prdidx; }else{ ap->rx_std_skbuff[oldidx] = NULL; ap->rx_std_skbuff[prdidx] = newskb; prdidx = (prdidx + 1) % RX_STD_RING_ENTRIES; ap->rx_std_skbprd = prdidx; } /* * Fly baby, fly! */ csum = ap->rx_return_ring[idx].tcp_udp_csum; skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); /* * If the checksum is correct and this is not a * fragment, tell the stack that the data is correct. */ if(!(csum ^ 0xffff) && (!(((struct iphdr *)skb->data)->frag_off & __constant_htons(IP_MF|IP_OFFSET)))) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); /* send it up */ ap->stats.rx_packets++; ap->stats.rx_bytes += skb->len; if ((prdidx & 0x7) == 0){ struct cmd cmd; if (jumbo) cmd.evt = C_SET_RX_JUMBO_PRD_IDX; else cmd.evt = C_SET_RX_PRD_IDX; cmd.code = 0; cmd.idx = prdidx; ace_issue_cmd(regs, &cmd); } idx = (idx + 1) % RX_RETURN_RING_ENTRIES; } out: /* * According to the documentation RxRetCsm is obsolete with * the 12.3.x Firmware - my Tigon I NIC's seem to disagree! */ writel(idx, ®s->RxRetCsm); ap->cur_rx = idx; return idx; error: idx = rxretprd; goto out;}static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs){ struct ace_private *ap; struct ace_regs *regs; struct device *dev = (struct device *)dev_id; u32 txcsm, rxretcsm, rxretprd; u32 evtcsm, evtprd; ap = (struct ace_private *)dev->priv; regs = ap->regs; spin_lock(&ap->lock); /* * In case of PCI shared interrupts or spurious interrupts, * we want to make sure it is actually our interrupt before * spending any time in here. */ if (!(readl(®s->HostCtrl) & IN_INT)){ spin_unlock(&ap->lock); return; } /* * Tell the card not to generate interrupts while we are in here. */ writel(1, ®s->Mb0Lo); /* * Service RX ints before TX */ rxretprd = ap->rx_ret_prd; rxretcsm = ap->cur_rx; if (rxretprd != rxretcsm) rxretprd = ace_rx_int(dev, rxretprd, rxretcsm); txcsm = ap->tx_csm; if (txcsm != ap->tx_ret_csm) { u32 idx = ap->tx_ret_csm; do { ap->stats.tx_packets++; ap->stats.tx_bytes += ap->tx_skbuff[idx]->len; dev_kfree_skb(ap->tx_skbuff[idx]); ap->tx_skbuff[idx] = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -