📄 sgiseeq.c
字号:
hregs->tx_ndptr = PHYSADDR(td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; }}static inline void sgiseeq_tx(struct 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 inline void tx_maybe_unbusy(struct sgiseeq_private *sp, struct device *dev){ if((TX_BUFFS_AVAIL(sp) >= 0) && dev->tbusy) { dev->tbusy = 0; mark_bh(NET_BH); }}static void sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct device *dev = (struct 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; dev->interrupt = 1; /* 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); tx_maybe_unbusy(sp, dev); dev->interrupt = 0;}static int sgiseeq_open(struct 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); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; restore_flags(flags); return 0;}static int sgiseeq_close(struct device *dev){ struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; volatile struct sgiseeq_regs *sregs = sp->sregs; dev->start = 0; dev->tbusy = 1; /* Shutdown the Seeq. */ reset_hpc3_and_seeq(sp->hregs, sregs); free_irq(dev->irq, dev); return 0;}static inline int sgiseeq_reset(struct 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; dev->interrupt = 0; dev->start = 1; dev->tbusy = 0; return 0;}void sgiseeq_my_reset(void){ printk("RESET!\n"); sgiseeq_reset(gdev);}static inline int verify_tx(struct sgiseeq_private *sp, struct device *dev, struct sk_buff *skb){ /* Are we bolixed? */ if(dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 20) return 1; printk("%s: transmit timed out, ticks=%d resetting\n", dev->name, tickssofar); sgiseeq_reset(dev); return 0; } /* Are we getting in someone else's way? */ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return -1; } /* Can we even send anything? */ if(!TX_BUFFS_AVAIL(sp)) return -1; return 0;}static int sgiseeq_start_xmit(struct sk_buff *skb, struct 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; if(verify_tx(sp, dev, skb)) return -1; /* Yeee... */ save_flags(flags); cli(); /* Setup... */ skblen = skb->len; len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; 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 *)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)) dev->tbusy = 0; restore_flags(flags); return 0;}static struct enet_statistics *sgiseeq_get_stats(struct device *dev){ struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; return &sp->stats;}static void sgiseeq_set_multicast(struct 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 device *dev, struct sgiseeq_regs *sregs, struct hpc3_ethregs *hregs, int irq){ static unsigned version_printed = 0; int i; struct sgiseeq_private *sp; if(dev == NULL) { dev = init_etherdev(0, sizeof(struct sgiseeq_private)); } else { 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->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 device *dev){ char *ep; /* First get the ethernet address of the onboard * interface from ARCS. */ ep = romvec->get_evar("eaddr"); str2eaddr(onboard_eth_addr, ep); return sgiseeq_init(dev, (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)), &hpc3c0->ethregs, 3);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -