📄 82596.c
字号:
lp->iscp.stat = ISCP_BUSY; lp->cmd_backlog = 0; lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL; if (i596_debug > 1) printk("%s: starting i82596.\n", dev->name);#if !defined(CONFIG_MVME16x_NET) && !defined(CONFIG_BVME6000_NET) (void) inb(ioaddr + 0x10); outb(4, ioaddr + 0xf);#endif CA(dev); while (lp->iscp.stat) if (--boguscnt == 0) { printk("%s: i82596 initialization timed out with status %4.4x, cmd %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); break; } lp->scb.command = 0;#ifdef CONFIG_MVME16x_NET if (MACH_IS_MVME16x) { volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; /* Enable ints, etc. now */ pcc2[0x2a] = 0x08; pcc2[0x2a] = 0x55; /* Edge sensitive */ pcc2[0x2b] = 0x55; }#endif#ifdef CONFIG_BVME6000_NET if (MACH_IS_BVME6000) { volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG; *ethirq = 3; }#endif memcpy(lp->i596_config, init_setup, 14); lp->set_conf.command = CmdConfigure; i596_add_cmd(dev, &lp->set_conf); memcpy(lp->eth_addr, dev->dev_addr, 6); lp->set_add.command = CmdSASetup; i596_add_cmd(dev, &lp->set_add); lp->tdr.command = CmdTDR; i596_add_cmd(dev, &lp->tdr); boguscnt = 200000; save_flags(flags); cli(); while (lp->scb.command) if (--boguscnt == 0) { printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); break; } lp->scb.command = RX_START; CA(dev); restore_flags(flags); boguscnt = 2000; while (lp->scb.command) if (--boguscnt == 0) { printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n", lp->scb.status, lp->scb.command); break; } return;}static inline int i596_rx(struct device *dev){ struct i596_private *lp = (struct i596_private *) dev->priv; struct i596_rfd *rfd; int frames = 0; if (i596_debug > 3) printk("i596_rx()\n"); rfd = WSWAPrfd(lp->scb.rfd); /* Reference next frame descriptor to check */ while ((rfd->stat) & STAT_C) { /* Loop while we have complete frames */ if (i596_debug > 2) print_eth(rfd->data); if ((rfd->stat) & STAT_OK) { /* a good frame */ int pkt_len = rfd->count & 0x3fff; struct sk_buff *skb = dev_alloc_skb(pkt_len); frames++; if (skb == NULL) { printk("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; } else { skb->dev = dev; memcpy(skb_put(skb, pkt_len), rfd->data, pkt_len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } } else { lp->stats.rx_errors++; if ((rfd->stat) & 0x0001) lp->stats.collisions++; if ((rfd->stat) & 0x0080) lp->stats.rx_length_errors++; if ((rfd->stat) & 0x0100) lp->stats.rx_over_errors++; if ((rfd->stat) & 0x0200) lp->stats.rx_fifo_errors++; if ((rfd->stat) & 0x0400) lp->stats.rx_frame_errors++; if ((rfd->stat) & 0x0800) lp->stats.rx_crc_errors++; if ((rfd->stat) & 0x1000) lp->stats.rx_length_errors++; } /* Clear the buffer descriptor count and EOF + F flags */ rfd->stat = 0; rfd->count = 0; rfd->cmd = CMD_EOL; lp->rx_tail->cmd = 0; lp->rx_tail = rfd; lp->scb.rfd = rfd->next; rfd = WSWAPrfd(lp->scb.rfd); /* Next frame descriptor to check */ } if (i596_debug > 3) printk("frames %d\n", frames); return 0;}static inline void i596_cleanup_cmd(struct i596_private *lp){ struct i596_cmd *ptr; int boguscnt = 1000; if (i596_debug > 4) printk("i596_cleanup_cmd\n"); while (lp->cmd_head != (struct i596_cmd *) I596_NULL) { ptr = lp->cmd_head; lp->cmd_head = WSWAPcmd(lp->cmd_head->next); lp->cmd_backlog--; switch ((ptr->command) & 0x7) { case CmdTx: { struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; struct sk_buff *skb = tx_cmd->skb; dev_kfree_skb(skb); lp->stats.tx_errors++; lp->stats.tx_aborted_errors++; ptr->next = (struct i596_cmd *) I596_NULL; kfree(tx_cmd); break; } case CmdMulticastList: { ptr->next = (struct i596_cmd *) I596_NULL; kfree(ptr); break; } default: ptr->next = (struct i596_cmd *) I596_NULL; } } while (lp->scb.command) if (--boguscnt == 0) { printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n", lp->scb.status, lp->scb.command); break; } lp->scb.cmd = WSWAPcmd(lp->cmd_head);}static inline void i596_reset(struct device *dev, struct i596_private *lp, int ioaddr){ int boguscnt = 1000; unsigned long flags; if (i596_debug > 1) printk("i596_reset\n"); save_flags(flags); cli(); while (lp->scb.command) if (--boguscnt == 0) { printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n", lp->scb.status, lp->scb.command); break; } dev->start = 0; dev->tbusy = 1; lp->scb.command = CUC_ABORT | RX_ABORT; CA(dev); /* wait for shutdown */ boguscnt = 4000; while (lp->scb.command) if (--boguscnt == 0) { printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n", lp->scb.status, lp->scb.command); break; } restore_flags(flags); i596_cleanup_cmd(lp); i596_rx(dev); dev->start = 1; dev->tbusy = 0; dev->interrupt = 0; init_i596_mem(dev);}static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd){ struct i596_private *lp = (struct i596_private *) dev->priv; int ioaddr = dev->base_addr; unsigned long flags; int boguscnt = 1000; if (i596_debug > 4) printk("i596_add_cmd\n"); cmd->status = 0; cmd->command |= (CMD_EOL | CMD_INTR); cmd->next = (struct i596_cmd *) I596_NULL; save_flags(flags); cli(); /* * RGH 300597: Looks to me like there could be a race condition * here. Just because we havn't picked up all the command items * yet, doesn't mean that the 82596 hasn't finished processing * them. So, we may need to do a CUC_START anyway. * Maybe not. If it interrupts saying the CU is idle when there * is still something in the cmd queue, the int handler with restart * the CU. */ if (lp->cmd_head != (struct i596_cmd *) I596_NULL) { lp->cmd_tail->next = WSWAPcmd(cmd); } else { lp->cmd_head = cmd; while (lp->scb.command) if (--boguscnt == 0) { printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n", lp->scb.status, lp->scb.command); break; } lp->scb.cmd = WSWAPcmd(cmd); lp->scb.command = CUC_START; CA(dev); } lp->cmd_tail = cmd; lp->cmd_backlog++; lp->cmd_head = WSWAPcmd(lp->scb.cmd); /* Is this redundant? RGH 300597 */ restore_flags(flags); if (lp->cmd_backlog > max_cmd_backlog) { unsigned long tickssofar = jiffies - lp->last_cmd; if (tickssofar < ticks_limit) return; printk("%s: command unit timed out, status resetting.\n", dev->name); i596_reset(dev, lp, ioaddr); }}static int i596_open(struct device *dev){ int i; if (i596_debug > 1) printk("%s: i596_open() irq %d.\n", dev->name, dev->irq); if (request_irq(dev->irq, &i596_interrupt, 0, "apricot", dev)) return -EAGAIN;#ifdef CONFIG_MVME16x_NET if (MACH_IS_MVME16x) { if (request_irq(0x56, &i596_error, 0, "apricot_error", dev)) return -EAGAIN; }#endif if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE) printk("%s: only able to allocate %d receive buffers\n", dev->name, i); if (i < 4) { free_irq(dev->irq, dev); return -EAGAIN; } dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; MOD_INC_USE_COUNT; /* Initialize the 82596 memory */ init_i596_mem(dev); return 0; /* Always succeed */}static int i596_start_xmit(struct sk_buff *skb, struct device *dev){ struct i596_private *lp = (struct i596_private *) dev->priv; int ioaddr = dev->base_addr; struct tx_cmd *tx_cmd; if (i596_debug > 2) printk("%s: 82596 start xmit\n", dev->name); /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; printk("%s: transmit timed out, status resetting.\n", dev->name); lp->stats.tx_errors++; /* Try to restart the adaptor */ if (lp->last_restart == lp->stats.tx_packets) { if (i596_debug > 1) printk("Resetting board.\n"); /* Shutdown and restart */ i596_reset(dev, lp, ioaddr); } else { /* Issue a channel attention signal */ if (i596_debug > 1) printk("Kicking board.\n"); lp->scb.command = CUC_START | RX_START; CA(dev); lp->last_restart = lp->stats.tx_packets; } dev->tbusy = 0; dev->trans_start = jiffies; } if (i596_debug > 3) printk("%s: i596_start_xmit() called\n", dev->name); /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; dev->trans_start = jiffies; tx_cmd = (struct tx_cmd *) kmalloc((sizeof(struct tx_cmd) + sizeof(struct i596_tbd)), GFP_ATOMIC); if (tx_cmd == NULL) { printk("%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name); lp->stats.tx_dropped++; dev_kfree_skb(skb); } else { struct i596_tbd *tbd = (struct i596_tbd *) (tx_cmd + 1); tx_cmd->tbd = WSWAPtbd(tbd); tbd->next = (struct i596_tbd *) I596_NULL; tx_cmd->cmd.command = CMD_FLEX | CmdTx; tx_cmd->skb = skb; tx_cmd->pad = 0; tx_cmd->size = 0; tbd->pad = 0; tbd->size = EOF | length; tbd->data = WSWAPchar(skb->data); if (i596_debug > 3) print_eth(skb->data); i596_add_cmd(dev, (struct i596_cmd *) tx_cmd); lp->stats.tx_packets++; lp->stats.tx_bytes += length; } } dev->tbusy = 0; return 0;}static void print_eth(char *add){ int i; printk("print_eth(%08x)\n", (unsigned int) add); printk("Dest "); for (i = 0; i < 6; i++) printk(" %2.2X", (unsigned char) add[i]); printk("\n"); printk("Source"); for (i = 0; i < 6; i++) printk(" %2.2X", (unsigned char) add[i + 6]); printk("\n"); printk("type %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);}__initfunc(int i82596_probe(struct device *dev)){ int i; struct i596_private *lp; char eth_addr[6];#ifdef CONFIG_MVME16x_NET if (MACH_IS_MVME16x) { static int probed = 0; if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) { printk("Ethernet probe disabled - chip not present\n"); return ENODEV; } if (probed) return ENODEV; probed++; memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */ dev->base_addr = MVME_I596_BASE; dev->irq = (unsigned) MVME16x_IRQ_I596; }#endif#ifdef CONFIG_BVME6000_NET if (MACH_IS_BVME6000) { volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE; unsigned char msr = rtc[3];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -