📄 lp486e.c
字号:
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); lp->stats.tx_packets++; } return 0;}static voidi596_tx_timeout (struct net_device *dev) { volatile struct i596_private *lp = dev->priv; int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ 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) { 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 = lp->stats.tx_packets; } netif_wake_queue(dev);}static voidprint_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]);}int __initlp486e_probe(struct net_device *dev) { volatile 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, dev->name)) { printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR); return -EBUSY; } /* * Allocate working memory, 16-byte aligned */ dev->mem_start = (unsigned long) kmalloc(sizeof(struct i596_private) + 0x0f, GFP_KERNEL); if (!dev->mem_start) goto err_out; dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0); lp = (struct i596_private *) dev->priv; memset((void *)lp, 0, sizeof(struct i596_private)); /* * Do we really have this thing? */ if (i596_scp_setup(dev)) { ret = -ENODEV; goto err_out_kfree; } dev->base_addr = IOADDR; dev->irq = IRQ; ether_setup(dev); /* * 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->get_stats = &i596_get_stats; 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: kfree ((void *) dev->mem_start);err_out: release_region(IOADDR, LP486E_TOTAL_SIZE); return ret;}static void inlinei596_handle_CU_completion(struct net_device *dev, volatile struct i596_private *lp, unsigned short status, unsigned short *ack_cmdp) { volatile struct i596_cmd *cmd; int frames_out = 0; int commands_done = 0; int cmd_val; 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 { lp->stats.tx_errors++; if (i596_debug) printk("transmission failure:%04x\n", cmd->status); if (cmd->status & 0x0020) lp->stats.collisions++; if (!(cmd->status & 0x0040)) lp->stats.tx_heartbeat_errors++; if (cmd->status & 0x0400) lp->stats.tx_carrier_errors++; if (cmd->status & 0x0800) lp->stats.collisions++; if (cmd->status & 0x1000) lp->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; } } cmd = lp->cmd_head; while (cmd && (cmd != lp->cmd_tail)) { cmd->command &= 0x1fff; cmd = pa_to_va(cmd->pa_next); } if (lp->cmd_head) *ack_cmdp |= CUC_START; lp->scb.pa_cmd = va_to_pa(lp->cmd_head);}static voidi596_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_instance; volatile struct i596_private *lp; unsigned short status, ack_cmd = 0; int frames_in = 0; if (dev == NULL) { printk ("i596_interrupt(): irq %d for unknown device.\n", irq); return; } 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;}static int i596_close(struct net_device *dev) { volatile 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;}static struct net_device_stats * i596_get_stats(struct net_device *dev) { struct i596_private *lp = dev->priv; return &lp->stats;}/** Set or clear the multicast filter for this adaptor.*/static void set_multicast_list(struct net_device *dev) { volatile 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 = (struct i596_cmd *) kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC); if (cmd == NULL) { printk ("%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");MODULE_PARM(debug, "i");//MODULE_PARM(max_interrupt_work, "i");//MODULE_PARM(reverse_probe, "i");//MODULE_PARM(rx_copybreak, "i");MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");static struct net_device dev_lp486e;static int full_duplex;static int options;static int io = IOADDR;static int irq = IRQ;static int __init lp486e_init_module(void) { struct net_device *dev = &dev_lp486e; dev->irq = irq; dev->base_addr = io; dev->init = lp486e_probe; if (register_netdev(dev) != 0) return -EIO; full_duplex = 0; options = 0; return 0;}static void __exit lp486e_cleanup_module(void) { unregister_netdev(&dev_lp486e); kfree((void *)dev_lp486e.mem_start); dev_lp486e.priv = NULL; release_region(dev_lp486e.base_addr, LP486E_TOTAL_SIZE);}module_init(lp486e_init_module);module_exit(lp486e_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -