📄 sunhme.c
字号:
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); happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise); /* XXX Currently no Happy Meal cards I know off support 100BaseT4, * XXX and this is because the DP83840 does not support it, changes * XXX would need to be made to the tx/rx logic in the driver as well * XXX so I completely skip checking for it in the BMSR for now. */#ifdef AUTO_SWITCH_DEBUG ASD(("%s: Advertising [ ", hp->dev->name)); if (hp->sw_advertise & ADVERTISE_10HALF) ASD(("10H ")); if (hp->sw_advertise & ADVERTISE_10FULL) ASD(("10F ")); if (hp->sw_advertise & ADVERTISE_100HALF) ASD(("100H ")); if (hp->sw_advertise & ADVERTISE_100FULL) ASD(("100F "));#endif /* Enable Auto-Negotiation, this is usually on already... */ hp->sw_bmcr |= BMCR_ANENABLE; happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); /* Restart it to make sure it is going. */ hp->sw_bmcr |= BMCR_ANRESTART; happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); /* BMCR_ANRESTART self clears when the process has begun. */ timeout = 64; /* More than enough. */ while (--timeout) { hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR); if (!(hp->sw_bmcr & BMCR_ANRESTART)) break; /* got it. */ udelay(10); } if (!timeout) { printk(KERN_ERR "%s: Happy Meal would not start auto negotiation " "BMCR=0x%04x\n", hp->dev->name, hp->sw_bmcr); printk(KERN_NOTICE "%s: Performing force link detection.\n", hp->dev->name); goto force_link; } else { hp->timer_state = arbwait; } } else {force_link: /* Force the link up, trying first a particular mode. * Either we are here at the request of ethtool or * because the Happy Meal would not start to autoneg. */ /* Disable auto-negotiation in BMCR, enable the duplex and * speed setting, init the timer state machine, and fire it off. */ if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { hp->sw_bmcr = BMCR_SPEED100; } else { if (ep->speed == SPEED_100) hp->sw_bmcr = BMCR_SPEED100; else hp->sw_bmcr = 0; if (ep->duplex == DUPLEX_FULL) hp->sw_bmcr |= BMCR_FULLDPLX; } happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); if (!is_lucent_phy(hp)) { /* OK, seems we need do disable the transceiver for the first * tick to make sure we get an accurate link state at the * second tick. */ hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig); } hp->timer_state = ltrywait; } hp->timer_ticks = 0; hp->happy_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */ hp->happy_timer.data = (unsigned long) hp; hp->happy_timer.function = &happy_meal_timer; add_timer(&hp->happy_timer);}#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */static int happy_meal_init(struct happy_meal *hp, int from_irq){ unsigned long gregs = hp->gregs; unsigned long etxregs = hp->etxregs; unsigned long erxregs = hp->erxregs; unsigned long bregs = hp->bigmacregs; unsigned long tregs = hp->tcvregs; u32 regtmp, rxcfg; unsigned char *e = &hp->dev->dev_addr[0]; /* If auto-negotiation timer is running, kill it. */ del_timer(&hp->happy_timer); HMD(("happy_meal_init: happy_flags[%08x] ", hp->happy_flags)); if (!(hp->happy_flags & HFLAG_INIT)) { HMD(("set HFLAG_INIT, ")); hp->happy_flags |= HFLAG_INIT; happy_meal_get_counters(hp, bregs); } /* Stop polling. */ HMD(("to happy_meal_poll_stop\n")); happy_meal_poll_stop(hp, tregs); /* Stop transmitter and receiver. */ HMD(("happy_meal_init: to happy_meal_stop\n")); happy_meal_stop(hp, gregs); /* Alloc and reset the tx/rx descriptor chains. */ HMD(("happy_meal_init: to happy_meal_init_rings\n")); happy_meal_init_rings(hp, from_irq); /* Shut up the MIF. */ HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ", hme_read32(hp, tregs + TCVR_IMASK))); hme_write32(hp, tregs + TCVR_IMASK, 0xffff); /* See if we can enable the MIF frame on this card to speak to the DP83840. */ if (hp->happy_flags & HFLAG_FENABLE) { HMD(("use frame old[%08x], ", hme_read32(hp, tregs + TCVR_CFG))); hme_write32(hp, tregs + TCVR_CFG, hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_BENABLE)); } else { HMD(("use bitbang old[%08x], ", hme_read32(hp, tregs + TCVR_CFG))); hme_write32(hp, tregs + TCVR_CFG, hme_read32(hp, tregs + TCVR_CFG) | TCV_CFG_BENABLE); } /* Check the state of the transceiver. */ HMD(("to happy_meal_transceiver_check\n")); happy_meal_transceiver_check(hp, tregs); /* Put the Big Mac into a sane state. */ HMD(("happy_meal_init: ")); switch(hp->tcvr_type) { case none: /* Cannot operate if we don't know the transceiver type! */ HMD(("AAIEEE no transceiver type, EAGAIN")); return -EAGAIN; case internal: /* Using the MII buffers. */ HMD(("internal, using MII, ")); hme_write32(hp, bregs + BMAC_XIFCFG, 0); break; case external: /* Not using the MII, disable it. */ HMD(("external, disable MII, ")); hme_write32(hp, bregs + BMAC_XIFCFG, BIGMAC_XCFG_MIIDISAB); break; }; if (happy_meal_tcvr_reset(hp, tregs)) return -EAGAIN; /* Reset the Happy Meal Big Mac transceiver and the receiver. */ HMD(("tx/rx reset, ")); happy_meal_tx_reset(hp, bregs); happy_meal_rx_reset(hp, bregs); /* Set jam size and inter-packet gaps to reasonable defaults. */ HMD(("jsize/ipg1/ipg2, ")); hme_write32(hp, bregs + BMAC_JSIZE, DEFAULT_JAMSIZE); hme_write32(hp, bregs + BMAC_IGAP1, DEFAULT_IPG1); hme_write32(hp, bregs + BMAC_IGAP2, DEFAULT_IPG2); /* Load up the MAC address and random seed. */ HMD(("rseed/macaddr, ")); /* The docs recommend to use the 10LSB of our MAC here. */ hme_write32(hp, bregs + BMAC_RSEED, ((e[5] | e[4]<<8)&0x3ff)); hme_write32(hp, bregs + BMAC_MACADDR2, ((e[4] << 8) | e[5])); hme_write32(hp, bregs + BMAC_MACADDR1, ((e[2] << 8) | e[3])); hme_write32(hp, bregs + BMAC_MACADDR0, ((e[0] << 8) | e[1])); HMD(("htable, ")); if ((hp->dev->flags & IFF_ALLMULTI) || (hp->dev->mc_count > 64)) { hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE3, 0xffff); } else if ((hp->dev->flags & IFF_PROMISC) == 0) { u16 hash_table[4]; struct dev_mc_list *dmi = hp->dev->mc_list; 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 + BMAC_HTABLE0, hash_table[0]); hme_write32(hp, bregs + BMAC_HTABLE1, hash_table[1]); hme_write32(hp, bregs + BMAC_HTABLE2, hash_table[2]); hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]); } else { hme_write32(hp, bregs + BMAC_HTABLE3, 0); hme_write32(hp, bregs + BMAC_HTABLE2, 0); hme_write32(hp, bregs + BMAC_HTABLE1, 0); hme_write32(hp, bregs + BMAC_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 + ERX_RING, (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))); hme_write32(hp, etxregs + ETX_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 + GREG_CFG)));#ifndef __sparc__ /* It is always PCI and can handle 64byte bursts. */ hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64);#else if ((hp->happy_bursts & DMA_BURST64) && ((hp->happy_flags & HFLAG_PCI) != 0#ifdef CONFIG_SBUS || sbus_can_burst64(hp->happy_dev)#endif || 0)) { 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 */#ifdef CONFIG_SBUS if ((hp->happy_flags & HFLAG_PCI) == 0 && sbus_can_dma_64bit(hp->happy_dev)) { sbus_set_sbus64(hp->happy_dev, hp->happy_bursts); gcfg |= GREG_CFG_64BIT; }#endif HMD(("64>")); hme_write32(hp, gregs + GREG_CFG, gcfg); } else if (hp->happy_bursts & DMA_BURST32) { HMD(("32>")); hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST32); } else if (hp->happy_bursts & DMA_BURST16) { HMD(("16>")); hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST16); } else { HMD(("XXX>")); hme_write32(hp, gregs + GREG_CFG, 0); }#endif /* __sparc__ */ /* Turn off interrupts we do not want to hear. */ HMD((", enable global interrupts, ")); hme_write32(hp, gregs + GREG_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 + ETX_RSIZE))); hme_write32(hp, etxregs + ETX_RSIZE, (TX_RING_SIZE >> ETX_RSIZE_SHIFT) - 1); /* Enable transmitter DVMA. */ HMD(("tx dma enable old[%08x], ", hme_read32(hp, etxregs + ETX_CFG))); hme_write32(hp, etxregs + ETX_CFG, hme_read32(hp, etxregs + ETX_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 + ERX_CFG))); hme_write32(hp, erxregs + ERX_CFG, ERX_CFG_DEFAULT(RX_OFFSET)); regtmp = hme_read32(hp, erxregs + ERX_CFG); hme_write32(hp, erxregs + ERX_CFG, ERX_CFG_DEFAULT(RX_OFFSET)); if (hme_read32(hp, erxregs + ERX_CFG) != ERX_CFG_DEFAULT(RX_OFFSET)) { printk(KERN_ERR "happy meal: Eieee, rx config register gets greasy fries.\n"); printk(KERN_ERR "happy meal: Trying to set %08x, reread gives %08x\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 + BMAC_RXCFG))); rxcfg = BIGMAC_RXCFG_HENABLE; if (hp->dev->flags & IFF_PROMISC) rxcfg |= BIGMAC_RXCFG_PMISC; hme_write32(hp, bregs + BMAC_RXCFG, 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 + BMAC_TXCFG, 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 + BMAC_XIFCFG))); hme_write32(hp, bregs + BMAC_XIFCFG, regtmp); /* Start things up. */ HMD(("tx old[%08x] and rx [%08x] ON!\n", hme_read32(hp, bregs + BMAC_TXCFG), hme_read32(hp, bregs + BMAC_RXCFG))); hme_write32(hp, bregs + BMAC_TXCFG, hme_read32(hp, bregs + BMAC_TXCFG) | BIGMAC_TXCFG_ENABLE); hme_write32(hp, bregs + BMAC_RXCFG, hme_read32(hp, bregs + BMAC_RXCFG) | 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){ unsigned long tregs = hp->tcvregs; unsigned long bregs = hp->bigmacregs; unsigned long gregs = hp->gregs; happy_meal_stop(hp, gregs); hme_write32(hp, tregs + TCVR_IMASK, 0xffff); if (hp->happy_flags & HFLAG_FENABLE) hme_write32(hp, tregs + TCVR_CFG, hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_BENABLE)); else hme_write32(hp, tregs + TCVR_CFG, hme_read32(hp, tregs + TCVR_CFG) | TCV_CFG_BENABLE); happy_meal_transceiver_check(hp, tregs); switch(hp->tcvr_type) { case none: return; case internal: hme_write32(hp, bregs + BMAC_XIFCFG, 0); break; case external: hme_write32(hp, bregs + BMAC_XIFCFG, 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -