📄 lasi_82596.c
字号:
pcc2[0x2b] = 0x1d; printk("%s: Error interrupt\n", dev->name); i596_display_data(dev);}#endif#define virt_to_dma(lp,v) ((char *)(v)-(char *)(lp)+(char *)((lp)->dma_addr))static inline void init_rx_bufs(struct net_device *dev){ struct i596_private *lp = (struct i596_private *)dev->priv; int i; struct i596_rfd *rfd; struct i596_rbd *rbd; /* First build the Receive Buffer Descriptor List */ for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) { dma_addr_t dma_addr; struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ + 4); if (skb == NULL) panic("82596: alloc_skb() failed"); skb_reserve(skb, 2); dma_addr = pci_map_single(NULL, skb->tail,PKT_BUF_SZ, PCI_DMA_FROMDEVICE); skb->dev = dev; rbd->v_next = rbd+1; rbd->b_next = WSWAPrbd(virt_to_dma(lp,rbd+1)); rbd->b_addr = WSWAPrbd(virt_to_dma(lp,rbd)); rbd->skb = skb; rbd->v_data = skb->tail; rbd->b_data = WSWAPchar(dma_addr); rbd->size = PKT_BUF_SZ; } lp->rbd_head = lp->rbds; rbd = lp->rbds + rx_ring_size - 1; rbd->v_next = lp->rbds; rbd->b_next = WSWAPrbd(virt_to_dma(lp,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_dma(lp,rfd+1)); rfd->cmd = CMD_FLEX; } lp->rfd_head = lp->rfds; lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,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_dma(lp,lp->rfds)); rfd->cmd = CMD_EOL|CMD_FLEX; CHECK_WBACK_INV(lp, sizeof(struct i596_private));}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; pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); 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_dma(lp,lp->rfds)); lp->rbd_head = lp->rbds; lp->rfds[0].rbd = WSWAPrbd(virt_to_dma(lp,lp->rbds)); CHECK_WBACK_INV(lp, sizeof(struct i596_private));}static int init_i596_mem(struct net_device *dev){ struct i596_private *lp = (struct i596_private *) dev->priv; unsigned long flags; disable_irq(dev->irq); /* disable IRQs from LAN */ DEB(DEB_INIT, printk("RESET 82596 port: %08lX (with IRQ%d disabled)\n", dev->base_addr + PA_I82596_RESET, dev->irq)); gsc_writel(0, (void*)(dev->base_addr + PA_I82596_RESET)); /* Hard Reset */ udelay(100); /* Wait 100us - seems to help */ /* change the scp address */ lp->last_cmd = jiffies; lp->scp.sysbus = 0x0000006c; lp->scp.iscp = WSWAPiscp(virt_to_dma(lp,&(lp->iscp))); lp->iscp.scb = WSWAPscb(virt_to_dma(lp,&(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)); CHECK_WBACK(&(lp->scp), sizeof(struct i596_scp)); CHECK_WBACK(&(lp->iscp), sizeof(struct i596_iscp)); MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_dma(lp,&lp->scp)); 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; CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb)); enable_irq(dev->irq); /* enable IRQs from LAN */ 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; CHECK_WBACK(&(lp->cf_cmd), sizeof(struct cf_cmd)); 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; CHECK_WBACK(&(lp->sa_cmd), sizeof(struct sa_cmd)); i596_add_cmd(dev, &lp->sa_cmd.cmd); DEB(DEB_INIT,printk("%s: queuing CmdTDR\n", dev->name)); lp->tdr_cmd.cmd.command = CmdTDR; CHECK_WBACK(&(lp->tdr_cmd), sizeof(struct tdr_cmd)); 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; lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds)); CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb)); 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 */ CHECK_INV(rfd, sizeof(struct i596_rfd)); 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; CHECK_INV(rbd, sizeof(struct i596_rbd)); } 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; dma_addr_t dma_addr; pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* Get fresh skbuff to replace filled one. */ newskb = dev_alloc_skb(PKT_BUF_SZ + 4); if (newskb == NULL) { skb = NULL; /* drop pkt */ goto memory_squeeze; } skb_reserve(newskb, 2); /* Pass up the skb already on the Rx ring. */ skb_put(skb, pkt_len); rx_in_place = 1; rbd->skb = newskb; newskb->dev = dev; dma_addr = pci_map_single(NULL, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); rbd->v_data = newskb->tail; rbd->b_data = WSWAPchar(dma_addr); CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd)); } 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 */ pci_dma_sync_single(NULL, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); skb_reserve(skb, 2); memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len); } skb->len = pkt_len; skb->protocol=eth_type_trans(skb,dev); 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; CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd)); } /* 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; CHECK_WBACK_INV(rfd->v_prev, sizeof(struct i596_rfd)); CHECK_WBACK_INV(rfd, sizeof(struct i596_rfd)); rfd = lp->rfd_head; CHECK_INV(rfd, sizeof(struct i596_rfd)); } 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; pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE); 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; } CHECK_WBACK_INV(ptr, sizeof(struct i596_cmd)); } wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out"); lp->scb.cmd = I596_NULL; CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb));}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); /* FIXME: this command might cause an lpmc */ lp->scb.command = CUC_ABORT | RX_ABORT; CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb)); 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 cmd_head %p\n", lp->cmd_head)); cmd->status = 0; cmd->command |= (CMD_EOL | CMD_INTR); cmd->v_next = cmd->b_next = I596_NULL; CHECK_WBACK(cmd, sizeof(struct i596_cmd)); 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_dma(lp,&cmd->status)); CHECK_WBACK(lp->cmd_tail, sizeof(struct i596_cmd)); } else { lp->cmd_head = cmd; wait_cmd(dev,lp,100,"i596_add_cmd timed out"); lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&cmd->status)); lp->scb.command = CUC_START; CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb)); 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);#if 1 i596_reset(dev, lp, ioaddr);#endif }}#if 0/* this function makes a perfectly adequate probe... but we have a device list */static int i596_test(struct net_device *dev){ struct i596_private *lp = (struct i596_private *) dev->priv; volatile int *tint; u32 data; tint = (volatile int *)(&(lp->scp)); data = virt_to_dma(lp,tint); tint[1] = -1; CHECK_WBACK(tint,PAGE_SIZE); MPU_PORT(dev, 1, data); for(data = 1000000; data; data--) { CHECK_INV(tint,PAGE_SIZE); if(tint[1] != -1) break; } printk("i596_test result %d\n", tint[1]);}#endifstatic 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; } request_region(dev->base_addr, 12, dev->name); 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"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -