📄 sunhme.c
字号:
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, MII_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, MII_BMCR, hp->sw_bmcr); /* Restart it to make sure it is going. */ hp->sw_bmcr |= BMCR_ANRESTART; happy_meal_tcvr_write(hp, tregs, MII_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, MII_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, MII_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);}/* hp->happy_lock must be held */static int happy_meal_init(struct happy_meal *hp){ void __iomem *gregs = hp->gregs; void __iomem *etxregs = hp->etxregs; void __iomem *erxregs = hp->erxregs; void __iomem *bregs = hp->bigmacregs; void __iomem *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); /* 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; u32 crc; 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 = ether_crc_le(6, addrs); 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", ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)), ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)))); hme_write32(hp, erxregs + ERX_RING, ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))); hme_write32(hp, etxregs + ETX_RING, ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))); /* Parity issues in the ERX unit of some HME revisions can cause some * registers to not be written unless their parity is even. Detect such * lost writes and simply rewrite with a low bit set (which will be ignored * since the rxring needs to be 2K aligned). */ if (hme_read32(hp, erxregs + ERX_RING) != ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))) hme_write32(hp, erxregs + ERX_RING, ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)) | 0x4); /* 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 its 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 | BIGMAC_RXCFG_REJME; 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; /* Don't turn on the "don't give up" bit for now. It could cause hme * to deadlock with the PHY if a Jabber occurs. */ hme_write32(hp, bregs + BMAC_TXCFG, regtmp /*| BIGMAC_TXCFG_DGIVEUP*/); /* Give up after 16 TX attempts. */ hme_write32(hp, bregs + BMAC_ALIMIT, 16); /* 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;}/* hp->happy_lock must be held */static void happy_meal_set_initial_advertisement(struct happy_meal *hp){ void __iomem *tregs = hp->tcvregs; void __iomem *bregs = hp->bigmacregs; void __iomem *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, MII_BMSR); hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_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, MII_ADVERTISE, hp->sw_advertise);}/* Once status is latched (by happy_meal_interrupt) it is cleared by
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -