📄 depca.c
字号:
printk(" starting at 0x%.5lx", mem_start); /* ** Enable the shadow RAM. */ nicsr |= SHE; outw(nicsr, DEPCA_NICSR); /* ** Calculate the ring size based on the available RAM ** found above. Allocate an equal number of buffers, each ** of size PKT_BUF_SZ (1544 bytes) to the Tx and Rx. Make sure ** that this ring size is <= RING_SIZE. The ring size must be ** a power of 2. */ j = ((0x10000 - offset) / PKT_BUF_SZ) >> 1; for (i=0;j>1;i++) { j >>= 1; } /* Hold the ring size information here before the depca ** private structure is allocated. Need this for the memory ** space calculations. */ j = 1 << i; /* ** Set up memory information in the device structure. ** Align the descriptor rings on an 8 byte (quadword) boundary. ** ** depca_private area ** rx ring descriptors ** tx ring descriptors ** rx buffers ** tx buffers ** */ /* private area & initialise */ dev->priv = (void *)((mem_start + 0x07) & ~0x07); lp = (struct depca_private *)dev->priv; memset(dev->priv, 0, sizeof(struct depca_private)); /* Tx & Rx descriptors (aligned to a quadword boundary) */ mem_start = ((((unsigned long)dev->priv + sizeof(struct depca_private)) + (unsigned long)0x07) & (unsigned long)~0x07); lp->rx_ring = (struct depca_rx_head *)mem_start; mem_start += (sizeof(struct depca_rx_head) * j); lp->tx_ring = (struct depca_tx_head *)mem_start; mem_start += (sizeof(struct depca_tx_head) * j); lp->dma_buffs = mem_start & 0x00ffffff; mem_start += (PKT_BUF_SZ * j); /* (mem_start now points to the start of the Tx buffers) */ /* Initialise the data structures */ memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j); memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j); /* This should never happen. */ if ((int)(lp->rx_ring) & 0x07) { printk("\n **ERROR** DEPCA Rx and Tx descriptor rings not on a quadword boundary.\n"); return -ENXIO; } /* ** Finish initialising the ring information. */ lp->ringSize = j; if (lp->ringSize > RING_SIZE) lp->ringSize = RING_SIZE; lp->rmask = lp->ringSize - 1; /* ** calculate the real RLEN size for the descriptors. It is ** log2(ringSize). */ for (i=0, j = lp->ringSize; j>1; i++) { j >>= 1; } lp->rlen = (unsigned long)(i << 29); /* ** load the initialisation block */ depca_init_ring(dev); /* ** Initialise the control and status registers */ LoadCSRs(dev); /* ** Enable DEPCA board interrupts for autoprobing */ nicsr = ((nicsr & ~IM)|IEN); outw(nicsr, DEPCA_NICSR); /* The DMA channel may be passed in on this parameter. */ dev->dma = 0; /* To auto-IRQ we enable the initialization-done and DMA err, interrupts. For now we will always get a DMA error. */ if (dev->irq < 2) { autoirq_setup(0); /* Trigger an initialization just for the interrupt. */ outw(INEA | INIT, DEPCA_DATA); dev->irq = autoirq_report(1); if (dev->irq) { printk(" and probed IRQ%d.\n", dev->irq); } else { printk(". Failed to detect IRQ line.\n"); status = -EAGAIN; } } else { printk(". Assigned IRQ%d.\n", dev->irq); } } else { status = -ENXIO; } if (!status) { if (depca_debug > 0) { printk(version); } /* The DEPCA-specific entries in the device structure. */ dev->open = &depca_open; dev->hard_start_xmit = &depca_start_xmit; dev->stop = &depca_close; dev->get_stats = &depca_get_stats;#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list;#endif dev->mem_start = 0; /* Fill in the generic field of the device structure. */ for (i = 0; i < DEV_NUMBUFFS; i++) { dev->buffs[i] = NULL; } dev->hard_header = eth_header; dev->add_arp = eth_add_arp; dev->queue_xmit = dev_queue_xmit; dev->rebuild_header = eth_rebuild_header; dev->type_trans = eth_type_trans; dev->type = ARPHRD_ETHER; dev->hard_header_len = ETH_HLEN; dev->mtu = 1500; /* eth_mtu */ dev->addr_len = ETH_ALEN; for (i = 0; i < dev->addr_len; i++) { dev->broadcast[i]=0xff; } /* New-style flags. */ dev->flags = IFF_BROADCAST; dev->family = AF_INET; dev->pa_addr = 0; dev->pa_brdaddr = 0; dev->pa_mask = 0; dev->pa_alen = sizeof(unsigned long); } } else { status = -ENXIO; } return status;}static intdepca_open(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; int i,nicsr,ioaddr = dev->base_addr; if (request_irq(dev->irq, &depca_interrupt)) { printk("depca_open(): Requested IRQ%d is busy\n",dev->irq); return -EAGAIN; } irq2dev_map[dev->irq] = dev; /* ** Stop the DEPCA & get the board status information. */ STOP_DEPCA; nicsr = inw(DEPCA_NICSR); /* ** Re-initialize the DEPCA... */ depca_init_ring(dev); /* initialize the descriptor rings */ LoadCSRs(dev); if (depca_debug > 1){ printk("%s: depca open with irq %d\n",dev->name,dev->irq); printk("Descriptor head addresses:\n"); printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring); printk("Descriptor addresses:\n"); for (i=0;i<lp->ringSize;i++){ printk("\t0x%8.8lx 0x%8.8lx\n",(long)&lp->rx_ring[i].base, (long)&lp->tx_ring[i].base); } printk("Buffer addresses:\n"); for (i=0;i<lp->ringSize;i++){ printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring[i].base, (long)lp->tx_ring[i].base); } printk("Initialisation block at 0x%8.8lx\n",(long)&lp->init_block); printk("\tmode: 0x%4.4x\n",lp->init_block.mode); printk("\tphysical address: "); for (i=0;i<6;i++){ printk("%2.2x:",(short)lp->init_block.phys_addr[i]); } printk("\n\tlogical address filter: 0x"); for (i=0;i<4;i++){ printk("%2.2x",(short)lp->init_block.filter[i]); } printk("\n\trx_ring at: 0x%8.8lx\n",(long)lp->init_block.rx_ring); printk("\ttx_ring at: 0x%8.8lx\n",(long)lp->init_block.tx_ring); printk("dma_buffs: 0x%8.8lx\n",(long)lp->dma_buffs); printk("Ring size: %d\nMask: 0x%2.2x\nLog2(ringSize): 0x%8.8lx\n", (short)lp->ringSize, (char)lp->rmask, (long)lp->rlen); outw(CSR2,DEPCA_ADDR); printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA)); outw(CSR1,DEPCA_ADDR); printk("%4.4x\n",inw(DEPCA_DATA)); outw(CSR3,DEPCA_ADDR); printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA)); } /* ** Enable DEPCA board interrupts */ nicsr = ((nicsr & ~IM & ~LED)|SHE|IEN); outw(nicsr, DEPCA_NICSR); outw(CSR0,DEPCA_ADDR); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; InitRestartDepca(dev); /* ignore the return status */ if (depca_debug > 1){ printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA)); printk("nicsr: 0x%4.4x\n",inw(DEPCA_NICSR)); } return 0; /* Always succeed */}/* Initialize the lance Rx and Tx descriptor rings. */static voiddepca_init_ring(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; unsigned long i; lp->init_block.mode = DTX | DRX; /* Disable Rx and Tx. */ lp->cur_rx = lp->cur_tx = 0; lp->dirty_rx = lp->dirty_tx = 0; /* Initialize the base addresses and length of each buffer in the ring */ for (i = 0; i < lp->ringSize; i++) { lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | R_OWN; lp->rx_ring[i].buf_length = -PKT_BUF_SZ; lp->tx_ring[i].base = (lp->dma_buffs + (i+lp->ringSize) * PKT_BUF_SZ) & (unsigned long)(0x00ffffff); } /* Set up the initialization block */ for (i = 0; i < ETH_ALEN; i++) { lp->init_block.phys_addr[i] = dev->dev_addr[i]; } for (i = 0; i < 4; i++) { lp->init_block.filter[i] = 0x0000; } lp->init_block.rx_ring = (unsigned long)lp->rx_ring | lp->rlen; lp->init_block.tx_ring = (unsigned long)lp->tx_ring | lp->rlen; lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */ }/* ** Writes a socket buffer to TX descriptor ring and starts transmission */static intdepca_start_xmit(struct sk_buff *skb, struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; int ioaddr = dev->base_addr; int status = 0; /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) { status = -1; } else { STOP_DEPCA; printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, inw(DEPCA_DATA)); depca_init_ring(dev); LoadCSRs(dev); InitRestartDepca(dev); dev->tbusy=0; dev->trans_start = jiffies; } return status; } if (skb == NULL) { dev_tint(dev); return 0; } /* Fill in the ethernet header. */ if (!skb->arp && dev->rebuild_header(skb->data, dev)) { skb->dev = dev; arp_queue (skb); return 0; } skb->arp=1; if (skb->len <= 0) { return 0; } if (depca_debug > 3) { outw(CSR0, DEPCA_ADDR); printk("%s: depca_start_xmit() called, csr0 %4.4x.\n", dev->name, inw(DEPCA_DATA)); } /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); /* ** The TX buffer, skb, has to be copied into the local network RAM ** for the LANCE to access it. The skb may be at > 16MB for large ** (memory) systems. */ { /* Fill in a Tx ring entry */ unsigned char *buf; int entry = lp->cur_tx++; int len; long skbL = skb->len; char *p = (char *) skb->data; entry &= lp->rmask; /* Ring around buffer number. */ buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff); /* Wait for a full ring to free up */ while (lp->tx_ring[entry].base < 0); /* ** Caution: the write order is important here... don't set up the ** ownership rights until all the other information is in place. */ len = ((skbL > PKT_SZ) ? PKT_SZ : skbL); /* skb too long */ if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */ skbL -= len; lp->tx_ring[entry].length = -len; /* Clears various error flags */ lp->tx_ring[entry].misc = 0x0000; /* copy the data from the socket buffer to the net memory */ memcpy((unsigned char *)(buf), skb->data, len); /* Hand over buffer ownership to the LANCE */ if (skbL <= 0) lp->tx_ring[entry].base |= (T_ENP); lp->tx_ring[entry].base |= (T_OWN|T_STP); /* Trigger an immediate send demand. */ outw(CSR0, DEPCA_ADDR); outw(INEA | TDMD, DEPCA_DATA); dev->trans_start = jiffies; for (p += len; skbL > 0; p += len) { /* Get new buffer pointer */ entry = lp->cur_tx++; entry &= lp->rmask; /* Ring around buffer number. */ buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff); /* Wait for a full ring to free up */ while (lp->tx_ring[entry].base < 0); dev->tbusy=0; /* Copy ethernet header to the new buffer */ memcpy((unsigned char *)buf, skb->data, PKT_HDR_LEN); /* Determine length of data buffer */ len = ((skbL > DAT_SZ) ? DAT_SZ : skbL); /* skbL too long */ if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */ skbL -= len; lp->tx_ring[entry].length = -len; /* Clears various error flags */ lp->tx_ring[entry].misc = 0x0000; /* copy the data from the socket buffer to the net memory */ memcpy((unsigned char *)(buf + PKT_HDR_LEN), (unsigned char *)p, len); /* Hand over buffer ownership to the LANCE */ if (skbL <= 0) lp->tx_ring[entry].base |= T_ENP; lp->tx_ring[entry].base |= T_OWN; } if (depca_debug > 4) { unsigned char *pkt = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff); printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n", dev->name, entry, (unsigned long) &lp->tx_ring[entry], lp->tx_ring[entry].base, -lp->tx_ring[entry].length); printk("%s: Tx %2.2x %2.2x %2.2x ... %2.2x %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x %2.2x %2.2x.\n", dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6], pkt[7], pkt[8], pkt[11], pkt[12], pkt[13], pkt[14], pkt[15]); } /* Check if the TX ring is full or not - 'tbusy' cleared if not full. */ if (lp->tx_ring[(entry+1) & lp->rmask].base >= 0) { dev->tbusy=0; } if (skb->free) { kfree_skb (skb, FREE_WRITE); } } return 0;}/*** The DEPCA interrupt handler. */static void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -