diff --git a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/Jamfile b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/Jamfile index 3c9a3eecf6..e98f1bd1a7 100644 --- a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/Jamfile +++ b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/Jamfile @@ -14,3 +14,6 @@ KernelStaticLibrary marvell_yukon_mii.a ukphy_subr.c ; +ObjectHdrs [ FGristFiles e1000phy$(SUFOBJ) ] + : [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR) libs compat freebsd_network ] ; +Includes [ FGristFiles e1000phy.c ] : miidevs.h ; diff --git a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/e1000phy.c b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/e1000phy.c index a3bf616a89..f0d159bbac 100644 --- a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/e1000phy.c +++ b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/e1000phy.c @@ -30,7 +30,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/dev/mii/e1000phy.c,v 1.18 2006/12/11 11:09:48 yongari Exp $"); +__FBSDID("$FreeBSD$"); /* * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY. @@ -105,7 +105,9 @@ static const struct mii_phydesc e1000phys[] = { MII_PHY_DESC(MARVELL, E1149), MII_PHY_DESC(MARVELL, E1111), MII_PHY_DESC(MARVELL, E1116), + MII_PHY_DESC(MARVELL, E1116R), MII_PHY_DESC(MARVELL, E1118), + MII_PHY_DESC(MARVELL, E3016), MII_PHY_DESC(xxMARVELL, E1000), MII_PHY_DESC(xxMARVELL, E1011), MII_PHY_DESC(xxMARVELL, E1000_3), @@ -128,7 +130,6 @@ e1000phy_attach(device_t dev) struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; - int fast_ether; esc = device_get_softc(dev); sc = &esc->mii_sc; @@ -141,10 +142,8 @@ e1000phy_attach(device_t dev) sc->mii_phy = ma->mii_phyno; sc->mii_service = e1000phy_service; sc->mii_pdata = mii; - sc->mii_anegticks = MII_ANEGTICKS_GIGE; mii->mii_instance++; - fast_ether = 0; esc->mii_model = MII_MODEL(ma->mii_id2); switch (esc->mii_model) { case MII_MODEL_MARVELL_E1011: @@ -152,54 +151,30 @@ e1000phy_attach(device_t dev) if (PHY_READ(sc, E1000_ESSR) & E1000_ESSR_FIBER_LINK) sc->mii_flags |= MIIF_HAVEFIBER; break; - case MII_MODEL_MARVELL_E3082: - /* 88E3082 10/100 Fast Ethernet PHY. */ - sc->mii_anegticks = MII_ANEGTICKS; - fast_ether = 1; + case MII_MODEL_MARVELL_E1149: + /* + * Some 88E1149 PHY's page select is initialized to + * point to other bank instead of copper/fiber bank + * which in turn resulted in wrong registers were + * accessed during PHY operation. It is believed that + * page 0 should be used for copper PHY so reinitialize + * E1000_EADR to select default copper PHY. If parent + * device know the type of PHY(either copper or fiber), + * that information should be used to select default + * type of PHY. + */ + PHY_WRITE(sc, E1000_EADR, 0); break; } e1000phy_reset(sc); + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + if (sc->mii_capabilities & BMSR_EXTSTAT) + sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); device_printf(dev, " "); - -#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), - E1000_CR_ISOLATE); - if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), - E1000_CR_SPEED_10); - printf("10baseT, "); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), - E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX); - printf("10baseT-FDX, "); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), - E1000_CR_SPEED_100); - printf("100baseTX, "); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), - E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX); - printf("100baseTX-FDX, "); - if (fast_ether == 0) { - /* - * 1000BT-simplex not supported; driver must ignore - * this entry, but it must be present in order to - * manually set full-duplex. - */ - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, - sc->mii_inst), E1000_CR_SPEED_1000); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, - sc->mii_inst), - E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); - printf("1000baseTX-FDX, "); - } - } else { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), - E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); - printf("1000baseSX-FDX, "); - } - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); - printf("auto\n"); -#undef ADD + mii_phy_add_media(sc); + printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); @@ -209,7 +184,7 @@ static void e1000phy_reset(struct mii_softc *sc) { struct e1000phy_softc *esc; - uint16_t reg; + uint16_t reg, page; esc = (struct e1000phy_softc *)sc; reg = PHY_READ(sc, E1000_SCR); @@ -218,12 +193,13 @@ e1000phy_reset(struct mii_softc *sc) PHY_WRITE(sc, E1000_SCR, reg); if (esc->mii_model == MII_MODEL_MARVELL_E1112) { /* Select 1000BASE-X only mode. */ + page = PHY_READ(sc, E1000_EADR); PHY_WRITE(sc, E1000_EADR, 2); reg = PHY_READ(sc, E1000_SCR); reg &= ~E1000_SCR_MODE_MASK; reg |= E1000_SCR_MODE_1000BX; PHY_WRITE(sc, E1000_SCR, reg); - PHY_WRITE(sc, E1000_EADR, 1); + PHY_WRITE(sc, E1000_EADR, page); } } else { switch (esc->mii_model) { @@ -235,27 +211,71 @@ e1000phy_reset(struct mii_softc *sc) /* Disable energy detect mode. */ reg &= ~E1000_SCR_EN_DETECT_MASK; reg |= E1000_SCR_AUTO_X_MODE; + if (esc->mii_model == MII_MODEL_MARVELL_E1116) + reg &= ~E1000_SCR_POWER_DOWN; + reg |= E1000_SCR_ASSERT_CRS_ON_TX; break; case MII_MODEL_MARVELL_E3082: reg |= (E1000_SCR_AUTO_X_MODE >> 1); + reg |= E1000_SCR_ASSERT_CRS_ON_TX; + break; + case MII_MODEL_MARVELL_E3016: + reg |= E1000_SCR_AUTO_MDIX; + reg &= ~(E1000_SCR_EN_DETECT | + E1000_SCR_SCRAMBLER_DISABLE); + reg |= E1000_SCR_LPNP; + /* XXX Enable class A driver for Yukon FE+ A0. */ + PHY_WRITE(sc, 0x1C, PHY_READ(sc, 0x1C) | 0x0001); break; default: reg &= ~E1000_SCR_AUTO_X_MODE; + reg |= E1000_SCR_ASSERT_CRS_ON_TX; break; } - /* Enable CRS on TX. */ - reg |= E1000_SCR_ASSERT_CRS_ON_TX; - /* Auto correction for reversed cable polarity. */ - reg &= ~E1000_SCR_POLARITY_REVERSAL; + if (esc->mii_model != MII_MODEL_MARVELL_E3016) { + /* Auto correction for reversed cable polarity. */ + reg &= ~E1000_SCR_POLARITY_REVERSAL; + } PHY_WRITE(sc, E1000_SCR, reg); + + if (esc->mii_model == MII_MODEL_MARVELL_E1116 || + esc->mii_model == MII_MODEL_MARVELL_E1149) { + page = PHY_READ(sc, E1000_EADR); + /* Select page 2, MAC specific control register. */ + PHY_WRITE(sc, E1000_EADR, 2); + reg = PHY_READ(sc, E1000_SCR); + reg |= E1000_SCR_RGMII_POWER_UP; + PHY_WRITE(sc, E1000_SCR, reg); + PHY_WRITE(sc, E1000_EADR, page); + } } switch (MII_MODEL(esc->mii_model)) { case MII_MODEL_MARVELL_E3082: case MII_MODEL_MARVELL_E1112: - case MII_MODEL_MARVELL_E1116: case MII_MODEL_MARVELL_E1118: + break; + case MII_MODEL_MARVELL_E1116: case MII_MODEL_MARVELL_E1149: + page = PHY_READ(sc, E1000_EADR); + /* Select page 3, LED control register. */ + PHY_WRITE(sc, E1000_EADR, 3); + PHY_WRITE(sc, E1000_SCR, + E1000_SCR_LED_LOS(1) | /* Link/Act */ + E1000_SCR_LED_INIT(8) | /* 10Mbps */ + E1000_SCR_LED_STAT1(7) | /* 100Mbps */ + E1000_SCR_LED_STAT0(7)); /* 1000Mbps */ + /* Set blink rate. */ + PHY_WRITE(sc, E1000_IER, E1000_PULSE_DUR(E1000_PULSE_170MS) | + E1000_BLINK_RATE(E1000_BLINK_84MS)); + PHY_WRITE(sc, E1000_EADR, page); + break; + case MII_MODEL_MARVELL_E3016: + /* LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED. */ + PHY_WRITE(sc, 0x16, 0x0B << 8 | 0x05 << 4 | 0x04); + /* Integrated register calibration workaround. */ + PHY_WRITE(sc, 0x1D, 17); + PHY_WRITE(sc, 0x1E, 0x3F60); break; default: /* Force TX_CLK to 25MHz clock. */ @@ -313,12 +333,14 @@ e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) speed = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_1000_T: - if (esc->mii_model == MII_MODEL_MARVELL_E3082) + if ((sc->mii_extcapabilities & + (EXTSR_1000TFDX | EXTSR_1000THDX)) == 0) return (EINVAL); speed = E1000_CR_SPEED_1000; break; case IFM_1000_SX: - if (esc->mii_model == MII_MODEL_MARVELL_E3082) + if ((sc->mii_extcapabilities & + (EXTSR_1000XFDX | EXTSR_1000XHDX)) == 0) return (EINVAL); speed = E1000_CR_SPEED_1000; break; @@ -364,7 +386,8 @@ e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) PHY_WRITE(sc, E1000_1GCR, gig | E1000_1GCR_MS_ENABLE); } else { - if (esc->mii_model != MII_MODEL_MARVELL_E3082) + if ((sc->mii_extcapabilities & + (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, E1000_1GCR, 0); } PHY_WRITE(sc, E1000_AR, E1000_AR_SELECTOR_FIELD); @@ -387,8 +410,10 @@ done: /* * Only used for autonegotiation. */ - if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { + sc->mii_ticks = 0; break; + } /* * check for link. @@ -401,8 +426,10 @@ done: } /* Announce link loss right after it happens. */ + if (sc->mii_ticks++ == 0) + break; if (sc->mii_ticks <= sc->mii_anegticks) - return (0); + break; sc->mii_ticks = 0; e1000phy_reset(sc); @@ -422,18 +449,14 @@ static void e1000phy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; - int bmsr, bmcr, esr, gsr, ssr, isr, ar, lpar; + int bmcr, bmsr, gsr, ssr, ar, lpar; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); - esr = PHY_READ(sc, E1000_ESR); bmcr = PHY_READ(sc, E1000_CR); ssr = PHY_READ(sc, E1000_SSR); - isr = PHY_READ(sc, E1000_ISR); - ar = PHY_READ(sc, E1000_AR); - lpar = PHY_READ(sc, E1000_LPAR); if (bmsr & E1000_SR_LINK_STATUS) mii->mii_media_status |= IFM_ACTIVE; @@ -441,22 +464,28 @@ e1000phy_status(struct mii_softc *sc) if (bmcr & E1000_CR_LOOPBACK) mii->mii_media_active |= IFM_LOOP; - if ((((bmcr & E1000_CR_AUTO_NEG_ENABLE) != 0) && - ((bmsr & E1000_SR_AUTO_NEG_COMPLETE) == 0)) || - ((ssr & E1000_SSR_LINK) == 0) || - ((ssr & E1000_SSR_SPD_DPLX_RESOLVED) == 0)) { + if ((bmcr & E1000_CR_AUTO_NEG_ENABLE) != 0 && + (ssr & E1000_SSR_SPD_DPLX_RESOLVED) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { - if (ssr & E1000_SSR_1000MBS) + switch (ssr & E1000_SSR_SPEED) { + case E1000_SSR_1000MBS: mii->mii_media_active |= IFM_1000_T; - else if (ssr & E1000_SSR_100MBS) + break; + case E1000_SSR_100MBS: mii->mii_media_active |= IFM_100_TX; - else + break; + case E1000_SSR_10MBS: mii->mii_media_active |= IFM_10_T; + break; + default: + mii->mii_media_active |= IFM_NONE; + return; + } } else { if (ssr & E1000_SSR_1000MBS) mii->mii_media_active |= IFM_1000_SX; @@ -468,6 +497,8 @@ e1000phy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_HDX; if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { + ar = PHY_READ(sc, E1000_AR); + lpar = PHY_READ(sc, E1000_LPAR); /* FLAG0==rx-flow-control FLAG1==tx-flow-control */ if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) { mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; @@ -494,16 +525,19 @@ static int e1000phy_mii_phy_auto(struct e1000phy_softc *esc) { struct mii_softc *sc; + uint16_t reg; sc = &esc->mii_sc; - if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) - PHY_WRITE(sc, E1000_AR, E1000_AR_10T | E1000_AR_10T_FD | + if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { + reg = PHY_READ(sc, E1000_AR); + reg |= E1000_AR_10T | E1000_AR_10T_FD | E1000_AR_100TX | E1000_AR_100TX_FD | - E1000_AR_PAUSE | E1000_AR_ASM_DIR); - else + E1000_AR_PAUSE | E1000_AR_ASM_DIR; + PHY_WRITE(sc, E1000_AR, reg | E1000_AR_SELECTOR_FIELD); + } else PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD | E1000_FA_1000X | E1000_FA_SYM_PAUSE | E1000_FA_ASYM_PAUSE); - if (esc->mii_model != MII_MODEL_MARVELL_E3082) + if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, E1000_1GCR, E1000_1GCR_1000T_FD | E1000_1GCR_1000T); PHY_WRITE(sc, E1000_CR, diff --git a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/e1000phyreg.h b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/e1000phyreg.h index b80bea2e36..41b9c0937e 100644 --- a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/e1000phyreg.h +++ b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/e1000phyreg.h @@ -1,4 +1,4 @@ -/* $FreeBSD: src/sys/dev/mii/e1000phyreg.h,v 1.4 2006/12/11 10:43:32 yongari Exp $ */ +/* $FreeBSD$ */ /*- * Principal Author: Parag Patel * Copyright (c) 2001 @@ -236,6 +236,16 @@ #define E1000_SCR_TX_FIFO_DEPTH_10 0x8000 #define E1000_SCR_TX_FIFO_DEPTH_12 0xC000 +/* 88E3016 only */ +#define E1000_SCR_AUTO_MDIX 0x0030 +#define E1000_SCR_SIGDET_POLARITY 0x0040 +#define E1000_SCR_EXT_DISTANCE 0x0080 +#define E1000_SCR_FEFI_DISABLE 0x0100 +#define E1000_SCR_NLP_GEN_DISABLE 0x0800 +#define E1000_SCR_LPNP 0x1000 +#define E1000_SCR_NLP_CHK_DISABLE 0x2000 +#define E1000_SCR_EN_DETECT 0x4000 + #define E1000_SCR_EN_DETECT_MASK 0x0300 /* 88E1112 page 2 */ @@ -244,6 +254,21 @@ #define E1000_SCR_MODE_COPPER 0x0280 #define E1000_SCR_MODE_1000BX 0x0380 +/* 88E1116 page 0 */ +#define E1000_SCR_POWER_DOWN 0x0004 +/* 88E1116, 88E1149 page 2 */ +#define E1000_SCR_RGMII_POWER_UP 0x0008 + +/* 88E1116, 88E1149 page 3 */ +#define E1000_SCR_LED_STAT0_MASK 0x000F +#define E1000_SCR_LED_STAT1_MASK 0x00F0 +#define E1000_SCR_LED_INIT_MASK 0x0F00 +#define E1000_SCR_LED_LOS_MASK 0xF000 +#define E1000_SCR_LED_STAT0(x) ((x) & E1000_SCR_LED_STAT0_MASK) +#define E1000_SCR_LED_STAT1(x) ((x) & E1000_SCR_LED_STAT1_MASK) +#define E1000_SCR_LED_INIT(x) ((x) & E1000_SCR_LED_INIT_MASK) +#define E1000_SCR_LED_LOS(x) ((x) & E1000_SCR_LED_LOS_MASK) + #define E1000_SSR 0x11 /* special status register */ #define E1000_SSR_JABBER 0x0001 #define E1000_SSR_REV_POLARITY 0x0002 @@ -271,6 +296,26 @@ #define E1000_IER_SPEED_CHANGED 0x4000 #define E1000_IER_AUTO_NEG_ERR 0x8000 +/* 88E1116, 88E1149 page 3, LED timer control. */ +#define E1000_PULSE_MASK 0x7000 +#define E1000_PULSE_NO_STR 0 /* no pulse stretching */ +#define E1000_PULSE_21MS 1 /* 21 ms to 42 ms */ +#define E1000_PULSE_42MS 2 /* 42 ms to 84 ms */ +#define E1000_PULSE_84MS 3 /* 84 ms to 170 ms */ +#define E1000_PULSE_170MS 4 /* 170 ms to 340 ms */ +#define E1000_PULSE_340MS 5 /* 340 ms to 670 ms */ +#define E1000_PULSE_670MS 6 /* 670 ms to 1300 ms */ +#define E1000_PULSE_1300MS 7 /* 1300 ms to 2700 ms */ +#define E1000_PULSE_DUR(x) ((x) & E1000_PULSE_MASK) + +#define E1000_BLINK_MASK 0x0700 +#define E1000_BLINK_42MS 0 /* 42 ms */ +#define E1000_BLINK_84MS 1 /* 84 ms */ +#define E1000_BLINK_170MS 2 /* 170 ms */ +#define E1000_BLINK_340MS 3 /* 340 ms */ +#define E1000_BLINK_670MS 4 /* 670 ms */ +#define E1000_BLINK_RATE(x) ((x) & E1000_BLINK_MASK) + #define E1000_ISR 0x13 /* interrupt status reg */ #define E1000_ISR_JABBER 0x0001 #define E1000_ISR_POLARITY_CHANGE 0x0002 diff --git a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/miidevs.h b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/miidevs.h deleted file mode 100644 index 874d5dd973..0000000000 --- a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/miidevs.h +++ /dev/null @@ -1,40 +0,0 @@ -#define MII_OUI_MARVELL 0x005043 -#define MII_OUI_xxMARVELL 0x000ac2 - -#define MII_MODEL_MARVELL_E1000 0x0000 -#define MII_MODEL_MARVELL_E1011 0x0002 -#define MII_MODEL_MARVELL_E1000_3 0x0003 -#define MII_MODEL_MARVELL_E1000S 0x0004 -#define MII_MODEL_MARVELL_E1000_5 0x0005 -#define MII_MODEL_MARVELL_E1000_6 0x0006 -#define MII_MODEL_MARVELL_E3082 0x0008 -#define MII_MODEL_MARVELL_E1112 0x0009 -#define MII_MODEL_MARVELL_E1149 0x000b -#define MII_MODEL_MARVELL_E1111 0x000c -#define MII_MODEL_MARVELL_E1116 0x0021 -#define MII_MODEL_MARVELL_E1118 0x0022 - -#define MII_MODEL_xxMARVELL_E1000 0x0005 -#define MII_MODEL_xxMARVELL_E1011 0x0002 -#define MII_MODEL_xxMARVELL_E1000_3 0x0003 -#define MII_MODEL_xxMARVELL_E1000_5 0x0005 -#define MII_MODEL_xxMARVELL_E1111 0x000c - -#define MII_STR_MARVELL_E1000 "Marvell 88E1000 Gigabit PHY" -#define MII_STR_MARVELL_E1011 "Marvell 88E1011 Gigabit PHY" -#define MII_STR_MARVELL_E1000_3 "Marvell 88E1000 Gigabit PHY" -#define MII_STR_MARVELL_E1000S "Marvell 88E1000S Gigabit PHY" -#define MII_STR_MARVELL_E1000_5 "Marvell 88E1000 Gigabit PHY" -#define MII_STR_MARVELL_E1000_6 "Marvell 88E1000 Gigabit PHY" -#define MII_STR_MARVELL_E3082 "Marvell 88E3082 10/100 Fast Ethernet PHY" -#define MII_STR_MARVELL_E1112 "Marvell 88E1112 Gigabit PHY" -#define MII_STR_MARVELL_E1149 "Marvell 88E1149 Gigabit PHY" -#define MII_STR_MARVELL_E1111 "Marvell 88E1111 Gigabit PHY" -#define MII_STR_MARVELL_E1116 "Marvell 88E1116 Gigabit PHY" -#define MII_STR_MARVELL_E1118 "Marvell 88E1118 Gigabit PHY" - -#define MII_STR_xxMARVELL_E1000 "Marvell 88E1000 Gigabit PHY" -#define MII_STR_xxMARVELL_E1011 "Marvell 88E1011 Gigabit PHY" -#define MII_STR_xxMARVELL_E1000_3 "Marvell 88E1000 Gigabit PHY" -#define MII_STR_xxMARVELL_E1000_5 "Marvell 88E1000 Gigabit PHY" -#define MII_STR_xxMARVELL_E1111 "Marvell 88E1111 Gigabit PHY" diff --git a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/ukphy.c b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/ukphy.c index 10347825bf..e51964041d 100644 --- a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/ukphy.c +++ b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/ukphy.c @@ -67,7 +67,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/dev/mii/ukphy.c,v 1.20 2007/01/20 00:52:29 marius Exp $"); +__FBSDID("$FreeBSD$"); /* * driver for generic unknown PHYs diff --git a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/ukphy_subr.c b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/ukphy_subr.c index fb40b75c1d..fdfc9727d8 100644 --- a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/ukphy_subr.c +++ b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/mii/ukphy_subr.c @@ -38,7 +38,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/dev/mii/ukphy_subr.c,v 1.8.8.1 2006/07/19 04:40:26 yongari Exp $"); +__FBSDID("$FreeBSD$"); /* * Subroutines shared by the ukphy driver and other PHY drivers. @@ -112,10 +112,10 @@ ukphy_status(struct mii_softc *phy) else if ((gtcr & GTCR_ADV_1000THDX) && (gtsr & GTSR_LP_1000THDX)) mii->mii_media_active |= IFM_1000_T; - else if (anlpar & ANLPAR_T4) - mii->mii_media_active |= IFM_100_T4; else if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_T4) + mii->mii_media_active |= IFM_100_T4; else if (anlpar & ANLPAR_TX) mii->mii_media_active |= IFM_100_TX; else if (anlpar & ANLPAR_10_FD) diff --git a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/msk/if_msk.c b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/msk/if_msk.c index 60759c4afb..73d5232b76 100644 --- a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/msk/if_msk.c +++ b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/msk/if_msk.c @@ -99,7 +99,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/dev/msk/if_msk.c,v 1.26 2007/12/05 09:41:58 remko Exp $"); +__FBSDID("$FreeBSD$"); #include #include @@ -156,6 +156,8 @@ static int msi_disable = 0; TUNABLE_INT("hw.msk.msi_disable", &msi_disable); static int legacy_intr = 0; TUNABLE_INT("hw.msk.legacy_intr", &legacy_intr); +static int jumbo_disable = 0; +TUNABLE_INT("hw.msk.jumbo_disable", &jumbo_disable); #define MSK_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) @@ -188,13 +190,19 @@ static struct msk_product { { VENDORID_MARVELL, DEVICEID_MRVL_8062X, "Marvell Yukon 88E8062 SX/LX Gigabit Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_8035, - "Marvell Yukon 88E8035 Gigabit Ethernet" }, + "Marvell Yukon 88E8035 Fast Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_8036, - "Marvell Yukon 88E8036 Gigabit Ethernet" }, + "Marvell Yukon 88E8036 Fast Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_8038, - "Marvell Yukon 88E8038 Gigabit Ethernet" }, + "Marvell Yukon 88E8038 Fast Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_8039, - "Marvell Yukon 88E8039 Gigabit Ethernet" }, + "Marvell Yukon 88E8039 Fast Ethernet" }, + { VENDORID_MARVELL, DEVICEID_MRVL_8040, + "Marvell Yukon 88E8040 Fast Ethernet" }, + { VENDORID_MARVELL, DEVICEID_MRVL_8040T, + "Marvell Yukon 88E8040T Fast Ethernet" }, + { VENDORID_MARVELL, DEVICEID_MRVL_8048, + "Marvell Yukon 88E8048 Fast Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_4361, "Marvell Yukon 88E8050 Gigabit Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_4360, @@ -205,8 +213,14 @@ static struct msk_product { "Marvell Yukon 88E8055 Gigabit Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_4364, "Marvell Yukon 88E8056 Gigabit Ethernet" }, + { VENDORID_MARVELL, DEVICEID_MRVL_4365, + "Marvell Yukon 88E8070 Gigabit Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_436A, "Marvell Yukon 88E8058 Gigabit Ethernet" }, + { VENDORID_MARVELL, DEVICEID_MRVL_436B, + "Marvell Yukon 88E8071 Gigabit Ethernet" }, + { VENDORID_MARVELL, DEVICEID_MRVL_436C, + "Marvell Yukon 88E8072 Gigabit Ethernet" }, { VENDORID_DLINK, DEVICEID_DLINK_DGE550SX, "D-Link 550SX Gigabit Ethernet" }, { VENDORID_DLINK, DEVICEID_DLINK_DGE560T, @@ -216,9 +230,10 @@ static struct msk_product { static const char *model_name[] = { "Yukon XL", "Yukon EC Ultra", - "Yukon Unknown", + "Yukon EX", "Yukon EC", - "Yukon FE" + "Yukon FE", + "Yukon FE+" }; static int mskc_probe(device_t); @@ -244,16 +259,19 @@ static __inline void msk_rxput(struct msk_if_softc *); static int msk_handle_events(struct msk_softc *); static void msk_handle_hwerr(struct msk_if_softc *, uint32_t); static void msk_intr_hwerr(struct msk_softc *); -static void msk_rxeof(struct msk_if_softc *, uint32_t, int); -static void msk_jumbo_rxeof(struct msk_if_softc *, uint32_t, int); +#ifndef __NO_STRICT_ALIGNMENT +static __inline void msk_fixup_rx(struct mbuf *); +#endif +static void msk_rxeof(struct msk_if_softc *, uint32_t, uint32_t, int); +static void msk_jumbo_rxeof(struct msk_if_softc *, uint32_t, uint32_t, int); static void msk_txeof(struct msk_if_softc *, int); -static struct mbuf *msk_defrag(struct mbuf *, int, int); static int msk_encap(struct msk_if_softc *, struct mbuf **); static void msk_tx_task(void *, int); static void msk_start(struct ifnet *); static int msk_ioctl(struct ifnet *, u_long, caddr_t); static void msk_set_prefetch(struct msk_softc *, int, bus_addr_t, uint32_t); static void msk_set_rambuffer(struct msk_if_softc *); +static void msk_set_tx_stfwd(struct msk_if_softc *); static void msk_init(void *); static void msk_init_locked(struct msk_if_softc *); static void msk_stop(struct msk_if_softc *); @@ -265,9 +283,9 @@ static void msk_dmamap_cb(void *, bus_dma_segment_t *, int, int); static int msk_status_dma_alloc(struct msk_softc *); static void msk_status_dma_free(struct msk_softc *); static int msk_txrx_dma_alloc(struct msk_if_softc *); +static int msk_rx_dma_jalloc(struct msk_if_softc *); static void msk_txrx_dma_free(struct msk_if_softc *); -static void *msk_jalloc(struct msk_if_softc *); -static void msk_jfree(void *, void *); +static void msk_rx_dma_jfree(struct msk_if_softc *); static int msk_init_rx_ring(struct msk_if_softc *); static int msk_init_jumbo_rx_ring(struct msk_if_softc *); static void msk_init_tx_ring(struct msk_if_softc *); @@ -281,12 +299,15 @@ static int msk_phy_writereg(struct msk_if_softc *, int, int, int); static int msk_miibus_readreg(device_t, int, int); static int msk_miibus_writereg(device_t, int, int, int); static void msk_miibus_statchg(device_t); -static void msk_link_task(void *, int); -static void msk_setmulti(struct msk_if_softc *); +static void msk_rxfilter(struct msk_if_softc *); static void msk_setvlan(struct msk_if_softc *, struct ifnet *); -static void msk_setpromisc(struct msk_if_softc *); +static void msk_stats_clear(struct msk_if_softc *); +static void msk_stats_update(struct msk_if_softc *); +static int msk_sysctl_stat32(SYSCTL_HANDLER_ARGS); +static int msk_sysctl_stat64(SYSCTL_HANDLER_ARGS); +static void msk_sysctl_node(struct msk_if_softc *); static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); static int sysctl_hw_msk_proc_limit(SYSCTL_HANDLER_ARGS); @@ -450,15 +471,6 @@ msk_phy_writereg(struct msk_if_softc *sc_if, int phy, int reg, int val) static void msk_miibus_statchg(device_t dev) -{ - struct msk_if_softc *sc_if; - - sc_if = device_get_softc(dev); - taskqueue_enqueue(taskqueue_swi, &sc_if->msk_link_task); -} - -static void -msk_link_task(void *arg, int pending) { struct msk_softc *sc; struct msk_if_softc *sc_if; @@ -466,25 +478,38 @@ msk_link_task(void *arg, int pending) struct ifnet *ifp; uint32_t gmac; - sc_if = (struct msk_if_softc *)arg; + sc_if = device_get_softc(dev); sc = sc_if->msk_softc; - MSK_IF_LOCK(sc_if); + MSK_IF_LOCK_ASSERT(sc_if); mii = device_get_softc(sc_if->msk_miibus); ifp = sc_if->msk_ifp; - if (mii == NULL || ifp == NULL) { - MSK_IF_UNLOCK(sc_if); + if (mii == NULL || ifp == NULL || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; + + sc_if->msk_flags &= ~MSK_FLAG_LINK; + if ((mii->mii_media_status & (IFM_AVALID | IFM_ACTIVE)) == + (IFM_AVALID | IFM_ACTIVE)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + case IFM_100_TX: + sc_if->msk_flags |= MSK_FLAG_LINK; + break; + case IFM_1000_T: + case IFM_1000_SX: + case IFM_1000_LX: + case IFM_1000_CX: + if ((sc_if->msk_flags & MSK_FLAG_FASTETHER) == 0) + sc_if->msk_flags |= MSK_FLAG_LINK; + break; + default: + break; + } } - if (mii->mii_media_status & IFM_ACTIVE) { - if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) - sc_if->msk_link = 1; - } else - sc_if->msk_link = 0; - - if (sc_if->msk_link != 0) { + if ((sc_if->msk_flags & MSK_FLAG_LINK) != 0) { /* Enable Tx FIFO Underrun. */ CSR_WRITE_1(sc, MR_ADDR(sc_if->msk_port, GMAC_IRQ_MSK), GM_IS_TX_FF_UR | GM_IS_RX_FF_OR); @@ -541,17 +566,17 @@ msk_link_task(void *arg, int pending) msk_phy_writereg(sc_if, PHY_ADDR_MARV, PHY_MARV_INT_MASK, 0); /* Disable Rx/Tx MAC. */ gmac = GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL); - gmac &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); - GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, gmac); - /* Read again to ensure writing. */ - GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL); + if ((GM_GPCR_RX_ENA | GM_GPCR_TX_ENA) != 0) { + gmac &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); + GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, gmac); + /* Read again to ensure writing. */ + GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL); + } } - - MSK_IF_UNLOCK(sc_if); } static void -msk_setmulti(struct msk_if_softc *sc_if) +msk_rxfilter(struct msk_if_softc *sc_if) { struct msk_softc *sc; struct ifnet *ifp; @@ -568,15 +593,14 @@ msk_setmulti(struct msk_if_softc *sc_if) bzero(mchash, sizeof(mchash)); mode = GMAC_READ_2(sc, sc_if->msk_port, GM_RX_CTRL); - mode |= GM_RXCR_UCF_ENA; - if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { - if ((ifp->if_flags & IFF_PROMISC) != 0) - mode &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); - else if ((ifp->if_flags & IFF_ALLMULTI) != 0) { - mchash[0] = 0xffff; - mchash[1] = 0xffff; - } + if ((ifp->if_flags & IFF_PROMISC) != 0) + mode &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); + else if ((ifp->if_flags & IFF_ALLMULTI) != 0) { + mode |= GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA; + mchash[0] = 0xffff; + mchash[1] = 0xffff; } else { + mode |= GM_RXCR_UCF_ENA; IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) @@ -589,7 +613,8 @@ msk_setmulti(struct msk_if_softc *sc_if) mchash[crc >> 5] |= 1 << (crc & 0x1f); } IF_ADDR_UNLOCK(ifp); - mode |= GM_RXCR_MCF_ENA; + if (mchash[0] != 0 || mchash[1] != 0) + mode |= GM_RXCR_MCF_ENA; } GMAC_WRITE_2(sc, sc_if->msk_port, GM_MC_ADDR_H1, @@ -622,26 +647,6 @@ msk_setvlan(struct msk_if_softc *sc_if, struct ifnet *ifp) } } -static void -msk_setpromisc(struct msk_if_softc *sc_if) -{ - struct msk_softc *sc; - struct ifnet *ifp; - uint16_t mode; - - MSK_IF_LOCK_ASSERT(sc_if); - - sc = sc_if->msk_softc; - ifp = sc_if->msk_ifp; - - mode = GMAC_READ_2(sc, sc_if->msk_port, GM_RX_CTRL); - if (ifp->if_flags & IFF_PROMISC) - mode &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); - else - mode |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); - GMAC_WRITE_2(sc, sc_if->msk_port, GM_RX_CTRL, mode); -} - static int msk_init_rx_ring(struct msk_if_softc *sc_if) { @@ -784,7 +789,12 @@ msk_newbuf(struct msk_if_softc *sc_if, int idx) return (ENOBUFS); m->m_len = m->m_pkthdr.len = MCLBYTES; - m_adj(m, ETHER_ALIGN); + if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) == 0) + m_adj(m, ETHER_ALIGN); +#ifndef __NO_STRICT_ALIGNMENT + else + m_adj(m, MSK_RX_BUF_ALIGN); +#endif if (bus_dmamap_load_mbuf_sg(sc_if->msk_cdata.msk_rx_tag, sc_if->msk_cdata.msk_rx_sparemap, m, segs, &nsegs, @@ -823,25 +833,21 @@ msk_jumbo_newbuf(struct msk_if_softc *sc_if, int idx) bus_dma_segment_t segs[1]; bus_dmamap_t map; int nsegs; - void *buf; - MGETHDR(m, M_DONTWAIT, MT_DATA); + m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); if (m == NULL) return (ENOBUFS); - buf = msk_jalloc(sc_if); - if (buf == NULL) { - m_freem(m); - return (ENOBUFS); - } - /* Attach the buffer to the mbuf. */ - MEXTADD(m, buf, MSK_JLEN, msk_jfree, (struct msk_if_softc *)sc_if, 0, - EXT_NET_DRV); if ((m->m_flags & M_EXT) == 0) { m_freem(m); return (ENOBUFS); } - m->m_pkthdr.len = m->m_len = MSK_JLEN; - m_adj(m, ETHER_ALIGN); + m->m_len = m->m_pkthdr.len = MJUM9BYTES; + if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) == 0) + m_adj(m, ETHER_ALIGN); +#ifndef __NO_STRICT_ALIGNMENT + else + m_adj(m, MSK_RX_BUF_ALIGN); +#endif if (bus_dmamap_load_mbuf_sg(sc_if->msk_cdata.msk_jumbo_rx_tag, sc_if->msk_cdata.msk_jumbo_rx_sparemap, m, segs, &nsegs, @@ -880,15 +886,16 @@ msk_mediachange(struct ifnet *ifp) { struct msk_if_softc *sc_if; struct mii_data *mii; + int error; sc_if = ifp->if_softc; MSK_IF_LOCK(sc_if); mii = device_get_softc(sc_if->msk_miibus); - mii_mediachg(mii); + error = mii_mediachg(mii); MSK_IF_UNLOCK(sc_if); - return (0); + return (error); } /* @@ -902,6 +909,10 @@ msk_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) sc_if = ifp->if_softc; MSK_IF_LOCK(sc_if); + if ((ifp->if_flags & IFF_UP) == 0) { + MSK_IF_UNLOCK(sc_if); + return; + } mii = device_get_softc(sc_if->msk_miibus); mii_pollstat(mii); @@ -924,38 +935,41 @@ msk_ioctl(struct ifnet *ifp, u_long command, caddr_t data) switch(command) { case SIOCSIFMTU: - if (ifr->ifr_mtu > MSK_JUMBO_MTU || ifr->ifr_mtu < ETHERMIN) { - error = EINVAL; - break; - } - if (sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_FE && - ifr->ifr_mtu > MSK_MAX_FRAMELEN) { - error = EINVAL; - break; - } MSK_IF_LOCK(sc_if); - ifp->if_mtu = ifr->ifr_mtu; - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + if (ifr->ifr_mtu > MSK_JUMBO_MTU || ifr->ifr_mtu < ETHERMIN) + error = EINVAL; + else if (ifp->if_mtu != ifr->ifr_mtu) { + if (ifr->ifr_mtu > ETHERMTU) { + if ((sc_if->msk_flags & MSK_FLAG_JUMBO) == 0) { + error = EINVAL; + MSK_IF_UNLOCK(sc_if); + break; + } + if ((sc_if->msk_flags & + MSK_FLAG_JUMBO_NOCSUM) != 0) { + ifp->if_hwassist &= + ~(MSK_CSUM_FEATURES | CSUM_TSO); + ifp->if_capenable &= + ~(IFCAP_TSO4 | IFCAP_TXCSUM); + VLAN_CAPABILITIES(ifp); + } + } + ifp->if_mtu = ifr->ifr_mtu; msk_init_locked(sc_if); + } MSK_IF_UNLOCK(sc_if); break; case SIOCSIFFLAGS: MSK_IF_LOCK(sc_if); if ((ifp->if_flags & IFF_UP) != 0) { - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { - if (((ifp->if_flags ^ sc_if->msk_if_flags) - & IFF_PROMISC) != 0) { - msk_setpromisc(sc_if); - msk_setmulti(sc_if); - } - } else { - if (sc_if->msk_detach == 0) - msk_init_locked(sc_if); - } - } else { - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) - msk_stop(sc_if); - } + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && + ((ifp->if_flags ^ sc_if->msk_if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) != 0) + msk_rxfilter(sc_if); + else if ((sc_if->msk_flags & MSK_FLAG_DETACH) == 0) + msk_init_locked(sc_if); + } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + msk_stop(sc_if); sc_if->msk_if_flags = ifp->if_flags; MSK_IF_UNLOCK(sc_if); break; @@ -963,7 +977,7 @@ msk_ioctl(struct ifnet *ifp, u_long command, caddr_t data) case SIOCDELMULTI: MSK_IF_LOCK(sc_if); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) - msk_setmulti(sc_if); + msk_rxfilter(sc_if); MSK_IF_UNLOCK(sc_if); break; case SIOCGIFMEDIA: @@ -974,33 +988,35 @@ msk_ioctl(struct ifnet *ifp, u_long command, caddr_t data) case SIOCSIFCAP: MSK_IF_LOCK(sc_if); mask = ifr->ifr_reqcap ^ ifp->if_capenable; - if ((mask & IFCAP_TXCSUM) != 0) { + if ((mask & IFCAP_TXCSUM) != 0 && + (IFCAP_TXCSUM & ifp->if_capabilities) != 0) { ifp->if_capenable ^= IFCAP_TXCSUM; - if ((IFCAP_TXCSUM & ifp->if_capenable) != 0 && - (IFCAP_TXCSUM & ifp->if_capabilities) != 0) + if ((IFCAP_TXCSUM & ifp->if_capenable) != 0) ifp->if_hwassist |= MSK_CSUM_FEATURES; else ifp->if_hwassist &= ~MSK_CSUM_FEATURES; } - if ((mask & IFCAP_VLAN_HWTAGGING) != 0) { + if ((mask & IFCAP_RXCSUM) != 0 && + (IFCAP_RXCSUM & ifp->if_capabilities) != 0) + ifp->if_capenable ^= IFCAP_RXCSUM; + if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && + (IFCAP_VLAN_HWTAGGING & ifp->if_capabilities) != 0) { ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; msk_setvlan(sc_if, ifp); } - - if ((mask & IFCAP_TSO4) != 0) { + if ((mask & IFCAP_VLAN_HWCSUM) != 0 && + (IFCAP_VLAN_HWCSUM & ifp->if_capabilities) != 0) + ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; + if ((mask & IFCAP_TSO4) != 0 && + (IFCAP_TSO4 & ifp->if_capabilities) != 0) { ifp->if_capenable ^= IFCAP_TSO4; - if ((IFCAP_TSO4 & ifp->if_capenable) != 0 && - (IFCAP_TSO4 & ifp->if_capabilities) != 0) + if ((IFCAP_TSO4 & ifp->if_capenable) != 0) ifp->if_hwassist |= CSUM_TSO; else ifp->if_hwassist &= ~CSUM_TSO; } - if (sc_if->msk_framesize > MSK_MAX_FRAMELEN && - sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_EC_U) { - /* - * In Yukon EC Ultra, TSO & checksum offload is not - * supported for jumbo frame. - */ + if (ifp->if_mtu > ETHERMTU && + (sc_if->msk_flags & MSK_FLAG_JUMBO_NOCSUM) != 0) { ifp->if_hwassist &= ~(MSK_CSUM_FEATURES | CSUM_TSO); ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TXCSUM); } @@ -1042,14 +1058,16 @@ mskc_setup_rambuffer(struct msk_softc *sc) { int next; int i; - uint8_t val; /* Get adapter SRAM size. */ - val = CSR_READ_1(sc, B2_E_0); - sc->msk_ramsize = (val == 0) ? 128 : val * 4; + sc->msk_ramsize = CSR_READ_1(sc, B2_E_0) * 4; if (bootverbose) device_printf(sc->msk_dev, "RAM buffer size : %dKB\n", sc->msk_ramsize); + if (sc->msk_ramsize == 0) + return (0); + + sc->msk_pflags |= MSK_FLAG_RAMBUF; /* * Give receiver 2/3 of memory and round down to the multiple * of 1024. Tx/Rx RAM buffer size of Yukon II shoud be multiple @@ -1082,7 +1100,7 @@ mskc_setup_rambuffer(struct msk_softc *sc) static void msk_phy_power(struct msk_softc *sc, int mode) { - uint32_t val; + uint32_t our, val; int i; switch (mode) { @@ -1108,16 +1126,21 @@ msk_phy_power(struct msk_softc *sc, int mode) val = pci_read_config(sc->msk_dev, PCI_OUR_REG_1, 4); val &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); - if (sc->msk_hw_id == CHIP_ID_YUKON_XL && - sc->msk_hw_rev > CHIP_REV_YU_XL_A1) { - /* Deassert Low Power for 1st PHY. */ - val |= PCI_Y2_PHY1_COMA; - if (sc->msk_num_port > 1) - val |= PCI_Y2_PHY2_COMA; - } else if (sc->msk_hw_id == CHIP_ID_YUKON_EC_U) { - uint32_t our; - - CSR_WRITE_2(sc, B0_CTST, Y2_HW_WOL_ON); + if (sc->msk_hw_id == CHIP_ID_YUKON_XL) { + if (sc->msk_hw_rev > CHIP_REV_YU_XL_A1) { + /* Deassert Low Power for 1st PHY. */ + val |= PCI_Y2_PHY1_COMA; + if (sc->msk_num_port > 1) + val |= PCI_Y2_PHY2_COMA; + } + } + /* Release PHY from PowerDown/COMA mode. */ + pci_write_config(sc->msk_dev, PCI_OUR_REG_1, val, 4); + switch (sc->msk_hw_id) { + case CHIP_ID_YUKON_EC_U: + case CHIP_ID_YUKON_EX: + case CHIP_ID_YUKON_FE_P: + CSR_WRITE_2(sc, B0_CTST, Y2_HW_WOL_OFF); /* Enable all clocks. */ pci_write_config(sc->msk_dev, PCI_OUR_REG_3, 0, 4); @@ -1126,11 +1149,22 @@ msk_phy_power(struct msk_softc *sc, int mode) PCI_ASPM_INT_FIFO_EMPTY|PCI_ASPM_CLKRUN_REQUEST); /* Set all bits to 0 except bits 15..12. */ pci_write_config(sc->msk_dev, PCI_OUR_REG_4, our, 4); - /* Set to default value. */ - pci_write_config(sc->msk_dev, PCI_OUR_REG_5, 0, 4); + our = pci_read_config(sc->msk_dev, PCI_OUR_REG_5, 4); + our &= PCI_CTL_TIM_VMAIN_AV_MSK; + pci_write_config(sc->msk_dev, PCI_OUR_REG_5, our, 4); + pci_write_config(sc->msk_dev, PCI_CFG_REG_1, 0, 4); + /* + * Disable status race, workaround for + * Yukon EC Ultra & Yukon EX. + */ + val = CSR_READ_4(sc, B2_GP_IO); + val |= GLB_GPIO_STAT_RACE_DIS; + CSR_WRITE_4(sc, B2_GP_IO, val); + CSR_READ_4(sc, B2_GP_IO); + break; + default: + break; } - /* Release PHY from PowerDown/COMA mode. */ - pci_write_config(sc->msk_dev, PCI_OUR_REG_1, val, 4); for (i = 0; i < sc->msk_num_port; i++) { CSR_WRITE_2(sc, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_SET); @@ -1181,10 +1215,18 @@ mskc_reset(struct msk_softc *sc) CSR_WRITE_2(sc, B0_CTST, CS_RST_CLR); /* Disable ASF. */ - if (sc->msk_hw_id < CHIP_ID_YUKON_XL) { - CSR_WRITE_4(sc, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); - CSR_WRITE_2(sc, B0_CTST, Y2_ASF_DISABLE); - } + if (sc->msk_hw_id == CHIP_ID_YUKON_EX) { + status = CSR_READ_2(sc, B28_Y2_ASF_HCU_CCSR); + /* Clear AHB bridge & microcontroller reset. */ + status &= ~(Y2_ASF_HCU_CCSR_AHB_RST | + Y2_ASF_HCU_CCSR_CPU_RST_MODE); + /* Clear ASF microcontroller state. */ + status &= ~ Y2_ASF_HCU_CCSR_UC_STATE_MSK; + CSR_WRITE_2(sc, B28_Y2_ASF_HCU_CCSR, status); + } else + CSR_WRITE_1(sc, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); + CSR_WRITE_2(sc, B0_CTST, Y2_ASF_DISABLE); + /* * Since we disabled ASF, S/W reset is required for Power Management. */ @@ -1236,6 +1278,10 @@ mskc_reset(struct msk_softc *sc) CSR_WRITE_4(sc, MR_ADDR(i, GMAC_CTRL), GMC_RST_SET); CSR_WRITE_4(sc, MR_ADDR(i, GMAC_CTRL), GMC_RST_CLR); CSR_WRITE_4(sc, MR_ADDR(i, GMAC_CTRL), GMC_F_LOOPB_OFF); + if (sc->msk_hw_id == CHIP_ID_YUKON_EX) + CSR_WRITE_4(sc, MR_ADDR(i, GMAC_CTRL), + GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON | + GMC_BYP_RETR_ON); } CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_OFF); @@ -1413,6 +1459,7 @@ msk_attach(device_t dev) sc_if->msk_if_dev = dev; sc_if->msk_port = port; sc_if->msk_softc = sc; + sc_if->msk_flags = sc->msk_pflags; sc->msk_if[port] = sc_if; /* Setup Tx/Rx queue register offsets. */ if (port == MSK_PORT_A) { @@ -1426,10 +1473,11 @@ msk_attach(device_t dev) } callout_init_mtx(&sc_if->msk_tick_ch, &sc_if->msk_softc->msk_mtx, 0); - TASK_INIT(&sc_if->msk_link_task, 0, msk_link_task, sc_if); + msk_sysctl_node(sc_if); if ((error = msk_txrx_dma_alloc(sc_if) != 0)) goto fail; + msk_rx_dma_jalloc(sc_if); ifp = sc_if->msk_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { @@ -1454,6 +1502,13 @@ msk_attach(device_t dev) * make Rx checksum offload work on Yukon II hardware. */ ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_TSO4; + /* + * Enable Rx checksum offloading if controller support new + * descriptor format. + */ + if ((sc_if->msk_flags & MSK_FLAG_DESCV2) != 0 && + (sc_if->msk_flags & MSK_FLAG_NORX_CSUM) == 0) + ifp->if_capabilities |= IFCAP_RXCSUM; ifp->if_hwassist = MSK_CSUM_FEATURES | CSUM_TSO; ifp->if_capenable = ifp->if_capabilities; ifp->if_ioctl = msk_ioctl; @@ -1488,9 +1543,23 @@ msk_attach(device_t dev) MSK_IF_LOCK(sc_if); /* VLAN capability setup */ - ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; - if (ifp->if_capabilities & IFCAP_HWCSUM) - ifp->if_capabilities |= IFCAP_VLAN_HWCSUM; + ifp->if_capabilities |= IFCAP_VLAN_MTU; + if ((sc_if->msk_flags & MSK_FLAG_NOHWVLAN) == 0) { + /* + * Due to Tx checksum offload hardware bugs, msk(4) manually + * computes checksum for short frames. For VLAN tagged frames + * this workaround does not work so disable checksum offload + * for VLAN interface. + */ + ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; + /* + * Enable Rx checksum offloading for VLAN taggedd frames + * if controller support new descriptor format. + */ + if ((sc_if->msk_flags & MSK_FLAG_DESCV2) != 0 && + (sc_if->msk_flags & MSK_FLAG_NORX_CSUM) == 0) + ifp->if_capabilities |= IFCAP_VLAN_HWCSUM; + } ifp->if_capenable = ifp->if_capabilities; /* @@ -1500,9 +1569,6 @@ msk_attach(device_t dev) */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); - sc_if->msk_framesize = ifp->if_mtu + ETHER_HDR_LEN + - ETHER_VLAN_ENCAP_LEN; - /* * Do miibus setup. */ @@ -1574,7 +1640,7 @@ mskc_attach(device_t dev) sc->msk_hw_rev = (CSR_READ_1(sc, B2_MAC_CFG) >> 4) & 0x0f; /* Bail out if chip is not recognized. */ if (sc->msk_hw_id < CHIP_ID_YUKON_XL || - sc->msk_hw_id > CHIP_ID_YUKON_FE) { + sc->msk_hw_id > CHIP_ID_YUKON_FE_P) { device_printf(dev, "unknown device: id=0x%02x, rev=0x%02x\n", sc->msk_hw_id, sc->msk_hw_rev); mtx_destroy(&sc->msk_mtx); @@ -1625,14 +1691,57 @@ mskc_attach(device_t dev) switch (sc->msk_hw_id) { case CHIP_ID_YUKON_EC: + sc->msk_clock = 125; /* 125 Mhz */ + sc->msk_pflags |= MSK_FLAG_JUMBO; + break; case CHIP_ID_YUKON_EC_U: sc->msk_clock = 125; /* 125 Mhz */ + sc->msk_pflags |= MSK_FLAG_JUMBO | MSK_FLAG_JUMBO_NOCSUM; + break; + case CHIP_ID_YUKON_EX: + sc->msk_clock = 125; /* 125 Mhz */ + sc->msk_pflags |= MSK_FLAG_JUMBO | MSK_FLAG_DESCV2 | + MSK_FLAG_AUTOTX_CSUM; + /* + * Yukon Extreme seems to have silicon bug for + * automatic Tx checksum calculation capability. + */ + if (sc->msk_hw_rev == CHIP_REV_YU_EX_B0) + sc->msk_pflags &= ~MSK_FLAG_AUTOTX_CSUM; + /* + * Yukon Extreme A0 could not use store-and-forward + * for jumbo frames, so disable Tx checksum + * offloading for jumbo frames. + */ + if (sc->msk_hw_rev == CHIP_REV_YU_EX_A0) + sc->msk_pflags |= MSK_FLAG_JUMBO_NOCSUM; break; case CHIP_ID_YUKON_FE: sc->msk_clock = 100; /* 100 Mhz */ + sc->msk_pflags |= MSK_FLAG_FASTETHER; + break; + case CHIP_ID_YUKON_FE_P: + sc->msk_clock = 50; /* 50 Mhz */ + sc->msk_pflags |= MSK_FLAG_FASTETHER | MSK_FLAG_DESCV2 | + MSK_FLAG_AUTOTX_CSUM; + if (sc->msk_hw_rev == CHIP_REV_YU_FE_P_A0) { + /* + * XXX + * FE+ A0 has status LE writeback bug so msk(4) + * does not rely on status word of received frame + * in msk_rxeof() which in turn disables all + * hardware assistance bits reported by the status + * word as well as validity of the recevied frame. + * Just pass received frames to upper stack with + * minimal test and let upper stack handle them. + */ + sc->msk_pflags |= MSK_FLAG_NOHWVLAN | + MSK_FLAG_NORXCHK | MSK_FLAG_NORX_CSUM; + } break; case CHIP_ID_YUKON_XL: sc->msk_clock = 156; /* 156 Mhz */ + sc->msk_pflags |= MSK_FLAG_JUMBO; break; default: sc->msk_clock = 156; /* 156 Mhz */ @@ -1662,7 +1771,7 @@ mskc_attach(device_t dev) if (sc->msk_num_port == 1 && pci_alloc_msi(dev, &msir) == 0) { if (msic == msir) { - sc->msk_msi = 1; + sc->msk_pflags |= MSK_FLAG_MSI; sc->msk_irq_spec = msic == 2 ? msk_irq_spec_msi2 : msk_irq_spec_msi; @@ -1788,13 +1897,12 @@ msk_detach(device_t dev) ifp = sc_if->msk_ifp; if (device_is_attached(dev)) { /* XXX */ - sc_if->msk_detach = 1; + sc_if->msk_flags |= MSK_FLAG_DETACH; msk_stop(sc_if); /* Can't hold locks while calling detach. */ MSK_IF_UNLOCK(sc_if); callout_drain(&sc_if->msk_tick_ch); taskqueue_drain(taskqueue_fast, &sc_if->msk_tx_task); - taskqueue_drain(taskqueue_swi, &sc_if->msk_link_task); ether_ifdetach(ifp); MSK_IF_LOCK(sc_if); } @@ -1810,6 +1918,7 @@ msk_detach(device_t dev) * } */ + msk_rx_dma_jfree(sc_if); msk_txrx_dma_free(sc_if); bus_generic_detach(dev); @@ -1872,7 +1981,7 @@ mskc_detach(device_t dev) sc->msk_intrhand[1] = NULL; } bus_release_resources(dev, sc->msk_irq_spec, sc->msk_irq); - if (sc->msk_msi) + if ((sc->msk_pflags & MSK_FLAG_MSI) != 0) pci_release_msi(dev); bus_release_resources(dev, sc->msk_res_spec, sc->msk_res); mtx_destroy(&sc->msk_mtx); @@ -1970,15 +2079,9 @@ msk_txrx_dma_alloc(struct msk_if_softc *sc_if) struct msk_dmamap_arg ctx; struct msk_txdesc *txd; struct msk_rxdesc *rxd; - struct msk_rxdesc *jrxd; - struct msk_jpool_entry *entry; - uint8_t *ptr; + bus_size_t rxalign; int error, i; - mtx_init(&sc_if->msk_jlist_mtx, "msk_jlist_mtx", NULL, MTX_DEF); - SLIST_INIT(&sc_if->msk_jfree_listhead); - SLIST_INIT(&sc_if->msk_jinuse_listhead); - /* Create parent DMA tag. */ /* * XXX @@ -2050,42 +2153,6 @@ msk_txrx_dma_alloc(struct msk_if_softc *sc_if) goto fail; } - /* Create tag for jumbo Rx ring. */ - error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */ - MSK_RING_ALIGN, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MSK_JUMBO_RX_RING_SZ, /* maxsize */ - 1, /* nsegments */ - MSK_JUMBO_RX_RING_SZ, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc_if->msk_cdata.msk_jumbo_rx_ring_tag); - if (error != 0) { - device_printf(sc_if->msk_if_dev, - "failed to create jumbo Rx ring DMA tag\n"); - goto fail; - } - - /* Create tag for jumbo buffer blocks. */ - error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */ - PAGE_SIZE, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MSK_JMEM, /* maxsize */ - 1, /* nsegments */ - MSK_JMEM, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc_if->msk_cdata.msk_jumbo_tag); - if (error != 0) { - device_printf(sc_if->msk_if_dev, - "failed to create jumbo Rx buffer block DMA tag\n"); - goto fail; - } - /* Create tag for Tx buffers. */ error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */ 1, 0, /* alignment, boundary */ @@ -2104,9 +2171,16 @@ msk_txrx_dma_alloc(struct msk_if_softc *sc_if) goto fail; } + rxalign = 1; + /* + * Workaround hardware hang which seems to happen when Rx buffer + * is not aligned on multiple of FIFO word(8 bytes). + */ + if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) != 0) + rxalign = MSK_RX_BUF_ALIGN; /* Create tag for Rx buffers. */ error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */ - 1, 0, /* alignment, boundary */ + rxalign, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ @@ -2122,24 +2196,6 @@ msk_txrx_dma_alloc(struct msk_if_softc *sc_if) goto fail; } - /* Create tag for jumbo Rx buffers. */ - error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */ - PAGE_SIZE, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MCLBYTES * MSK_MAXRXSEGS, /* maxsize */ - MSK_MAXRXSEGS, /* nsegments */ - MSK_JLEN, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc_if->msk_cdata.msk_jumbo_rx_tag); - if (error != 0) { - device_printf(sc_if->msk_if_dev, - "failed to create jumbo Rx DMA tag\n"); - goto fail; - } - /* Allocate DMA'able memory and load the DMA map for Tx ring. */ error = bus_dmamem_alloc(sc_if->msk_cdata.msk_tx_ring_tag, (void **)&sc_if->msk_rdata.msk_tx_ring, BUS_DMA_WAITOK | @@ -2182,29 +2238,6 @@ msk_txrx_dma_alloc(struct msk_if_softc *sc_if) } sc_if->msk_rdata.msk_rx_ring_paddr = ctx.msk_busaddr; - /* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */ - error = bus_dmamem_alloc(sc_if->msk_cdata.msk_jumbo_rx_ring_tag, - (void **)&sc_if->msk_rdata.msk_jumbo_rx_ring, - BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, - &sc_if->msk_cdata.msk_jumbo_rx_ring_map); - if (error != 0) { - device_printf(sc_if->msk_if_dev, - "failed to allocate DMA'able memory for jumbo Rx ring\n"); - goto fail; - } - - ctx.msk_busaddr = 0; - error = bus_dmamap_load(sc_if->msk_cdata.msk_jumbo_rx_ring_tag, - sc_if->msk_cdata.msk_jumbo_rx_ring_map, - sc_if->msk_rdata.msk_jumbo_rx_ring, MSK_JUMBO_RX_RING_SZ, - msk_dmamap_cb, &ctx, 0); - if (error != 0) { - device_printf(sc_if->msk_if_dev, - "failed to load DMA'able memory for jumbo Rx ring\n"); - goto fail; - } - sc_if->msk_rdata.msk_jumbo_rx_ring_paddr = ctx.msk_busaddr; - /* Create DMA maps for Tx buffers. */ for (i = 0; i < MSK_TX_RING_CNT; i++) { txd = &sc_if->msk_cdata.msk_txdesc[i]; @@ -2237,12 +2270,97 @@ msk_txrx_dma_alloc(struct msk_if_softc *sc_if) goto fail; } } + +fail: + return (error); +} + +static int +msk_rx_dma_jalloc(struct msk_if_softc *sc_if) +{ + struct msk_dmamap_arg ctx; + struct msk_rxdesc *jrxd; + bus_size_t rxalign; + int error, i; + + if (jumbo_disable != 0 || (sc_if->msk_flags & MSK_FLAG_JUMBO) == 0) { + sc_if->msk_flags &= ~MSK_FLAG_JUMBO; + device_printf(sc_if->msk_if_dev, + "disabling jumbo frame support\n"); + return (0); + } + /* Create tag for jumbo Rx ring. */ + error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */ + MSK_RING_ALIGN, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MSK_JUMBO_RX_RING_SZ, /* maxsize */ + 1, /* nsegments */ + MSK_JUMBO_RX_RING_SZ, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc_if->msk_cdata.msk_jumbo_rx_ring_tag); + if (error != 0) { + device_printf(sc_if->msk_if_dev, + "failed to create jumbo Rx ring DMA tag\n"); + goto jumbo_fail; + } + + rxalign = 1; + /* + * Workaround hardware hang which seems to happen when Rx buffer + * is not aligned on multiple of FIFO word(8 bytes). + */ + if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) != 0) + rxalign = MSK_RX_BUF_ALIGN; + /* Create tag for jumbo Rx buffers. */ + error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */ + rxalign, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MJUM9BYTES, /* maxsize */ + 1, /* nsegments */ + MJUM9BYTES, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc_if->msk_cdata.msk_jumbo_rx_tag); + if (error != 0) { + device_printf(sc_if->msk_if_dev, + "failed to create jumbo Rx DMA tag\n"); + goto jumbo_fail; + } + + /* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */ + error = bus_dmamem_alloc(sc_if->msk_cdata.msk_jumbo_rx_ring_tag, + (void **)&sc_if->msk_rdata.msk_jumbo_rx_ring, + BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, + &sc_if->msk_cdata.msk_jumbo_rx_ring_map); + if (error != 0) { + device_printf(sc_if->msk_if_dev, + "failed to allocate DMA'able memory for jumbo Rx ring\n"); + goto jumbo_fail; + } + + ctx.msk_busaddr = 0; + error = bus_dmamap_load(sc_if->msk_cdata.msk_jumbo_rx_ring_tag, + sc_if->msk_cdata.msk_jumbo_rx_ring_map, + sc_if->msk_rdata.msk_jumbo_rx_ring, MSK_JUMBO_RX_RING_SZ, + msk_dmamap_cb, &ctx, 0); + if (error != 0) { + device_printf(sc_if->msk_if_dev, + "failed to load DMA'able memory for jumbo Rx ring\n"); + goto jumbo_fail; + } + sc_if->msk_rdata.msk_jumbo_rx_ring_paddr = ctx.msk_busaddr; + /* Create DMA maps for jumbo Rx buffers. */ if ((error = bus_dmamap_create(sc_if->msk_cdata.msk_jumbo_rx_tag, 0, &sc_if->msk_cdata.msk_jumbo_rx_sparemap)) != 0) { device_printf(sc_if->msk_if_dev, "failed to create spare jumbo Rx dmamap\n"); - goto fail; + goto jumbo_fail; } for (i = 0; i < MSK_JUMBO_RX_RING_CNT; i++) { jrxd = &sc_if->msk_cdata.msk_jumbo_rxdesc[i]; @@ -2253,54 +2371,17 @@ msk_txrx_dma_alloc(struct msk_if_softc *sc_if) if (error != 0) { device_printf(sc_if->msk_if_dev, "failed to create jumbo Rx dmamap\n"); - goto fail; + goto jumbo_fail; } } - /* Allocate DMA'able memory and load the DMA map for jumbo buf. */ - error = bus_dmamem_alloc(sc_if->msk_cdata.msk_jumbo_tag, - (void **)&sc_if->msk_rdata.msk_jumbo_buf, - BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, - &sc_if->msk_cdata.msk_jumbo_map); - if (error != 0) { - device_printf(sc_if->msk_if_dev, - "failed to allocate DMA'able memory for jumbo buf\n"); - goto fail; - } + return (0); - ctx.msk_busaddr = 0; - error = bus_dmamap_load(sc_if->msk_cdata.msk_jumbo_tag, - sc_if->msk_cdata.msk_jumbo_map, sc_if->msk_rdata.msk_jumbo_buf, - MSK_JMEM, msk_dmamap_cb, &ctx, 0); - if (error != 0) { - device_printf(sc_if->msk_if_dev, - "failed to load DMA'able memory for jumbobuf\n"); - goto fail; - } - sc_if->msk_rdata.msk_jumbo_buf_paddr = ctx.msk_busaddr; - - /* - * Now divide it up into 9K pieces and save the addresses - * in an array. - */ - ptr = sc_if->msk_rdata.msk_jumbo_buf; - for (i = 0; i < MSK_JSLOTS; i++) { - sc_if->msk_cdata.msk_jslots[i] = ptr; - ptr += MSK_JLEN; - entry = malloc(sizeof(struct msk_jpool_entry), - M_DEVBUF, M_WAITOK); - if (entry == NULL) { - device_printf(sc_if->msk_if_dev, - "no memory for jumbo buffers!\n"); - error = ENOMEM; - goto fail; - } - entry->slot = i; - SLIST_INSERT_HEAD(&sc_if->msk_jfree_listhead, entry, - jpool_entries); - } - -fail: +jumbo_fail: + msk_rx_dma_jfree(sc_if); + device_printf(sc_if->msk_if_dev, "disabling jumbo frame support " + "due to resource shortage\n"); + sc_if->msk_flags &= ~MSK_FLAG_JUMBO; return (error); } @@ -2309,39 +2390,8 @@ msk_txrx_dma_free(struct msk_if_softc *sc_if) { struct msk_txdesc *txd; struct msk_rxdesc *rxd; - struct msk_rxdesc *jrxd; - struct msk_jpool_entry *entry; int i; - MSK_JLIST_LOCK(sc_if); - while ((entry = SLIST_FIRST(&sc_if->msk_jinuse_listhead))) { - device_printf(sc_if->msk_if_dev, - "asked to free buffer that is in use!\n"); - SLIST_REMOVE_HEAD(&sc_if->msk_jinuse_listhead, jpool_entries); - SLIST_INSERT_HEAD(&sc_if->msk_jfree_listhead, entry, - jpool_entries); - } - - while (!SLIST_EMPTY(&sc_if->msk_jfree_listhead)) { - entry = SLIST_FIRST(&sc_if->msk_jfree_listhead); - SLIST_REMOVE_HEAD(&sc_if->msk_jfree_listhead, jpool_entries); - free(entry, M_DEVBUF); - } - MSK_JLIST_UNLOCK(sc_if); - - /* Destroy jumbo buffer block. */ - if (sc_if->msk_cdata.msk_jumbo_map) - bus_dmamap_unload(sc_if->msk_cdata.msk_jumbo_tag, - sc_if->msk_cdata.msk_jumbo_map); - - if (sc_if->msk_rdata.msk_jumbo_buf) { - bus_dmamem_free(sc_if->msk_cdata.msk_jumbo_tag, - sc_if->msk_rdata.msk_jumbo_buf, - sc_if->msk_cdata.msk_jumbo_map); - sc_if->msk_rdata.msk_jumbo_buf = NULL; - sc_if->msk_cdata.msk_jumbo_map = NULL; - } - /* Tx ring. */ if (sc_if->msk_cdata.msk_tx_ring_tag) { if (sc_if->msk_cdata.msk_tx_ring_map) @@ -2372,21 +2422,6 @@ msk_txrx_dma_free(struct msk_if_softc *sc_if) bus_dma_tag_destroy(sc_if->msk_cdata.msk_rx_ring_tag); sc_if->msk_cdata.msk_rx_ring_tag = NULL; } - /* Jumbo Rx ring. */ - if (sc_if->msk_cdata.msk_jumbo_rx_ring_tag) { - if (sc_if->msk_cdata.msk_jumbo_rx_ring_map) - bus_dmamap_unload(sc_if->msk_cdata.msk_jumbo_rx_ring_tag, - sc_if->msk_cdata.msk_jumbo_rx_ring_map); - if (sc_if->msk_cdata.msk_jumbo_rx_ring_map && - sc_if->msk_rdata.msk_jumbo_rx_ring) - bus_dmamem_free(sc_if->msk_cdata.msk_jumbo_rx_ring_tag, - sc_if->msk_rdata.msk_jumbo_rx_ring, - sc_if->msk_cdata.msk_jumbo_rx_ring_map); - sc_if->msk_rdata.msk_jumbo_rx_ring = NULL; - sc_if->msk_cdata.msk_jumbo_rx_ring_map = NULL; - bus_dma_tag_destroy(sc_if->msk_cdata.msk_jumbo_rx_ring_tag); - sc_if->msk_cdata.msk_jumbo_rx_ring_tag = NULL; - } /* Tx buffers. */ if (sc_if->msk_cdata.msk_tx_tag) { for (i = 0; i < MSK_TX_RING_CNT; i++) { @@ -2418,6 +2453,33 @@ msk_txrx_dma_free(struct msk_if_softc *sc_if) bus_dma_tag_destroy(sc_if->msk_cdata.msk_rx_tag); sc_if->msk_cdata.msk_rx_tag = NULL; } + if (sc_if->msk_cdata.msk_parent_tag) { + bus_dma_tag_destroy(sc_if->msk_cdata.msk_parent_tag); + sc_if->msk_cdata.msk_parent_tag = NULL; + } +} + +static void +msk_rx_dma_jfree(struct msk_if_softc *sc_if) +{ + struct msk_rxdesc *jrxd; + int i; + + /* Jumbo Rx ring. */ + if (sc_if->msk_cdata.msk_jumbo_rx_ring_tag) { + if (sc_if->msk_cdata.msk_jumbo_rx_ring_map) + bus_dmamap_unload(sc_if->msk_cdata.msk_jumbo_rx_ring_tag, + sc_if->msk_cdata.msk_jumbo_rx_ring_map); + if (sc_if->msk_cdata.msk_jumbo_rx_ring_map && + sc_if->msk_rdata.msk_jumbo_rx_ring) + bus_dmamem_free(sc_if->msk_cdata.msk_jumbo_rx_ring_tag, + sc_if->msk_rdata.msk_jumbo_rx_ring, + sc_if->msk_cdata.msk_jumbo_rx_ring_map); + sc_if->msk_rdata.msk_jumbo_rx_ring = NULL; + sc_if->msk_cdata.msk_jumbo_rx_ring_map = NULL; + bus_dma_tag_destroy(sc_if->msk_cdata.msk_jumbo_rx_ring_tag); + sc_if->msk_cdata.msk_jumbo_rx_ring_tag = NULL; + } /* Jumbo Rx buffers. */ if (sc_if->msk_cdata.msk_jumbo_rx_tag) { for (i = 0; i < MSK_JUMBO_RX_RING_CNT; i++) { @@ -2437,155 +2499,6 @@ msk_txrx_dma_free(struct msk_if_softc *sc_if) bus_dma_tag_destroy(sc_if->msk_cdata.msk_jumbo_rx_tag); sc_if->msk_cdata.msk_jumbo_rx_tag = NULL; } - - if (sc_if->msk_cdata.msk_parent_tag) { - bus_dma_tag_destroy(sc_if->msk_cdata.msk_parent_tag); - sc_if->msk_cdata.msk_parent_tag = NULL; - } - mtx_destroy(&sc_if->msk_jlist_mtx); -} - -/* - * Allocate a jumbo buffer. - */ -static void * -msk_jalloc(struct msk_if_softc *sc_if) -{ - struct msk_jpool_entry *entry; - - MSK_JLIST_LOCK(sc_if); - - entry = SLIST_FIRST(&sc_if->msk_jfree_listhead); - - if (entry == NULL) { - MSK_JLIST_UNLOCK(sc_if); - return (NULL); - } - - SLIST_REMOVE_HEAD(&sc_if->msk_jfree_listhead, jpool_entries); - SLIST_INSERT_HEAD(&sc_if->msk_jinuse_listhead, entry, jpool_entries); - - MSK_JLIST_UNLOCK(sc_if); - - return (sc_if->msk_cdata.msk_jslots[entry->slot]); -} - -/* - * Release a jumbo buffer. - */ -static void -msk_jfree(void *buf, void *args) -{ - struct msk_if_softc *sc_if; - struct msk_jpool_entry *entry; - int i; - - /* Extract the softc struct pointer. */ - sc_if = (struct msk_if_softc *)args; - KASSERT(sc_if != NULL, ("%s: can't find softc pointer!", __func__)); - - MSK_JLIST_LOCK(sc_if); - /* Calculate the slot this buffer belongs to. */ - i = ((vm_offset_t)buf - - (vm_offset_t)sc_if->msk_rdata.msk_jumbo_buf) / MSK_JLEN; - KASSERT(i >= 0 && i < MSK_JSLOTS, - ("%s: asked to free buffer that we don't manage!", __func__)); - - entry = SLIST_FIRST(&sc_if->msk_jinuse_listhead); - KASSERT(entry != NULL, ("%s: buffer not in use!", __func__)); - entry->slot = i; - SLIST_REMOVE_HEAD(&sc_if->msk_jinuse_listhead, jpool_entries); - SLIST_INSERT_HEAD(&sc_if->msk_jfree_listhead, entry, jpool_entries); - if (SLIST_EMPTY(&sc_if->msk_jinuse_listhead)) - wakeup(sc_if); - - MSK_JLIST_UNLOCK(sc_if); -} - -/* - * It's copy of ath_defrag(ath(4)). - * - * Defragment an mbuf chain, returning at most maxfrags separate - * mbufs+clusters. If this is not possible NULL is returned and - * the original mbuf chain is left in it's present (potentially - * modified) state. We use two techniques: collapsing consecutive - * mbufs and replacing consecutive mbufs by a cluster. - */ -static struct mbuf * -msk_defrag(struct mbuf *m0, int how, int maxfrags) -{ - struct mbuf *m, *n, *n2, **prev; - u_int curfrags; - - /* - * Calculate the current number of frags. - */ - curfrags = 0; - for (m = m0; m != NULL; m = m->m_next) - curfrags++; - /* - * First, try to collapse mbufs. Note that we always collapse - * towards the front so we don't need to deal with moving the - * pkthdr. This may be suboptimal if the first mbuf has much - * less data than the following. - */ - m = m0; -again: - for (;;) { - n = m->m_next; - if (n == NULL) - break; - if ((m->m_flags & M_RDONLY) == 0 && - n->m_len < M_TRAILINGSPACE(m)) { - bcopy(mtod(n, void *), mtod(m, char *) + m->m_len, - n->m_len); - m->m_len += n->m_len; - m->m_next = n->m_next; - m_free(n); - if (--curfrags <= maxfrags) - return (m0); - } else - m = n; - } - KASSERT(maxfrags > 1, - ("maxfrags %u, but normal collapse failed", maxfrags)); - /* - * Collapse consecutive mbufs to a cluster. - */ - prev = &m0->m_next; /* NB: not the first mbuf */ - while ((n = *prev) != NULL) { - if ((n2 = n->m_next) != NULL && - n->m_len + n2->m_len < MCLBYTES) { - m = m_getcl(how, MT_DATA, 0); - if (m == NULL) - goto bad; - bcopy(mtod(n, void *), mtod(m, void *), n->m_len); - bcopy(mtod(n2, void *), mtod(m, char *) + n->m_len, - n2->m_len); - m->m_len = n->m_len + n2->m_len; - m->m_next = n2->m_next; - *prev = m; - m_free(n); - m_free(n2); - if (--curfrags <= maxfrags) /* +1 cl -2 mbufs */ - return m0; - /* - * Still not there, try the normal collapse - * again before we allocate another cluster. - */ - goto again; - } - prev = &n->m_next; - } - /* - * No place where we can collapse to a cluster; punt. - * This can occur if, for example, you request 2 frags - * but the packet requires that both be clusters (we - * never reallocate the first mbuf to avoid moving the - * packet header). - */ -bad: - return (NULL); } static int @@ -2604,7 +2517,10 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head) tcp_offset = offset = 0; m = *m_head; - if ((m->m_pkthdr.csum_flags & (MSK_CSUM_FEATURES | CSUM_TSO)) != 0) { + if (((sc_if->msk_flags & MSK_FLAG_AUTOTX_CSUM) == 0 && + (m->m_pkthdr.csum_flags & MSK_CSUM_FEATURES) != 0) || + ((sc_if->msk_flags & MSK_FLAG_DESCV2) == 0 && + (m->m_pkthdr.csum_flags & CSUM_TSO) != 0)) { /* * Since mbuf has no protocol specific structure information * in it we have to inspect protocol information here to @@ -2618,7 +2534,16 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head) struct ip *ip; struct tcphdr *tcp; - /* TODO check for M_WRITABLE(m) */ + if (M_WRITABLE(m) == 0) { + /* Get a writable copy. */ + m = m_dup(*m_head, M_DONTWAIT); + m_freem(*m_head); + if (m == NULL) { + *m_head = NULL; + return (ENOBUFS); + } + *m_head = m; + } offset = sizeof(struct ether_header); m = m_pullup(m, offset); @@ -2654,16 +2579,21 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head) * resort to S/W checksum routine when we encounter short * TCP frames. * Short UDP packets appear to be handled correctly by - * Yukon II. + * Yukon II. Also I assume this bug does not happen on + * controllers that use newer descriptor format or + * automatic Tx checksum calaulcation. */ - if (m->m_pkthdr.len < MSK_MIN_FRAMELEN && + if ((sc_if->msk_flags & MSK_FLAG_AUTOTX_CSUM) == 0 && + (m->m_pkthdr.len < MSK_MIN_FRAMELEN) && (m->m_pkthdr.csum_flags & CSUM_TCP) != 0) { - uint16_t csum; - - csum = in_cksum_skip(m, ntohs(ip->ip_len) + offset - - (ip->ip_hl << 2), offset); + m = m_pullup(m, offset + sizeof(struct tcphdr)); + if (m == NULL) { + *m_head = NULL; + return (ENOBUFS); + } *(uint16_t *)(m->m_data + offset + - m->m_pkthdr.csum_data) = csum; + m->m_pkthdr.csum_data) = in_cksum_skip(m, + m->m_pkthdr.len, offset); m->m_pkthdr.csum_flags &= ~CSUM_TCP; } if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { @@ -2685,7 +2615,7 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head) error = bus_dmamap_load_mbuf_sg(sc_if->msk_cdata.msk_tx_tag, map, *m_head, txsegs, &nseg, BUS_DMA_NOWAIT); if (error == EFBIG) { - m = msk_defrag(*m_head, M_DONTWAIT, MSK_MAXTXSEGS); + m = m_collapse(*m_head, M_DONTWAIT, MSK_MAXTXSEGS); if (m == NULL) { m_freem(*m_head); *m_head = NULL; @@ -2720,11 +2650,18 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head) /* Check TSO support. */ if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { - tso_mtu = offset + m->m_pkthdr.tso_segsz; + if ((sc_if->msk_flags & MSK_FLAG_DESCV2) != 0) + tso_mtu = m->m_pkthdr.tso_segsz; + else + tso_mtu = offset + m->m_pkthdr.tso_segsz; if (tso_mtu != sc_if->msk_cdata.msk_tso_mtu) { tx_le = &sc_if->msk_rdata.msk_tx_ring[prod]; tx_le->msk_addr = htole32(tso_mtu); - tx_le->msk_control = htole32(OP_LRGLEN | HW_OWNER); + if ((sc_if->msk_flags & MSK_FLAG_DESCV2) != 0) + tx_le->msk_control = htole32(OP_MSS | HW_OWNER); + else + tx_le->msk_control = + htole32(OP_LRGLEN | HW_OWNER); sc_if->msk_cdata.msk_tx_cnt++; MSK_INC(prod, MSK_TX_RING_CNT); sc_if->msk_cdata.msk_tso_mtu = tso_mtu; @@ -2748,15 +2685,21 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head) } /* Check if we have to handle checksum offload. */ if (tso == 0 && (m->m_pkthdr.csum_flags & MSK_CSUM_FEATURES) != 0) { - tx_le = &sc_if->msk_rdata.msk_tx_ring[prod]; - tx_le->msk_addr = htole32(((tcp_offset + m->m_pkthdr.csum_data) - & 0xffff) | ((uint32_t)tcp_offset << 16)); - tx_le->msk_control = htole32(1 << 16 | (OP_TCPLISW | HW_OWNER)); - control = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; - if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) - control |= UDPTCP; - sc_if->msk_cdata.msk_tx_cnt++; - MSK_INC(prod, MSK_TX_RING_CNT); + if ((sc_if->msk_flags & MSK_FLAG_AUTOTX_CSUM) != 0) + control |= CALSUM; + else { + tx_le = &sc_if->msk_rdata.msk_tx_ring[prod]; + tx_le->msk_addr = htole32(((tcp_offset + + m->m_pkthdr.csum_data) & 0xffff) | + ((uint32_t)tcp_offset << 16)); + tx_le->msk_control = htole32(1 << 16 | + (OP_TCPLISW | HW_OWNER)); + control = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; + if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) + control |= UDPTCP; + sc_if->msk_cdata.msk_tx_cnt++; + MSK_INC(prod, MSK_TX_RING_CNT); + } } si = prod; @@ -2827,7 +2770,7 @@ msk_start(struct ifnet *ifp) MSK_IF_LOCK(sc_if); if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != - IFF_DRV_RUNNING || sc_if->msk_link == 0) { + IFF_DRV_RUNNING || (sc_if->msk_flags & MSK_FLAG_LINK) == 0) { MSK_IF_UNLOCK(sc_if); return; } @@ -2884,11 +2827,12 @@ msk_watchdog(struct msk_if_softc *sc_if) if (sc_if->msk_watchdog_timer == 0 || --sc_if->msk_watchdog_timer) return; ifp = sc_if->msk_ifp; - if (sc_if->msk_link == 0) { + if ((sc_if->msk_flags & MSK_FLAG_LINK) == 0) { if (bootverbose) if_printf(sc_if->msk_ifp, "watchdog timeout " "(missed link)\n"); ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; msk_init_locked(sc_if); return; } @@ -2913,6 +2857,7 @@ msk_watchdog(struct msk_if_softc *sc_if) if_printf(ifp, "watchdog timeout\n"); ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; msk_init_locked(sc_if); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) taskqueue_enqueue(taskqueue_fast, &sc_if->msk_tx_task); @@ -2971,7 +2916,7 @@ mskc_suspend(device_t dev) /* Put hardware reset. */ CSR_WRITE_2(sc, B0_CTST, CS_RST_SET); - sc->msk_suspended = 1; + sc->msk_pflags |= MSK_FLAG_SUSPEND; MSK_UNLOCK(sc); @@ -2991,18 +2936,39 @@ mskc_resume(device_t dev) mskc_reset(sc); for (i = 0; i < sc->msk_num_port; i++) { if (sc->msk_if[i] != NULL && sc->msk_if[i]->msk_ifp != NULL && - ((sc->msk_if[i]->msk_ifp->if_flags & IFF_UP) != 0)) + ((sc->msk_if[i]->msk_ifp->if_flags & IFF_UP) != 0)) { + sc->msk_if[i]->msk_ifp->if_drv_flags &= + ~IFF_DRV_RUNNING; msk_init_locked(sc->msk_if[i]); + } } - sc->msk_suspended = 0; + sc->msk_pflags &= ~MSK_FLAG_SUSPEND; MSK_UNLOCK(sc); return (0); } +#ifndef __NO_STRICT_ALIGNMENT +static __inline void +msk_fixup_rx(struct mbuf *m) +{ + int i; + uint16_t *src, *dst; + + src = mtod(m, uint16_t *); + dst = src - 3; + + for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) + *dst++ = *src++; + + m->m_data -= (MSK_RX_BUF_ALIGN - ETHER_ALIGN); +} +#endif + static void -msk_rxeof(struct msk_if_softc *sc_if, uint32_t status, int len) +msk_rxeof(struct msk_if_softc *sc_if, uint32_t status, uint32_t control, + int len) { struct mbuf *m; struct ifnet *ifp; @@ -3019,7 +2985,18 @@ msk_rxeof(struct msk_if_softc *sc_if, uint32_t status, int len) if ((status & GMR_FS_VLAN) != 0 && (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) rxlen -= ETHER_VLAN_ENCAP_LEN; - if (len > sc_if->msk_framesize || + if ((sc_if->msk_flags & MSK_FLAG_NORXCHK) != 0) { + /* + * For controllers that returns bogus status code + * just do minimal check and let upper stack + * handle this frame. + */ + if (len > MSK_MAX_FRAMELEN || len < ETHER_HDR_LEN) { + ifp->if_ierrors++; + msk_discard_rxbuf(sc_if, cons); + break; + } + } else if (len > sc_if->msk_framesize || ((status & GMR_FS_ANY_ERR) != 0) || ((status & GMR_FS_RX_OK) == 0) || (rxlen != len)) { /* Don't count flow-control packet as errors. */ @@ -3038,7 +3015,23 @@ msk_rxeof(struct msk_if_softc *sc_if, uint32_t status, int len) } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; +#ifndef __NO_STRICT_ALIGNMENT + if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) != 0) + msk_fixup_rx(m); +#endif ifp->if_ipackets++; + if ((ifp->if_capenable & IFCAP_RXCSUM) != 0 && + (control & (CSS_IPV4 | CSS_IPFRAG)) == CSS_IPV4) { + m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; + if ((control & CSS_IPV4_CSUM_OK) != 0) + m->m_pkthdr.csum_flags |= CSUM_IP_VALID; + if ((control & (CSS_TCP | CSS_UDP)) != 0 && + (control & (CSS_TCPUDP_CSUM_OK)) != 0) { + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | + CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } + } /* Check for VLAN tagged packets. */ if ((status & GMR_FS_VLAN) != 0 && (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { @@ -3055,7 +3048,8 @@ msk_rxeof(struct msk_if_softc *sc_if, uint32_t status, int len) } static void -msk_jumbo_rxeof(struct msk_if_softc *sc_if, uint32_t status, int len) +msk_jumbo_rxeof(struct msk_if_softc *sc_if, uint32_t status, uint32_t control, + int len) { struct mbuf *m; struct ifnet *ifp; @@ -3091,7 +3085,23 @@ msk_jumbo_rxeof(struct msk_if_softc *sc_if, uint32_t status, int len) } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; +#ifndef __NO_STRICT_ALIGNMENT + if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) != 0) + msk_fixup_rx(m); +#endif ifp->if_ipackets++; + if ((ifp->if_capenable & IFCAP_RXCSUM) != 0 && + (control & (CSS_IPV4 | CSS_IPFRAG)) == CSS_IPV4) { + m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; + if ((control & CSS_IPV4_CSUM_OK) != 0) + m->m_pkthdr.csum_flags |= CSUM_IP_VALID; + if ((control & (CSS_TCP | CSS_UDP)) != 0 && + (control & (CSS_TCPUDP_CSUM_OK)) != 0) { + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | + CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } + } /* Check for VLAN tagged packets. */ if ((status & GMR_FS_VLAN) != 0 && (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { @@ -3351,7 +3361,7 @@ msk_rxput(struct msk_if_softc *sc_if) struct msk_softc *sc; sc = sc_if->msk_softc; - if (sc_if->msk_framesize >(MCLBYTES - ETHER_HDR_LEN)) + if (sc_if->msk_framesize > (MCLBYTES - MSK_RX_BUF_ALIGN)) bus_dmamap_sync( sc_if->msk_cdata.msk_jumbo_rx_ring_tag, sc_if->msk_cdata.msk_jumbo_rx_ring_map, @@ -3418,10 +3428,11 @@ msk_handle_events(struct msk_softc *sc) sc_if->msk_vtag = ntohs(len); break; case OP_RXSTAT: - if (sc_if->msk_framesize > (MCLBYTES - ETHER_HDR_LEN)) - msk_jumbo_rxeof(sc_if, status, len); + if (sc_if->msk_framesize > + (MCLBYTES - MSK_RX_BUF_ALIGN)) + msk_jumbo_rxeof(sc_if, status, control, len); else - msk_rxeof(sc_if, status, len); + msk_rxeof(sc_if, status, control, len); rxprog++; /* * Because there is no way to sync single Rx LE @@ -3481,7 +3492,8 @@ msk_legacy_intr(void *xsc) /* Reading B0_Y2_SP_ISRC2 masks further interrupts. */ status = CSR_READ_4(sc, B0_Y2_SP_ISRC2); - if (status == 0 || status == 0xffffffff || sc->msk_suspended != 0 || + if (status == 0 || status == 0xffffffff || + (sc->msk_pflags & MSK_FLAG_SUSPEND) != 0 || (status & sc->msk_intrmask) == 0) { CSR_WRITE_4(sc, B0_Y2_SP_ICR, 2); return; @@ -3568,7 +3580,8 @@ msk_int_task(void *arg, int pending) /* Get interrupt source. */ status = CSR_READ_4(sc, B0_ISRC); - if (status == 0 || status == 0xffffffff || sc->msk_suspended != 0 || + if (status == 0 || status == 0xffffffff || + (sc->msk_pflags & MSK_FLAG_SUSPEND) != 0 || (status & sc->msk_intrmask) == 0) goto done; @@ -3626,6 +3639,48 @@ done: CSR_WRITE_4(sc, B0_Y2_SP_ICR, 2); } +static void +msk_set_tx_stfwd(struct msk_if_softc *sc_if) +{ + struct msk_softc *sc; + struct ifnet *ifp; + + ifp = sc_if->msk_ifp; + sc = sc_if->msk_softc; + switch (sc->msk_hw_id) { + case CHIP_ID_YUKON_EX: + if (sc->msk_hw_rev == CHIP_REV_YU_EX_A0) + goto yukon_ex_workaround; + if (ifp->if_mtu > ETHERMTU) + CSR_WRITE_4(sc, + MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), + TX_JUMBO_ENA | TX_STFW_ENA); + else + CSR_WRITE_4(sc, + MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), + TX_JUMBO_DIS | TX_STFW_ENA); + break; + default: +yukon_ex_workaround: + if (ifp->if_mtu > ETHERMTU) { + /* Set Tx GMAC FIFO Almost Empty Threshold. */ + CSR_WRITE_4(sc, + MR_ADDR(sc_if->msk_port, TX_GMF_AE_THR), + MSK_ECU_JUMBO_WM << 16 | MSK_ECU_AE_THR); + /* Disable Store & Forward mode for Tx. */ + CSR_WRITE_4(sc, + MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), + TX_JUMBO_ENA | TX_STFW_DIS); + } else { + /* Enable Store & Forward mode for Tx. */ + CSR_WRITE_4(sc, + MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), + TX_JUMBO_DIS | TX_STFW_ENA); + } + break; + } +} + static void msk_init(void *xsc) { @@ -3644,6 +3699,7 @@ msk_init_locked(struct msk_if_softc *sc_if) struct mii_data *mii; uint16_t eaddr[ETHER_ADDR_LEN / 2]; uint16_t gmac; + uint32_t reg; int error, i; MSK_IF_LOCK_ASSERT(sc_if); @@ -3652,47 +3708,44 @@ msk_init_locked(struct msk_if_softc *sc_if) sc = sc_if->msk_softc; mii = device_get_softc(sc_if->msk_miibus); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; + error = 0; /* Cancel pending I/O and free all Rx/Tx buffers. */ msk_stop(sc_if); - sc_if->msk_framesize = ifp->if_mtu + ETHER_HDR_LEN + - ETHER_VLAN_ENCAP_LEN; - if (sc_if->msk_framesize > MSK_MAX_FRAMELEN && - sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_EC_U) { - /* - * In Yukon EC Ultra, TSO & checksum offload is not - * supported for jumbo frame. - */ + if (ifp->if_mtu < ETHERMTU) + sc_if->msk_framesize = ETHERMTU; + else + sc_if->msk_framesize = ifp->if_mtu; + sc_if->msk_framesize += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; + if (ifp->if_mtu > ETHERMTU && + (sc_if->msk_flags & MSK_FLAG_JUMBO_NOCSUM) != 0) { ifp->if_hwassist &= ~(MSK_CSUM_FEATURES | CSUM_TSO); ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TXCSUM); } + /* GMAC Control reset. */ + CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), GMC_RST_SET); + CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), GMC_RST_CLR); + CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), GMC_F_LOOPB_OFF); + if (sc->msk_hw_id == CHIP_ID_YUKON_EX) + CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), + GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON | + GMC_BYP_RETR_ON); + /* - * Initialize GMAC first. - * Without this initialization, Rx MAC did not work as expected - * and Rx MAC garbled status LEs and it resulted in out-of-order - * or duplicated frame delivery which in turn showed very poor - * Rx performance.(I had to write a packet analysis code that - * could be embeded in driver to diagnose this issue.) - * I've spent almost 2 months to fix this issue. If I have had - * datasheet for Yukon II I wouldn't have encountered this. :-( + * Initialize GMAC first such that speed/duplex/flow-control + * parameters are renegotiated when interface is brought up. */ - gmac = GM_GPCR_SPEED_100 | GM_GPCR_SPEED_1000 | GM_GPCR_DUP_FULL; - GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, gmac); + GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, 0); /* Dummy read the Interrupt Source Register. */ CSR_READ_1(sc, MR_ADDR(sc_if->msk_port, GMAC_IRQ_SRC)); - /* Set MIB Clear Counter Mode. */ - gmac = GMAC_READ_2(sc, sc_if->msk_port, GM_PHY_ADDR); - GMAC_WRITE_2(sc, sc_if->msk_port, GM_PHY_ADDR, gmac | GM_PAR_MIB_CLR); - /* Read all MIB Counters with Clear Mode set. */ - for (i = 0; i < GM_MIB_CNT_SIZE; i++) - GMAC_READ_2(sc, sc_if->msk_port, GM_MIB_CNT_BASE + 8 * i); - /* Clear MIB Clear Counter Mode. */ - gmac &= ~GM_PAR_MIB_CLR; - GMAC_WRITE_2(sc, sc_if->msk_port, GM_PHY_ADDR, gmac); + /* Clear MIB stats. */ + msk_stats_clear(sc_if); /* Disable FCS. */ GMAC_WRITE_2(sc, sc_if->msk_port, GM_RX_CTRL, GM_RXCR_CRC_DIS); @@ -3711,7 +3764,7 @@ msk_init_locked(struct msk_if_softc *sc_if) gmac = DATA_BLIND_VAL(DATA_BLIND_DEF) | GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); - if (sc_if->msk_framesize > MSK_MAX_FRAMELEN) + if (ifp->if_mtu > ETHERMTU) gmac |= GM_SMOD_JUMBO_ENA; GMAC_WRITE_2(sc, sc_if->msk_port, GM_SERIAL_MODE, gmac); @@ -3732,22 +3785,29 @@ msk_init_locked(struct msk_if_softc *sc_if) /* Configure Rx MAC FIFO. */ CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T), GMF_RST_SET); CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T), GMF_RST_CLR); - CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T), - GMF_OPER_ON | GMF_RX_F_FL_ON); + reg = GMF_OPER_ON | GMF_RX_F_FL_ON; + if (sc->msk_hw_id == CHIP_ID_YUKON_FE_P || + sc->msk_hw_id == CHIP_ID_YUKON_EX) + reg |= GMF_RX_OVER_ON; + CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T), reg); - /* Set promiscuous mode. */ - msk_setpromisc(sc_if); - - /* Set multicast filter. */ - msk_setmulti(sc_if); + /* Set receive filter. */ + msk_rxfilter(sc_if); /* Flush Rx MAC FIFO on any flow control or error. */ CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR); - /* Set Rx FIFO flush threshold to 64 bytes. */ - CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_FL_THR), - RX_GMF_FL_THR_DEF); + /* + * Set Rx FIFO flush threshold to 64 bytes + 1 FIFO word + * due to hardware hang on receipt of pause frames. + */ + reg = RX_GMF_FL_THR_DEF + 1; + /* Another magic for Yukon FE+ - From Linux. */ + if (sc->msk_hw_id == CHIP_ID_YUKON_FE_P && + sc->msk_hw_rev == CHIP_REV_YU_FE_P_A0) + reg = 0x178; + CSR_WRITE_2(sc, MR_ADDR(sc_if->msk_port, RX_GMF_FL_THR), reg); /* Configure Tx MAC FIFO. */ CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), GMF_RST_SET); @@ -3757,28 +3817,24 @@ msk_init_locked(struct msk_if_softc *sc_if) /* Configure hardware VLAN tag insertion/stripping. */ msk_setvlan(sc_if, ifp); - if (sc->msk_hw_id == CHIP_ID_YUKON_EC_U) { + if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) == 0) { /* Set Rx Pause threshould. */ CSR_WRITE_1(sc, MR_ADDR(sc_if->msk_port, RX_GMF_LP_THR), MSK_ECU_LLPP); CSR_WRITE_1(sc, MR_ADDR(sc_if->msk_port, RX_GMF_UP_THR), MSK_ECU_ULPP); - if (sc_if->msk_framesize > MSK_MAX_FRAMELEN) { - /* - * Set Tx GMAC FIFO Almost Empty Threshold. - */ - CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_AE_THR), - MSK_ECU_JUMBO_WM << 16 | MSK_ECU_AE_THR); - /* Disable Store & Forward mode for Tx. */ - CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), - TX_JUMBO_ENA | TX_STFW_DIS); - } else { - /* Enable Store & Forward mode for Tx. */ - CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), - TX_JUMBO_DIS | TX_STFW_ENA); - } + /* Configure store-and-forward for Tx. */ + msk_set_tx_stfwd(sc_if); } + if (sc->msk_hw_id == CHIP_ID_YUKON_FE_P && + sc->msk_hw_rev == CHIP_REV_YU_FE_P_A0) { + /* Disable dynamic watermark - from Linux. */ + reg = CSR_READ_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_EA)); + reg &= ~0x03; + CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_EA), reg); + } + /* * Disable Force Sync bit and Alloc bit in Tx RAM interface * arbiter as we don't use Sync Tx queue. @@ -3799,10 +3855,23 @@ msk_init_locked(struct msk_if_softc *sc_if) CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR), BMU_OPER_INIT); CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR), BMU_FIFO_OP_ON); CSR_WRITE_2(sc, Q_ADDR(sc_if->msk_txq, Q_WM), MSK_BMU_TX_WM); - if (sc->msk_hw_id == CHIP_ID_YUKON_EC_U && - sc->msk_hw_rev == CHIP_REV_YU_EC_U_A0) { - /* Fix for Yukon-EC Ultra: set BMU FIFO level */ - CSR_WRITE_2(sc, Q_ADDR(sc_if->msk_txq, Q_AL), MSK_ECU_TXFF_LEV); + switch (sc->msk_hw_id) { + case CHIP_ID_YUKON_EC_U: + if (sc->msk_hw_rev == CHIP_REV_YU_EC_U_A0) { + /* Fix for Yukon-EC Ultra: set BMU FIFO level */ + CSR_WRITE_2(sc, Q_ADDR(sc_if->msk_txq, Q_AL), + MSK_ECU_TXFF_LEV); + } + break; + case CHIP_ID_YUKON_EX: + /* + * Yukon Extreme seems to have silicon bug for + * automatic Tx checksum calculation capability. + */ + if (sc->msk_hw_rev == CHIP_REV_YU_EX_B0) + CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_F), + F_TX_CHK_AUTO_OFF); + break; } /* Setup Rx Queue Bus Memory Interface. */ @@ -3823,7 +3892,7 @@ msk_init_locked(struct msk_if_softc *sc_if) /* Disable Rx checksum offload and RSS hash. */ CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_rxq, Q_CSR), BMU_DIS_RX_CHKSUM | BMU_DIS_RX_RSS_HASH); - if (sc_if->msk_framesize > (MCLBYTES - ETHER_HDR_LEN)) { + if (sc_if->msk_framesize > (MCLBYTES - MSK_RX_BUF_ALIGN)) { msk_set_prefetch(sc, sc_if->msk_rxq, sc_if->msk_rdata.msk_jumbo_rx_ring_paddr, MSK_JUMBO_RX_RING_CNT - 1); @@ -3854,7 +3923,7 @@ msk_init_locked(struct msk_if_softc *sc_if) CSR_WRITE_4(sc, B0_IMSK, sc->msk_intrmask); CSR_READ_4(sc, B0_IMSK); - sc_if->msk_link = 0; + sc_if->msk_flags &= ~MSK_FLAG_LINK; mii_mediachg(mii); ifp->if_drv_flags |= IFF_DRV_RUNNING; @@ -3870,6 +3939,8 @@ msk_set_rambuffer(struct msk_if_softc *sc_if) int ltpp, utpp; sc = sc_if->msk_softc; + if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) == 0) + return; /* Setup Rx Queue. */ CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_rxq, RB_CTRL), RB_RST_CLR); @@ -3973,6 +4044,8 @@ msk_stop(struct msk_if_softc *sc_if) GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, val); /* Read again to ensure writing. */ GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL); + /* Update stats and clear counters. */ + msk_stats_update(sc_if); /* Stop Tx BMU. */ CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR), BMU_STOP); @@ -3981,7 +4054,7 @@ msk_stop(struct msk_if_softc *sc_if) if ((val & (BMU_STOP | BMU_IDLE)) == 0) { CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR), BMU_STOP); - CSR_READ_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR)); + val = CSR_READ_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR)); } else break; DELAY(1); @@ -4085,9 +4158,298 @@ msk_stop(struct msk_if_softc *sc_if) * Mark the interface down. */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - sc_if->msk_link = 0; + sc_if->msk_flags &= ~MSK_FLAG_LINK; } +/* + * When GM_PAR_MIB_CLR bit of GM_PHY_ADDR is set, reading lower + * counter clears high 16 bits of the counter such that accessing + * lower 16 bits should be the last operation. + */ +#define MSK_READ_MIB32(x, y) \ + (((uint32_t)GMAC_READ_2(sc, x, (y) + 4)) << 16) + \ + (uint32_t)GMAC_READ_2(sc, x, y) +#define MSK_READ_MIB64(x, y) \ + (((uint64_t)MSK_READ_MIB32(x, (y) + 8)) << 32) + \ + (uint64_t)MSK_READ_MIB32(x, y) + +static void +msk_stats_clear(struct msk_if_softc *sc_if) +{ + struct msk_softc *sc; + uint32_t reg; + uint16_t gmac; + int i; + + MSK_IF_LOCK_ASSERT(sc_if); + + sc = sc_if->msk_softc; + /* Set MIB Clear Counter Mode. */ + gmac = GMAC_READ_2(sc, sc_if->msk_port, GM_PHY_ADDR); + GMAC_WRITE_2(sc, sc_if->msk_port, GM_PHY_ADDR, gmac | GM_PAR_MIB_CLR); + /* Read all MIB Counters with Clear Mode set. */ + for (i = GM_RXF_UC_OK; i <= GM_TXE_FIFO_UR; i++) + reg = MSK_READ_MIB32(sc_if->msk_port, i); + /* Clear MIB Clear Counter Mode. */ + gmac &= ~GM_PAR_MIB_CLR; + GMAC_WRITE_2(sc, sc_if->msk_port, GM_PHY_ADDR, gmac); +} + +static void +msk_stats_update(struct msk_if_softc *sc_if) +{ + struct msk_softc *sc; + struct ifnet *ifp; + struct msk_hw_stats *stats; + uint16_t gmac; + uint32_t reg; + + MSK_IF_LOCK_ASSERT(sc_if); + + ifp = sc_if->msk_ifp; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + sc = sc_if->msk_softc; + stats = &sc_if->msk_stats; + /* Set MIB Clear Counter Mode. */ + gmac = GMAC_READ_2(sc, sc_if->msk_port, GM_PHY_ADDR); + GMAC_WRITE_2(sc, sc_if->msk_port, GM_PHY_ADDR, gmac | GM_PAR_MIB_CLR); + + /* Rx stats. */ + stats->rx_ucast_frames += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_UC_OK); + stats->rx_bcast_frames += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_BC_OK); + stats->rx_pause_frames += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_MPAUSE); + stats->rx_mcast_frames += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_MC_OK); + stats->rx_crc_errs += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_FCS_ERR); + reg = MSK_READ_MIB32(sc_if->msk_port, GM_RXF_SPARE1); + stats->rx_good_octets += + MSK_READ_MIB64(sc_if->msk_port, GM_RXO_OK_LO); + stats->rx_bad_octets += + MSK_READ_MIB64(sc_if->msk_port, GM_RXO_ERR_LO); + stats->rx_runts += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_SHT); + stats->rx_runt_errs += + MSK_READ_MIB32(sc_if->msk_port, GM_RXE_FRAG); + stats->rx_pkts_64 += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_64B); + stats->rx_pkts_65_127 += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_127B); + stats->rx_pkts_128_255 += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_255B); + stats->rx_pkts_256_511 += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_511B); + stats->rx_pkts_512_1023 += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_1023B); + stats->rx_pkts_1024_1518 += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_1518B); + stats->rx_pkts_1519_max += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_MAX_SZ); + stats->rx_pkts_too_long += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_LNG_ERR); + stats->rx_pkts_jabbers += + MSK_READ_MIB32(sc_if->msk_port, GM_RXF_JAB_PKT); + reg = MSK_READ_MIB32(sc_if->msk_port, GM_RXF_SPARE2); + stats->rx_fifo_oflows += + MSK_READ_MIB32(sc_if->msk_port, GM_RXE_FIFO_OV); + reg = MSK_READ_MIB32(sc_if->msk_port, GM_RXF_SPARE3); + + /* Tx stats. */ + stats->tx_ucast_frames += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_UC_OK); + stats->tx_bcast_frames += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_BC_OK); + stats->tx_pause_frames += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_MPAUSE); + stats->tx_mcast_frames += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_MC_OK); + stats->tx_octets += + MSK_READ_MIB64(sc_if->msk_port, GM_TXO_OK_LO); + stats->tx_pkts_64 += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_64B); + stats->tx_pkts_65_127 += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_127B); + stats->tx_pkts_128_255 += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_255B); + stats->tx_pkts_256_511 += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_511B); + stats->tx_pkts_512_1023 += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_1023B); + stats->tx_pkts_1024_1518 += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_1518B); + stats->tx_pkts_1519_max += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_MAX_SZ); + reg = MSK_READ_MIB32(sc_if->msk_port, GM_TXF_SPARE1); + stats->tx_colls += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_COL); + stats->tx_late_colls += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_LAT_COL); + stats->tx_excess_colls += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_ABO_COL); + stats->tx_multi_colls += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_MUL_COL); + stats->tx_single_colls += + MSK_READ_MIB32(sc_if->msk_port, GM_TXF_SNG_COL); + stats->tx_underflows += + MSK_READ_MIB32(sc_if->msk_port, GM_TXE_FIFO_UR); + /* Clear MIB Clear Counter Mode. */ + gmac &= ~GM_PAR_MIB_CLR; + GMAC_WRITE_2(sc, sc_if->msk_port, GM_PHY_ADDR, gmac); +} + +static int +msk_sysctl_stat32(SYSCTL_HANDLER_ARGS) +{ + struct msk_softc *sc; + struct msk_if_softc *sc_if; + uint32_t result, *stat; + int off; + + sc_if = (struct msk_if_softc *)arg1; + sc = sc_if->msk_softc; + off = arg2; + stat = (uint32_t *)((uint8_t *)&sc_if->msk_stats + off); + + MSK_IF_LOCK(sc_if); + result = MSK_READ_MIB32(sc_if->msk_port, GM_MIB_CNT_BASE + off * 2); + result += *stat; + MSK_IF_UNLOCK(sc_if); + + return (sysctl_handle_int(oidp, &result, 0, req)); +} + +static int +msk_sysctl_stat64(SYSCTL_HANDLER_ARGS) +{ + struct msk_softc *sc; + struct msk_if_softc *sc_if; + uint64_t result, *stat; + int off; + + sc_if = (struct msk_if_softc *)arg1; + sc = sc_if->msk_softc; + off = arg2; + stat = (uint64_t *)((uint8_t *)&sc_if->msk_stats + off); + + MSK_IF_LOCK(sc_if); + result = MSK_READ_MIB64(sc_if->msk_port, GM_MIB_CNT_BASE + off * 2); + result += *stat; + MSK_IF_UNLOCK(sc_if); + + return (sysctl_handle_quad(oidp, &result, 0, req)); +} + +#undef MSK_READ_MIB32 +#undef MSK_READ_MIB64 + +#define MSK_SYSCTL_STAT32(sc, c, o, p, n, d) \ + SYSCTL_ADD_PROC(c, p, OID_AUTO, o, CTLTYPE_UINT | CTLFLAG_RD, \ + sc, offsetof(struct msk_hw_stats, n), msk_sysctl_stat32, \ + "IU", d) +#define MSK_SYSCTL_STAT64(sc, c, o, p, n, d) \ + SYSCTL_ADD_PROC(c, p, OID_AUTO, o, CTLTYPE_UINT | CTLFLAG_RD, \ + sc, offsetof(struct msk_hw_stats, n), msk_sysctl_stat64, \ + "Q", d) + +static void +msk_sysctl_node(struct msk_if_softc *sc_if) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *child, *schild; + struct sysctl_oid *tree; + + ctx = device_get_sysctl_ctx(sc_if->msk_if_dev); + child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc_if->msk_if_dev)); + + tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, + NULL, "MSK Statistics"); + schild = child = SYSCTL_CHILDREN(tree); + tree = SYSCTL_ADD_NODE(ctx, schild, OID_AUTO, "rx", CTLFLAG_RD, + NULL, "MSK RX Statistics"); + child = SYSCTL_CHILDREN(tree); + MSK_SYSCTL_STAT32(sc_if, ctx, "ucast_frames", + child, rx_ucast_frames, "Good unicast frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "bcast_frames", + child, rx_bcast_frames, "Good broadcast frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "pause_frames", + child, rx_pause_frames, "Pause frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "mcast_frames", + child, rx_mcast_frames, "Multicast frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "crc_errs", + child, rx_crc_errs, "CRC errors"); + MSK_SYSCTL_STAT64(sc_if, ctx, "good_octets", + child, rx_good_octets, "Good octets"); + MSK_SYSCTL_STAT64(sc_if, ctx, "bad_octets", + child, rx_bad_octets, "Bad octets"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_64", + child, rx_pkts_64, "64 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_65_127", + child, rx_pkts_65_127, "65 to 127 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_128_255", + child, rx_pkts_128_255, "128 to 255 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_256_511", + child, rx_pkts_256_511, "256 to 511 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_512_1023", + child, rx_pkts_512_1023, "512 to 1023 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_1024_1518", + child, rx_pkts_1024_1518, "1024 to 1518 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_1519_max", + child, rx_pkts_1519_max, "1519 to max frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_too_long", + child, rx_pkts_too_long, "frames too long"); + MSK_SYSCTL_STAT32(sc_if, ctx, "jabbers", + child, rx_pkts_jabbers, "Jabber errors"); + MSK_SYSCTL_STAT32(sc_if, ctx, "overflows", + child, rx_fifo_oflows, "FIFO overflows"); + + tree = SYSCTL_ADD_NODE(ctx, schild, OID_AUTO, "tx", CTLFLAG_RD, + NULL, "MSK TX Statistics"); + child = SYSCTL_CHILDREN(tree); + MSK_SYSCTL_STAT32(sc_if, ctx, "ucast_frames", + child, tx_ucast_frames, "Unicast frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "bcast_frames", + child, tx_bcast_frames, "Broadcast frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "pause_frames", + child, tx_pause_frames, "Pause frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "mcast_frames", + child, tx_mcast_frames, "Multicast frames"); + MSK_SYSCTL_STAT64(sc_if, ctx, "octets", + child, tx_octets, "Octets"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_64", + child, tx_pkts_64, "64 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_65_127", + child, tx_pkts_65_127, "65 to 127 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_128_255", + child, tx_pkts_128_255, "128 to 255 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_256_511", + child, tx_pkts_256_511, "256 to 511 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_512_1023", + child, tx_pkts_512_1023, "512 to 1023 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_1024_1518", + child, tx_pkts_1024_1518, "1024 to 1518 bytes frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "frames_1519_max", + child, tx_pkts_1519_max, "1519 to max frames"); + MSK_SYSCTL_STAT32(sc_if, ctx, "colls", + child, tx_colls, "Collisions"); + MSK_SYSCTL_STAT32(sc_if, ctx, "late_colls", + child, tx_late_colls, "Late collisions"); + MSK_SYSCTL_STAT32(sc_if, ctx, "excess_colls", + child, tx_excess_colls, "Excessive collisions"); + MSK_SYSCTL_STAT32(sc_if, ctx, "multi_colls", + child, tx_multi_colls, "Multiple collisions"); + MSK_SYSCTL_STAT32(sc_if, ctx, "single_colls", + child, tx_single_colls, "Single collisions"); + MSK_SYSCTL_STAT32(sc_if, ctx, "underflows", + child, tx_underflows, "FIFO underflows"); +} + +#undef MSK_SYSCTL_STAT32 +#undef MSK_SYSCTL_STAT64 + static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) { diff --git a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/msk/if_mskreg.h b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/msk/if_mskreg.h index abd82c0ae4..d345b60b94 100644 --- a/src/add-ons/kernel/drivers/network/marvell_yukon/dev/msk/if_mskreg.h +++ b/src/add-ons/kernel/drivers/network/marvell_yukon/dev/msk/if_mskreg.h @@ -93,7 +93,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/*$FreeBSD: src/sys/dev/msk/if_mskreg.h,v 1.11 2007/12/05 09:41:58 remko Exp $*/ +/*$FreeBSD$*/ /* * SysKonnect PCI vendor ID @@ -130,13 +130,19 @@ #define DEVICEID_MRVL_8035 0x4350 #define DEVICEID_MRVL_8036 0x4351 #define DEVICEID_MRVL_8038 0x4352 -#define DEVICEID_MRVL_8039 0X4353 +#define DEVICEID_MRVL_8039 0x4353 +#define DEVICEID_MRVL_8040 0x4354 +#define DEVICEID_MRVL_8040T 0x4355 +#define DEVICEID_MRVL_8048 0x435A #define DEVICEID_MRVL_4360 0x4360 #define DEVICEID_MRVL_4361 0x4361 #define DEVICEID_MRVL_4362 0x4362 #define DEVICEID_MRVL_4363 0x4363 #define DEVICEID_MRVL_4364 0x4364 +#define DEVICEID_MRVL_4365 0x4365 #define DEVICEID_MRVL_436A 0x436A +#define DEVICEID_MRVL_436B 0x436B +#define DEVICEID_MRVL_436C 0x436C /* * D-Link gigabit ethernet device ID @@ -221,6 +227,8 @@ #define PCI_OUR_REG_3 0x80 /* 32 bit Our Register 3 */ #define PCI_OUR_REG_4 0x84 /* 32 bit Our Register 4 */ #define PCI_OUR_REG_5 0x88 /* 32 bit Our Register 5 */ +#define PCI_CFG_REG_0 0x90 /* 32 bit Config Register 0 */ +#define PCI_CFG_REG_1 0x94 /* 32 bit Config Register 1 */ /* PCI Express Capability */ #define PEX_CAP_ID 0xe0 /* 8 bit PEX Capability ID */ @@ -321,6 +329,56 @@ #define PCI_CLK_GATE_PEX_UNIT_ENA BIT_1 /* Enable Gate PEX Unit Clock */ #define PCI_CLK_GATE_ROOT_COR_ENA BIT_0 /* Enable Gate Root Core Clock */ +/* PCI_OUR_REG_5 32 bit Our Register 5 (Yukon-ECU only) */ + /* Bit 31..27: for A3 & later */ +#define PCI_CTL_DIV_CORE_CLK_ENA BIT_31 /* Divide Core Clock Enable */ +#define PCI_CTL_SRESET_VMAIN_AV BIT_30 /* Soft Reset for Vmain_av De-Glitch */ +#define PCI_CTL_BYPASS_VMAIN_AV BIT_29 /* Bypass En. for Vmain_av De-Glitch */ +#define PCI_CTL_TIM_VMAIN_AV1 BIT_28 /* Bit 28..27: Timer Vmain_av Mask */ +#define PCI_CTL_TIM_VMAIN_AV0 BIT_27 /* Bit 28..27: Timer Vmain_av Mask */ +#define PCI_CTL_TIM_VMAIN_AV_MSK (BIT_28 | BIT_27) + /* Bit 26..16: Release Clock on Event */ +#define PCI_REL_PCIE_RST_DE_ASS BIT_26 /* PCIe Reset De-Asserted */ +#define PCI_REL_GPHY_REC_PACKET BIT_25 /* GPHY Received Packet */ +#define PCI_REL_INT_FIFO_N_EMPTY BIT_24 /* Internal FIFO Not Empty */ +#define PCI_REL_MAIN_PWR_AVAIL BIT_23 /* Main Power Available */ +#define PCI_REL_CLKRUN_REQ_REL BIT_22 /* CLKRUN Request Release */ +#define PCI_REL_PCIE_RESET_ASS BIT_21 /* PCIe Reset Asserted */ +#define PCI_REL_PME_ASSERTED BIT_20 /* PME Asserted */ +#define PCI_REL_PCIE_EXIT_L1_ST BIT_19 /* PCIe Exit L1 State */ +#define PCI_REL_LOADER_NOT_FIN BIT_18 /* EPROM Loader Not Finished */ +#define PCI_REL_PCIE_RX_EX_IDLE BIT_17 /* PCIe Rx Exit Electrical Idle State */ +#define PCI_REL_GPHY_LINK_UP BIT_16 /* GPHY Link Up */ + /* Bit 10.. 0: Mask for Gate Clock */ +#define PCI_GAT_PCIE_RST_ASSERTED BIT_10 /* PCIe Reset Asserted */ +#define PCI_GAT_GPHY_N_REC_PACKET BIT_9 /* GPHY Not Received Packet */ +#define PCI_GAT_INT_FIFO_EMPTY BIT_8 /* Internal FIFO Empty */ +#define PCI_GAT_MAIN_PWR_N_AVAIL BIT_7 /* Main Power Not Available */ +#define PCI_GAT_CLKRUN_REQ_REL BIT_6 /* CLKRUN Not Requested */ +#define PCI_GAT_PCIE_RESET_ASS BIT_5 /* PCIe Reset Asserted */ +#define PCI_GAT_PME_DE_ASSERTED BIT_4 /* PME De-Asserted */ +#define PCI_GAT_PCIE_ENTER_L1_ST BIT_3 /* PCIe Enter L1 State */ +#define PCI_GAT_LOADER_FINISHED BIT_2 /* EPROM Loader Finished */ +#define PCI_GAT_PCIE_RX_EL_IDLE BIT_1 /* PCIe Rx Electrical Idle State */ +#define PCI_GAT_GPHY_LINK_DOWN BIT_0 /* GPHY Link Down */ + +/* PCI_CFG_REG_1 32 bit Config Register 1 */ +#define PCI_CF1_DIS_REL_EVT_RST BIT_24 /* Dis. Rel. Event during PCIE reset */ + /* Bit 23..21: Release Clock on Event */ +#define PCI_CF1_REL_LDR_NOT_FIN BIT_23 /* EEPROM Loader Not Finished */ +#define PCI_CF1_REL_VMAIN_AVLBL BIT_22 /* Vmain available */ +#define PCI_CF1_REL_PCIE_RESET BIT_21 /* PCI-E reset */ + /* Bit 20..18: Gate Clock on Event */ +#define PCI_CF1_GAT_LDR_NOT_FIN BIT_20 /* EEPROM Loader Finished */ +#define PCI_CF1_GAT_PCIE_RX_IDLE BIT_19 /* PCI-E Rx Electrical idle */ +#define PCI_CF1_GAT_PCIE_RESET BIT_18 /* PCI-E Reset */ +#define PCI_CF1_PRST_PHY_CLKREQ BIT_17 /* Enable PCI-E rst & PM2PHY gen. CLKREQ */ +#define PCI_CF1_PCIE_RST_CLKREQ BIT_16 /* Enable PCI-E rst generate CLKREQ */ + +#define PCI_CF1_ENA_CFG_LDR_DONE BIT_8 /* Enable core level Config loader done */ +#define PCI_CF1_ENA_TXBMU_RD_IDLE BIT_1 /* Enable TX BMU Read IDLE for ASPM */ +#define PCI_CF1_ENA_TXBMU_WR_IDLE BIT_0 /* Enable TX BMU Write IDLE for ASPM */ + /* PEX_DEV_CTRL 16 bit PEX Device Control (Yukon-2) */ #define PEX_DC_MAX_RRS_MSK (7<<12) /* Bit 14..12: Max. Read Request Size */ #define PEX_DC_EN_NO_SNOOP BIT_11 /* Enable No Snoop */ @@ -617,6 +675,7 @@ #define B28_Y2_SMB_CSD_REG 0x0e44 /* 32 bit ASF SMB Control/Status/Data */ #define B28_Y2_ASF_IRQ_V_BASE 0x0e60 /* 32 bit ASF IRQ Vector Base */ #define B28_Y2_ASF_STAT_CMD 0x0e68 /* 32 bit ASF Status and Command Reg */ +#define B28_Y2_ASF_HCU_CCSR 0x0e68 /* 32 bit ASF HCU CCSR (Yukon EX) */ #define B28_Y2_ASF_HOST_COM 0x0e6c /* 32 bit ASF Host Communication Reg */ #define B28_Y2_DATA_REG_1 0x0e70 /* 32 bit ASF/Host Data Register 1 */ #define B28_Y2_DATA_REG_2 0x0e74 /* 32 bit ASF/Host Data Register 2 */ @@ -826,8 +885,10 @@ #define CHIP_ID_YUKON_LP 0xb2 /* Chip ID for YUKON-LP */ #define CHIP_ID_YUKON_XL 0xb3 /* Chip ID for YUKON-2 XL */ #define CHIP_ID_YUKON_EC_U 0xb4 /* Chip ID for YUKON-2 EC Ultra */ +#define CHIP_ID_YUKON_EX 0xb5 /* Chip ID for YUKON-2 Extreme */ #define CHIP_ID_YUKON_EC 0xb6 /* Chip ID for YUKON-2 EC */ #define CHIP_ID_YUKON_FE 0xb7 /* Chip ID for YUKON-2 FE */ +#define CHIP_ID_YUKON_FE_P 0xb8 /* Chip ID for YUKON-2 FE+ */ #define CHIP_REV_YU_XL_A0 0 /* Chip Rev. for Yukon-2 A0 */ #define CHIP_REV_YU_XL_A1 1 /* Chip Rev. for Yukon-2 A1 */ @@ -841,6 +902,11 @@ #define CHIP_REV_YU_EC_U_A0 1 #define CHIP_REV_YU_EC_U_A1 2 +#define CHIP_REV_YU_FE_P_A0 0 /* Chip Rev. for Yukon-2 FE+ A0 */ + +#define CHIP_REV_YU_EX_A0 1 /* Chip Rev. for Yukon-2 EX A0 */ +#define CHIP_REV_YU_EX_B0 2 /* Chip Rev. for Yukon-2 EX B0 */ + /* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */ #define Y2_STATUS_LNK2_INAC BIT_7 /* Status Link 2 inactiv (0 = activ) */ #define Y2_CLK_GAT_LNK2_DIS BIT_6 /* Disable clock gating Link 2 */ @@ -905,6 +971,18 @@ #define TST_CFG_WRITE_ON BIT_1 /* Enable Config Reg WR */ #define TST_CFG_WRITE_OFF BIT_0 /* Disable Config Reg WR */ +/* B2_GP_IO */ +#define GLB_GPIO_CLK_DEB_ENA BIT_31 /* Clock Debug Enable */ +#define GLB_GPIO_CLK_DBG_MSK 0x3c000000 /* Clock Debug */ + +#define GLB_GPIO_INT_RST_D3_DIS BIT_15 /* Disable Internal Reset After D3 to D0 */ +#define GLB_GPIO_LED_PAD_SPEED_UP BIT_14 /* LED PAD Speed Up */ +#define GLB_GPIO_STAT_RACE_DIS BIT_13 /* Status Race Disable */ +#define GLB_GPIO_TEST_SEL_MSK 0x00001800 /* Testmode Select */ +#define GLB_GPIO_TEST_SEL_BASE BIT_11 +#define GLB_GPIO_RAND_ENA BIT_10 /* Random Enable */ +#define GLB_GPIO_RAND_BIT_1 BIT_9 /* Random Bit 1 */ + /* B2_I2C_CTRL 32 bit I2C HW Control Register */ #define I2C_FLAG BIT_31 /* Start read/write if WR */ #define I2C_ADDR (0x7fff<<16) /* Bit 30..16: Addr to be RD/WR */ @@ -1026,13 +1104,16 @@ /* Bit 10..0: same as for Rx */ /* Q_F 32 bit Flag Register */ -#define F_ALM_FULL BIT_27 /* Rx FIFO: almost full */ -#define F_EMPTY BIT_27 /* Tx FIFO: empty flag */ -#define F_FIFO_EOF BIT_26 /* Tag (EOF Flag) bit in FIFO */ -#define F_WM_REACHED BIT_25 /* Watermark reached */ -#define F_M_RX_RAM_DIS BIT_24 /* MAC Rx RAM Read Port disable */ -#define F_FIFO_LEVEL (0x1f<<16) /* Bit 23..16: # of Qwords in FIFO */ -#define F_WATER_MARK 0x0007ff /* Bit 10.. 0: Watermark */ +#define F_TX_CHK_AUTO_OFF BIT_31 /* Tx checksum auto-calc Off(Yukon EX)*/ +#define F_TX_CHK_AUTO_ON BIT_30 /* Tx checksum auto-calc On(Yukon EX)*/ +#define F_ALM_FULL BIT_28 /* Rx FIFO: almost full */ +#define F_EMPTY BIT_27 /* Tx FIFO: empty flag */ +#define F_FIFO_EOF BIT_26 /* Tag (EOF Flag) bit in FIFO */ +#define F_WM_REACHED BIT_25 /* Watermark reached */ +#define F_M_RX_RAM_DIS BIT_24 /* MAC Rx RAM Read Port disable */ +#define F_FIFO_LEVEL (0x1f<<16) + /* Bit 23..16: # of Qwords in FIFO */ +#define F_WATER_MARK 0x0007ff/* Bit 10.. 0: Watermark */ /* Queue Prefetch Unit Offsets, use Y2_PREF_Q_ADDR() to address (Yukon-2 only)*/ /* PREF_UNIT_CTRL_REG 32 bit Prefetch Control register */ @@ -1614,6 +1695,8 @@ (GM_MIB_CNT_BASE + 24) /* Multicast Frames Received OK */ #define GM_RXF_FCS_ERR \ (GM_MIB_CNT_BASE + 32) /* Rx Frame Check Seq. Error */ +#define GM_RXF_SPARE1 \ + (GM_MIB_CNT_BASE + 40) /* Rx spare 1 */ #define GM_RXO_OK_LO \ (GM_MIB_CNT_BASE + 48) /* Octets Received OK Low */ #define GM_RXO_OK_HI \ @@ -1644,8 +1727,12 @@ (GM_MIB_CNT_BASE + 152) /* Rx Frame too Long Error */ #define GM_RXF_JAB_PKT \ (GM_MIB_CNT_BASE + 160) /* Rx Jabber Packet Frame */ +#define GM_RXF_SPARE2 \ + (GM_MIB_CNT_BASE + 168) /* Rx spare 2 */ #define GM_RXE_FIFO_OV \ (GM_MIB_CNT_BASE + 176) /* Rx FIFO overflow Event */ +#define GM_RXF_SPARE3 \ + (GM_MIB_CNT_BASE + 184) /* Rx spare 3 */ #define GM_TXF_UC_OK \ (GM_MIB_CNT_BASE + 192) /* Unicast Frames Xmitted OK */ #define GM_TXF_BC_OK \ @@ -1672,6 +1759,8 @@ (GM_MIB_CNT_BASE + 280) /* 1024-1518 Byte Tx Frame */ #define GM_TXF_MAX_SZ \ (GM_MIB_CNT_BASE + 288) /* 1519-MaxSize Byte Tx Frame */ +#define GM_TXF_SPARE1 \ + (GM_MIB_CNT_BASE + 296) /* Tx spare 1 */ #define GM_TXF_COL \ (GM_MIB_CNT_BASE + 304) /* Tx Collision */ #define GM_TXF_LAT_COL \ @@ -1818,6 +1907,7 @@ GMR_FS_LONG_ERR | \ GMR_FS_MII_ERR | \ GMR_FS_BAD_FC | \ + GMR_FS_GOOD_FC | \ GMR_FS_UN_SIZE | \ GMR_FS_JABBER) @@ -1846,6 +1936,10 @@ #define RX_TRUNC_OFF BIT_26 /* disable packet truncation */ #define RX_VLAN_STRIP_ON BIT_25 /* enable VLAN stripping */ #define RX_VLAN_STRIP_OFF BIT_24 /* disable VLAN stripping */ +#define GMF_RX_OVER_ON BIT_19 /* enable flushing on receive overrun */ +#define GMF_RX_OVER_OFF BIT_18 /* disable flushing on receive overrun */ +#define GMF_ASF_RX_OVER_ON BIT_17 /* enable flushing of ASF when overrun */ +#define GMF_ASF_RX_OVER_OFF BIT_16 /* disable flushing of ASF when overrun */ #define GMF_WP_TST_ON BIT_14 /* Write Pointer Test On */ #define GMF_WP_TST_OFF BIT_13 /* Write Pointer Test Off */ #define GMF_WP_STEP BIT_12 /* Write Pointer Step/Increment */ @@ -1907,6 +2001,28 @@ #define Y2_ASF_UC_STATE (3<<2) /* ASF uC State */ #define Y2_ASF_CLK_HALT 0 /* ASF system clock stopped */ +/* B28_Y2_ASF_HCU_CCSR 32bit CPU Control and Status Register (Yukon EX) */ +#define Y2_ASF_HCU_CCSR_SMBALERT_MONITOR BIT_27 /* SMBALERT pin monitor */ +#define Y2_ASF_HCU_CCSR_CPU_SLEEP BIT_26 /* CPU sleep status */ +#define Y2_ASF_HCU_CCSR_CS_TO BIT_25 /* Clock Stretching Timeout */ +#define Y2_ASF_HCU_CCSR_WDOG BIT_24 /* Watchdog Reset */ +#define Y2_ASF_HCU_CCSR_CLR_IRQ_HOST BIT_17 /* Clear IRQ_HOST */ +#define Y2_ASF_HCU_CCSR_SET_IRQ_HCU BIT_16 /* Set IRQ_HCU */ +#define Y2_ASF_HCU_CCSR_AHB_RST BIT_9 /* Reset AHB bridge */ +#define Y2_ASF_HCU_CCSR_CPU_RST_MODE BIT_8 /* CPU Reset Mode */ +#define Y2_ASF_HCU_CCSR_SET_SYNC_CPU BIT_5 +#define Y2_ASF_HCU_CCSR_CPU_CLK_DIVIDE1 BIT_4 +#define Y2_ASF_HCU_CCSR_CPU_CLK_DIVIDE0 BIT_3 +#define Y2_ASF_HCU_CCSR_CPU_CLK_DIVIDE_MSK (BIT_4 | BIT_3) /* CPU Clock Divide */ +#define Y2_ASF_HCU_CCSR_CPU_CLK_DIVIDE_BASE BIT_3 +#define Y2_ASF_HCU_CCSR_OS_PRSNT BIT_2 /* ASF OS Present */ + /* Microcontroller State */ +#define Y2_ASF_HCU_CCSR_UC_STATE_MSK 3 +#define Y2_ASF_HCU_CCSR_UC_STATE_BASE BIT_0 +#define Y2_ASF_HCU_CCSR_ASF_RESET 0 +#define Y2_ASF_HCU_CCSR_ASF_HALTED BIT_1 +#define Y2_ASF_HCU_CCSR_ASF_RUNNING BIT_0 + /* B28_Y2_ASF_HOST_COM 32 bit ASF Host Communication Reg */ /* This register is used by the ASF firmware */ #define Y2_ASF_CLR_ASFI BIT_1 /* Clear host IRQ */ @@ -1920,6 +2036,14 @@ #define SC_STAT_RST_SET BIT_0 /* Set Status Unit Reset */ /* GMAC_CTRL 32 bit GMAC Control Reg (YUKON only) */ +#define GMC_SEC_RST BIT_15 /* MAC SEC RST */ +#define GMC_SEC_RST_OFF BIT_14 /* MAC SEC RST Off */ +#define GMC_BYP_MACSECRX_ON BIT_13 /* Bypass MAC SEC RX */ +#define GMC_BYP_MACSECRX_OFF BIT_12 /* Bypass MAC SEC RX Off */ +#define GMC_BYP_MACSECTX_ON BIT_11 /* Bypass MAC SEC TX */ +#define GMC_BYP_MACSECTX_OFF BIT_10 /* Bypass MAC SEC TX Off */ +#define GMC_BYP_RETR_ON BIT_9 /* Bypass MAC retransmit FIFO On */ +#define GMC_BYP_RETR_OFF BIT_8 /* Bypass MAC retransmit FIFO Off */ #define GMC_H_BURST_ON BIT_7 /* Half Duplex Burst Mode On */ #define GMC_H_BURST_OFF BIT_6 /* Half Duplex Burst Mode Off */ #define GMC_F_LOOPB_ON BIT_5 /* FIFO Loopback On */ @@ -2113,6 +2237,8 @@ struct msk_stat_desc { #define OP_ADDR64VLAN (OP_ADDR64 | OP_VLAN) #define OP_LRGLEN 0x24000000 #define OP_LRGLENVLAN (OP_LRGLEN | OP_VLAN) +#define OP_MSS 0x28000000 +#define OP_MSSVLAN (OP_MSS | OP_VLAN) #define OP_BUFFER 0x40000000 #define OP_PACKET 0x41000000 #define OP_LARGESEND 0x43000000 @@ -2131,8 +2257,19 @@ struct msk_stat_desc { #define OP_PUTIDX 0x70000000 #define STLE_OP_MASK 0xff000000 +#define STLE_CSS_MASK 0x00ff0000 #define STLE_LEN_MASK 0x0000ffff +/* CSS defined in status LE(valid for descriptor V2 format). */ +#define CSS_TCPUDP_CSUM_OK 0x00800000 +#define CSS_UDP 0x00400000 +#define CSS_TCP 0x00200000 +#define CSS_IPFRAG 0x00100000 +#define CSS_IPV6 0x00080000 +#define CSS_IPV4_CSUM_OK 0x00040000 +#define CSS_IPV4 0x00020000 +#define CSS_PORT 0x00010000 + /* Descriptor Bit Definition */ /* TxCtrl Transmit Buffer Control Field */ /* RxCtrl Receive Buffer Control Field */ @@ -2157,12 +2294,12 @@ struct msk_stat_desc { #define MSK_TX_RING_CNT 256 #define MSK_RX_RING_CNT 256 +#define MSK_RX_BUF_ALIGN 8 #define MSK_JUMBO_RX_RING_CNT MSK_RX_RING_CNT #define MSK_STAT_RING_CNT ((1 + 3) * (MSK_TX_RING_CNT + MSK_RX_RING_CNT)) #define MSK_MAXTXSEGS 32 #define MSK_TSO_MAXSGSIZE 4096 #define MSK_TSO_MAXSIZE (65535 + sizeof(struct ether_vlan_header)) -#define MSK_MAXRXSEGS 32 /* * It seems that the hardware requires extra decriptors(LEs) to offload @@ -2189,20 +2326,6 @@ struct msk_stat_desc { #define MSK_MAX_FRAMELEN \ (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN) #define MSK_MIN_FRAMELEN (ETHER_MIN_LEN - ETHER_CRC_LEN) -#define MSK_JSLOTS ((MSK_RX_RING_CNT * 3) / 2) - -#define MSK_JRAWLEN (MSK_JUMBO_FRAMELEN + ETHER_ALIGN) -#define MSK_JLEN (MSK_JRAWLEN + (sizeof(uint64_t) - \ - (MSK_JRAWLEN % sizeof(uint64_t)))) -#define MSK_JPAGESZ PAGE_SIZE -#define MSK_RESID \ - (MSK_JPAGESZ - (MSK_JLEN * MSK_JSLOTS) % MSK_JPAGESZ) -#define MSK_JMEM ((MSK_JLEN * MSK_JSLOTS) + MSK_RESID) - -struct msk_jpool_entry { - int slot; - SLIST_ENTRY(msk_jpool_entry) jpool_entries; -}; struct msk_txdesc { struct mbuf *tx_m; @@ -2228,10 +2351,6 @@ struct msk_chain_data { bus_dmamap_t msk_rx_ring_map; bus_dmamap_t msk_rx_sparemap; bus_dma_tag_t msk_jumbo_rx_tag; - bus_dma_tag_t msk_jumbo_tag; - bus_dmamap_t msk_jumbo_map; - bus_dma_tag_t msk_jumbo_mtag; - caddr_t msk_jslots[MSK_JSLOTS]; struct msk_rxdesc msk_jumbo_rxdesc[MSK_JUMBO_RX_RING_CNT]; bus_dma_tag_t msk_jumbo_rx_ring_tag; bus_dmamap_t msk_jumbo_rx_ring_map; @@ -2253,8 +2372,6 @@ struct msk_ring_data { bus_addr_t msk_rx_ring_paddr; struct msk_rx_desc *msk_jumbo_rx_ring; bus_addr_t msk_jumbo_rx_ring_paddr; - void *msk_jumbo_buf; - bus_addr_t msk_jumbo_buf_paddr; }; #define MSK_TX_RING_ADDR(sc, i) \ @@ -2289,6 +2406,52 @@ struct msk_ring_data { /* Forward decl. */ struct msk_if_softc; +struct msk_hw_stats { + /* Rx stats. */ + uint32_t rx_ucast_frames; + uint32_t rx_bcast_frames; + uint32_t rx_pause_frames; + uint32_t rx_mcast_frames; + uint32_t rx_crc_errs; + uint32_t rx_spare1; + uint64_t rx_good_octets; + uint64_t rx_bad_octets; + uint32_t rx_runts; + uint32_t rx_runt_errs; + uint32_t rx_pkts_64; + uint32_t rx_pkts_65_127; + uint32_t rx_pkts_128_255; + uint32_t rx_pkts_256_511; + uint32_t rx_pkts_512_1023; + uint32_t rx_pkts_1024_1518; + uint32_t rx_pkts_1519_max; + uint32_t rx_pkts_too_long; + uint32_t rx_pkts_jabbers; + uint32_t rx_spare2; + uint32_t rx_fifo_oflows; + uint32_t rx_spare3; + /* Tx stats. */ + uint32_t tx_ucast_frames; + uint32_t tx_bcast_frames; + uint32_t tx_pause_frames; + uint32_t tx_mcast_frames; + uint64_t tx_octets; + uint32_t tx_pkts_64; + uint32_t tx_pkts_65_127; + uint32_t tx_pkts_128_255; + uint32_t tx_pkts_256_511; + uint32_t tx_pkts_512_1023; + uint32_t tx_pkts_1024_1518; + uint32_t tx_pkts_1519_max; + uint32_t tx_spare1; + uint32_t tx_colls; + uint32_t tx_late_colls; + uint32_t tx_excess_colls; + uint32_t tx_multi_colls; + uint32_t tx_single_colls; + uint32_t tx_underflows; +}; + /* Softc for the Marvell Yukon II controller. */ struct msk_softc { struct resource *msk_res[1]; /* I/O resource */ @@ -2306,9 +2469,8 @@ struct msk_softc { uint32_t msk_coppertype; uint32_t msk_intrmask; uint32_t msk_intrhwemask; - int msk_suspended; + uint32_t msk_pflags; int msk_clock; - int msk_msi; struct msk_if_softc *msk_if[2]; device_t msk_devs[2]; int msk_txqsize; @@ -2346,7 +2508,20 @@ struct msk_if_softc { int msk_framesize; int msk_phytype; int msk_phyaddr; - int msk_link; + uint32_t msk_flags; +#define MSK_FLAG_MSI 0x0001 +#define MSK_FLAG_FASTETHER 0x0004 +#define MSK_FLAG_JUMBO 0x0008 +#define MSK_FLAG_JUMBO_NOCSUM 0x0010 +#define MSK_FLAG_RAMBUF 0x0020 +#define MSK_FLAG_DESCV2 0x0040 +#define MSK_FLAG_AUTOTX_CSUM 0x0080 +#define MSK_FLAG_NOHWVLAN 0x0100 +#define MSK_FLAG_NORXCHK 0x0200 +#define MSK_FLAG_NORX_CSUM 0x0400 +#define MSK_FLAG_SUSPEND 0x2000 +#define MSK_FLAG_DETACH 0x4000 +#define MSK_FLAG_LINK 0x8000 struct callout msk_tick_ch; int msk_watchdog_timer; uint32_t msk_txq; /* Tx. Async Queue offset */ @@ -2355,19 +2530,12 @@ struct msk_if_softc { struct msk_chain_data msk_cdata; struct msk_ring_data msk_rdata; struct msk_softc *msk_softc; /* parent controller */ - struct task msk_link_task; + struct msk_hw_stats msk_stats; struct task msk_tx_task; int msk_if_flags; - int msk_detach; uint16_t msk_vtag; /* VLAN tag id. */ - SLIST_HEAD(__msk_jfreehead, msk_jpool_entry) msk_jfree_listhead; - SLIST_HEAD(__msk_jinusehead, msk_jpool_entry) msk_jinuse_listhead; - struct mtx msk_jlist_mtx; }; -#define MSK_JLIST_LOCK(_sc) mtx_lock(&(_sc)->msk_jlist_mtx) -#define MSK_JLIST_UNLOCK(_sc) mtx_unlock(&(_sc)->msk_jlist_mtx) - #define MSK_TIMEOUT 1000 #define MSK_PHY_POWERUP 1 #define MSK_PHY_POWERDOWN 0 diff --git a/src/libs/compat/freebsd_network/compat/dev/mii/miidevs b/src/libs/compat/freebsd_network/compat/dev/mii/miidevs index f35cb7b859..3b62654b68 100644 --- a/src/libs/compat/freebsd_network/compat/dev/mii/miidevs +++ b/src/libs/compat/freebsd_network/compat/dev/mii/miidevs @@ -1,4 +1,4 @@ -$FreeBSD: src/sys/dev/mii/miidevs,v 1.62 2008/10/23 01:27:15 yongari Exp $ +$FreeBSD$ /*$NetBSD: miidevs,v 1.6 1999/05/14 11:37:30 drochner Exp $*/ /*- @@ -52,6 +52,7 @@ $FreeBSD: src/sys/dev/mii/miidevs,v 1.62 2008/10/23 01:27:15 yongari Exp $ oui AGERE 0x00a0bc Agere Systems oui ALTIMA 0x0010a9 Altima Communications oui AMD 0x00001a Advanced Micro Devices +oui ASIX 0x00602e Asix Semiconductor oui ATHEROS 0x001374 Atheros Communications oui BROADCOM 0x001018 Broadcom Corporation oui BROADCOM2 0x000af7 Broadcom Corporation @@ -120,6 +121,9 @@ model AMD 79c973phy 0x0036 Am79c973 internal PHY model AMD 79c978 0x0039 Am79c978 HomePNA PHY model xxAMD 79C873 0x0000 Am79C873/DM9101 10/100 media interface +/* Asix semiconductor PHYs. */ +model ASIX AX88X9X 0x0031 Ax88x9x internal PHY + /* Atheros Communications/Attansic PHYs. */ model ATHEROS F1 0x0001 Atheros F1 10/100/1000 PHY model ATHEROS F2 0x0002 Atheros F2 10/100 PHY @@ -243,6 +247,7 @@ model MARVELL E1111 0x000c Marvell 88E1111 Gigabit PHY model MARVELL E1116 0x0021 Marvell 88E1116 Gigabit PHY model MARVELL E1116R 0x0024 Marvell 88E1116R Gigabit PHY model MARVELL E1118 0x0022 Marvell 88E1118 Gigabit PHY +model MARVELL E3016 0x0026 Marvell 88E3016 10/100 Fast Ethernet PHY model xxMARVELL E1000 0x0005 Marvell 88E1000 Gigabit PHY model xxMARVELL E1011 0x0002 Marvell 88E1011 Gigabit PHY model xxMARVELL E1000_3 0x0003 Marvell 88E1000 Gigabit PHY