📄 dgrs.c
字号:
*/ if (priv0->use_dma && priv0->dmadesc_h && len > 64) { /* * If we can use DMA and its a long frame, copy it using * DMA chaining. */ DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */ DMACHAIN *ddp_s; /* Switch physical DMA desc. pointer */ uchar *phys_p; /* * Get the physical address of the STREAMS buffer. * NOTE: allocb() guarantees that the whole buffer * is in a single page if the length < 4096. */ phys_p = (uchar *) virt_to_phys(putp); ddp_h = priv0->dmadesc_h; ddp_s = priv0->dmadesc_s; tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp); for (;;) { int count; int amt; count = tbdp->count; amt = count & 0x3fff; if (amt == 0) break; /* For safety */ if ( (p-putp) >= len) { printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp)); proc_reset(dev0, 1); /* Freeze IDT */ break; /* For Safety */ } ddp_h->pciaddr = (ulong) phys_p; ddp_h->lcladdr = S2DMA(tbdp->buf); ddp_h->len = amt; phys_p += amt; p += amt; if (count & I596_TBD_EOF) { ddp_h->next = PLX_DMA_DESC_TO_HOST | PLX_DMA_DESC_EOC; ++ddp_h; break; } else { ++ddp_s; ddp_h->next = PLX_DMA_DESC_TO_HOST | (ulong) ddp_s; tbdp = (I596_TBD *) S2H(tbdp->next); ++ddp_h; } } if (ddp_h - priv0->dmadesc_h) { int rc; rc = do_plx_dma(dev0, 0, (ulong) priv0->dmadesc_s, len, 0); if (rc) { printk("%s: Chained DMA failure\n", devN->name); goto again; } } } else if (priv0->use_dma) { /* * If we can use DMA and its a shorter frame, copy it * using single DMA transfers. */ uchar *phys_p; /* * Get the physical address of the STREAMS buffer. * NOTE: allocb() guarantees that the whole buffer * is in a single page if the length < 4096. */ phys_p = (uchar *) virt_to_phys(putp); tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp); for (;;) { int count; int amt; int rc; count = tbdp->count; amt = count & 0x3fff; if (amt == 0) break; /* For safety */ if ( (p-putp) >= len) { printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp)); proc_reset(dev0, 1); /* Freeze IDT */ break; /* For Safety */ } rc = do_plx_dma(dev0, (ulong) phys_p, S2DMA(tbdp->buf), amt, 1); if (rc) { memcpy(p, S2H(tbdp->buf), amt); printk("%s: Single DMA failed\n", devN->name); } phys_p += amt; p += amt; if (count & I596_TBD_EOF) break; tbdp = (I596_TBD *) S2H(tbdp->next); } } else { /* * Otherwise, copy it piece by piece using memcpy() */ tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp); for (;;) { int count; int amt; count = tbdp->count; amt = count & 0x3fff; if (amt == 0) break; /* For safety */ if ( (p-putp) >= len) { printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp)); proc_reset(dev0, 1); /* Freeze IDT */ break; /* For Safety */ } memcpy(p, S2H(tbdp->buf), amt); p += amt; if (count & I596_TBD_EOF) break; tbdp = (I596_TBD *) S2H(tbdp->next); } } /* * Pass the frame to upper half */ skb->protocol = eth_type_trans(skb, devN); netif_rx(skb); devN->last_rx = jiffies; ++privN->stats.rx_packets; privN->stats.rx_bytes += len;out: cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;}/* * Start transmission of a frame * * The interface to the board is simple: we pretend that we are * a fifth 82596 ethernet controller 'receiving' data, and copy the * data into the same structures that a real 82596 would. This way, * the board firmware handles the host 'port' the same as any other. * * NOTE: we do not use Bus master DMA for this routine. Turns out * that it is not needed. Slave writes over the PCI bus are about * as fast as DMA, due to the fact that the PLX part can do burst * writes. The same is not true for data being read from the board. * * For multi-NIC mode, we tell the firmware the desired 82596 * output port by setting the special "dstchan" member at the * end of the traditional 82596 RFD structure. */static int dgrs_start_xmit(struct sk_buff *skb, struct net_device *devN){ DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv; struct net_device *dev0; DGRS_PRIV *priv0; I596_RBD *rbdp; int count; int i, len, amt; /* * Determine 0th priv and dev structure pointers */ if (dgrs_nicmode) { dev0 = privN->devtbl[0]; priv0 = (DGRS_PRIV *) dev0->priv; } else { dev0 = devN; priv0 = privN; } if (dgrs_debug > 1) printk("%s: xmit len=%d\n", devN->name, (int) skb->len); devN->trans_start = jiffies; netif_start_queue(devN); if (priv0->rfdp->cmd & I596_RFD_EL) { /* Out of RFD's */ if (0) printk("%s: NO RFD's\n", devN->name); goto no_resources; } rbdp = priv0->rbdp; count = 0; priv0->rfdp->rbdp = (I596_RBD *) H2S(rbdp); i = 0; len = skb->len; for (;;) { if (rbdp->size & I596_RBD_EL) { /* Out of RBD's */ if (0) printk("%s: NO RBD's\n", devN->name); goto no_resources; } amt = min_t(unsigned int, len, rbdp->size - count); memcpy( (char *) S2H(rbdp->buf) + count, skb->data + i, amt); i += amt; count += amt; len -= amt; if (len == 0) { if (skb->len < 60) rbdp->count = 60 | I596_RBD_EOF; else rbdp->count = count | I596_RBD_EOF; rbdp = (I596_RBD *) S2H(rbdp->next); goto frame_done; } else if (count < 32) { /* More data to come, but we used less than 32 * bytes of this RBD. Keep filling this RBD. */ {} /* Yes, we do nothing here */ } else { rbdp->count = count; rbdp = (I596_RBD *) S2H(rbdp->next); count = 0; } }frame_done: priv0->rbdp = rbdp; if (dgrs_nicmode) priv0->rfdp->dstchan = privN->chan; priv0->rfdp->status = I596_RFD_C | I596_RFD_OK; priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next); ++privN->stats.tx_packets; dev_kfree_skb (skb); return (0);no_resources: priv0->scbp->status |= I596_SCB_RNR; /* simulate I82596 */ return (-EAGAIN);}/* * Open the interface */static intdgrs_open( struct net_device *dev ){ netif_start_queue(dev); return (0);}/* * Close the interface */static int dgrs_close( struct net_device *dev ){ netif_stop_queue(dev); return (0);}/* * Get statistics */static struct net_device_stats *dgrs_get_stats( struct net_device *dev ){ DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; return (&priv->stats);}/* * Set multicast list and/or promiscuous mode */static void dgrs_set_multicast_list( struct net_device *dev){ DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; priv->port->is_promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;}/* * Unique ioctl's */static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd){ DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv; DGRS_IOCTL ioc; int i; if (cmd != DGRSIOCTL) return -EINVAL; if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL))) return -EFAULT; switch (ioc.cmd) { case DGRS_GETMEM: if (ioc.len != sizeof(ulong)) return -EINVAL; if(copy_to_user(ioc.data, &devN->mem_start, ioc.len)) return -EFAULT; return (0); case DGRS_SETFILTER: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (ioc.port > privN->bcomm->bc_nports) return -EINVAL; if (ioc.filter >= NFILTERS) return -EINVAL; if (ioc.len > privN->bcomm->bc_filter_area_len) return -EINVAL; /* Wait for old command to finish */ for (i = 0; i < 1000; ++i) { if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 ) break; udelay(1); } if (i >= 1000) return -EIO; privN->bcomm->bc_filter_port = ioc.port; privN->bcomm->bc_filter_num = ioc.filter; privN->bcomm->bc_filter_len = ioc.len; if (ioc.len) { if(copy_from_user(S2HN(privN->bcomm->bc_filter_area), ioc.data, ioc.len)) return -EFAULT; privN->bcomm->bc_filter_cmd = BC_FILTER_SET; } else privN->bcomm->bc_filter_cmd = BC_FILTER_CLR; return(0); default: return -EOPNOTSUPP; }}/* * Process interrupts * * dev, priv will always refer to the 0th device in Multi-NIC mode. */static void dgrs_intr(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev0 = (struct net_device *) dev_id; DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; I596_CB *cbp; int cmd; int i; ++priv0->intrcnt; if (1) ++priv0->bcomm->bc_cnt[4]; if (0) { static int cnt = 100; if (--cnt > 0) printk("%s: interrupt: irq %d\n", dev0->name, irq); } /* * Get 596 command */ cmd = priv0->scbp->cmd; /* * See if RU has been restarted */ if ( (cmd & I596_SCB_RUC) == I596_SCB_RUC_START) { if (0) printk("%s: RUC start\n", dev0->name); priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp); priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp); priv0->scbp->status &= ~(I596_SCB_RNR|I596_SCB_RUS); /* * Tell upper half (halves) */ if (dgrs_nicmode) { for (i = 0; i < priv0->nports; ++i) netif_wake_queue (priv0->devtbl[i]); } else netif_wake_queue (dev0); /* if (bd->flags & TX_QUEUED) DL_sched(bd, bdd); */ } /* * See if any CU commands to process */ if ( (cmd & I596_SCB_CUC) != I596_SCB_CUC_START) { priv0->scbp->cmd = 0; /* Ignore all other commands */ goto ack_intr; } priv0->scbp->status &= ~(I596_SCB_CNA|I596_SCB_CUS); /* * Process a command */ cbp = (I596_CB *) S2H(priv0->scbp->cbp); priv0->scbp->cmd = 0; /* Safe to clear the command */ for (;;) { switch (cbp->nop.cmd & I596_CB_CMD) { case I596_CB_CMD_XMIT: dgrs_rcv_frame(dev0, priv0, cbp); break; default: cbp->nop.status = I596_CB_STATUS_C | I596_CB_STATUS_OK; break; } if (cbp->nop.cmd & I596_CB_CMD_EL) break; cbp = (I596_CB *) S2H(cbp->nop.next); } priv0->scbp->status |= I596_SCB_CNA; /* * Ack the interrupt */ack_intr: if (priv0->plxreg) OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);}/* * Download the board firmware */static int __init dgrs_download(struct net_device *dev0){ DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; int is; int i; static int iv2is[16] = { 0, 0, 0, ES4H_IS_INT3, 0, ES4H_IS_INT5, 0, ES4H_IS_INT7, 0, 0, ES4H_IS_INT10, ES4H_IS_INT11, ES4H_IS_INT12, 0, 0, ES4H_IS_INT15 }; /* * Map in the dual port memory */ priv0->vmem = ioremap(dev0->mem_start, 2048*1024); if (!priv0->vmem) { printk("%s: cannot map in board memory\n", dev0->name); return -ENXIO; } /* * Hold the processor and configure the board addresses */ if (priv0->plxreg) { /* PCI bus */ proc_reset(dev0, 1); } else { /* EISA bus */ is = iv2is[dev0->irq & 0x0f]; if (!is) { printk("%s: Illegal IRQ %d\n", dev0->name, dev0->irq); return -ENXIO; } OUTB(dev0->base_addr + ES4H_AS_31_24, (uchar) (dev0->mem_start >> 24) ); OUTB(dev0->base_addr + ES4H_AS_23_16,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -