--- if_msk.c.orig 2008-01-18 10:50:48.000000000 +0900 +++ if_msk.c 2008-01-24 19:25:11.000000000 +0900 @@ -195,6 +195,8 @@ "Marvell Yukon 88E8038 Gigabit Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_8039, "Marvell Yukon 88E8039 Gigabit Ethernet" }, + { VENDORID_MARVELL, DEVICEID_MRVL_8040, + "Marvell Yukon 88E8040 Fast Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_4361, "Marvell Yukon 88E8050 Gigabit Ethernet" }, { VENDORID_MARVELL, DEVICEID_MRVL_4360, @@ -219,6 +221,7 @@ "Yukon Unknown", "Yukon EC", "Yukon FE" + "Yukon FE+" }; static int mskc_probe(device_t); @@ -927,12 +930,32 @@ error = EINVAL; break; } - if (sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_FE && - ifr->ifr_mtu > MSK_MAX_FRAMELEN) { - error = EINVAL; + MSK_IF_LOCK(sc_if); + if (ifr->ifr_mtu > MSK_MAX_FRAMELEN) { + switch (sc_if->msk_softc->msk_hw_id) { + case CHIP_ID_YUKON_FE: + case CHIP_ID_YUKON_FE_P: + error = EINVAL; + break; + case CHIP_ID_YUKON_EC_U: + /* + * In Yukon EC Ultra, TSO & checksum offload + * is not supported for jumbo frame. + */ + ifp->if_hwassist &= + ~(MSK_CSUM_FEATURES | CSUM_TSO); + ifp->if_capenable &= + ~(IFCAP_TSO4 | IFCAP_TXCSUM); + VLAN_CAPABILITIES(ifp); + break; + default: + break; + } + } + if (error != 0) { + MSK_IF_UNLOCK(sc_if); break; } - MSK_IF_LOCK(sc_if); ifp->if_mtu = ifr->ifr_mtu; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) msk_init_locked(sc_if); @@ -974,25 +997,29 @@ MSK_IF_LOCK(sc_if); mask = ifr->ifr_reqcap ^ ifp->if_capenable; if ((mask & IFCAP_TXCSUM) != 0) { - ifp->if_capenable ^= IFCAP_TXCSUM; - if ((IFCAP_TXCSUM & ifp->if_capenable) != 0 && - (IFCAP_TXCSUM & ifp->if_capabilities) != 0) - ifp->if_hwassist |= MSK_CSUM_FEATURES; - else - ifp->if_hwassist &= ~MSK_CSUM_FEATURES; + if ((IFCAP_TXCSUM & ifp->if_capabilities) != 0) { + ifp->if_capenable ^= IFCAP_TXCSUM; + 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) { - ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; - msk_setvlan(sc_if, ifp); + if ((ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { + ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + msk_setvlan(sc_if, ifp); + } } if ((mask & IFCAP_TSO4) != 0) { - ifp->if_capenable ^= IFCAP_TSO4; - if ((IFCAP_TSO4 & ifp->if_capenable) != 0 && - (IFCAP_TSO4 & ifp->if_capabilities) != 0) - ifp->if_hwassist |= CSUM_TSO; - else - ifp->if_hwassist &= ~CSUM_TSO; + if ((IFCAP_TSO4 & ifp->if_capabilities) != 0) { + ifp->if_capenable ^= IFCAP_TSO4; + 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) { @@ -1081,7 +1108,7 @@ static void msk_phy_power(struct msk_softc *sc, int mode) { - uint32_t val; + uint32_t our, val; int i; switch (mode) { @@ -1107,16 +1134,18 @@ 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); + switch (sc->msk_hw_id) { + case 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; + } + break; + case CHIP_ID_YUKON_EC_U: + 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); @@ -1127,9 +1156,13 @@ 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); + 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); @@ -1487,9 +1520,19 @@ 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; + if (sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_FE_P && + sc_if->msk_softc->msk_hw_rev == CHIP_REV_YU_FE_P_A0) { + /* + * Due to the FE+'s status writeback bug, msk(4) ignores + * status word in msk_rxeof(). So msk(4) canot take + * advantage of VLAN hardware assistance. + */ + ifp->if_capabilities |= IFCAP_VLAN_MTU; + } else { + ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; + if (ifp->if_capabilities & IFCAP_HWCSUM) + ifp->if_capabilities |= IFCAP_VLAN_HWCSUM; + } ifp->if_capenable = ifp->if_capabilities; /* @@ -1630,6 +1673,9 @@ case CHIP_ID_YUKON_FE: sc->msk_clock = 100; /* 100 Mhz */ break; + case CHIP_ID_YUKON_FE_P: + sc->msk_clock = 50; /* 50 Mhz */ + break; case CHIP_ID_YUKON_XL: sc->msk_clock = 156; /* 156 Mhz */ break; @@ -2633,11 +2679,19 @@ /* Check TSO support. */ if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { - tso_mtu = offset + m->m_pkthdr.tso_segsz; + /* FE+ uses different Op code and format. */ + if (sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_FE_P) + 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_softc->msk_hw_id == CHIP_ID_YUKON_FE_P) + 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; @@ -2932,14 +2986,27 @@ if ((status & GMR_FS_VLAN) != 0 && (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) rxlen -= ETHER_VLAN_ENCAP_LEN; + 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. */ - if ((status & GMR_FS_GOOD_FC) == 0) - ifp->if_ierrors++; - msk_discard_rxbuf(sc_if, cons); - break; + if (sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_FE_P && + sc_if->msk_softc->msk_hw_rev == + CHIP_REV_YU_FE_P_A0) { + /* + * XXX + * According to Linux, this FE+ generates + * bogus status LEs so it cannot rely on + * hardware status. Let upper layer handle + * recevied frame. + */ + } else { + /* Don't count flow-control packet as errors. */ + if ((status & GMR_FS_GOOD_FC) == 0) + ifp->if_ierrors++; + msk_discard_rxbuf(sc_if, cons); + break; + } } rxd = &sc_if->msk_cdata.msk_rxdesc[cons]; m = rxd->rx_m; @@ -3557,6 +3624,7 @@ 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); @@ -3645,8 +3713,11 @@ /* 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_rev == CHIP_REV_YU_FE_P_A0) + 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); @@ -3658,9 +3729,16 @@ 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. + * Increase the threshold to workaround pause bug. - From Linux. + */ + 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_4(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); --- if_mskreg.h.orig 2007-12-05 18:41:58.000000000 +0900 +++ if_mskreg.h 2008-01-24 19:32:54.000000000 +0900 @@ -130,7 +130,8 @@ #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_4360 0x4360 #define DEVICEID_MRVL_4361 0x4361 #define DEVICEID_MRVL_4362 0x4362 @@ -828,6 +829,7 @@ #define CHIP_ID_YUKON_EC_U 0xb4 /* Chip ID for YUKON-2 EC Ultra */ #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 +843,8 @@ #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 */ + /* 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 */ @@ -1818,6 +1822,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 +1851,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 */ @@ -2113,6 +2122,8 @@ #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