diff options
author | dg <dg@FreeBSD.org> | 1997-03-17 11:08:16 +0000 |
---|---|---|
committer | dg <dg@FreeBSD.org> | 1997-03-17 11:08:16 +0000 |
commit | 8032f5328d8046c507154b8fdad9c17459bfb0c9 (patch) | |
tree | 1927984bcafa4dee1f2bec9126ab19549f49c537 /sys/dev/fxp | |
parent | 1062c914df46ad60942bb36e0bf0e6d8dc429171 (diff) | |
download | FreeBSD-src-8032f5328d8046c507154b8fdad9c17459bfb0c9.zip FreeBSD-src-8032f5328d8046c507154b8fdad9c17459bfb0c9.tar.gz |
Fixed two deficiencies in the driver that have existed since it was
written:
1) Full duplex mode is now supported (and works!)
2) The 10Mbps-only PCI Pro/10 should now work (untested, however)
Thanks to Justin Gibbs for providing a PCI bus analyzer trace while the
Intel Windows driver was configuring the board...this made it possible
to figure out the mystery bit that I wasn't setting in the PHY for full
duplex to work.
Diffstat (limited to 'sys/dev/fxp')
-rw-r--r-- | sys/dev/fxp/if_fxp.c | 111 | ||||
-rw-r--r-- | sys/dev/fxp/if_fxpreg.h | 28 |
2 files changed, 116 insertions, 23 deletions
diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index ff4fef7..0b154cc 100644 --- a/sys/dev/fxp/if_fxp.c +++ b/sys/dev/fxp/if_fxp.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: if_fxp.c,v 1.29 1997/02/22 09:44:05 peter Exp $ */ /* @@ -88,6 +88,9 @@ struct fxp_softc { struct fxp_stats *fxp_stats; /* Pointer to interface stats */ int tx_queued; /* # of active TxCB's */ int promisc_mode; /* promiscuous mode enabled */ + int phy_primary_addr; /* address of primary PHY */ + int phy_primary_device; /* device type of primary PHY */ + int phy_10Mbps_only; /* PHY is 10Mbps-only device */ }; static u_long fxp_count; @@ -134,9 +137,12 @@ static int fxp_ioctl __P((struct ifnet *, int, caddr_t)); static void fxp_init __P((void *)); static void fxp_stop __P((struct fxp_softc *)); static void fxp_watchdog __P((struct ifnet *)); -static void fxp_get_macaddr __P((struct fxp_softc *)); static int fxp_add_rfabuf __P((struct fxp_softc *, struct mbuf *)); static void fxp_shutdown __P((int, void *)); +static int fxp_mdi_read __P((struct fxp_csr *, int, int)); +static void fxp_mdi_write __P((struct fxp_csr *, int, int, int)); +static void fxp_read_eeprom __P((struct fxp_csr *, u_short *, int, int)); + timeout_t fxp_stats_update; @@ -208,7 +214,7 @@ fxp_probe(config_id, device_id) { if (((device_id & 0xffff) == FXP_VENDORID_INTEL) && ((device_id >> 16) & 0xffff) == FXP_DEVICEID_i82557) - return ("Intel EtherExpress Pro/100B Fast Ethernet"); + return ("Intel EtherExpress Pro 10/100B Ethernet"); return NULL; } @@ -225,6 +231,7 @@ fxp_attach(config_id, unit) struct ifnet *ifp; vm_offset_t pbase; int s, i; + u_short data; sc = malloc(sizeof(struct fxp_softc), M_DEVBUF, M_NOWAIT); if (sc == NULL) @@ -275,6 +282,14 @@ fxp_attach(config_id, unit) } } + /* + * Get info about the primary PHY + */ + fxp_read_eeprom(sc->csr, (u_short *)&data, 6, 1); + sc->phy_primary_addr = data & 0xff; + sc->phy_primary_device = (data >> 8) & 0x3f; + sc->phy_10Mbps_only = data >> 15; + ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = unit; @@ -287,9 +302,14 @@ fxp_attach(config_id, unit) ifp->if_baudrate = 100000000; ifp->if_init = fxp_init; - fxp_get_macaddr(sc); - printf("fxp%d: Ethernet address %6D\n", unit, - sc->arpcom.ac_enaddr, ":"); + /* + * Read MAC address + */ + fxp_read_eeprom(sc->csr, (u_short *)sc->arpcom.ac_enaddr, 0, 3); + printf("fxp%d: Ethernet address %6D", unit, sc->arpcom.ac_enaddr, ":"); + if (sc->phy_10Mbps_only) + printf(", 10Mbps"); + printf("\n"); /* * Attach the interface. @@ -328,25 +348,23 @@ fail: } /* - * Read station (MAC) address from serial EEPROM. Basically, you - * manually shift in the read opcode (one bit at a time) and then - * shift in the address, and then you shift out the data (all of - * this one bit at a time). The word size is 16 bits, so you have - * to provide the address for every 16 bits of data. The MAC address - * is in the first 3 words (6 bytes total). + * Read from the serial EEPROM. Basically, you manually shift in + * the read opcode (one bit at a time) and then shift in the address, + * and then you shift out the data (all of this one bit at a time). + * The word size is 16 bits, so you have to provide the address for + * every 16 bits of data. */ static void -fxp_get_macaddr(sc) - struct fxp_softc *sc; -{ +fxp_read_eeprom(csr, data, offset, words) struct fxp_csr *csr; - u_short reg, *data; + u_short *data; + int offset; + int words; +{ + u_short reg; int i, x; - csr = sc->csr; - data = (u_short *)sc->arpcom.ac_enaddr; - - for (i = 0; i < 3; i++) { + for (i = 0; i < words; i++) { csr->eeprom_control = FXP_EEPROM_EECS; /* * Shift in read opcode. @@ -367,7 +385,7 @@ fxp_get_macaddr(sc) * Shift in address. */ for (x = 6; x > 0; x--) { - if (i & (1 << (x - 1))) { + if ((i + offset) & (1 << (x - 1))) { reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; } else { reg = FXP_EEPROM_EECS; @@ -864,7 +882,7 @@ fxp_init(xsc) cbp->save_bf = prm; /* save bad frames */ cbp->disc_short_rx = !prm; /* discard short packets */ cbp->underrun_retry = 1; /* retry mode (1) on DMA underrun */ - cbp->mediatype = 1; /* (MII) interface mode */ + cbp->mediatype = !sc->phy_10Mbps_only; /* interface mode */ cbp->nsai = 1; /* (don't) disable source addr insert */ cbp->preamble_length = 2; /* (7 byte) preamble */ cbp->loopback = 0; /* (don't) loopback */ @@ -941,6 +959,17 @@ fxp_init(xsc) csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); csr->scb_command = FXP_SCB_COMMAND_RU_START; + /* + * Toggle a few bits in the DP83840 PHY. + */ + if (sc->phy_primary_device == FXP_PHY_DP83840) { + fxp_mdi_write(sc->csr, sc->phy_primary_addr, FXP_DP83840_PCR, + fxp_mdi_read(sc->csr, sc->phy_primary_addr, FXP_DP83840_PCR) | + FXP_DP83840_PCR_LED4_MODE | /* LED4 always indicates duplex */ + FXP_DP83840_PCR_F_CONNECT | /* force link disconnect bypass */ + FXP_DP83840_PCR_BIT10); /* XXX I have no idea */ + } + ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; splx(s); @@ -1014,6 +1043,44 @@ fxp_add_rfabuf(sc, oldm) } static int +fxp_mdi_read(csr, phy, reg) + struct fxp_csr *csr; + int phy; + int reg; +{ + int count = 10000; + + csr->mdi_control = (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21); + + while ((csr->mdi_control & 0x10000000) == 0 && count--) + DELAY(1); + + if (count <= 0) + printf("fxp_mdi_read: timed out\n"); + + return (csr->mdi_control & 0xffff); +} + +static void +fxp_mdi_write(csr, phy, reg, value) + struct fxp_csr *csr; + int phy; + int reg; + int value; +{ + int count = 10000; + + csr->mdi_control = (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) + | (value & 0xffff); + + while ((csr->mdi_control & 10000000) == 0 && count--) + DELAY(1); + + if (count <= 0) + printf("fxp_mdi_write: timed out\n"); +} + +static int fxp_ioctl(ifp, command, data) struct ifnet *ifp; int command; diff --git a/sys/dev/fxp/if_fxpreg.h b/sys/dev/fxp/if_fxpreg.h index e62e727..b6005d7 100644 --- a/sys/dev/fxp/if_fxpreg.h +++ b/sys/dev/fxp/if_fxpreg.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: if_fxpreg.h,v 1.6 1997/02/22 09:44:06 peter Exp $ */ #define FXP_VENDORID_INTEL 0x8086 @@ -275,3 +275,29 @@ struct fxp_stats { #define FXP_EEPROM_OPC_ERASE 0x4 #define FXP_EEPROM_OPC_WRITE 0x5 #define FXP_EEPROM_OPC_READ 0x6 + +/* + * Management Data Interface opcodes + */ +#define FXP_MDI_WRITE 0x1 +#define FXP_MDI_READ 0x2 + +/* + * PHY device types + */ +#define FXP_PHY_NONE 0 +#define FXP_PHY_82553A 1 +#define FXP_PHY_82553C 2 +#define FXP_PHY_82503 3 +#define FXP_PHY_DP83840 4 +#define FXP_PHY_80C240 5 +#define FXP_PHY_80C24 6 + +/* + * DP84830 PHY, PCS Configuration Register + */ +#define FXP_DP83840_PCR 0x17 +#define FXP_DP83840_PCR_LED4_MODE 0x0002 /* 1 = LED4 always indicates full duplex */ +#define FXP_DP83840_PCR_F_CONNECT 0x0020 /* 1 = force link disconnect function bypass */ +#define FXP_DP83840_PCR_BIT8 0x0100 +#define FXP_DP83840_PCR_BIT10 0x0400 |