📄 sunhme.c
字号:
*/static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status){ int reset = 0; /* Only print messages for non-counter related interrupts. */ if (status & (GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND | GREG_STAT_MAXPKTERR | GREG_STAT_RXERR | GREG_STAT_RXPERR | GREG_STAT_RXTERR | GREG_STAT_EOPERR | GREG_STAT_MIFIRQ | GREG_STAT_TXEACK | GREG_STAT_TXLERR | GREG_STAT_TXPERR | GREG_STAT_TXTERR | GREG_STAT_SLVERR | GREG_STAT_SLVPERR)) printk(KERN_ERR "%s: Error interrupt for happy meal, status = %08x\n", hp->dev->name, status); if (status & GREG_STAT_RFIFOVF) { /* Receive FIFO overflow is harmless and the hardware will take care of it, just some packets are lost. Who cares. */ printk(KERN_DEBUG "%s: Happy Meal receive FIFO overflow.\n", hp->dev->name); } if (status & GREG_STAT_STSTERR) { /* BigMAC SQE link test failed. */ printk(KERN_ERR "%s: Happy Meal BigMAC SQE test failed.\n", hp->dev->name); reset = 1; } if (status & GREG_STAT_TFIFO_UND) { /* Transmit FIFO underrun, again DMA error likely. */ printk(KERN_ERR "%s: Happy Meal transmitter FIFO underrun, DMA error.\n", hp->dev->name); reset = 1; } if (status & GREG_STAT_MAXPKTERR) { /* Driver error, tried to transmit something larger * than ethernet max mtu. */ printk(KERN_ERR "%s: Happy Meal MAX Packet size error.\n", hp->dev->name); reset = 1; } if (status & GREG_STAT_NORXD) { /* This is harmless, it just means the system is * quite loaded and the incomming packet rate was * faster than the interrupt handler could keep up * with. */ printk(KERN_INFO "%s: Happy Meal out of receive " "descriptors, packet dropped.\n", hp->dev->name); } if (status & (GREG_STAT_RXERR|GREG_STAT_RXPERR|GREG_STAT_RXTERR)) { /* All sorts of DMA receive errors. */ printk(KERN_ERR "%s: Happy Meal rx DMA errors [ ", hp->dev->name); if (status & GREG_STAT_RXERR) printk("GenericError "); if (status & GREG_STAT_RXPERR) printk("ParityError "); if (status & GREG_STAT_RXTERR) printk("RxTagBotch "); printk("]\n"); reset = 1; } if (status & GREG_STAT_EOPERR) { /* Driver bug, didn't set EOP bit in tx descriptor given * to the happy meal. */ printk(KERN_ERR "%s: EOP not set in happy meal transmit descriptor!\n", hp->dev->name); reset = 1; } if (status & GREG_STAT_MIFIRQ) { /* MIF signalled an interrupt, were we polling it? */ printk(KERN_ERR "%s: Happy Meal MIF interrupt.\n", hp->dev->name); } if (status & (GREG_STAT_TXEACK|GREG_STAT_TXLERR|GREG_STAT_TXPERR|GREG_STAT_TXTERR)) { /* All sorts of transmit DMA errors. */ printk(KERN_ERR "%s: Happy Meal tx DMA errors [ ", hp->dev->name); if (status & GREG_STAT_TXEACK) printk("GenericError "); if (status & GREG_STAT_TXLERR) printk("LateError "); if (status & GREG_STAT_TXPERR) printk("ParityErro "); if (status & GREG_STAT_TXTERR) printk("TagBotch "); printk("]\n"); reset = 1; } if (status & (GREG_STAT_SLVERR|GREG_STAT_SLVPERR)) { /* Bus or parity error when cpu accessed happy meal registers * or it's internal FIFO's. Should never see this. */ printk(KERN_ERR "%s: Happy Meal register access SBUS slave (%s) error.\n", hp->dev->name, (status & GREG_STAT_SLVPERR) ? "parity" : "generic"); reset = 1; } if (reset) { printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name); happy_meal_init(hp, 1); return 1; } return 0;}static void happy_meal_mif_interrupt(struct happy_meal *hp){ unsigned long tregs = hp->tcvregs; printk(KERN_INFO "%s: Link status change.\n", hp->dev->name); hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR); hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA); /* Use the fastest transmission protocol possible. */ if (hp->sw_lpa & LPA_100FULL) { printk(KERN_INFO "%s: Switching to 100Mbps at full duplex.", hp->dev->name); hp->sw_bmcr |= (BMCR_FULLDPLX | BMCR_SPEED100); } else if (hp->sw_lpa & LPA_100HALF) { printk(KERN_INFO "%s: Switching to 100MBps at half duplex.", hp->dev->name); hp->sw_bmcr |= BMCR_SPEED100; } else if (hp->sw_lpa & LPA_10FULL) { printk(KERN_INFO "%s: Switching to 10MBps at full duplex.", hp->dev->name); hp->sw_bmcr |= BMCR_FULLDPLX; } else { printk(KERN_INFO "%s: Using 10Mbps at half duplex.", hp->dev->name); } happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); /* Finally stop polling and shut up the MIF. */ happy_meal_poll_stop(hp, tregs);}#ifdef TXDEBUG#define TXD(x) printk x#else#define TXD(x)#endifstatic void happy_meal_tx(struct happy_meal *hp){ struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; struct happy_meal_txd *this; struct net_device *dev = hp->dev; int elem; spin_lock(&hp->happy_lock); elem = hp->tx_old; TXD(("TX<")); while (elem != hp->tx_new) { struct sk_buff *skb; u32 flags, dma_addr; TXD(("[%d]", elem)); this = &txbase[elem]; flags = hme_read_desc32(hp, &this->tx_flags); if (flags & TXFLAG_OWN) break; dma_addr = hme_read_desc32(hp, &this->tx_addr); skb = hp->tx_skbs[elem]; hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE); hp->tx_skbs[elem] = NULL; hp->net_stats.tx_bytes += skb->len; dev_kfree_skb_irq(skb); hp->net_stats.tx_packets++; elem = NEXT_TX(elem); } hp->tx_old = elem; TXD((">")); if (netif_queue_stopped(dev) && TX_BUFFS_AVAIL(hp) > 0) netif_wake_queue(dev); spin_unlock(&hp->happy_lock);}#ifdef RXDEBUG#define RXD(x) printk x#else#define RXD(x)#endif/* Originally I used to handle the allocation failure by just giving back just * that one ring buffer to the happy meal. Problem is that usually when that * condition is triggered, the happy meal expects you to do something reasonable * with all of the packets it has DMA'd in. So now I just drop the entire * ring when we cannot get a new skb and give them all back to the happy meal, * maybe things will be "happier" now. */static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev){ struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0]; struct happy_meal_rxd *this; int elem = hp->rx_new, drops = 0; u32 flags; RXD(("RX<")); this = &rxbase[elem]; while (!((flags = hme_read_desc32(hp, &this->rx_flags)) & RXFLAG_OWN)) { struct sk_buff *skb; int len = flags >> 16; u16 csum = flags & RXFLAG_CSUM; u32 dma_addr = hme_read_desc32(hp, &this->rx_addr); RXD(("[%d ", elem)); /* Check for errors. */ if ((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) { RXD(("ERR(%08x)]", flags)); hp->net_stats.rx_errors++; if (len < ETH_ZLEN) hp->net_stats.rx_length_errors++; if (len & (RXFLAG_OVERFLOW >> 16)) { hp->net_stats.rx_over_errors++; hp->net_stats.rx_fifo_errors++; } /* Return it to the Happy meal. */ drop_it: hp->net_stats.rx_dropped++; hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), dma_addr); goto next; } skb = hp->rx_skbs[elem]; if (len > RX_COPY_THRESHOLD) { struct sk_buff *new_skb; /* Now refill the entry, if we can. */ new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); if (new_skb == NULL) { drops++; goto drop_it; } hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE); hp->rx_skbs[elem] = new_skb; new_skb->dev = dev; skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE)); skb_reserve(new_skb, RX_OFFSET); /* Trim the original skb for the netif. */ skb_trim(skb, len); } else { struct sk_buff *copy_skb = dev_alloc_skb(len + 2); if (copy_skb == NULL) { drops++; goto drop_it; } copy_skb->dev = dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); hme_dma_sync(hp, dma_addr, len, DMA_FROMDEVICE); memcpy(copy_skb->data, skb->data, len); /* Reuse original ring buffer. */ hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), dma_addr); skb = copy_skb; } /* This card is _fucking_ hot... */ if (!(csum ^ 0xffff)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; RXD(("len=%d csum=%4x]", len, csum)); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); hp->net_stats.rx_packets++; hp->net_stats.rx_bytes += len; next: elem = NEXT_RX(elem); this = &rxbase[elem]; } hp->rx_new = elem; if (drops) printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name); RXD((">"));}static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; struct happy_meal *hp = (struct happy_meal *) dev->priv; u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); HMD(("happy_meal_interrupt: status=%08x ", happy_status)); if (happy_status & GREG_STAT_ERRORS) { HMD(("ERRORS ")); if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status)) return; } if (happy_status & GREG_STAT_MIFIRQ) { HMD(("MIFIRQ ")); happy_meal_mif_interrupt(hp); } if (happy_status & GREG_STAT_TXALL) { HMD(("TXALL ")); happy_meal_tx(hp); } if (happy_status & GREG_STAT_RXTOHOST) { HMD(("RXTOHOST ")); happy_meal_rx(hp, dev); } HMD(("done\n"));}#ifdef CONFIG_SBUSstatic void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs){ struct quattro *qp = (struct quattro *) cookie; int i; for (i = 0; i < 4; i++) { struct net_device *dev = qp->happy_meals[i]; struct happy_meal *hp = (struct happy_meal *) dev->priv; u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); HMD(("quattro_interrupt: status=%08x ", happy_status)); if (!(happy_status & (GREG_STAT_ERRORS | GREG_STAT_MIFIRQ | GREG_STAT_TXALL | GREG_STAT_RXTOHOST))) continue; if (happy_status & GREG_STAT_ERRORS) { HMD(("ERRORS ")); if (happy_meal_is_not_so_happy(hp, happy_status)) break; } if (happy_status & GREG_STAT_MIFIRQ) { HMD(("MIFIRQ ")); happy_meal_mif_interrupt(hp); } if (happy_status & GREG_STAT_TXALL) { HMD(("TXALL ")); happy_meal_tx(hp); } if (happy_status & GREG_STAT_RXTOHOST) { HMD(("RXTOHOST ")); happy_meal_rx(hp, dev); } } HMD(("done\n"));}#endifstatic int happy_meal_open(struct net_device *dev){ struct happy_meal *hp = (struct happy_meal *) dev->priv; int res; HMD(("happy_meal_open: ")); /* On SBUS Quattro QFE cards, all hme interrupts are concentrated * into a single source which we register handling at probe time. */ if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) { if (request_irq(dev->irq, &happy_meal_interrupt, SA_SHIRQ, "HAPPY MEAL", (void *)dev)) { HMD(("EAGAIN\n"));#ifdef __sparc__ printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n", __irq_itoa(dev->irq));#else printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n", dev->irq);#endif return -EAGAIN; } } HMD(("to happy_meal_init\n")); res = happy_meal_init(hp, 0); if (!res) { MOD_INC_USE_COUNT; } return res;}static int happy_meal_close(struct net_device *dev){ struct happy_meal *hp = (struct happy_meal *) dev->priv; happy_meal_stop(hp, hp->gregs); happy_meal_clean_rings(hp); /* If auto-negotiation timer is running, kill it. */ del_timer(&hp->happy_timer); /* On Quattro QFE cards, all hme interrupts are concentrated * into a single source which we register handling at probe * time and never unregister. */ if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) free_irq(dev->irq, (void *)dev); MOD_DEC_USE_COUNT; return 0;}#ifdef SXDEBUG#define SXD(x) printk x#else#define SXD(x)#endif#ifdef CONFIG_SBUSstatic void happy_meal_tx_timeout(struct net_device *dev){ struct happy_meal *hp = (struct happy_meal *) dev->priv; printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); tx_dump_log(); printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name, hme_read32(hp, h
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -