?? 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 int
depca_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 void
depca_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 int
depca_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 + -