ewrk3.c
字号:
** Determine the base address and window length for the EWRK3 ** RAM from the memory base register. */ mem_start = inb(EWRK3_MBR); shmem_length = 0; if (mem_start != 0) { if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) { mem_start *= SHMEM_64K; shmem_length = SHMEM_64K; } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) { mem_start *= SHMEM_32K; shmem_length = SHMEM_32K; } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) { mem_start = mem_start * SHMEM_2K + 0x80000; shmem_length = SHMEM_2K; } else { return -ENXIO; } } /* ** See the top of this source code for comments about ** uncommenting this line. *//* FORCE_2K_MODE; */ if (hard_strapped) { printk(" is hard strapped.\n"); } else if (mem_start) { printk(" has a %dk RAM window", (int) (shmem_length >> 10)); printk(" at 0x%.5lx", mem_start); } else { printk(" is in I/O only mode"); } lp = netdev_priv(dev); lp->shmem_base = mem_start; lp->shmem = ioremap(mem_start, shmem_length); if (!lp->shmem) return -ENOMEM; lp->shmem_length = shmem_length; lp->lemac = lemac; lp->hard_strapped = hard_strapped; lp->led_mask = CR_LED; spin_lock_init(&lp->hw_lock); lp->mPage = 64; if (cmr & CMR_DRAM) lp->mPage <<= 1; /* 2 DRAMS on module */ sprintf(lp->adapter_name, "%s (%s)", name, dev->name); lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM; if (!hard_strapped) { /* ** Enable EWRK3 board interrupts for autoprobing */ icr |= ICR_IE; /* Enable interrupts */ outb(icr, EWRK3_ICR); /* 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) {#ifndef MODULE u_char irqnum; unsigned long irq_mask; irq_mask = probe_irq_on(); /* ** Trigger a TNE interrupt. */ icr |= ICR_TNEM; outb(1, EWRK3_TDQ); /* Write to the TX done queue */ outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */ irqnum = irq[((icr & IRQ_SEL) >> 4)]; mdelay(20); dev->irq = probe_irq_off(irq_mask); if ((dev->irq) && (irqnum == dev->irq)) { printk(" and uses IRQ%d.\n", dev->irq); } else { if (!dev->irq) { printk(" and failed to detect IRQ line.\n"); } else if ((irqnum == 1) && (lemac == LeMAC2)) { printk(" and an illegal IRQ line detected.\n"); } else { printk(", but incorrect IRQ line detected.\n"); } iounmap(lp->shmem); return -ENXIO; } DISABLE_IRQs; /* Mask all interrupts */#endif /* MODULE */ } else { printk(" and requires IRQ%d.\n", dev->irq); } } if (ewrk3_debug > 1) { printk(version); } /* The EWRK3-specific entries in the device structure. */ dev->open = ewrk3_open; dev->hard_start_xmit = ewrk3_queue_pkt; dev->stop = ewrk3_close; dev->set_multicast_list = set_multicast_list; dev->do_ioctl = ewrk3_ioctl; if (lp->adapter_name[4] == '3') SET_ETHTOOL_OPS(dev, ðtool_ops_203); else SET_ETHTOOL_OPS(dev, ðtool_ops); dev->tx_timeout = ewrk3_timeout; dev->watchdog_timeo = QUEUE_PKT_TIMEOUT; dev->mem_start = 0; return 0;}static int ewrk3_open(struct net_device *dev){ struct ewrk3_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int status = 0; u_char icr, csr; /* ** Stop the TX and RX... */ STOP_EWRK3; if (!lp->hard_strapped) { if (request_irq(dev->irq, (void *) ewrk3_interrupt, 0, "ewrk3", dev)) { printk("ewrk3_open(): Requested IRQ%d is busy\n", dev->irq); status = -EAGAIN; } else { /* ** Re-initialize the EWRK3... */ ewrk3_init(dev); if (ewrk3_debug > 1) { DECLARE_MAC_BUF(mac); printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq); printk(" physical address: %s\n", print_mac(mac, dev->dev_addr)); if (lp->shmem_length == 0) { printk(" no shared memory, I/O only mode\n"); } else { printk(" start of shared memory: 0x%08lx\n", lp->shmem_base); printk(" window length: 0x%04lx\n", lp->shmem_length); } printk(" # of DRAMS: %d\n", ((inb(EWRK3_CMR) & 0x02) ? 2 : 1)); printk(" csr: 0x%02x\n", inb(EWRK3_CSR)); printk(" cr: 0x%02x\n", inb(EWRK3_CR)); printk(" icr: 0x%02x\n", inb(EWRK3_ICR)); printk(" cmr: 0x%02x\n", inb(EWRK3_CMR)); printk(" fmqc: 0x%02x\n", inb(EWRK3_FMQC)); } netif_start_queue(dev); /* ** Unmask EWRK3 board interrupts */ icr = inb(EWRK3_ICR); ENABLE_IRQs; } } else { printk(KERN_ERR "%s: ewrk3 available for hard strapped set up only.\n", dev->name); printk(KERN_ERR " Run the 'ewrk3setup' utility or remove the hard straps.\n"); return -EINVAL; } return status;}/* ** Initialize the EtherWORKS 3 operating conditions */static void ewrk3_init(struct net_device *dev){ struct ewrk3_private *lp = netdev_priv(dev); u_char csr, page; u_long iobase = dev->base_addr; int i; /* ** Enable any multicasts */ set_multicast_list(dev); /* ** Set hardware MAC address. Address is initialized from the EEPROM ** during startup but may have since been changed by the user. */ for (i=0; i<ETH_ALEN; i++) outb(dev->dev_addr[i], EWRK3_PAR0 + i); /* ** Clean out any remaining entries in all the queues here */ while (inb(EWRK3_TQ)); while (inb(EWRK3_TDQ)); while (inb(EWRK3_RQ)); while (inb(EWRK3_FMQ)); /* ** Write a clean free memory queue */ for (page = 1; page < lp->mPage; page++) { /* Write the free page numbers */ outb(page, EWRK3_FMQ); /* to the Free Memory Queue */ } START_EWRK3; /* Enable the TX and/or RX */}/* * Transmit timeout */static void ewrk3_timeout(struct net_device *dev){ struct ewrk3_private *lp = netdev_priv(dev); u_char icr, csr; u_long iobase = dev->base_addr; if (!lp->hard_strapped) { printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n", dev->name, inb(EWRK3_CSR)); /* ** Mask all board interrupts */ DISABLE_IRQs; /* ** Stop the TX and RX... */ STOP_EWRK3; ewrk3_init(dev); /* ** Unmask EWRK3 board interrupts */ ENABLE_IRQs; dev->trans_start = jiffies; netif_wake_queue(dev); }}/* ** Writes a socket buffer to the free page queue */static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev){ struct ewrk3_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; void __iomem *buf = NULL; u_char icr; u_char page; spin_lock_irq (&lp->hw_lock); DISABLE_IRQs; /* if no resources available, exit, request packet be queued */ if (inb (EWRK3_FMQC) == 0) { printk (KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n", dev->name); printk (KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", dev->name, inb (EWRK3_CSR), inb (EWRK3_ICR), inb (EWRK3_FMQC)); goto err_out; } /* ** Get a free page from the FMQ */ if ((page = inb (EWRK3_FMQ)) >= lp->mPage) { printk ("ewrk3_queue_pkt(): Invalid free memory page (%d).\n", (u_char) page); goto err_out; } /* ** Set up shared memory window and pointer into the window */ if (lp->shmem_length == IO_ONLY) { outb (page, EWRK3_IOPR); } else if (lp->shmem_length == SHMEM_2K) { buf = lp->shmem; outb (page, EWRK3_MPR); } else if (lp->shmem_length == SHMEM_32K) { buf = (((short) page << 11) & 0x7800) + lp->shmem; outb ((page >> 4), EWRK3_MPR); } else if (lp->shmem_length == SHMEM_64K) { buf = (((short) page << 11) & 0xf800) + lp->shmem; outb ((page >> 5), EWRK3_MPR); } else { printk (KERN_ERR "%s: Oops - your private data area is hosed!\n", dev->name); BUG (); } /* ** Set up the buffer control structures and copy the data from ** the socket buffer to the shared memory . */ if (lp->shmem_length == IO_ONLY) { int i; u_char *p = skb->data; outb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA); outb ((char) (skb->len & 0xff), EWRK3_DATA); outb ((char) ((skb->len >> 8) & 0xff), EWRK3_DATA); outb ((char) 0x04, EWRK3_DATA); for (i = 0; i < skb->len; i++) { outb (*p++, EWRK3_DATA); } outb (page, EWRK3_TQ); /* Start sending pkt */ } else { writeb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), buf); /* ctrl byte */ buf += 1; writeb ((char) (skb->len & 0xff), buf); /* length (16 bit xfer) */ buf += 1; if (lp->txc) { writeb(((skb->len >> 8) & 0xff) | XCT, buf); buf += 1; writeb (0x04, buf); /* index byte */ buf += 1; writeb (0x00, (buf + skb->len)); /* Write the XCT flag */ memcpy_toio (buf, skb->data, PRELOAD); /* Write PRELOAD bytes */ outb (page, EWRK3_TQ); /* Start sending pkt */ memcpy_toio (buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD); writeb (0xff, (buf + skb->len)); /* Write the XCT flag */ } else { writeb ((skb->len >> 8) & 0xff, buf); buf += 1; writeb (0x04, buf); /* index byte */ buf += 1; memcpy_toio (buf, skb->data, skb->len); /* Write data bytes */ outb (page, EWRK3_TQ); /* Start sending pkt */ } } ENABLE_IRQs; spin_unlock_irq (&lp->hw_lock); dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb (skb); /* Check for free resources: stop Tx queue if there are none */ if (inb (EWRK3_FMQC) == 0) netif_stop_queue (dev); return 0;err_out: ENABLE_IRQs; spin_unlock_irq (&lp->hw_lock); return 1;}/* ** The EWRK3 interrupt handler. */static irqreturn_t ewrk3_interrupt(int irq, void *dev_id){ struct net_device *dev = dev_id; struct ewrk3_private *lp; u_long iobase; u_char icr, cr, csr; lp = netdev_priv(dev); iobase = dev->base_addr; /* get the interrupt information */ csr = inb(EWRK3_CSR); /* ** Mask the EWRK3 board interrupts and turn on the LED */ spin_lock(&lp->hw_lock); DISABLE_IRQs; cr = inb(EWRK3_CR); cr |= lp->led_mask; outb(cr, EWRK3_CR); if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */ ewrk3_rx(dev); if (csr & CSR_TNE) /* Tx interrupt (packet sent) */ ewrk3_tx(dev); /* ** Now deal with the TX/RX disable flags. These are set when there ** are no more resources. If resources free up then enable these ** interrupts, otherwise mask them - failure to do this will result ** in the system hanging in an interrupt loop. */ if (inb(EWRK3_FMQC)) { /* any resources available? */ lp->irq_mask |= ICR_TXDM | ICR_RXDM; /* enable the interrupt source */ csr &= ~(CSR_TXD | CSR_RXD); /* ensure restart of a stalled TX or RX */ outb(csr, EWRK3_CSR); netif_wake_queue(dev); } else { lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM); /* disable the interrupt source */ } /* Unmask the EWRK3 board interrupts and turn off the LED */ cr &= ~(lp->led_mask); outb(cr, EWRK3_CR); ENABLE_IRQs; spin_unlock(&lp->hw_lock); return IRQ_HANDLED;}/* Called with lp->hw_lock held */static int ewrk3_rx(struct net_device *dev){ struct ewrk3_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int i, status = 0; u_char page; void __iomem *buf = NULL; while (inb(EWRK3_RQC) && !status) { /* Whilst there's incoming data */ if ((page = inb(EWRK3_RQ)) < lp->mPage) { /* Get next entry's buffer page */ /* ** Set up shared memory window and pointer into the window */ if (lp->shmem_length == IO_ONLY) { outb(page, EWRK3_IOPR); } else if (lp->shmem_length == SHMEM_2K) { buf = lp->shmem; outb(page, EWRK3_MPR); } else if (lp->shmem_length == SHMEM_32K) { buf = (((short) page << 11) & 0x7800) + lp->shmem; outb((page >> 4), EWRK3_MPR); } else if (lp->shmem_length == SHMEM_64K) { buf = (((short) page << 11) & 0xf800) + lp->shmem; outb((page >> 5), EWRK3_MPR); } else { status = -1; printk("%s: Oops - your private data area is hosed!\n", dev->name); } if (!status) { char rx_status; int pkt_len; if (lp->shmem_length == IO_ONLY) { rx_status = inb(EWRK3_DATA); pkt_len = inb(EWRK3_DATA); pkt_len |= ((u_short) inb(EWRK3_DATA) << 8); } else { rx_status = readb(buf); buf += 1; pkt_len = readw(buf); buf += 3; } if (!(rx_status & R_ROK)) { /* There was an error. */ dev->stats.rx_errors++; /* Update the error stats. */ if (rx_status & R_DBE) dev->stats.rx_frame_errors++; if (rx_status & R_CRC) dev->stats.rx_crc_errors++; if (rx_status & R_PLL) dev->stats.rx_fifo_errors++; } else { struct sk_buff *skb; if ((skb = dev_alloc_skb(pkt_len + 2)) != NULL) { unsigned char *p; skb_reserve(skb, 2); /* Align to 16 bytes */ p = skb_put(skb, pkt_len); if (lp->shmem_length == IO_ONLY) { *p = inb(EWRK3_DATA); /* dummy read */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -