Add some code to support 82580[ER]. Tested on my own I340-T4.

- Fix CTRL_EXT_SWDPIN() and CTRL_EXT_SWDPIO() macros. The bit order of the
   SW definable pin is not 6543 but 3654!!!

 - Rewrite the code to read MAC address from eeprom.

 - Add some code to support 82580.

TODO:
 - ukphy -> somephy
This commit is contained in:
msaitoh 2010-06-25 04:03:14 +00:00
parent d6d8c40941
commit 5e478d2ed7
2 changed files with 175 additions and 31 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_wm.c,v 1.207 2010/05/25 01:17:55 msaitoh Exp $ */
/* $NetBSD: if_wm.c,v 1.208 2010/06/25 04:03:14 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@ -76,7 +76,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.207 2010/05/25 01:17:55 msaitoh Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.208 2010/06/25 04:03:14 msaitoh Exp $");
#include "rnd.h"
@ -510,6 +510,7 @@ static int wm_add_rxbuf(struct wm_softc *, int);
static int wm_read_eeprom(struct wm_softc *, int, int, u_int16_t *);
static int wm_read_eeprom_eerd(struct wm_softc *, int, int, u_int16_t *);
static int wm_validate_eeprom_checksum(struct wm_softc *);
static int wm_read_mac_addr(struct wm_softc *, uint8_t *);
static void wm_tick(void *);
static void wm_set_filter(struct wm_softc *);
@ -1098,7 +1099,7 @@ wm_attach(device_t parent, device_t self, void *aux)
prop_data_t ea;
prop_number_t pn;
uint8_t enaddr[ETHER_ADDR_LEN];
uint16_t myea[ETHER_ADDR_LEN / 2], cfg1, cfg2, swdpin, io3;
uint16_t cfg1, cfg2, swdpin, io3;
pcireg_t preg, memtype;
uint16_t eeprom_data, apme_mask;
uint32_t reg;
@ -1246,7 +1247,8 @@ wm_attach(device_t parent, device_t self, void *aux)
*/
if ((sc->sc_type == WM_T_82546) || (sc->sc_type == WM_T_82546_3)
|| (sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_80003)
|| (sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576))
|| (sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
|| (sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER))
sc->sc_funcid = (CSR_READ(sc, WMREG_STATUS)
>> STATUS_FUNCID_SHIFT) & STATUS_FUNCID_MASK;
else
@ -1605,29 +1607,10 @@ wm_attach(device_t parent, device_t self, void *aux)
KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
memcpy(enaddr, prop_data_data_nocopy(ea), ETHER_ADDR_LEN);
} else {
if (wm_read_eeprom(sc, EEPROM_OFF_MACADDR,
sizeof(myea) / sizeof(myea[0]), myea)) {
if (wm_read_mac_addr(sc, enaddr) != 0)
aprint_error_dev(sc->sc_dev,
"unable to read Ethernet address\n");
return;
}
enaddr[0] = myea[0] & 0xff;
enaddr[1] = myea[0] >> 8;
enaddr[2] = myea[1] & 0xff;
enaddr[3] = myea[1] >> 8;
enaddr[4] = myea[2] & 0xff;
enaddr[5] = myea[2] >> 8;
}
/*
* Toggle the LSB of the MAC address on the second port
* of the dual port controller.
*/
if ((sc->sc_type == WM_T_82546) || (sc->sc_type == WM_T_82546_3)
|| (sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_80003)
|| (sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) {
if (sc->sc_funcid == 1)
enaddr[5] ^= 1;
return;
}
aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n",
@ -3595,6 +3578,8 @@ wm_reset(struct wm_softc *sc)
case WM_T_82574:
case WM_T_82575:
case WM_T_82576:
case WM_T_82580:
case WM_T_82580ER:
case WM_T_82583:
default:
/* Everything else can safely use the documented method. */
@ -3653,6 +3638,8 @@ wm_reset(struct wm_softc *sc)
break;
case WM_T_82575:
case WM_T_82576:
case WM_T_82580:
case WM_T_82580ER:
case WM_T_80003:
case WM_T_ICH8:
case WM_T_ICH9:
@ -3671,13 +3658,19 @@ wm_reset(struct wm_softc *sc)
switch (sc->sc_type) {
case WM_T_82575:
case WM_T_82576:
#if 0 /* XXX */
case WM_T_82580:
case WM_T_82580ER:
#endif
case WM_T_ICH8:
case WM_T_ICH9:
if ((CSR_READ(sc, WMREG_EECD) & EECD_EE_PRES) == 0) {
/* Not found */
sc->sc_flags |= WM_F_EEPROM_INVALID;
if (sc->sc_type == WM_T_82575) /* 82575 only */
if ((sc->sc_type == WM_T_82575)
|| (sc->sc_type == WM_T_82576)
|| (sc->sc_type == WM_T_82580)
|| (sc->sc_type == WM_T_82580ER))
wm_reset_init_script_82575(sc);
}
break;
@ -3685,6 +3678,11 @@ wm_reset(struct wm_softc *sc)
break;
}
if ((sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER)) {
/* clear global device reset status bit */
CSR_WRITE(sc, WMREG_STATUS, STATUS_DEV_RST_SET);
}
/* Clear any pending interrupt events. */
CSR_WRITE(sc, WMREG_IMC, 0xffffffffU);
reg = CSR_READ(sc, WMREG_ICR);
@ -4224,6 +4222,8 @@ wm_get_auto_rd_done(struct wm_softc *sc)
case WM_T_82583:
case WM_T_82575:
case WM_T_82576:
case WM_T_82580:
case WM_T_82580ER:
case WM_T_80003:
case WM_T_ICH8:
case WM_T_ICH9:
@ -4309,6 +4309,7 @@ wm_get_cfg_done(struct wm_softc *sc)
case WM_T_82575:
case WM_T_82576:
case WM_T_82580:
case WM_T_82580ER:
mask = EEMNGCTL_CFGDONE_0 << sc->sc_funcid;
for (i = 0; i < WM_PHY_CFG_TIMEOUT; i++) {
if (CSR_READ(sc, WMREG_EEMNGCTL) & mask)
@ -4692,6 +4693,101 @@ wm_poll_eerd_eewr_done(struct wm_softc *sc, int rw)
return done;
}
static int
wm_read_mac_addr(struct wm_softc *sc, uint8_t *enaddr)
{
uint16_t myea[ETHER_ADDR_LEN / 2];
uint16_t offset;
int do_invert = 0;
if (sc->sc_funcid == 0)
offset = EEPROM_OFF_MACADDR;
else {
switch (sc->sc_type) {
case WM_T_82580:
case WM_T_82580ER:
switch (sc->sc_funcid) {
case 1:
offset = EEPROM_OFF_LAN1;
break;
case 2:
offset = EEPROM_OFF_LAN2;
break;
case 3:
offset = EEPROM_OFF_LAN3;
break;
default:
goto bad;
/* NOTREACHED */
break;
}
break;
case WM_T_82571:
case WM_T_82575:
case WM_T_82576:
case WM_T_80003:
if (wm_read_eeprom(sc, EEPROM_ALT_MAC_ADDR_PTR, 1,
&offset) != 0) {
goto bad;
}
/* no pointer */
if (offset == 0xffff) {
/* reset the offset to LAN0 */
offset = EEPROM_OFF_MACADDR;
do_invert = 1;
goto do_read;
}
switch (sc->sc_funcid) {
case 1:
offset += EEPROM_OFF_MACADDR_LAN1;
break;
case 2:
offset += EEPROM_OFF_MACADDR_LAN2;
break;
case 3:
offset += EEPROM_OFF_MACADDR_LAN3;
break;
default:
goto bad;
/* NOTREACHED */
break;
}
break;
default:
do_invert = 1;
break;
}
}
do_read:
if (wm_read_eeprom(sc, offset, sizeof(myea) / sizeof(myea[0]),
myea) != 0) {
goto bad;
}
enaddr[0] = myea[0] & 0xff;
enaddr[1] = myea[0] >> 8;
enaddr[2] = myea[1] & 0xff;
enaddr[3] = myea[1] >> 8;
enaddr[4] = myea[2] & 0xff;
enaddr[5] = myea[2] >> 8;
/*
* Toggle the LSB of the MAC address on the second port
* of some dual port cards.
*/
if (do_invert != 0)
enaddr[5] ^= 1;
return 0;
bad:
aprint_error_dev(sc->sc_dev, "unable to read Ethernet address\n");
return -1;
}
/*
* wm_add_rxbuf:
*
@ -5494,8 +5590,35 @@ wm_gmii_mediainit(struct wm_softc *sc, pci_product_id_t prodid)
ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_gmii_mediachange,
wm_gmii_mediastatus);
mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
MII_OFFSET_ANY, MIIF_DOPAUSE);
if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
|| (sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER)) {
if ((sc->sc_flags & WM_F_SGMII) == 0) {
/* Attach only one port */
mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, 1,
MII_OFFSET_ANY, MIIF_DOPAUSE);
} else {
int i;
uint32_t ctrl_ext;
/* Power on sgmii phy if it is disabled */
ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
CSR_WRITE(sc, WMREG_CTRL_EXT,
ctrl_ext &~ CTRL_EXT_SWDPIN(3));
CSR_WRITE_FLUSH(sc);
delay(300*1000); /* XXX too long */
/* from 1 to 8 */
for (i = 1; i < 8; i++)
mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff,
i, MII_OFFSET_ANY, MIIF_DOPAUSE);
/* restore previous sfp cage power state */
CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
}
} else {
mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
MII_OFFSET_ANY, MIIF_DOPAUSE);
}
if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
/* if failed, retry with *_bm_* */
@ -7290,6 +7413,10 @@ wm_get_wakeup(struct wm_softc *sc)
case WM_T_82574:
case WM_T_82575:
case WM_T_82576:
#if 0 /* XXX */
case WM_T_82580:
case WM_T_82580ER:
#endif
if ((CSR_READ(sc, WMREG_FWSM) & FWSM_MODE_MASK) != 0)
sc->sc_flags |= WM_F_ARC_SUBSYS_VALID;
sc->sc_flags |= WM_F_ASF_FIRMWARE_PRES;

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_wmreg.h,v 1.41 2010/06/25 03:47:57 msaitoh Exp $ */
/* $NetBSD: if_wmreg.h,v 1.42 2010/06/25 04:03:14 msaitoh Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@ -232,6 +232,7 @@ struct livengood_tcpip_ctxdesc {
#define STATUS_PCIXSPD_100_133 STATUS_PCIXSPD(2)
#define STATUS_PCIXSPD_MASK STATUS_PCIXSPD(3)
#define STATUS_GIO_M_ENA (1U << 19) /* GIO master enable */
#define STATUS_DEV_RST_SET (1U << 20) /* Device Reset Set */
#define WMREG_EECD 0x0010 /* EEPROM Control Register */
#define EECD_SK (1U << 0) /* clock */
@ -280,6 +281,7 @@ struct livengood_tcpip_ctxdesc {
#define EEPROM_OFF_K1_CONFIG 0x1b /* NVM K1 Config */
#define EEPROM_OFF_SWDPIN 0x20 /* SWD Pins (Cordova) */
#define EEPROM_OFF_CFG3_PORTA 0x24 /* config word 3 */
#define EEPROM_ALT_MAC_ADDR_PTR 0x37 /* to the alternative MAC addresses */
#define EEPROM_CFG1_LVDID (1U << 0)
#define EEPROM_CFG1_LSSID (1U << 1)
@ -323,6 +325,18 @@ struct livengood_tcpip_ctxdesc {
#define EEPROM_CFG3_APME (1U << 10)
#define EEPROM_OFF_MACADDR_LAN1 3 /* macaddr offset from PTR (port 1) */
#define EEPROM_OFF_MACADDR_LAN2 6 /* macaddr offset from PTR (port 2) */
#define EEPROM_OFF_MACADDR_LAN3 9 /* macaddr offset from PTR (port 3) */
/*
* EEPROM Partitioning. See Table 6-1, "EEPROM Top Level Partitioning"
* in 82580's datasheet.
*/
#define EEPROM_OFF_LAN1 0x0080 /* Offset for LAN1 (82580)*/
#define EEPROM_OFF_LAN2 0x00c0 /* Offset for LAN1 (82580)*/
#define EEPROM_OFF_LAN3 0x0100 /* Offset for LAN1 (82580)*/
#define WMREG_EERD 0x0014 /* EEPROM read */
#define EERD_DONE 0x02 /* done bit */
#define EERD_START 0x01 /* First bit for telling part to start operation */
@ -333,10 +347,13 @@ struct livengood_tcpip_ctxdesc {
#define CTRL_EXT_GPI_EN(x) (1U << (x)) /* gpin interrupt enable */
#define CTRL_EXT_SWDPINS_SHIFT 4
#define CTRL_EXT_SWDPINS_MASK 0x0d
#define CTRL_EXT_SWDPIN(x) (1U << (CTRL_EXT_SWDPINS_SHIFT + (x) - 4))
/* The bit order of the SW Definable pin is not 6543 but 3654! */
#define CTRL_EXT_SWDPIN(x) (1U << (CTRL_EXT_SWDPINS_SHIFT \
+ ((x) == 3 ? 3 : ((x) - 4))))
#define CTRL_EXT_SWDPIO_SHIFT 8
#define CTRL_EXT_SWDPIO_MASK 0x0d
#define CTRL_EXT_SWDPIO(x) (1U << (CTRL_EXT_SWDPIO_SHIFT + (x) - 4))
#define CTRL_EXT_SWDPIO(x) (1U << (CTRL_EXT_SWDPIO_SHIFT \
+ ((x) == 3 ? 3 : ((x) - 4))))
#define CTRL_EXT_ASDCHK (1U << 12) /* ASD check */
#define CTRL_EXT_EE_RST (1U << 13) /* EEPROM reset */
#define CTRL_EXT_IPS (1U << 14) /* invert power state bit 0 */