lp486e.c
来自「linux 内核源代码」· C语言 代码 · 共 1,337 行 · 第 1/3 页
C
1,337 行
tx_cmd->pad = 0; tx_cmd->size = 0; tx_cmd_tbd->pad = 0; tx_cmd_tbd->size = (EOF | length); tx_cmd_tbd->pa_data = va_to_pa (skb->data); tx_cmd_tbd->skb = skb; if (i596_debug & LOG_SRCDST) print_eth (skb->data); i596_add_cmd (dev, (struct i596_cmd *) tx_cmd); dev->stats.tx_packets++; } return 0;}static voidi596_tx_timeout (struct net_device *dev) { struct i596_private *lp = dev->priv; int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name); dev->stats.tx_errors++; /* Try to restart the adaptor */ if (lp->last_restart == dev->stats.tx_packets) { printk ("Resetting board.\n"); /* Shutdown and restart */ i596_reset (dev, lp, ioaddr); } else { /* Issue a channel attention signal */ printk ("Kicking board.\n"); lp->scb.command = (CUC_START | RX_START); CA(); lp->last_restart = dev->stats.tx_packets; } netif_wake_queue(dev);}static void print_eth(char *add){ int i; 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]);}static int __init lp486e_probe(struct net_device *dev) { struct i596_private *lp; unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 }; unsigned char *bios; int i, j; int ret = -ENOMEM; static int probed; if (probed) return -ENODEV; probed++; if (!request_region(IOADDR, LP486E_TOTAL_SIZE, DRV_NAME)) { printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR); return -EBUSY; } lp = (struct i596_private *) dev->priv; spin_lock_init(&lp->cmd_lock); /* * Do we really have this thing? */ if (i596_scp_setup(dev)) { ret = -ENODEV; goto err_out_kfree; } dev->base_addr = IOADDR; dev->irq = IRQ; /* * How do we find the ethernet address? I don't know. * One possibility is to look at the EISA configuration area * [0xe8000-0xe9fff]. This contains the ethernet address * but not at a fixed address - things depend on setup options. * * If we find no address, or the wrong address, use * ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6 * with the value found in the BIOS setup. */ bios = bus_to_virt(0xe8000); for (j = 0; j < 0x2000; j++) { if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) { printk("%s: maybe address at BIOS 0x%x:", dev->name, 0xe8000+j); for (i = 0; i < 6; i++) { eth_addr[i] = bios[i+j]; printk(" %2.2X", eth_addr[i]); } printk("\n"); } } printk("%s: lp486e 82596 at %#3lx, IRQ %d,", dev->name, dev->base_addr, dev->irq); for (i = 0; i < 6; i++) printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]); printk("\n"); /* The LP486E-specific entries in the device structure. */ dev->open = &i596_open; dev->stop = &i596_close; dev->hard_start_xmit = &i596_start_xmit; dev->set_multicast_list = &set_multicast_list; dev->watchdog_timeo = 5*HZ; dev->tx_timeout = i596_tx_timeout;#if 0 /* selftest reports 0x320925ae - don't know what that means */ i596_port_do(dev, PORT_SELFTEST, "selftest"); i596_port_do(dev, PORT_DUMP, "dump");#endif return 0;err_out_kfree: release_region(IOADDR, LP486E_TOTAL_SIZE); return ret;}static inline voidi596_handle_CU_completion(struct net_device *dev, struct i596_private *lp, unsigned short status, unsigned short *ack_cmdp) { struct i596_cmd *cmd; int frames_out = 0; int commands_done = 0; int cmd_val; unsigned long flags; spin_lock_irqsave(&lp->cmd_lock, flags); cmd = lp->cmd_head; while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) { cmd = lp->cmd_head; lp->cmd_head = pa_to_va(lp->cmd_head->pa_next); lp->cmd_backlog--; commands_done++; cmd_val = cmd->command & 0x7;#if 0 printk("finished CU %s command (%d)\n", CUcmdnames[cmd_val], cmd_val);#endif switch (cmd_val) { case CmdTx: { struct tx_cmd *tx_cmd; struct i596_tbd *tx_cmd_tbd; tx_cmd = (struct tx_cmd *) cmd; tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd); frames_out++; if (cmd->status & CMD_STAT_OK) { if (i596_debug) print_eth(pa_to_va(tx_cmd_tbd->pa_data)); } else { dev->stats.tx_errors++; if (i596_debug) printk("transmission failure:%04x\n", cmd->status); if (cmd->status & 0x0020) dev->stats.collisions++; if (!(cmd->status & 0x0040)) dev->stats.tx_heartbeat_errors++; if (cmd->status & 0x0400) dev->stats.tx_carrier_errors++; if (cmd->status & 0x0800) dev->stats.collisions++; if (cmd->status & 0x1000) dev->stats.tx_aborted_errors++; } dev_kfree_skb_irq(tx_cmd_tbd->skb); cmd->pa_next = I596_NULL; kfree((unsigned char *)tx_cmd); netif_wake_queue(dev); break; } case CmdMulticastList: cmd->pa_next = I596_NULL; kfree((unsigned char *)cmd); break; case CmdTDR: { unsigned long status = *((unsigned long *) (cmd + 1)); if (status & 0x8000) { if (i596_debug) printk("%s: link ok.\n", dev->name); } else { if (status & 0x4000) printk("%s: Transceiver problem.\n", dev->name); if (status & 0x2000) printk("%s: Termination problem.\n", dev->name); if (status & 0x1000) printk("%s: Short circuit.\n", dev->name); printk("%s: Time %ld.\n", dev->name, status & 0x07ff); } } default: cmd->pa_next = I596_NULL; lp->last_cmd = jiffies; } barrier(); } cmd = lp->cmd_head; while (cmd && (cmd != lp->cmd_tail)) { cmd->command &= 0x1fff; cmd = pa_to_va(cmd->pa_next); barrier(); } if (lp->cmd_head) *ack_cmdp |= CUC_START; lp->scb.pa_cmd = va_to_pa(lp->cmd_head); spin_unlock_irqrestore(&lp->cmd_lock, flags);}static irqreturn_ti596_interrupt (int irq, void *dev_instance) { struct net_device *dev = (struct net_device *) dev_instance; struct i596_private *lp; unsigned short status, ack_cmd = 0; int frames_in = 0; lp = (struct i596_private *) dev->priv; /* * The 82596 examines the command, performs the required action, * and then clears the SCB command word. */ if (lp->scb.command && i596_timeout(dev, "interrupt", 40)) ; /* * The status word indicates the status of the 82596. * It is modified only by the 82596. * * [So, we must not clear it. I find often status 0xffff, * which is not one of the values allowed by the docs.] */ status = lp->scb.status;#if 0 if (i596_debug) { printk("%s: i596 interrupt, ", dev->name); i596_out_status(status); }#endif /* Impossible, but it happens - perhaps when we get a receive interrupt but scb.pa_rfd is I596_NULL. */ if (status == 0xffff) { printk("%s: i596_interrupt: got status 0xffff\n", dev->name); goto out; } ack_cmd = (status & STAT_ACK); if (status & (STAT_CX | STAT_CNA)) i596_handle_CU_completion(dev, lp, status, &ack_cmd); if (status & (STAT_FR | STAT_RNR)) { /* Restart the receive unit when it got inactive somehow */ if ((status & STAT_RNR) && netif_running(dev)) ack_cmd |= RX_START; if (status & STAT_FR) { frames_in = i596_rx(dev); if (!frames_in) printk("receive frame reported, but no frames\n"); } } /* acknowledge the interrupt */ /* if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev)) ack_cmd |= CUC_START; */ if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100)) ; lp->scb.command = ack_cmd; CLEAR_INT(); CA(); out: return IRQ_HANDLED;}static int i596_close(struct net_device *dev) { struct i596_private *lp = dev->priv; netif_stop_queue(dev); if (i596_debug) printk("%s: Shutting down ethercard, status was %4.4x.\n", dev->name, lp->scb.status); lp->scb.command = (CUC_ABORT | RX_ABORT); CA(); i596_cleanup_cmd(dev); if (lp->scb.command && i596_timeout(dev, "i596_close", 200)) ; free_irq(dev->irq, dev); remove_rx_bufs(dev); return 0;}/** Set or clear the multicast filter for this adaptor.*/static void set_multicast_list(struct net_device *dev) { struct i596_private *lp = dev->priv; struct i596_cmd *cmd; if (i596_debug > 1) printk ("%s: set multicast list %d\n", dev->name, dev->mc_count); if (dev->mc_count > 0) { struct dev_mc_list *dmi; char *cp; cmd = kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC); if (cmd == NULL) { printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name); return; } cmd->command = CmdMulticastList; *((unsigned short *) (cmd + 1)) = dev->mc_count * 6; cp = ((char *)(cmd + 1))+2; for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) { memcpy(cp, dmi,6); cp += 6; } if (i596_debug & LOG_SRCDST) print_eth (((char *)(cmd + 1)) + 2); i596_add_cmd(dev, cmd); } else { if (lp->set_conf.pa_next != I596_NULL) { return; } if (dev->mc_count == 0 && !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { if (dev->flags & IFF_ALLMULTI) dev->flags |= IFF_PROMISC; lp->i596_config[8] &= ~0x01; } else { lp->i596_config[8] |= 0x01; } i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf); }}MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");MODULE_LICENSE("GPL");static struct net_device *dev_lp486e;static int full_duplex;static int options;static int io = IOADDR;static int irq = IRQ;module_param(debug, int, 0);//module_param(max_interrupt_work, int, 0);//module_param(reverse_probe, int, 0);//module_param(rx_copybreak, int, 0);module_param(options, int, 0);module_param(full_duplex, int, 0);static int __init lp486e_init_module(void) { int err; struct net_device *dev = alloc_etherdev(sizeof(struct i596_private)); if (!dev) return -ENOMEM; dev->irq = irq; dev->base_addr = io; err = lp486e_probe(dev); if (err) { free_netdev(dev); return err; } err = register_netdev(dev); if (err) { release_region(dev->base_addr, LP486E_TOTAL_SIZE); free_netdev(dev); return err; } dev_lp486e = dev; full_duplex = 0; options = 0; return 0;}static void __exit lp486e_cleanup_module(void) { unregister_netdev(dev_lp486e); release_region(dev_lp486e->base_addr, LP486E_TOTAL_SIZE); free_netdev(dev_lp486e);}module_init(lp486e_init_module);module_exit(lp486e_cleanup_module);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?