📄 sgiseeq.c
字号:
}static inline void kick_tx(struct sgiseeq_tx_desc *td, volatile struct hpc3_ethregs *hregs){ /* If the HPC aint doin nothin, and there are more packets * with ETXD cleared and XIU set we must make very certain * that we restart the HPC else we risk locking up the * adapter. The following code is only safe iff the HPCDMA * is not active! */ while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) == (HPCDMA_XIU | HPCDMA_ETXD)) td = (struct sgiseeq_tx_desc *)(long) KSEG1ADDR(td->tdma.pnext); if (td->tdma.cntinfo & HPCDMA_XIU) { hregs->tx_ndptr = PHYSADDR(td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; }}static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp, volatile struct hpc3_ethregs *hregs, volatile struct sgiseeq_regs *sregs){ struct sgiseeq_tx_desc *td; unsigned long status = hregs->tx_ctrl; int j; tx_maybe_reset_collisions(sp, sregs); if (!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) { /* Oops, HPC detected some sort of error. */ if (status & SEEQ_TSTAT_R16) sp->stats.tx_aborted_errors++; if (status & SEEQ_TSTAT_UFLOW) sp->stats.tx_fifo_errors++; if (status & SEEQ_TSTAT_LCLS) sp->stats.collisions++; } /* Ack 'em... */ for (j = sp->tx_old; j != sp->tx_new; j = NEXT_TX(j)) { td = &sp->srings.tx_desc[j]; if (!(td->tdma.cntinfo & (HPCDMA_XIU))) break; if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) { if(!(status & HPC3_ETXCTRL_ACTIVE)) { hregs->tx_ndptr = PHYSADDR(td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; } break; } sp->stats.tx_packets++; sp->tx_old = NEXT_TX(sp->tx_old); td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE); td->tdma.cntinfo |= HPCDMA_EOX; }}static void sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; volatile struct hpc3_ethregs *hregs = sp->hregs; volatile struct sgiseeq_regs *sregs = sp->sregs; /* Ack the IRQ and set software state. */ hregs->rx_reset = HPC3_ERXRST_CLRIRQ; /* Always check for received packets. */ sgiseeq_rx(dev, sp, hregs, sregs); /* Only check for tx acks iff we have something queued. */ if (sp->tx_old != sp->tx_new) sgiseeq_tx(dev, sp, hregs, sregs); if ((TX_BUFFS_AVAIL(sp) > 0) && netif_queue_stopped(dev)) { netif_wake_queue(dev); }}static int sgiseeq_open(struct net_device *dev){ struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv; volatile struct sgiseeq_regs *sregs = sp->sregs; unsigned long flags; save_flags(flags); cli(); if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, (void *) dev)) { printk("Seeq8003: Can't get irq %d\n", dev->irq); restore_flags(flags); return -EAGAIN; } init_seeq(dev, sp, sregs); netif_start_queue(dev); restore_flags(flags); return 0;}static int sgiseeq_close(struct net_device *dev){ struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; volatile struct sgiseeq_regs *sregs = sp->sregs; netif_stop_queue(dev); /* Shutdown the Seeq. */ reset_hpc3_and_seeq(sp->hregs, sregs); free_irq(dev->irq, dev); return 0;}static inline int sgiseeq_reset(struct net_device *dev){ struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; volatile struct sgiseeq_regs *sregs = sp->sregs; init_seeq(dev, sp, sregs); dev->trans_start = jiffies; netif_wake_queue(dev); return 0;}void sgiseeq_my_reset(void){ printk("RESET!\n"); sgiseeq_reset(gdev);}static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; volatile struct hpc3_ethregs *hregs = sp->hregs; unsigned long flags; struct sgiseeq_tx_desc *td; int skblen, len, entry; save_and_cli(flags); /* Setup... */ skblen = skb->len; len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; sp->stats.tx_bytes += len; entry = sp->tx_new; td = &sp->srings.tx_desc[entry]; /* Create entry. There are so many races with adding a new * descriptor to the chain: * 1) Assume that the HPC is off processing a DMA chain while * we are changing all of the following. * 2) Do no allow the HPC to look at a new descriptor until * we have completely set up it's state. This means, do * not clear HPCDMA_EOX in the current last descritptor * until the one we are adding looks consistant and could * be processes right now. * 3) The tx interrupt code must notice when we've added a new * entry and the HPC got to the end of the chain before we * added this new entry and restarted it. */ memcpy((char *)(long)td->buf_vaddr, skb->data, skblen); td->tdma.cntinfo = (len & HPCDMA_BCNT) | (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX); if (sp->tx_old != sp->tx_new) { struct sgiseeq_tx_desc *backend; backend = &sp->srings.tx_desc[PREV_TX(sp->tx_new)]; backend->tdma.cntinfo &= ~(HPCDMA_EOX); } sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */ /* Maybe kick the HPC back into motion. */ if (!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE)) kick_tx(&sp->srings.tx_desc[sp->tx_old], hregs); dev->trans_start = jiffies; dev_kfree_skb(skb); if (!TX_BUFFS_AVAIL(sp)) netif_stop_queue(dev); restore_flags(flags); return 0;}static void timeout(struct net_device *dev){ printk("%s: transmit timed out, resetting\n", dev->name); sgiseeq_reset(dev); dev->trans_start = jiffies; netif_wake_queue(dev);}static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev){ struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; return &sp->stats;}static void sgiseeq_set_multicast(struct net_device *dev){}static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs){ int i = 0; while (i < (nbufs - 1)) { buf[i].tdma.pnext = PHYSADDR(&buf[i + 1]); buf[i].tdma.pbuf = 0; i++; } buf[i].tdma.pnext = PHYSADDR(&buf[0]);}static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs){ int i = 0; while (i < (nbufs - 1)) { buf[i].rdma.pnext = PHYSADDR(&buf[i + 1]); buf[i].rdma.pbuf = 0; i++; } buf[i].rdma.pbuf = 0; buf[i].rdma.pnext = PHYSADDR(&buf[0]);}static char onboard_eth_addr[6];#define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf))int sgiseeq_init(struct net_device *dev, struct sgiseeq_regs *sregs, struct hpc3_ethregs *hregs, int irq){ static unsigned version_printed = 0; int i; struct sgiseeq_private *sp; dev->priv = (struct sgiseeq_private *) get_free_page(GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; if (!version_printed++) printk(version); printk("%s: SGI Seeq8003 ", dev->name); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i] = onboard_eth_addr[i], i == 5 ? ' ': ':'); printk("\n"); sp = (struct sgiseeq_private *) dev->priv;#ifdef DEBUG gpriv = sp; gdev = dev;#endif memset((char *)dev->priv, 0, sizeof(struct sgiseeq_private)); sp->sregs = sregs; sp->hregs = hregs; sp->name = sgiseeqstr; sp->srings.rx_desc = (struct sgiseeq_rx_desc *) (KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0]))); dma_cache_wback_inv((unsigned long)&sp->srings.rxvector, sizeof(sp->srings.rxvector)); sp->srings.tx_desc = (struct sgiseeq_tx_desc *) (KSEG1ADDR(ALIGNED(&sp->srings.txvector[0]))); dma_cache_wback_inv((unsigned long)&sp->srings.txvector, sizeof(sp->srings.txvector)); /* A couple calculations now, saves many cycles later. */ setup_rx_ring(sp->srings.rx_desc, SEEQ_RX_BUFFERS); setup_tx_ring(sp->srings.tx_desc, SEEQ_TX_BUFFERS); /* Reset the chip. */ hpc3_eth_reset((volatile struct hpc3_ethregs *) hregs); sp->is_edlc = !(sregs->rw.rregs.collision_tx[0] & 0xff); if (sp->is_edlc) { sp->control = (SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT | SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT | SEEQ_CTRL_ENCARR); } dev->open = sgiseeq_open; dev->stop = sgiseeq_close; dev->hard_start_xmit = sgiseeq_start_xmit; dev->tx_timeout = timeout; dev->watchdog_timeo = (200 * HZ) / 1000; dev->get_stats = sgiseeq_get_stats; dev->set_multicast_list = sgiseeq_set_multicast; dev->irq = irq; dev->dma = 0; ether_setup(dev); return 0;}static inline unsigned char str2hexnum(unsigned char c){ if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; return 0; /* foo */}static inline void str2eaddr(unsigned char *ea, unsigned char *str){ int i; for (i = 0; i < 6; i++) { unsigned char num; if(*str == ':') str++; num = str2hexnum(*str++) << 4; num |= (str2hexnum(*str++)); ea[i] = num; }}int sgiseeq_probe(struct net_device *dev){ static int initialized = 0; char *ep; if (initialized) /* Already initialized? */ return 1; initialized++; /* First get the ethernet address of the onboard interface from ARCS. * This is fragile; PROM doesn't like running from cache. * On MIPS64 it crashes for some other, yet unknown reason ... */ ep = ArcGetEnvironmentVariable("eaddr"); str2eaddr(onboard_eth_addr, ep); return sgiseeq_init(dev, (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)), &hpc3c0->ethregs, SGI_ENET_IRQ);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -