msk(4): Add Yukon FE+ support
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 31 Jul 2011 09:31:36 +0000 (17:31 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 31 Jul 2011 09:31:36 +0000 (17:31 +0800)
Obtained-from: FreeBSD 192734 192735 192736

sys/dev/netif/msk/if_msk.c
sys/dev/netif/msk/if_mskreg.h

index 40c97b3..ed8d5be 100644 (file)
@@ -174,6 +174,14 @@ static const struct msk_product {
            "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_8040T,
+           "Marvell Yukon 88E8040T Fast Ethernet" },
+       { VENDORID_MARVELL, DEVICEID_MRVL_8048,
+           "Marvell Yukon 88E8048 Fast Ethernet" },
+       { VENDORID_MARVELL, DEVICEID_MRVL_8070,
+           "Marvell Yukon 88E8070 Fast Ethernet" },
        { VENDORID_MARVELL, DEVICEID_MRVL_4361,
            "Marvell Yukon 88E8050 Gigabit Ethernet" },
        { VENDORID_MARVELL, DEVICEID_MRVL_4360,
@@ -195,10 +203,11 @@ static const struct msk_product {
 
 static const char *model_name[] = {
        "Yukon XL",
-        "Yukon EC Ultra",
-        "Yukon Unknown",
-        "Yukon EC",
-        "Yukon FE"
+       "Yukon EC Ultra",
+       "Yukon Unknown",
+       "Yukon EC",
+       "Yukon FE",
+       "Yukon FE+"
 };
 
 static int     mskc_probe(device_t);
@@ -1027,6 +1036,7 @@ mskc_phy_power(struct msk_softc *sc, int mode)
                        }
                        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. */
@@ -1515,7 +1525,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);
                error = ENXIO;
@@ -1593,6 +1603,24 @@ mskc_attach(device_t dev)
                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 */
+               /* DESCV2 */
+               sc->msk_pflags |= MSK_FLAG_FASTETHER;
+               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_NORXCHK;
+               }
+               break;
        case CHIP_ID_YUKON_XL:
                sc->msk_clock = 156;    /* 156 Mhz */
                break;
@@ -2711,7 +2739,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 -= EVL_ENCAPLEN;
-               if (len > sc_if->msk_framesize ||
+               if (sc_if->msk_flags & MSK_FLAG_NORXCHK) {
+                       /*
+                        * 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. */
@@ -3238,6 +3277,7 @@ msk_init(void *xsc)
        struct mii_data  *mii;
        uint16_t eaddr[ETHER_ADDR_LEN / 2];
        uint16_t gmac;
+       uint32_t reg;
        int error, i;
 
        ASSERT_SERIALIZED(ifp->if_serializer);
@@ -3321,8 +3361,10 @@ msk_init(void *xsc)
        /* 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)
+               reg |= GMF_RX_OVER_ON;
+       CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T), reg);
 
        /* Set receive filter. */
        msk_rxfilter(sc_if);
@@ -3335,8 +3377,13 @@ msk_init(void *xsc)
         * Set Rx FIFO flush threshold to 64 bytes 1 FIFO word
         * due to hardware hang on receipt of pause frames.
         */
-       CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_FL_THR),
-           RX_GMF_FL_THR_DEF + 1);
+       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);
@@ -3368,6 +3415,14 @@ msk_init(void *xsc)
                }
        }
 
+       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.
index 733cad1..6ae877d 100644 (file)
 #define DEVICEID_MRVL_8036     0x4351
 #define DEVICEID_MRVL_8038     0x4352
 #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_8070     0x4365
 #define DEVICEID_MRVL_436A     0x436A
 
 /*
 #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 */
 #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 */
 #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 */
@@ -2365,6 +2376,7 @@ struct msk_if_softc {
        uint32_t                msk_flags;
 #define MSK_FLAG_FASTETHER     0x0004
 #define MSK_FLAG_RAMBUF                0x0010
+#define MSK_FLAG_NORXCHK       0x0100
        struct callout          msk_tick_ch;
        uint32_t                msk_txq;        /* Tx. Async Queue offset */
        uint32_t                msk_txsq;       /* Tx. Syn Queue offset */