From owner-svn-src-all@FreeBSD.ORG Mon Mar 30 16:15:06 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9A9D21065705; Mon, 30 Mar 2009 16:15:06 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 8697B8FC1A; Mon, 30 Mar 2009 16:15:06 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n2UGF6ei071677; Mon, 30 Mar 2009 16:15:06 GMT (envelope-from imp@svn.freebsd.org) Received: (from imp@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n2UGF6Bn071672; Mon, 30 Mar 2009 16:15:06 GMT (envelope-from imp@svn.freebsd.org) Message-Id: <200903301615.n2UGF6Bn071672@svn.freebsd.org> From: Warner Losh Date: Mon, 30 Mar 2009 16:15:06 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r190559 - head/sys/dev/ed X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 30 Mar 2009 16:15:08 -0000 Author: imp Date: Mon Mar 30 16:15:06 2009 New Revision: 190559 URL: http://svn.freebsd.org/changeset/base/190559 Log: This is a major reworking of the AX88x90 support. o Introduce new chip_type AX88790. There's a few places we need to know the exact chip for workaronds. o Explain the AX88190 workaround for the ISR bits being stuck, and don't apply them to the AX88790. The datasheet says the bits are fixed, and experience confirms. o Fix mii bit-bang read code to read and discard the 'floating' bit. o Remove empty ed_pccard_ax88x90_mii_reset routine o Report error from mii_phy_probe o Don't use ed_probe_Novel_generic for ax88x90 chips. It puts them into an odd state sometimes. Instead, use a more stream-lined version that avoids the trouble spots. This was copied and tweaked from the original. o Move chip reset into its own routine. o Minor code optimiation on getting MAC address o Add code for coping with AX88790 cards that are in power down state and need to be kicked before the PHY registers for the internal phy read right. o Remove ugly cap of PHYs at 17. o For AX88790, we need to set a special bit for accessig phy 16 (the internal phy) and clear it for all others according to a chip erratum. o streamline the bit-bang code for AX88x90: the delays aren't needed according to the datasheet timing diagrams and also the Linux driver o Fix minor bit definition for direction bit. o Generally: Some comments reformatted o Only try the toshiba probe on cards labelled as toshiba # From another Akihabara card (this one from a few years ago from a # friend in Japan). Fix the Corega FEther II PCC-TXD. This one is # still on sale new, as of a few weeks ago. should fix all other AX88x90 # based cards, but I have some testing left to finish on my collection... Modified: head/sys/dev/ed/ax88x90reg.h head/sys/dev/ed/if_ed.c head/sys/dev/ed/if_ed_pccard.c head/sys/dev/ed/if_edreg.h Modified: head/sys/dev/ed/ax88x90reg.h ============================================================================== --- head/sys/dev/ed/ax88x90reg.h Mon Mar 30 16:01:09 2009 (r190558) +++ head/sys/dev/ed/ax88x90reg.h Mon Mar 30 16:15:06 2009 (r190559) @@ -30,7 +30,7 @@ /* AX88x90 based miibus defines */ #define ED_AX88X90_MIIBUS 0x04 /* MII bus register on ASIC */ #define ED_AX88X90_MII_CLK 0x01 -#define ED_AX88X90_MII_DIROUT 0x02 +#define ED_AX88X90_MII_DIRIN 0x02 #define ED_AX88X90_MII_DATAIN 0x04 #define ED_AX88X90_MII_DATAOUT 0x08 #define ED_AX88X90_TEST 0x05 /* "test" register on asic */ Modified: head/sys/dev/ed/if_ed.c ============================================================================== --- head/sys/dev/ed/if_ed.c Mon Mar 30 16:01:09 2009 (r190558) +++ head/sys/dev/ed/if_ed.c Mon Mar 30 16:15:06 2009 (r190559) @@ -427,10 +427,17 @@ ed_stop_hw(struct ed_softc *sc) * Wait for interface to enter stopped state, but limit # of checks to * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but * just in case it's an old one. + * + * The AX88190 and AX88190A chips have a problem with this, it seems, + * but there's no evidence that I've found for excluding the check. + * This may be due to the cryptic references to the ISR register being + * fixed in the AX88790. */ if (sc->chip_type != ED_CHIP_TYPE_AX88190) while (((ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST) == 0) && --n) continue; + if (n <= 0) + device_printf(sc->dev, "ed_stop_hw RST never set\n"); } /* @@ -916,10 +923,10 @@ edintr(void *arg) ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA); /* - * loop until there are no more new interrupts. When the card - * goes away, the hardware will read back 0xff. Looking at - * the interrupts, it would appear that 0xff is impossible, - * or at least extremely unlikely. + * loop until there are no more new interrupts. When the card goes + * away, the hardware will read back 0xff. Looking at the interrupts, + * it would appear that 0xff is impossible, or at least extremely + * unlikely. */ while ((isr = ed_nic_inb(sc, ED_P0_ISR)) != 0 && isr != 0xff) { @@ -930,12 +937,14 @@ edintr(void *arg) */ ed_nic_outb(sc, ED_P0_ISR, isr); - /* - * XXX workaround for AX88190 + /* + * The AX88190 and AX88190A has problems acking an interrupt + * and having them clear. This interferes with top-level loop + * here. Wait for all the bits to clear. + * * We limit this to 5000 iterations. At 1us per inb/outb, - * this translates to about 15ms, which should be plenty - * of time, and also gives protection in the card eject - * case. + * this translates to about 15ms, which should be plenty of + * time, and also gives protection in the card eject case. */ if (sc->chip_type == ED_CHIP_TYPE_AX88190) { count = 5000; /* 15ms */ @@ -1530,7 +1539,8 @@ ed_setrcr(struct ed_softc *sc) ED_ASSERT_LOCKED(sc); /* Bit 6 in AX88190 RCR register must be set. */ - if (sc->chip_type == ED_CHIP_TYPE_AX88190) + if (sc->chip_type == ED_CHIP_TYPE_AX88190 || + sc->chip_type == ED_CHIP_TYPE_AX88790) reg1 = ED_RCR_INTT; else reg1 = 0x00; Modified: head/sys/dev/ed/if_ed_pccard.c ============================================================================== --- head/sys/dev/ed/if_ed_pccard.c Mon Mar 30 16:01:09 2009 (r190558) +++ head/sys/dev/ed/if_ed_pccard.c Mon Mar 30 16:15:06 2009 (r190559) @@ -245,7 +245,6 @@ static void ed_pccard_dl100xx_mii_writeb int nbits); static int ed_pccard_ax88x90(device_t dev, const struct ed_product *); -static void ed_pccard_ax88x90_mii_reset(struct ed_softc *sc); static u_int ed_pccard_ax88x90_mii_readbits(struct ed_softc *sc, int nbits); static void ed_pccard_ax88x90_mii_writebits(struct ed_softc *sc, u_int val, int nbits); @@ -364,7 +363,7 @@ ed_pccard_rom_mac(device_t dev, uint8_t */ ed_pio_readmem(sc, 0, romdata, 32); if (bootverbose) - printf("ROM DATA: %32D\n", romdata, " "); + device_printf(dev, "ROM DATA: %32D\n", romdata, " "); if (romdata[28] != 0x57 || romdata[30] != 0x57) return (0); for (i = 0; i < ETHER_ADDR_LEN; i++) @@ -440,6 +439,7 @@ ed_pccard_attach(device_t dev) u_long size; static uint16_t *intr_vals[] = {NULL, NULL}; + sc->dev = dev; if ((pp = (const struct ed_product *) pccard_product_lookup(dev, (const struct pccard_product *) ed_pccard_products, sizeof(ed_pccard_products[0]), NULL)) == NULL) @@ -485,9 +485,8 @@ ed_pccard_attach(device_t dev) error = ed_pccard_tc5299j(dev, pp); if (error != 0) error = ed_probe_Novell_generic(dev, flags); - if (error != 0) { - if (pp->flags & NE2000DVF_TOSHIBA) - flags |= ED_FLAGS_TOSH_ETHER; + if (error != 0 && (pp->flags & NE2000DVF_TOSHIBA)) { + flags |= ED_FLAGS_TOSH_ETHER; flags |= ED_FLAGS_PCCARD; sc->asic_offset = ED_WD_ASIC_OFFSET; sc->nic_offset = ED_WD_NIC_OFFSET; @@ -564,11 +563,11 @@ ed_pccard_attach(device_t dev) ed_pccard_dl100xx_mii_reset(sc); (void)mii_phy_probe(dev, &sc->miibus, ed_ifmedia_upd, ed_ifmedia_sts); - } else if (sc->chip_type == ED_CHIP_TYPE_AX88190) { - ed_pccard_ax88x90_mii_reset(sc); + } else if (sc->chip_type == ED_CHIP_TYPE_AX88190 || + sc->chip_type == ED_CHIP_TYPE_AX88790) { if ((error = mii_phy_probe(dev, &sc->miibus, ed_ifmedia_upd, ed_ifmedia_sts)) != 0) { - device_printf(dev, "Missing mii!\n"); + device_printf(dev, "Missing mii %d!\n", error); goto bad; } @@ -722,11 +721,100 @@ ed_pccard_dl100xx_mii_readbits(struct ed return val; } +static void +ed_pccard_ax88x90_reset(struct ed_softc *sc) +{ + int i; + + /* Reset Card */ + ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP | ED_CR_PAGE_0); + ed_asic_outb(sc, ED_NOVELL_RESET, ed_asic_inb(sc, ED_NOVELL_RESET)); + + /* Wait for the interrupt to fire */ + for (i = 10000; i > 0; i--) + if (ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST) + break; + ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RST); /* ACK INTR */ + if (i == 0) + device_printf(sc->dev, "Reset didn't finish\n"); +} + +/* + * Probe and vendor-specific initialization routine for ax88x90 boards + */ +static int +ed_probe_ax88x90_generic(device_t dev, int flags) +{ + struct ed_softc *sc = device_get_softc(dev); + u_int memsize; + static char test_pattern[32] = "THIS is A memory TEST pattern"; + char test_buffer[32]; + + ed_pccard_ax88x90_reset(sc); + DELAY(10 * 1000); + + /* Make sure that we really have an 8390 based board */ + if (!ed_probe_generic8390(sc)) + return (ENXIO); + + sc->vendor = ED_VENDOR_NOVELL; + sc->mem_shared = 0; + sc->cr_proto = ED_CR_RD2; + + /* + * Test the ability to read and write to the NIC memory. + */ + + /* + * This prevents packets from being stored in the NIC memory when the + * readmem routine turns on the start bit in the CR. + */ + ed_nic_outb(sc, ED_P0_RCR, ED_RCR_MON); + + /* Temporarily initialize DCR for byte operations */ + ed_nic_outb(sc, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); + sc->isa16bit = 1; + ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); + ed_nic_outb(sc, ED_P0_PSTART, 16384 / ED_PAGE_SIZE); + ed_nic_outb(sc, ED_P0_PSTOP, 32768 / ED_PAGE_SIZE); + /* + * Write a test pattern in word mode. If this also fails, then + * we don't know what this board is. + */ + ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern)); + ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern)); + if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) != 0) + return (ENXIO); + sc->type = ED_TYPE_NE2000; + if (ed_asic_inb(sc, ED_AX88X90_TEST) != 0) + sc->chip_type = ED_CHIP_TYPE_AX88790; + else + sc->chip_type = ED_CHIP_TYPE_AX88190; + + /* 8k of memory plus an additional 8k if 16bit */ + memsize = 8192 + sc->isa16bit * 8192; + sc->mem_size = memsize; + + /* NIC memory doesn't start at zero on an NE board */ + /* The start address is tied to the bus width */ + sc->mem_start = 8192 + sc->isa16bit * 8192; + sc->mem_end = sc->mem_start + memsize; + sc->tx_page_start = memsize / ED_PAGE_SIZE; + sc->txb_cnt = 2; + sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; + sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE; + + sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; + /* clear any pending interrupts that might have occurred above */ + ed_nic_outb(sc, ED_P0_ISR, 0xff); + sc->sc_write_mbufs = ed_pio_write_mbufs; + return (0); +} + static int -ed_pccard_ax88x90_geteprom(struct ed_softc *sc) +ed_pccard_ax88x90_enaddr(struct ed_softc *sc) { - int prom[16],i; - u_char tmp; + int i, j; struct { unsigned char offset, value; } pg_seq[] = { @@ -739,42 +827,75 @@ ed_pccard_ax88x90_geteprom(struct ed_sof {ED_P0_ISR, 0xff}, {ED_P0_RCR, ED_RCR_MON | ED_RCR_INTT}, /* Set To Monitor */ {ED_P0_TCR, ED_TCR_LB0}, /* loopback mode. */ - {ED_P0_RBCR0, 32}, + {ED_P0_RBCR0, 0x20}, {ED_P0_RBCR1, 0x00}, {ED_P0_RSAR0, 0x00}, {ED_P0_RSAR1, 0x04}, {ED_P0_CR, ED_CR_RD0 | ED_CR_STA | ED_CR_PAGE_0}, }; - /* Reset Card */ - tmp = ed_asic_inb(sc, ED_NOVELL_RESET); - ed_asic_outb(sc, ED_NOVELL_RESET, tmp); - DELAY(5000); - ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP | ED_CR_PAGE_0); - DELAY(5000); - /* Card Settings */ for (i = 0; i < sizeof(pg_seq) / sizeof(pg_seq[0]); i++) ed_nic_outb(sc, pg_seq[i].offset, pg_seq[i].value); /* Get Data */ - for (i = 0; i < ETHER_ADDR_LEN / 2; i++) - prom[i] = ed_asic_inw(sc, 0); for (i = 0; i < ETHER_ADDR_LEN; i += 2) { - sc->enaddr[i] = prom[i / 2] & 0xff; - sc->enaddr[i + 1] = (prom[i / 2] >> 8) & 0xff; + j = ed_asic_inw(sc, 0); + sc->enaddr[i] = j & 0xff; + sc->enaddr[i + 1] = (j >> 8) & 0xff; } return (0); } +static int +ed_pccard_ax88x90_check_mii(device_t dev, struct ed_softc *sc) +{ + int i, id; + + /* + * All AX88x90 devices have MII and a PHY, so we use this to weed out + * chips that would otherwise make it through the tests we have after + * this point. + */ + for (i = 0; i < 32; i++) { + id = ed_miibus_readreg(dev, i, MII_BMSR); + if (id != 0 && id != 0xffff) + break; + } + /* + * Found one, we're good. + */ + if (i != 32) + return (0); + /* + * Didn't find anything, so try to power up and try again. The PHY + * may be not responding because we're in power down mode. + */ + if (sc->chip_type == ED_CHIP_TYPE_AX88190) + return (ENXIO); + pccard_ccr_write_1(dev, PCCARD_CCR_STATUS, PCCARD_CCR_STATUS_PWRDWN); + for (i = 0; i < 32; i++) { + id = ed_miibus_readreg(dev, i, MII_BMSR); + if (id != 0 && id != 0xffff) + break; + } + /* + * Still no joy? We're AFU, punt. + */ + if (i == 32) + return (ENXIO); + return (0); + +} + /* * Special setup for AX88[17]90 */ static int ed_pccard_ax88x90(device_t dev, const struct ed_product *pp) { - int error, iobase, i, id; - char *ts; + int error; + int iobase; struct ed_softc *sc = device_get_softc(dev); if (!(pp->flags & NE2000DVF_AX88X90)) @@ -786,93 +907,51 @@ ed_pccard_ax88x90(device_t dev, const st /* * Set the IOBASE Register. The AX88x90 cards are potentially * multifunction cards, and thus requires a slight workaround. - * We write the address the card is at. + * We write the address the card is at, on the off chance that this + * card is not MFC. + * XXX I'm not sure that this is still needed... */ iobase = rman_get_start(sc->port_res); pccard_ccr_write_1(dev, PCCARD_CCR_IOBASE0, iobase & 0xff); pccard_ccr_write_1(dev, PCCARD_CCR_IOBASE1, (iobase >> 8) & 0xff); - ts = "AX88190"; - if (ed_asic_inb(sc, ED_AX88X90_TEST) != 0) { - /* - * AX88790 (and I think AX88190A) chips need to be - * powered down. There's an erratum that says we should - * power down the PHY for 2.5s, but this seems to power - * down the whole card. I'm unsure why this was done, but - * appears to be required for proper operation. - */ - pccard_ccr_write_1(dev, PCCARD_CCR_STATUS, - PCCARD_CCR_STATUS_PWRDWN); - /* - * Linux axnet driver selects the internal phy for the ax88790 - */ - ed_asic_outb(sc, ED_AX88X90_GPIO, ED_AX88X90_GPIO_INT_PHY); - ts = "AX88790"; - } - - /* - * Check to see if we have a MII PHY ID at any of the first 17 - * locations. All AX88x90 devices have MII and a PHY, so we use - * this to weed out chips that would otherwise make it through - * the tests we have after this point. - */ sc->mii_readbits = ed_pccard_ax88x90_mii_readbits; sc->mii_writebits = ed_pccard_ax88x90_mii_writebits; - for (i = 0; i < 17; i++) { - id = ed_miibus_readreg(dev, i, MII_PHYIDR1); - if (id != 0 && id != 0xffff) - break; - } - if (i == 17) { - sc->mii_readbits = 0; - sc->mii_writebits = 0; - return (ENXIO); + error = ed_probe_ax88x90_generic(dev, device_get_flags(dev)); + if (error) { + if (bootverbose) + device_printf(dev, "probe ax88x90 failed %d\n", + error); + goto fail; } - - sc->chip_type = ED_CHIP_TYPE_AX88190; - error = ed_pccard_ax88x90_geteprom(sc); + error = ed_pccard_ax88x90_enaddr(sc); if (error) - return (error); - error = ed_probe_Novell_generic(dev, device_get_flags(dev)); - if (bootverbose) - device_printf(dev, "probe novel returns %d\n", error); - if (error == 0) { - sc->vendor = ED_VENDOR_NOVELL; - sc->type = ED_TYPE_NE2000; - sc->chip_type = ED_CHIP_TYPE_AX88190; - sc->type_str = ts; - } + goto fail; + error = ed_pccard_ax88x90_check_mii(dev, sc); + if (error) + goto fail; + sc->vendor = ED_VENDOR_NOVELL; + sc->type = ED_TYPE_NE2000; + if (sc->chip_type == ED_CHIP_TYPE_AX88190) + sc->type_str = "AX88190"; + else + sc->type_str = "AX88790"; + return (0); +fail:; + sc->mii_readbits = 0; + sc->mii_writebits = 0; return (error); } -/* MII bit-twiddling routines for cards using AX88x90 chipset */ -#define AX88X90_MIISET(sc, x) ed_asic_outb(sc, ED_AX88X90_MIIBUS, \ - ed_asic_inb(sc, ED_AX88X90_MIIBUS) | (x)) -#define AX88X90_MIICLR(sc, x) ed_asic_outb(sc, ED_AX88X90_MIIBUS, \ - ed_asic_inb(sc, ED_AX88X90_MIIBUS) & ~(x)) - -static void -ed_pccard_ax88x90_mii_reset(struct ed_softc *sc) -{ - /* Do nothing! */ -} - static void ed_pccard_ax88x90_mii_writebits(struct ed_softc *sc, u_int val, int nbits) { - int i; + int i, data; - AX88X90_MIICLR(sc, ED_AX88X90_MII_DIROUT); for (i = nbits - 1; i >= 0; i--) { - if ((val >> i) & 1) - AX88X90_MIISET(sc, ED_AX88X90_MII_DATAOUT); - else - AX88X90_MIICLR(sc, ED_AX88X90_MII_DATAOUT); - DELAY(10); - AX88X90_MIISET(sc, ED_AX88X90_MII_CLK); - DELAY(10); - AX88X90_MIICLR(sc, ED_AX88X90_MII_CLK); - DELAY(10); + data = (val >> i) & 1 ? ED_AX88X90_MII_DATAOUT : 0; + ed_asic_outb(sc, ED_AX88X90_MIIBUS, data); + ed_asic_outb(sc, ED_AX88X90_MIIBUS, data | ED_AX88X90_MII_CLK); } } @@ -881,16 +960,15 @@ ed_pccard_ax88x90_mii_readbits(struct ed { int i; u_int val = 0; + uint8_t mdio; - AX88X90_MIISET(sc, ED_AX88X90_MII_DIROUT); + mdio = ED_AX88X90_MII_DIRIN; for (i = nbits - 1; i >= 0; i--) { - AX88X90_MIISET(sc, ED_AX88X90_MII_CLK); - DELAY(10); + ed_asic_outb(sc, ED_AX88X90_MIIBUS, mdio); val <<= 1; if (ed_asic_inb(sc, ED_AX88X90_MIIBUS) & ED_AX88X90_MII_DATAIN) val++; - AX88X90_MIICLR(sc, ED_AX88X90_MII_CLK); - DELAY(10); + ed_asic_outb(sc, ED_AX88X90_MIIBUS, mdio | ED_AX88X90_MII_CLK); } return val; } @@ -1015,20 +1093,29 @@ ed_miibus_readreg(device_t dev, int phy, struct ed_softc *sc; int failed, val; + sc = device_get_softc(dev); /* - * The AX88790 seem to have phy 0..f external, and 0x10 internal. - * but they also seem to have a bogus one that shows up at phy - * 0x11 through 0x1f. + * The AX88790 has an interesting quirk. It has an internal phy that + * needs a special bit set to access, but can also have additional + * external PHYs set for things like HomeNET media. When accessing + * the internal PHY, a bit has to be set, when accessing the external + * PHYs, it must be clear. See Errata 1, page 51, in the AX88790 + * datasheet for more details. */ - if (phy >= 0x11) - return (0); + if (sc->chip_type == ED_CHIP_TYPE_AX88790) { + if (phy == 0x10) + ed_asic_outb(sc, ED_AX88X90_GPIO, + ED_AX88X90_GPIO_INT_PHY); + else + ed_asic_outb(sc, ED_AX88X90_GPIO, 0); + } - sc = device_get_softc(dev); (*sc->mii_writebits)(sc, 0xffffffff, 32); (*sc->mii_writebits)(sc, ED_MII_STARTDELIM, ED_MII_STARTDELIM_BITS); (*sc->mii_writebits)(sc, ED_MII_READOP, ED_MII_OP_BITS); (*sc->mii_writebits)(sc, phy, ED_MII_PHY_BITS); (*sc->mii_writebits)(sc, reg, ED_MII_REG_BITS); + (*sc->mii_readbits)(sc, ED_MII_ACK_BITS); failed = (*sc->mii_readbits)(sc, ED_MII_ACK_BITS); val = (*sc->mii_readbits)(sc, ED_MII_DATA_BITS); (*sc->mii_writebits)(sc, ED_MII_IDLE, ED_MII_IDLE_BITS); @@ -1040,15 +1127,22 @@ ed_miibus_writereg(device_t dev, int phy { struct ed_softc *sc; + sc = device_get_softc(dev); /* - * The AX88790 seem to have phy 0..f external, and 0x10 internal. - * but they also seem to have a bogus one that shows up at phy - * 0x11 through 0x1f. + * The AX88790 has an interesting quirk. It has an internal phy that + * needs a special bit set to access, but can also have additional + * external PHYs set for things like HomeNET media. When accessing + * the internal PHY, a bit has to be set, when accessing the external + * PHYs, it must be clear. See Errata 1, page 51, in the AX88790 + * datasheet for more details. */ - if (phy >= 0x11) - return (0); - - sc = device_get_softc(dev); + if (sc->chip_type == ED_CHIP_TYPE_AX88790) { + if (phy == 0x10) + ed_asic_outb(sc, ED_AX88X90_GPIO, + ED_AX88X90_GPIO_INT_PHY); + else + ed_asic_outb(sc, ED_AX88X90_GPIO, 0); + } (*sc->mii_writebits)(sc, 0xffffffff, 32); (*sc->mii_writebits)(sc, ED_MII_STARTDELIM, ED_MII_STARTDELIM_BITS); (*sc->mii_writebits)(sc, ED_MII_WRITEOP, ED_MII_OP_BITS); Modified: head/sys/dev/ed/if_edreg.h ============================================================================== --- head/sys/dev/ed/if_edreg.h Mon Mar 30 16:01:09 2009 (r190558) +++ head/sys/dev/ed/if_edreg.h Mon Mar 30 16:15:06 2009 (r190559) @@ -1075,6 +1075,7 @@ struct ed_ring { #define ED_CHIP_TYPE_TC5299J 5 #define ED_CHIP_TYPE_RTL8019 6 #define ED_CHIP_TYPE_RTL8029 7 +#define ED_CHIP_TYPE_AX88790 8 /* * MII bus definitions. These are common to both DL100xx and AX88x90 @@ -1091,6 +1092,6 @@ struct ed_ring { #define ED_MII_PHY_BITS 5 #define ED_MII_REG_BITS 5 #define ED_MII_TURNAROUND_BITS 2 -#define ED_MII_DATA_BITS 16 #define ED_MII_ACK_BITS 1 +#define ED_MII_DATA_BITS 16 #define ED_MII_IDLE_BITS 1