📄 82596.c
字号:
rbd->v_next = rbd+1; rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1)); rbd->b_addr = WSWAPrbd(virt_to_bus(rbd)); rbd->skb = skb; rbd->v_data = skb->tail; rbd->b_data = WSWAPchar(virt_to_bus(skb->tail)); rbd->size = PKT_BUF_SZ;#ifdef __mc68000__ cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ);#endif } lp->rbd_head = lp->rbds; rbd = lp->rbds + rx_ring_size - 1; rbd->v_next = lp->rbds; rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds)); /* Now build the Receive Frame Descriptor List */ for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) { rfd->rbd = I596_NULL; rfd->v_next = rfd+1; rfd->v_prev = rfd-1; rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1)); rfd->cmd = CMD_FLEX; } lp->rfd_head = lp->rfds; lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds)); rfd = lp->rfds; rfd->rbd = lp->rbd_head; rfd->v_prev = lp->rfds + rx_ring_size - 1; rfd = lp->rfds + rx_ring_size - 1; rfd->v_next = lp->rfds; rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds)); rfd->cmd = CMD_EOL|CMD_FLEX;}static inline void remove_rx_bufs(struct net_device *dev){ struct i596_private *lp = (struct i596_private *)dev->priv; struct i596_rbd *rbd; int i; for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) { if (rbd->skb == NULL) break; dev_kfree_skb(rbd->skb); }}static void rebuild_rx_bufs(struct net_device *dev){ struct i596_private *lp = (struct i596_private *) dev->priv; int i; /* Ensure rx frame/buffer descriptors are tidy */ for (i = 0; i < rx_ring_size; i++) { lp->rfds[i].rbd = I596_NULL; lp->rfds[i].cmd = CMD_FLEX; } lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX; lp->rfd_head = lp->rfds; lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds)); lp->rbd_head = lp->rbds; lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds));}static int init_i596_mem(struct net_device *dev){ struct i596_private *lp = (struct i596_private *) dev->priv;#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) short ioaddr = dev->base_addr;#endif unsigned long flags; MPU_PORT(dev, PORT_RESET, 0); udelay(100); /* Wait 100us - seems to help */#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)#ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; /* Disable all ints for now */ pcc2[0x28] = 1; pcc2[0x2a] = 0x48; /* Following disables snooping. Snooping is not required * as we make appropriate use of non-cached pages for * shared data, and cache_push/cache_clear. */ pcc2[0x2b] = 0x08; }#endif#ifdef ENABLE_BVME6000_NET if (MACH_IS_BVME6000) { volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG; *ethirq = 1; }#endif /* change the scp address */ MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus(&lp->scp));#elif defined(ENABLE_APRICOT) { u32 scp = virt_to_bus(&lp->scp); /* change the scp address */ outw(0, ioaddr); outw(0, ioaddr); outb(4, ioaddr + 0xf); outw(scp | 2, ioaddr); outw(scp >> 16, ioaddr); }#endif lp->last_cmd = jiffies;#ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) lp->scp.sysbus = 0x00000054;#endif#ifdef ENABLE_BVME6000_NET if (MACH_IS_BVME6000) lp->scp.sysbus = 0x0000004c;#endif#ifdef ENABLE_APRICOT if (MACH_IS_APRICOT) lp->scp.sysbus = 0x00440000;#endif lp->scp.iscp = WSWAPiscp(virt_to_bus(&(lp->iscp))); lp->iscp.scb = WSWAPscb(virt_to_bus(&(lp->scb))); lp->iscp.stat = ISCP_BUSY; lp->cmd_backlog = 0; lp->cmd_head = lp->scb.cmd = I596_NULL; DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name));#if defined(ENABLE_APRICOT) (void) inb(ioaddr + 0x10); outb(4, ioaddr + 0xf);#endif CA(dev); if (wait_istat(dev,lp,1000,"initialization timed out")) goto failed; DEB(DEB_INIT,printk("%s: i82596 initialization successful\n", dev->name)); /* Ensure rx frame/buffer descriptors are tidy */ rebuild_rx_bufs(dev); lp->scb.command = 0;#ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; /* Enable ints, etc. now */ pcc2[0x2a] = 0x55; /* Edge sensitive */ pcc2[0x2b] = 0x15; }#endif#ifdef ENABLE_BVME6000_NET if (MACH_IS_BVME6000) { volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG; *ethirq = 3; }#endif DEB(DEB_INIT,printk("%s: queuing CmdConfigure\n", dev->name)); memcpy(lp->cf_cmd.i596_config, init_setup, 14); lp->cf_cmd.cmd.command = CmdConfigure; i596_add_cmd(dev, &lp->cf_cmd.cmd); DEB(DEB_INIT,printk("%s: queuing CmdSASetup\n", dev->name)); memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6); lp->sa_cmd.cmd.command = CmdSASetup; i596_add_cmd(dev, &lp->sa_cmd.cmd); DEB(DEB_INIT,printk("%s: queuing CmdTDR\n", dev->name)); lp->tdr_cmd.cmd.command = CmdTDR; i596_add_cmd(dev, &lp->tdr_cmd.cmd); spin_lock_irqsave (&lp->lock, flags); if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) { spin_unlock_irqrestore (&lp->lock, flags); goto failed; } DEB(DEB_INIT,printk("%s: Issuing RX_START\n", dev->name)); lp->scb.command = RX_START; CA(dev); spin_unlock_irqrestore (&lp->lock, flags); if (wait_cmd(dev,lp,1000,"RX_START not processed")) goto failed; DEB(DEB_INIT,printk("%s: Receive unit started OK\n", dev->name)); return 0;failed: printk("%s: Failed to initialise 82596\n", dev->name); MPU_PORT(dev, PORT_RESET, 0); return -1;}static inline int i596_rx(struct net_device *dev){ struct i596_private *lp = (struct i596_private *)dev->priv; struct i596_rfd *rfd; struct i596_rbd *rbd; int frames = 0; DEB(DEB_RXFRAME,printk ("i596_rx(), rfd_head %p, rbd_head %p\n", lp->rfd_head, lp->rbd_head)); rfd = lp->rfd_head; /* Ref next frame to check */ while ((rfd->stat) & STAT_C) { /* Loop while complete frames */ if (rfd->rbd == I596_NULL) rbd = I596_NULL; else if (rfd->rbd == lp->rbd_head->b_addr) rbd = lp->rbd_head; else { printk("%s: rbd chain broken!\n", dev->name); /* XXX Now what? */ rbd = I596_NULL; } DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %p, rfd.stat %04x\n", rfd, rfd->rbd, rfd->stat)); if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) { /* a good frame */ int pkt_len = rbd->count & 0x3fff; struct sk_buff *skb = rbd->skb; int rx_in_place = 0; DEB(DEB_RXADDR,print_eth(rbd->v_data, "received")); frames++; /* Check if the packet is long enough to just accept * without copying to a properly sized skbuff. */ if (pkt_len > rx_copybreak) { struct sk_buff *newskb; /* Get fresh skbuff to replace filled one. */ newskb = dev_alloc_skb(PKT_BUF_SZ); if (newskb == NULL) { skb = NULL; /* drop pkt */ goto memory_squeeze; } /* Pass up the skb already on the Rx ring. */ skb_put(skb, pkt_len); rx_in_place = 1; rbd->skb = newskb; newskb->dev = dev; rbd->v_data = newskb->tail; rbd->b_data = WSWAPchar(virt_to_bus(newskb->tail));#ifdef __mc68000__ cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ);#endif } else skb = dev_alloc_skb(pkt_len + 2);memory_squeeze: if (skb == NULL) { /* XXX tulip.c can defer packets here!! */ printk ("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; } else { skb->dev = dev; if (!rx_in_place) { /* 16 byte align the data fields */ skb_reserve(skb, 2); memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len); } skb->protocol=eth_type_trans(skb,dev); skb->len = pkt_len;#ifdef __mc68000__ cache_clear(virt_to_phys(rbd->skb->tail), pkt_len);#endif netif_rx(skb); lp->stats.rx_packets++; lp->stats.rx_bytes+=pkt_len; } } else { DEB(DEB_ERRORS, printk("%s: Error, rfd.stat = 0x%04x\n", dev->name, rfd->stat)); 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 */ if (rbd != I596_NULL && (rbd->count & 0x4000)) { rbd->count = 0; lp->rbd_head = rbd->v_next; } /* Tidy the frame descriptor, marking it as end of list */ rfd->rbd = I596_NULL; rfd->stat = 0; rfd->cmd = CMD_EOL|CMD_FLEX; rfd->count = 0; /* Remove end-of-list from old end descriptor */ rfd->v_prev->cmd = CMD_FLEX; /* Update record of next frame descriptor to process */ lp->scb.rfd = rfd->b_next; lp->rfd_head = rfd->v_next; rfd = lp->rfd_head; } DEB(DEB_RXFRAME,printk ("frames %d\n", frames)); return 0;}static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp){ struct i596_cmd *ptr; while (lp->cmd_head != I596_NULL) { ptr = lp->cmd_head; lp->cmd_head = ptr->v_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->v_next = ptr->b_next = I596_NULL; tx_cmd->cmd.command = 0; /* Mark as free */ break; } default: ptr->v_next = ptr->b_next = I596_NULL; } } wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out"); lp->scb.cmd = I596_NULL;}static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr){ unsigned long flags; DEB(DEB_RESET,printk("i596_reset\n")); spin_lock_irqsave (&lp->lock, flags); wait_cmd(dev,lp,100,"i596_reset timed out"); netif_stop_queue(dev); lp->scb.command = CUC_ABORT | RX_ABORT; CA(dev); /* wait for shutdown */ wait_cmd(dev,lp,1000,"i596_reset 2 timed out"); spin_unlock_irqrestore (&lp->lock, flags); i596_cleanup_cmd(dev,lp); i596_rx(dev); netif_start_queue(dev); init_i596_mem(dev);}static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd){ struct i596_private *lp = (struct i596_private *) dev->priv; int ioaddr = dev->base_addr; unsigned long flags; DEB(DEB_ADDCMD,printk("i596_add_cmd\n")); cmd->status = 0; cmd->command |= (CMD_EOL | CMD_INTR); cmd->v_next = cmd->b_next = I596_NULL; spin_lock_irqsave (&lp->lock, flags); if (lp->cmd_head != I596_NULL) { lp->cmd_tail->v_next = cmd; lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status)); } else { lp->cmd_head = cmd; wait_cmd(dev,lp,100,"i596_add_cmd timed out"); lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status)); lp->scb.command = CUC_START; CA(dev); } lp->cmd_tail = cmd; lp->cmd_backlog++; spin_unlock_irqrestore (&lp->lock, 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 net_device *dev){ int res = 0; DEB(DEB_OPEN,printk("%s: i596_open() irq %d.\n", dev->name, dev->irq)); if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) { printk("%s: IRQ %d not free\n", dev->name, dev->irq); return -EAGAIN; }#ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { if (request_irq(0x56, &i596_error, 0, "i82596_error", dev)) return -EAGAIN; }#endif init_rx_bufs(dev); netif_start_queue(dev); MOD_INC_USE_COUNT; /* Initialize the 82596 memory */ if (init_i596_mem(dev)) { res = -EAGAIN; free_irq(dev->irq, dev); } return res;}static void i596_tx_timeout (struct net_device *dev){ struct i596_private *lp = (struct i596_private *) dev->priv; int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ DEB(DEB_ERRORS,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) { DEB(DEB_ERRORS,printk ("Resetting board.\n")); /* Shutdown and restart */ i596_reset (dev, lp, ioaddr); } else { /* Issue a channel attention signal */ DEB(DEB_ERRORS,printk ("Kicking board.\n")); lp->scb.command = CUC_START | RX_START; CA (dev); lp->last_restart = lp->stats.tx_packets; } dev->trans_start = jiffies; netif_wake_queue (dev);}static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct i596_private *lp = (struct i596_private *) dev->priv; struct tx_cmd *tx_cmd;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -