📄 rrunner.c
字号:
dev_kfree_skb(rrpriv->rx_skbuff[i]); rrpriv->rx_skbuff[i] = NULL; } } if (rr_init1(dev)) { spin_lock_irqsave(&rrpriv->lock, flags); writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); spin_unlock_irqrestore(&rrpriv->lock, flags); } } rrpriv->timer.expires = RUN_AT(5*HZ); add_timer(&rrpriv->timer);}static int rr_open(struct net_device *dev){ struct rr_private *rrpriv; struct rr_regs *regs; int ecode = 0; unsigned long flags; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; if (rrpriv->fw_rev < 0x00020000) { printk(KERN_WARNING "%s: trying to configure device with " "obsolete firmware\n", dev->name); ecode = -EBUSY; goto error; } rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl), GFP_KERNEL); if (!rrpriv->rx_ctrl) { ecode = -ENOMEM; goto error; } rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL); if (!rrpriv->info){ rrpriv->rx_ctrl = NULL; ecode = -ENOMEM; goto error; } memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); memset(rrpriv->info, 0, sizeof(struct rr_info)); wmb(); spin_lock_irqsave(&rrpriv->lock, flags); writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); spin_unlock_irqrestore(&rrpriv->lock, flags); if (request_irq(dev->irq, rr_interrupt, SA_SHIRQ, rrpriv->name, dev)) { printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); ecode = -EAGAIN; goto error; } if ((ecode = rr_init1(dev))) goto error; /* Set the timer to switch to check for link beat and perhaps switch to an alternate media type. */ init_timer(&rrpriv->timer); rrpriv->timer.expires = RUN_AT(5*HZ); /* 5 sec. watchdog */ rrpriv->timer.data = (unsigned long)dev; rrpriv->timer.function = &rr_timer; /* timer handler */ add_timer(&rrpriv->timer); netif_start_queue(dev); MOD_INC_USE_COUNT; return ecode; error: spin_lock_irqsave(&rrpriv->lock, flags); writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); spin_unlock_irqrestore(&rrpriv->lock, flags); if (rrpriv->info) { kfree(rrpriv->info); rrpriv->info = NULL; } if (rrpriv->rx_ctrl) { kfree(rrpriv->rx_ctrl); rrpriv->rx_ctrl = NULL; } netif_stop_queue(dev); rr_if_down(dev); return ecode;}static void rr_dump(struct net_device *dev){ struct rr_private *rrpriv; struct rr_regs *regs; u32 index, cons; short i; int len; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; printk("%s: dumping NIC TX rings\n", dev->name); printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n", readl(®s->RxPrd), readl(®s->TxPrd), readl(®s->EvtPrd), readl(®s->TxPi), rrpriv->info->tx_ctrl.pi); printk("Error code 0x%x\n", readl(®s->Fail1)); index = (((readl(®s->EvtPrd) >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES; cons = rrpriv->dirty_tx; printk("TX ring index %i, TX consumer %i\n", index, cons); if (rrpriv->tx_skbuff[index]){ len = min(0x80, rrpriv->tx_skbuff[index]->len); printk("skbuff for index %i is valid - dumping data (0x%x bytes - DMA len 0x%x)\n", index, len, rrpriv->tx_ring[index].size); for (i = 0; i < len; i++){ if (!(i & 7)) printk("\n"); printk("%02x ", (unsigned char) rrpriv->tx_skbuff[index]->data[i]); } printk("\n"); } if (rrpriv->tx_skbuff[cons]){ len = min(0x80, rrpriv->tx_skbuff[cons]->len); printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len); printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08lx), skbuff-addr %08lx, truesize 0x%x\n", rrpriv->tx_ring[cons].mode, rrpriv->tx_ring[cons].size, rrpriv->tx_ring[cons].addr.addrlo, (unsigned long)bus_to_virt(rrpriv->tx_ring[cons].addr.addrlo), (unsigned long)rrpriv->tx_skbuff[cons]->data, (unsigned int)rrpriv->tx_skbuff[cons]->truesize); for (i = 0; i < len; i++){ if (!(i & 7)) printk("\n"); printk("%02x ", (unsigned char)rrpriv->tx_ring[cons].size); } printk("\n"); } printk("dumping TX ring info:\n"); for (i = 0; i < TX_RING_ENTRIES; i++) printk("mode 0x%x, size 0x%x, phys-addr %08x\n", rrpriv->tx_ring[i].mode, rrpriv->tx_ring[i].size, rrpriv->tx_ring[i].addr.addrlo);}static int rr_close(struct net_device *dev){ struct rr_private *rrpriv; struct rr_regs *regs; u32 tmp; short i; netif_stop_queue(dev); rr_if_down(dev); rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; /* * Lock to make sure we are not cleaning up while another CPU * handling interrupts. */ spin_lock(&rrpriv->lock); tmp = readl(®s->HostCtrl); if (tmp & NIC_HALTED){ printk("%s: NIC already halted\n", dev->name); rr_dump(dev); }else{ tmp |= HALT_NIC | RR_CLEAR_INT; writel(tmp, ®s->HostCtrl); wmb(); } rrpriv->fw_running = 0; del_timer(&rrpriv->timer); writel(0, ®s->TxPi); writel(0, ®s->IpRxPi); writel(0, ®s->EvtCon); writel(0, ®s->EvtPrd); for (i = 0; i < CMD_RING_ENTRIES; i++) writel(0, ®s->CmdRing[i]); rrpriv->info->tx_ctrl.entries = 0; rrpriv->info->cmd_ctrl.pi = 0; rrpriv->info->evt_ctrl.pi = 0; rrpriv->rx_ctrl[4].entries = 0; for (i = 0; i < TX_RING_ENTRIES; i++) { if (rrpriv->tx_skbuff[i]) { rrpriv->tx_ring[i].size = 0; set_rraddr(&rrpriv->tx_ring[i].addr, 0); dev_kfree_skb(rrpriv->tx_skbuff[i]); rrpriv->tx_skbuff[i] = NULL; } } for (i = 0; i < RX_RING_ENTRIES; i++) { if (rrpriv->rx_skbuff[i]) { rrpriv->rx_ring[i].size = 0; set_rraddr(&rrpriv->rx_ring[i].addr, 0); dev_kfree_skb(rrpriv->rx_skbuff[i]); rrpriv->rx_skbuff[i] = NULL; } } if (rrpriv->rx_ctrl) { kfree(rrpriv->rx_ctrl); rrpriv->rx_ctrl = NULL; } if (rrpriv->info) { kfree(rrpriv->info); rrpriv->info = NULL; } free_irq(dev->irq, dev); spin_unlock(&rrpriv->lock); MOD_DEC_USE_COUNT; return 0;}static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct rr_private *rrpriv = (struct rr_private *)dev->priv; struct rr_regs *regs = rrpriv->regs; struct ring_ctrl *txctrl; unsigned long flags; u32 index, len = skb->len; u32 *ifield; struct sk_buff *new_skb; if (readl(®s->Mode) & FATAL_ERR) printk("error codes Fail1 %02x, Fail2 %02x\n", readl(®s->Fail1), readl(®s->Fail2)); /* * We probably need to deal with tbusy here to prevent overruns. */ if (skb_headroom(skb) < 8){ printk("incoming skb too small - reallocating\n"); if (!(new_skb = dev_alloc_skb(len + 8))) { dev_kfree_skb(skb); netif_wake_queue(dev); return -EBUSY; } skb_reserve(new_skb, 8); skb_put(new_skb, len); memcpy(new_skb->data, skb->data, len); dev_kfree_skb(skb); skb = new_skb; } ifield = (u32 *)skb_push(skb, 8); ifield[0] = 0; ifield[1] = skb->private.ifield; /* * We don't need the lock before we are actually going to start * fiddling with the control blocks. */ spin_lock_irqsave(&rrpriv->lock, flags); txctrl = &rrpriv->info->tx_ctrl; index = txctrl->pi; rrpriv->tx_skbuff[index] = skb; set_rraddr(&rrpriv->tx_ring[index].addr, skb->data); rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */ rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END; txctrl->pi = (index + 1) % TX_RING_ENTRIES; wmb(); writel(txctrl->pi, ®s->TxPi); if (txctrl->pi == rrpriv->dirty_tx){ rrpriv->tx_full = 1; netif_stop_queue(dev); } spin_unlock_irqrestore(&rrpriv->lock, flags); dev->trans_start = jiffies; return 0;}static struct net_device_stats *rr_get_stats(struct net_device *dev){ struct rr_private *rrpriv; rrpriv = (struct rr_private *)dev->priv; return(&rrpriv->stats);}/* * Read the firmware out of the EEPROM and put it into the SRAM * (or from user space - later) * * This operation requires the NIC to be halted and is performed with * interrupts disabled and with the spinlock hold. */static int rr_load_firmware(struct net_device *dev){ struct rr_private *rrpriv; struct rr_regs *regs; unsigned long eptr, segptr; int i, j; u32 localctrl, sptr, len, tmp; u32 p2len, p2size, nr_seg, revision, io, sram_size; struct eeprom *hw = NULL; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; if (dev->flags & IFF_UP) return -EBUSY; if (!(readl(®s->HostCtrl) & NIC_HALTED)){ printk("%s: Trying to load firmware to a running NIC.\n", dev->name); return -EBUSY; } localctrl = readl(®s->LocalCtrl); writel(0, ®s->LocalCtrl); writel(0, ®s->EvtPrd); writel(0, ®s->RxPrd); writel(0, ®s->TxPrd); /* * First wipe the entire SRAM, otherwise we might run into all * kinds of trouble ... sigh, this took almost all afternoon * to track down ;-( */ io = readl(®s->ExtIo); writel(0, ®s->ExtIo); sram_size = rr_read_eeprom_word(rrpriv, (void *)8); for (i = 200; i < sram_size / 4; i++){ writel(i * 4, ®s->WinBase); mb(); writel(0, ®s->WinData); mb(); } writel(io, ®s->ExtIo); mb(); eptr = (unsigned long)rr_read_eeprom_word(rrpriv, &hw->rncd_info.AddrRunCodeSegs); eptr = ((eptr & 0x1fffff) >> 3); p2len = rr_read_eeprom_word(rrpriv, (void *)(0x83*4)); p2len = (p2len << 2); p2size = rr_read_eeprom_word(rrpriv, (void *)(0x84*4)); p2size = ((p2size & 0x1fffff) >> 3); if ((eptr < p2size) || (eptr > (p2size + p2len))){ printk("%s: eptr is invalid\n", dev->name); goto out; } revision = rr_read_eeprom_word(rrpriv, &hw->manf.HeaderFmt); if (revision != 1){ printk("%s: invalid firmware format (%i)\n", dev->name, revision); goto out; } nr_seg = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr +=4;#if (DEBUG > 1) printk("%s: nr_seg %i\n", dev->name, nr_seg);#endif for (i = 0; i < nr_seg; i++){ sptr = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr += 4; len = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr += 4; segptr = (unsigned long)rr_read_eeprom_word(rrpriv, (void *)eptr); segptr = ((segptr & 0x1fffff) >> 3); eptr += 4;#if (DEBUG > 1) printk("%s: segment %i, sram address %06x, length %04x, segptr %06x\n", dev->name, i, sptr, len, segptr);#endif for (j = 0; j < len; j++){ tmp = rr_read_eeprom_word(rrpriv, (void *)segptr); writel(sptr, ®s->WinBase); mb(); writel(tmp, ®s->WinData); mb(); segptr += 4; sptr += 4; } }out: writel(localctrl, ®s->LocalCtrl); mb(); return 0;}static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct rr_private *rrpriv; unsigned char *image, *oldimage; unsigned int i; int error = -EOPNOTSUPP; rrpriv = dev->priv; switch(cmd){ case SIOCRRGFW: if (!capable(CAP_SYS_RAWIO)){ return -EPERM; } image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); if (!image){ printk(KERN_ERR "%s: Unable to allocate memory " "for EEPROM image\n", dev->name); return -ENOMEM; } spin_lock(&rrpriv->lock); if (rrpriv->fw_running){ printk("%s: Firmware already running\n", dev->name); error = -EPERM; goto out_spin; } i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES); if (i != EEPROM_BYTES){ printk(KERN_ERR "%s: Error reading EEPROM\n", dev->name); error = -EFAULT; goto out_spin; } spin_unlock(&rrpriv->lock); error = copy_to_user(rq->ifr_data, image, EEPROM_BYTES); if (error) error = -EFAULT; kfree(image); return error; case SIOCRRPFW: if (!capable(CAP_SYS_RAWIO)){ return -EPERM; } image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); if (!image){ printk(KERN_ERR "%s: Unable to allocate memory " "for EEPROM image\n", dev->name); return -ENOMEM; } oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); if (!oldimage){ kfree(image); printk(KERN_ERR "%s: Unable to allocate memory " "for old EEPROM image\n", dev->name); return -ENOMEM; } error = copy_from_user(image, rq->ifr_data, EEPROM_BYTES); if (error) { kfree(image); kfree(oldimage); return -EFAULT; } spin_lock(&rrpriv->lock); if (rrpriv->fw_running){ kfree(oldimage); printk("%s: Firmware already running\n", dev->name); error = -EPERM; goto out_spin; } printk("%s: Updating EEPROM firmware\n", dev->name); error = write_eeprom(rrpriv, 0, image, EEPROM_BYTES); if (error) printk(KERN_ERR "%s: Error writing EEPROM\n", dev->name); i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); if (i != EEPROM_BYTES) printk(KERN_ERR "%s: Error reading back EEPROM " "image\n", dev->name); spin_unlock(&rrpriv->lock); error = memcmp(image, oldimage, EEPROM_BYTES); if (error){ printk(KERN_ERR "%s: Error verifying EEPROM image\n", dev->name); error = -EFAULT; } kfree(image); kfree(oldimage); return error; case SIOCRRID: return put_user(0x52523032, (int *)(&rq->ifr_data[0])); default: return error; } out_spin: kfree(image); spin_unlock(&rrpriv->lock); return error;}/* * Local variables: * compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -