Subject: Re: Hardware
To: Frank van der Linden <frank@wins.uva.nl>
From: Matthias Drochner <drochner@zel459.zel.kfa-juelich.de>
List: port-i386
Date: 07/28/1999 14:18:59
frank@wins.uva.nl said:
> The 3com docs mention that Broadcomm PHYs may be used on their cards.
Good. I can't identify a separate phy chip on the card however,
so it is probably the on-chip phy which has this ID.
[Linux code]
> But you did manage to get it to probe, right? Could you send me a
> diff?
I'll append it. It is slightly obfuscated... hard to extract
useful information from a Linux driver...
The dummy read of phy 24 reg 1 is taken from Linux too - perhaps
it can be left out - didn't try yet.
It might be better to use the FreeBSD driver as reference, but I had
tested the card in a Linux box and knew that the code works.
> -FX cards probably don't have an MII interface, but are wrongly
> marked as such in if_ex_pci.c.
> [...]
> You're probably getting some random values back by accident,
> hence the weird PHY output.
There is at least no use for a mii phy, but it might be present
in the chip - perhaps 3com has only 1 ASIC version, and the cards
are differentiated by external circuity and EEPROM contents only.
The register values look too consistent for random values.
For the -FX cards, removing of the EX_CONF_MII works (didn't I mention
this already in another mail?), but I don't think we can get away that
easily in the general case. There is a 905b-combo card which has
AUI and BNC in addition to 100TX, and here probably neither the
"no MII" nor the "all MII" version will dtrt. (I don't have such
a card.)
best regards
Matthias
Index: elinkxl.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/elinkxl.c,v
retrieving revision 1.13
diff -c -2 -r1.13 elinkxl.c
*** elinkxl.c 1999/05/18 23:52:55 1.13
--- elinkxl.c 1999/07/28 11:38:27
***************
*** 380,383 ****
--- 380,384 ----
if (sc->ex_conf & EX_CONF_MII) {
+ (void)ex_mii_readreg((struct device *)sc, 24, 1);
/*
* Find PHY, extract media information from it.
***************
*** 1685,1688 ****
--- 1686,1753 ----
}
+ #define mdio_delay() bus_space_read_4(sc->sc_iot, sc->sc_ioh,
ELINK_W4_PHYSMGMT)
+
+ #define MDIO_SHIFT_CLK 0x01
+ #define MDIO_DIR_WRITE 0x04
+ #define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
+ #define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
+ #define MDIO_DATA_READ 0x02
+ #define MDIO_ENB_IN 0x00
+
+ /* Generate the preamble required for initial synchronization and
+ a few older transceivers. */
+ static void mdio_sync(struct ex_softc *sc, int bits)
+ {
+
+ /* Establish sync by sending at least 32 logic ones. */
+ while (-- bits >= 0) {
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ MDIO_DATA_WRITE1);
+ mdio_delay();
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
+ mdio_delay();
+ }
+ }
+
+ #define mii_preamble_required 1
+
+ static int mdio_read(struct ex_softc *sc, int phy_id, int location)
+ {
+ int i;
+ int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ unsigned int retval = 0;
+
+ if (mii_preamble_required)
+ mdio_sync(sc, 32);
+
+ /* Shift the read command bits out. */
+ for (i = 14; i >= 0; i--) {
+ int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ dataval);
+ mdio_delay();
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ dataval | MDIO_SHIFT_CLK);
+ mdio_delay();
+ }
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ MDIO_ENB_IN);
+ mdio_delay();
+ retval = (retval << 1) | ((bus_space_read_2(sc->sc_iot, sc->sc_ioh,
ELINK_W4_PHYSMGMT) & MDIO_DATA_READ) ? 1 : 0);
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ MDIO_ENB_IN | MDIO_SHIFT_CLK);
+ mdio_delay();
+ }
+ #if 0
+ return (retval>>1) & 0x1ffff;
+ #else
+ return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
+ #endif
+ }
+
+
/*
* The reason why all this stuff below is here, is that we need a special
***************
*** 1700,1703 ****
--- 1765,1769 ----
{
struct ex_softc *sc = (struct ex_softc *)v;
+ #if 0
int val = 0;
int err =0;
***************
*** 1742,1745 ****
--- 1808,1822 ----
return (err ? 0 : val);
+ #else
+ int val;
+
+ if ((sc->ex_conf & EX_CONF_INTPHY) && phy != ELINK_INTPHY_ID)
+ return 0;
+
+ GO_WINDOW(4);
+ val = mdio_read(sc, phy, reg);
+ GO_WINDOW(1);
+ return (val);
+ #endif
}