📄 dgrs.c
字号:
break; /* For safety */ if ( (p-putp) >= len) { printk("%s: cbp = %x\n", devN->name, 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 = %x\n", devN->name, 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 = %x\n", devN->name, 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); ++privN->stats.rx_packets;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 device *devN){ DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv; struct device *dev0; DGRS_PRIV *priv0; I596_RBD *rbdp; int count; int i, len, amt;# define mymin(A,B) ( (A) < (B) ? (A) : (B) ) /* * 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; devN->tbusy = 0; 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 = mymin(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 device *dev ){ dev->tbusy = 0; dev->interrupt = 0; dev->start = 1;#ifdef MODULE MOD_INC_USE_COUNT;#endif return (0);}/* * Close the interface */static int dgrs_close( struct device *dev ){ dev->start = 0; dev->tbusy = 1;#ifdef MODULE MOD_DEC_USE_COUNT;#endif return (0);}/* * Get statistics */static struct net_device_stats *dgrs_get_stats( struct 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 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 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 (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 device *dev0 = (struct 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) priv0->devtbl[i]->tbusy = 0; } else dev0->tbusy = 0; /* 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 */__initfunc(static intdgrs_download(struct 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, (uchar) (dev0->mem_start >> 16) ); priv0->is_reg = ES4H_IS_LINEAR | is | ((uchar) (dev0->mem_start >> 8) & ES4H_IS_AS15); OUTB(dev0->base_addr + ES4H_IS, priv0->is_reg); OUTB(dev0->base_addr + ES4H_EC, ES4H_EC_ENABLE); OUTB(dev0->base_addr + ES4H_PC, ES4H_PC_RESET); OUTB(dev0->base_addr + ES4H_MW, ES4H_MW_ENABLE | 0x00); } /* * See if we can do DMA on the SE-6 */ priv0->use_dma = check_board_dma(dev0); if (priv0->use_dma) printk("%s: Bus Master DMA is enabled.\n", dev0->name); /* * Load and verify the code at the desired address */ memcpy(priv0->vmem, dgrs_code, dgrs_ncode); /* Load code */ if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode)) { IOUNMAP(priv0->vmem); priv0->vmem = NULL; printk("%s: download compare failed\n", dev0->name); return -ENXIO; } /* * Configurables */ priv0->bcomm = (struct bios_comm *) (priv0->vmem + 0x0100); priv0->bcomm->bc_nowait = 1; /* Tell board to make printf not wait */ priv0->bcomm->bc_squelch = 0; /* Flag from Space.c */ priv0->bcomm->bc_150ohm = 0; /* Flag from Space.c */ priv0->bcomm->bc_spew = 0; /* Debug flag from Space.c */ priv0->bcomm->bc_maxrfd = 0; /* Debug flag from Space.c */ priv0->bcomm->bc_maxrbd = 0; /* Debug flag from Space.c */ /* * Tell board we are operating in switch mode (1) or in * multi-NIC mode (2). */ priv0->bcomm->bc_host = dgrs_nicmode ? BC_MULTINIC : BC_SWITCH; /* * Request memory space on board for DMA chains */ if (priv0->use_dma) priv0->bcomm->bc_hostarea_len = (2048/64) * 16;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -