📄 sunhme.c
字号:
char *addrs; int i, j, bit, byte; u32 crc, poly = CRC_POLYNOMIAL_LE; for(i = 0; i < 4; i++) hash_table[i] = 0; for(i = 0; i < hp->dev->mc_count; i++) { addrs = dmi->dmi_addr; dmi = dmi->next; if(!(*addrs & 1)) continue; crc = 0xffffffffU; for(byte = 0; byte < 6; byte++) { for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { int test; test = ((bit ^ crc) & 0x01); crc >>= 1; if(test) crc = crc ^ poly; } } crc >>= 26; hash_table[crc >> 4] |= 1 << (crc & 0xf); } hme_write32(hp, &bregs->htable0, hash_table[0]); hme_write32(hp, &bregs->htable1, hash_table[1]); hme_write32(hp, &bregs->htable2, hash_table[2]); hme_write32(hp, &bregs->htable3, hash_table[3]); } else { hme_write32(hp, &bregs->htable3, 0); hme_write32(hp, &bregs->htable2, 0); hme_write32(hp, &bregs->htable1, 0); hme_write32(hp, &bregs->htable0, 0); } /* Set the RX and TX ring ptrs. */ HMD(("ring ptrs rxr[%08x] txr[%08x]\n", (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)), (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)))); hme_write32(hp, &erxregs->rx_ring, (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))); hme_write32(hp, &etxregs->tx_ring, (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))); /* Set the supported burst sizes. */ HMD(("happy_meal_init: old[%08x] bursts<", hme_read32(hp, &gregs->cfg)));#ifdef __sparc_v9__ /* XXX Can sun4d do these too? */ if(hp->happy_bursts & DMA_BURST64) { u32 gcfg = GREG_CFG_BURST64; /* I have no idea if I should set the extended * transfer mode bit for Cheerio, so for now I * do not. -DaveM */ if((hp->happy_flags & HFLAG_PCI) == 0) { mmu_set_sbus64(hp->happy_sbus_dev, hp->happy_bursts); gcfg |= GREG_CFG_64BIT; } HMD(("64>")); hme_write32(hp, &gregs->cfg, gcfg); } else#endif if(hp->happy_bursts & DMA_BURST32) { HMD(("32>")); hme_write32(hp, &gregs->cfg, GREG_CFG_BURST32); } else if(hp->happy_bursts & DMA_BURST16) { HMD(("16>")); hme_write32(hp, &gregs->cfg, GREG_CFG_BURST16); } else { HMD(("XXX>")); hme_write32(hp, &gregs->cfg, 0); } /* Turn off interrupts we do not want to hear. */ HMD((", enable global interrupts, ")); hme_write32(hp, &gregs->imask, (GREG_IMASK_GOTFRAME | GREG_IMASK_RCNTEXP | GREG_IMASK_SENTFRAME | GREG_IMASK_TXPERR)); /* Set the transmit ring buffer size. */ HMD(("tx rsize=%d oreg[%08x], ", (int)TX_RING_SIZE, hme_read32(hp, &etxregs->tx_rsize))); hme_write32(hp, &etxregs->tx_rsize, (TX_RING_SIZE >> ETX_RSIZE_SHIFT) - 1); /* Enable transmitter DVMA. */ HMD(("tx dma enable old[%08x], ", hme_read32(hp, &etxregs->cfg))); hme_write32(hp, &etxregs->cfg, hme_read32(hp, &etxregs->cfg) | ETX_CFG_DMAENABLE); /* This chip really rots, for the receiver sometimes when you * write to it's control registers not all the bits get there * properly. I cannot think of a sane way to provide complete * coverage for this hardware bug yet. */ HMD(("erx regs bug old[%08x]\n", hme_read32(hp, &erxregs->cfg))); hme_write32(hp, &erxregs->cfg, ERX_CFG_DEFAULT(RX_OFFSET)); regtmp = hme_read32(hp, &erxregs->cfg); hme_write32(hp, &erxregs->cfg, ERX_CFG_DEFAULT(RX_OFFSET)); if(hme_read32(hp, &erxregs->cfg) != ERX_CFG_DEFAULT(RX_OFFSET)) { printk("happy meal: Eieee, rx config register gets greasy fries.\n"); printk("happy meal: Trying to set %08x, reread gives %08lx\n", ERX_CFG_DEFAULT(RX_OFFSET), regtmp); /* XXX Should return failure here... */ } /* Enable Big Mac hash table filter. */ HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ", hme_read32(hp, &bregs->rx_cfg))); rxcfg = BIGMAC_RXCFG_HENABLE; if(hp->dev->flags & IFF_PROMISC) rxcfg |= BIGMAC_RXCFG_PMISC; hme_write32(hp, &bregs->rx_cfg, rxcfg); /* Let the bits settle in the chip. */ udelay(10); /* Ok, configure the Big Mac transmitter. */ HMD(("BIGMAC init, ")); regtmp = 0; if(hp->happy_flags & HFLAG_FULL) regtmp |= BIGMAC_TXCFG_FULLDPLX; hme_write32(hp, &bregs->tx_cfg, regtmp | BIGMAC_TXCFG_DGIVEUP); /* Enable the output drivers no matter what. */ regtmp = BIGMAC_XCFG_ODENABLE; /* If card can do lance mode, enable it. */ if(hp->happy_flags & HFLAG_LANCE) regtmp |= (DEFAULT_IPG0 << 5) | BIGMAC_XCFG_LANCE; /* Disable the MII buffers if using external transceiver. */ if(hp->tcvr_type == external) regtmp |= BIGMAC_XCFG_MIIDISAB; HMD(("XIF config old[%08x], ", hme_read32(hp, &bregs->xif_cfg))); hme_write32(hp, &bregs->xif_cfg, regtmp); /* Start things up. */ HMD(("tx old[%08x] and rx [%08x] ON!\n", hme_read32(hp, &bregs->tx_cfg), hme_read32(hp, &bregs->rx_cfg))); hme_write32(hp, &bregs->tx_cfg, hme_read32(hp, &bregs->tx_cfg) | BIGMAC_TXCFG_ENABLE); hme_write32(hp, &bregs->rx_cfg, hme_read32(hp, &bregs->rx_cfg) | BIGMAC_RXCFG_ENABLE); /* Get the autonegotiation started, and the watch timer ticking. */ happy_meal_begin_auto_negotiation(hp, tregs, NULL); /* Success. */ return 0;}static void happy_meal_set_initial_advertisement(struct happy_meal *hp){ struct hmeal_tcvregs *tregs = hp->tcvregs; struct hmeal_bigmacregs *bregs = hp->bigmacregs; struct hmeal_gregs *gregs = hp->gregs; happy_meal_stop(hp, gregs); hme_write32(hp, &tregs->int_mask, 0xffff); if(hp->happy_flags & HFLAG_FENABLE) hme_write32(hp, &tregs->cfg, hme_read32(hp, &tregs->cfg) & ~(TCV_CFG_BENABLE)); else hme_write32(hp, &tregs->cfg, hme_read32(hp, &tregs->cfg) | TCV_CFG_BENABLE); happy_meal_transceiver_check(hp, tregs); switch(hp->tcvr_type) { case none: return; case internal: hme_write32(hp, &bregs->xif_cfg, 0); break; case external: hme_write32(hp, &bregs->xif_cfg, BIGMAC_XCFG_MIIDISAB); break; }; if(happy_meal_tcvr_reset(hp, tregs)) return; /* Latch PHY registers as of now. */ hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR); hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE); /* Advertise everything we can support. */ if(hp->sw_bmsr & BMSR_10HALF) hp->sw_advertise |= (ADVERTISE_10HALF); else hp->sw_advertise &= ~(ADVERTISE_10HALF); if(hp->sw_bmsr & BMSR_10FULL) hp->sw_advertise |= (ADVERTISE_10FULL); else hp->sw_advertise &= ~(ADVERTISE_10FULL); if(hp->sw_bmsr & BMSR_100HALF) hp->sw_advertise |= (ADVERTISE_100HALF); else hp->sw_advertise &= ~(ADVERTISE_100HALF); if(hp->sw_bmsr & BMSR_100FULL) hp->sw_advertise |= (ADVERTISE_100FULL); else hp->sw_advertise &= ~(ADVERTISE_100FULL); /* Update the PHY advertisement register. */ happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise);}/* Once status is latched (by happy_meal_interrupt) it is cleared by * the hardware, so we cannot re-read it and get a correct value. */static int happy_meal_is_not_so_happy(struct happy_meal *hp, struct hmeal_gregs *gregs, unsigned long status){ int reset = 0; /* Only print messages for non-counter related interrupts. */ if(status & (GREG_STAT_RFIFOVF | 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("%s: Error interrupt for happy meal, status = %08lx\n", hp->dev->name, status); if(status & GREG_STAT_RFIFOVF) { /* The receive FIFO overflowwed, usually a DMA error. */ printk("%s: Happy Meal receive FIFO overflow.\n", hp->dev->name); reset = 1; } if(status & GREG_STAT_STSTERR) { /* BigMAC SQE link test failed. */ printk("%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("%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("%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("%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("%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("%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("%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("%s: Happy Meal register access SBUS slave (%s) error.\n", hp->dev->name, (status & GREG_STAT_SLVPERR) ? "parity" : "generic"); reset = 1; } if(reset) { printk("%s: Resetting...\n", hp->dev->name); happy_meal_init(hp, 1); return 1; } return 0;}static inline void happy_meal_mif_interrupt(struct happy_meal *hp, struct hmeal_gregs *gregs, struct hmeal_tcvregs *tregs){ printk("%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("%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("%s: Switching to 100MBps at half duplex.", hp->dev->name); hp->sw_bmcr |= BMCR_SPEED100; } else if(hp->sw_lpa & LPA_10FULL) { printk("%s: Switching to 10MBps at full duplex.", hp->dev->name); hp->sw_bmcr |= BMCR_FULLDPLX; } else { printk("%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 inline 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; int elem = hp->tx_old; TXD(("TX<")); while(elem != hp->tx_new) { struct sk_buff *skb; TXD(("[%d]", elem)); this = &txbase[elem]; if(this->tx_flags & TXFLAG_OWN) break; skb = hp->tx_skbs[elem]; hp->tx_skbs[elem] = NULL; hp->net_stats.tx_bytes+=skb->len; dev_kfree_skb(skb); hp->net_stats.tx_packets++; elem = NEXT_TX(elem); } hp->tx_old = elem; TXD((">"));}#ifdef CONFIG_PCIstatic inline void pci_happy_meal_tx(struct happy_meal *hp){ struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; struct happy_meal_txd *this; int elem = hp->tx_old; TXD(("TX<")); while(elem != hp->tx_new) { struct sk_buff *skb; unsigned int flags; TXD(("[%d]", elem)); this = &txbase[elem];#ifdef __sparc_v9__ __asm__ __volatile__("lduwa [%1] %2, %0" : "=r" (flags) : "r" (&this->tx_flags), "i" (ASI_PL));#else flags = flip_dword(this->tx_flags);#endif if(flags & TXFLAG_OWN) break; skb = hp->tx_skbs[elem]; hp->tx_skbs[elem] = NULL; hp->net_stats.tx_bytes+=skb->len; dev_kfree_skb(skb); hp->net_stats.tx_packets++; elem = NEXT_TX(elem); } hp->tx_old = elem; TXD((">"));}#endif#ifndef __sparc_v9__static inline void sun4c_happy_meal_tx(struct happy_meal *hp){ struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; struct happy_meal_txd *this; int elem = hp->tx_old; TXD(("TX<")); while(elem != hp->tx_new) { TXD(("[%d]", elem)); this = &txbase[elem]; if(this->tx_flags & TXFLAG_OWN) break; hp->net_stats.tx_packets++; elem = NEXT_TX(elem); } hp->tx_old = elem; TXD((">"));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -