NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/42422: NetBSD 4.x and 5.x lacks support for Intel 82575/82576 NIC's



>Number:         42422
>Category:       kern
>Synopsis:       NetBSD 4.x and 5.x lacks support for Intel 82575/82576 NIC's
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Dec 07 15:35:00 +0000 2009
>Originator:     Dr. Wolfgang Stukenbrock
>Release:        NetBSD 4.0
>Organization:
Dr. Nagler & Company GmbH
        
>Environment:
        
        
System: NetBSD s012 4.0 NetBSD 4.0 (NSW-S012) #9: Fri Mar 13 12:31:52 CET 2009 
wgstuken@s012:/usr/src/sys/arch/amd64/compile/NSW-S012 amd64
Architecture: x86_64
Machine: amd64
>Description:
        There is no support in 4.x and 5.x of NetBSD for Intel's latest 
1000Tx-chips.
        Accedently Intel has retiered most of the supported chips, so there is 
a support problem for
        actual hardware.
        I've found a driver in FreeBSD that seems to base on Intel-Sources. In 
this driver there
        is a new interface type for the 82575 and 82676.
        Most code parts are still shared with to older chips, but the 
freeBSD-driver uses the new advanced
        recieve buffer descriptors of the chip that are required if someone is 
gooing to use the advanced
        features (e.g. virtualisation) of theese chips.
        As far as I see, NetBSD does not support features like that, so that it 
is possible to use the
        legacy interface of the 82575/82576.

        The following patches enables the 82575 found on the Intel X38ML board.

        remarks:
        - The patch supports only the 82575. Accedently I found no HW-Manual 
for the 82575, so I have used
          the 82576 manual and the freeBSD-driver as reference.
        - The patch does not support Fiber, Serdes or SGMII PHY. The X38ML 
board has a normal GMII-Phy, so I
          couldn't test any other. The Fiber/Serdes version may work with some 
small changes. The SGMII interface
          via I2C is completly new.
        - I simply do not know what some of the timing parameter used in the 
NetBSD-wm-driver or the freeBSD-driver mean.
          So someone that has advanced knowledge on that should have a look at 
it prior integrating it into NetBSD!
        - The support for non-EEPROM setups is taken from freeBSD. I've no 
chance to test it ...
        - Some registers changes their address starting with the 82575. They 
are still reachable vie the old addresse.
          Due to the fact, that the first one of them are still rachable on the 
old addresses for comparbility reasons,
          I have only added the new addresses in if_wmreg.h, but still use the 
old ones. Affected are the Queues, but
          NetBSD uses only queue 0.
        - The 82575 cannot be initialized until the RX-Queue is enabled. 
Therefore I moved some parts of the setup
          to a the end of the setup.
          I think this oulb be a good idea for all chips, but I've no manual 
for the old ones.
          In fact, the RDT register is written twice on every chip - that makes 
no sence ...
          (first when allocating the memory while the Rx-queue is still 
disables and than again after another reset of the chip.)


        Other bugs found in the current NetBSD wm driver version:
        - while waiting for the chip, the timeout variable is not decrented!
          If a chip will not get ready the dirver will hang - this is fixed in 
the patch.
        - in wm_attach some settings for the GPIO-Pins are extracted from the 
EEPROM and set into the CTLR register.
          This information is lost after the next chip-reset, e.g. when 
configuring the interface via "ifconfig".
          The EEPROM-Info is not applied again in the CTLR-register setup.
          For the X38ML-board this results in not setting the 
Watchdog-enable-bit again.
          I have no idea about the side effects when the bit is not set again.
          This issue is NOT addresses in this patch! The EEPROM-information is 
still lost after every chip-reset!
          (At least on the X38ML-Board with the BIOS-setup we are using, it 
seems to have no effect, but ...)
          I found this by printing the CTLR register on every change for 
debugging purpose.

          The patches works fine for us. We have no problems with it up to now.
>How-To-Repeat:
        not relevant.
>Fix:
        The following patches to the pcidevs-database, if_wm.c and if_wmreg.h 
enables support for the 82575
        found on the Intel X38ML-Serverboard. The set of pcidevs added to the 
pcidevs-database includes only the 82575
        version (not the 82576 ones), but all of them.
        I cannot garantie that other chips as the i82575EB (0x10a7) will work. 
(the two BG-versions will be recognized too ...)
        We are currently running an "upgraded" version of the wm-driver from 
NetBSD-4.0 - upgraded from current version
        some time ago. We have needed support for some additional chips ...
        I've verified that there is still no support for the 82575/82576 in 
current, but I cannot garantie that
        the line numbers matches the current version or that there are no 
effects that belongs to the latest changes
        in the LWP management in NetBSD 5.0 and later. Sorry.


--- pcidevs     2009/04/14 12:32:59     1.3
+++ pcidevs     2009/12/07 14:36:01
@@ -2045,6 +2045,8 @@
 product INTEL 82546GB_QUAD_COPPER 0x1099 i82546GB quad-port Gigabit Ethernet
 product INTEL 82573L           0x109a  i82573L Gigabit Ethernet
 product INTEL 82571EB_QUAD_COPPER 0x10a4 i82571EB quad-1000baseT Ethernet
+product INTEL 82575EB_COPPER   0x10a7 i82575EB dual-1000baseT Ethernet
+product INTEL 82575EB_FIBER_SERDES 0x10a9 i82575EB dual-1000baseX Ethernet 
(SERDES)
 product INTEL 82546GB_QUAD_COPPER_KSP3 0x10b5 i82546GB quad-port Gigabit 
Ethernet (KSP3)
 product INTEL 82572EI          0x10b9  i82572EI 1000baseT Ethernet
 product INTEL 80K3LAN_CPR_SPT 0x10ba   i80003 1000baseT Ethernet
@@ -2060,8 +2062,10 @@
 product INTEL 82801I_IGP_M_V   0x10cb  i82801H IGP (MV) LAN Controller
 product INTEL 82801J_D_BM_LF   0x10cd  i82801J (LF) LAN Controller
 product INTEL 82574L           0x10d3  i82574L 1000baseT Ethernet
+product INTEL 82575GB_QUAD_COPPER 0x10d6 i82575GB quad-1000baseT Ethernet
 product INTEL 82567LM_3                0x10de  i82567LM-3 LAN Controller
 product INTEL 82567LF_3                0x10df  i82567LF-3 LAN Controller
+product INTEL 82575GB_QUAD_COPPER_PM 0x10e2 i82575GB Quad-1000baseT Ethernet 
(PM)
 product INTEL 82801I_IGP_M_AMT 0x10f5  82801I Mobile (AMT) LAN Controller
 product INTEL 82815_DC100_HUB  0x1100  82815 Hub
 product INTEL 82815_DC100_AGP  0x1101  82815 AGP


--- pcidevs.h   2009/04/14 12:32:59     1.3
+++ pcidevs.h   2009/12/07 14:36:13
@@ -2052,6 +2052,9 @@
 #define        PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER   0x1099          /* 
i82546GB quad-port Gigabit Ethernet */
 #define        PCI_PRODUCT_INTEL_82573L        0x109a          /* i82573L 
Gigabit Ethernet */
 #define        PCI_PRODUCT_INTEL_82571EB_QUAD_COPPER   0x10a4          /* 
i82571EB quad-1000baseT Ethernet */
+#define        PCI_PRODUCT_INTEL_82571EB_QUAD_COPPER   0x10a4          /* 
i82571EB quad-1000baseT Ethernet */
+#define PCI_PRODUCT_INTEL_82575EB_COPPER           0x10A7
+#define PCI_PRODUCT_INTEL_82575EB_FIBER_SERDES     0x10A9
 #define        PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER_KSP3      0x10b5          
/* i82546GB quad-port Gigabit Ethernet (KSP3) */
 #define        PCI_PRODUCT_INTEL_82572EI       0x10b9          /* i82572EI 
1000baseT Ethernet */
 #define        PCI_PRODUCT_INTEL_80K3LAN_CPR_SPT       0x10ba          /* 
i80003 1000baseT Ethernet */
@@ -2067,8 +2070,10 @@
 #define        PCI_PRODUCT_INTEL_82801H_IGP_M_V        0x10cb          /* 
i82801H IGP (MV) LAN Controller */
 #define        PCI_PRODUCT_INTEL_82801J_D_BM_LF        0x10cd          /* 
i82801J (LF) LAN Controller */
 #define        PCI_PRODUCT_INTEL_82574L        0x10d3          /* i82574L 
1000baseT Ethernet */
+#define PCI_PRODUCT_INTEL_82575GB_QUAD_COPPER      0x10D6
 #define        PCI_PRODUCT_INTEL_82567LM_3     0x10de          /* i82567LM-3 
LAN Controller */
 #define        PCI_PRODUCT_INTEL_82567LF_3     0x10df          /* i82567LF-3 
LAN Controller */
+#define PCI_PRODUCT_INTEL_82575GB_QUAD_COPPER_PM   0x10E2
 #define        PCI_PRODUCT_INTEL_82801I_IGP_M_AMT      0x10f5          /* 
82801I Mobile (AMT) LAN Controller */
 #define        PCI_PRODUCT_INTEL_82815_DC100_HUB       0x1100          /* 
82815 Hub */
 #define        PCI_PRODUCT_INTEL_82815_DC100_AGP       0x1101          /* 
82815 AGP */


--- pcidevs_data.h      2009/04/14 12:32:59     1.3
+++ pcidevs_data.h      2009/12/07 14:36:45
@@ -7060,6 +7060,14 @@
            "i82571EB quad-1000baseT Ethernet",
        },
        {
+           PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575EB_COPPER,
+           "i82575EB dual-1000baseT Ethernet",
+       },
+       {
+           PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575EB_FIBER_SERDES,
+           "i82575EB dual-1000baseX Ethernet (SERDES)",
+       },
+       {
            PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER_KSP3,
            "i82546GB quad-port Gigabit Ethernet (KSP3)",
        },
@@ -7120,6 +7128,10 @@
            "i82574L 1000baseT Ethernet",
        },
        {
+           PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575GB_QUAD_COPPER,
+           "i82575GB quad-1000baseT Ethernet",
+       },
+       {
            PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82567LM_3,
            "i82567LM-3 LAN Controller",
        },
@@ -7128,6 +7140,10 @@
            "i82567LF-3 LAN Controller",
        },
        {
+           PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575GB_QUAD_COPPER_PM,
+           "i82575GB Quad-1000baseT Ethernet (PM)",
+       },
+       {
            PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_IGP_M_AMT,
            "82801I Mobile (AMT) LAN Controller",
        },
@@ -13196,4 +13212,4 @@
            "Video Controller",
        },
 };
-const int pci_nproducts = 2702;
+const int pci_nproducts = 2706;


--- if_wmreg.h  2009/04/14 12:33:22     1.3
+++ if_wmreg.h  2009/12/07 14:35:40
@@ -332,9 +332,11 @@
 #define        CTRL_EXT_RO_DIS         (1U << 17) /* relaxed ordering disabled 
*/
 #define        CTRL_EXT_LINK_MODE_MASK 0x00C00000
 #define        CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define        CTRL_EXT_LINK_MODE_SGMII 0x00800000
 #define        CTRL_EXT_LINK_MODE_TBI  0x00C00000
 #define        CTRL_EXT_LINK_MODE_KMRN 0x00000000
 #define        CTRL_EXT_LINK_MODE_SERDES 0x00C00000
+#define CTRL_EXT_I2C_ENA       0x02000000  /* I2C enable */
 #define        CTRL_EXT_DRV_LOAD       0x10000000
 
 
@@ -348,6 +350,12 @@
 #define        MDIC_I          (1U << 29)      /* interrupt on MDI complete */
 #define        MDIC_E          (1U << 30)      /* MDI error */
 
+#define WMREG_SCTL     0x0024  /* SerDes Control - RW */
+#define SCTL_CTL_READY  (1U << 31)     /* also used for other control 
registers on the 82575 for the no-EEPROM case */
+#define SCTL_CTL_DATA_MASK 0x000000ff  /* also used for other control 
registers on the 82575 for the no-EEPROM case */
+#define SCTL_CTL_ADDR_SHIFT 8          /* also used for other control 
registers on the 82575 for the no-EEPROM case */
+#define SCTL_CTL_POLL_TIMEOUT 640      /* also used for other control 
registers on the 82575 for the no-EEPROM case */
+
 #define        WMREG_FCAL      0x0028  /* Flow Control Address Low */
 #define        FCAL_CONST      0x00c28001      /* Flow Control MAC addr low */
 
@@ -438,25 +446,50 @@
 
 #define        WMREG_OLD_RDBAL0 0x0110 /* Receive Descriptor Base Low (ring 0) 
*/
 #define        WMREG_RDBAL     0x2800
+#define        WMREG_RDBAL_2   0x0c00  /* for 82576 ... */
 
 #define        WMREG_OLD_RDBAH0 0x0114 /* Receive Descriptor Base High (ring 
0) */
 #define        WMREG_RDBAH     0x2804
+#define        WMREG_RDBAH_2   0x0c04  /* for 82576 ... */
 
 #define        WMREG_OLD_RDLEN0 0x0118 /* Receive Descriptor Length (ring 0) */
 #define        WMREG_RDLEN     0x2808
+#define        WMREG_RDLEN_2   0x0c08  /* for 82576 ... */
+
+#define WMREG_SRRCTL   0x280c  /* additional recieve control used in 82575 ... 
*/
+#define WMREG_SRRCTL_2 0x0c0c  /* for 82576 ... */
+#define SRRCTL_BSIZEPKT_MASK                           0x0000007f
+#define SRRCTL_BSIZEPKT_SHIFT          10      /* Shift _right_ */
+#define SRRCTL_BSIZEHDRSIZE_MASK                       0x00000f00
+#define SRRCTL_BSIZEHDRSIZE_SHIFT      2       /* Shift _left_ */
+#define SRRCTL_DESCTYPE_LEGACY                         0x00000000
+#define SRRCTL_DESCTYPE_ADV_ONEBUF                     (1U << 25)
+#define SRRCTL_DESCTYPE_HDR_SPLIT                      (2U << 25)
+#define SRRCTL_DESCTYPE_HDR_REPLICATION                        (3U << 25)
+#define SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT      (4U << 25)
+#define SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS               (5U << 25) /* 82575 
only */
+#define SRRCTL_DESCTYPE_MASK                           (7U << 25)
+#define SRRCTL_DROP_EN                                 0x80000000
 
 #define        WMREG_OLD_RDH0  0x0120  /* Receive Descriptor Head (ring 0) */
 #define        WMREG_RDH       0x2810
+#define        WMREG_RDH_2     0x0c10  /* for 82576 ... */
 
 #define        WMREG_OLD_RDT0  0x0128  /* Receive Descriptor Tail (ring 0) */
 #define        WMREG_RDT       0x2818
+#define        WMREG_RDT_2     0x0c18  /* for 82576 ... */
 
 #define        WMREG_RXDCTL    0x2828  /* Receive Descriptor Control */
+#define        WMREG_RXDCTL_2  0x0c28  /* for 82576 ... */
 #define        RXDCTL_PTHRESH(x) ((x) << 0)    /* prefetch threshold */
 #define        RXDCTL_HTHRESH(x) ((x) << 8)    /* host threshold */
 #define        RXDCTL_WTHRESH(x) ((x) << 16)   /* write back threshold */
 #define        RXDCTL_GRAN     (1U << 24)      /* 0 = cacheline, 1 = 
descriptor */
 
+/* flags used starting with 82575 ... */
+#define RXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Tx Queue */
+#define RXDCTL_SWFLSH        0x04000000 /* Rx Desc. write-back flushing */
+
 #define        WMREG_OLD_RDTR1 0x0130  /* Receive Delay Timer (ring 1) */
 
 #define        WMREG_OLD_RDBA1_LO 0x0138 /* Receive Descriptor Base Low (ring 
1) */
@@ -582,6 +615,11 @@
 #define        TXDCTL_HTHRESH(x) ((x) << 8)    /* host threshold */
 #define        TXDCTL_WTHRESH(x) ((x) << 16)   /* write back threshold */
 
+/* flags used starting with 82575 ... */
+#define TXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Tx Queue */
+#define TXDCTL_SWFLSH        0x04000000 /* Tx Desc. write-back flushing */
+#define TXDCTL_PRIORITY      0x08000000
+
 #define        WMREG_TADV      0x382c  /* Transmit Absolute Interrupt Delay 
Timer */
 
 #define        WMREG_AIT       0x0458  /* Adaptive IFS Throttle */
@@ -608,6 +646,28 @@
 
 #define        WMREG_PBS       0x1000  /* Packet Buffer Size (ICH8 only ?) */
 
+#define WMREG_EICS     0x01520  /* Ext. Interrupt Cause Set - W0 */
+#define WMREG_EIMS     0x01524  /* Ext. Interrupt Mask Set/Read - RW */
+#define WMREG_EIMC     0x01528  /* Ext. Interrupt Mask Clear - WO */
+#define WMREG_EIAC     0x0152C  /* Ext. Interrupt Auto Clear - RW */
+#define WMREG_EIAM     0x01530  /* Ext. Interrupt Ack Auto Clear Mask - RW */
+
+#define WMREG_EICR     0x01580  /* Ext. Interrupt Cause Read - R/clr */
+
+#define EITR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */
+#define EITR_RX_QUEUE1 0x00000002 /* Rx Queue 1 Interrupt */
+#define EITR_RX_QUEUE2 0x00000004 /* Rx Queue 2 Interrupt */
+#define EITR_RX_QUEUE3 0x00000008 /* Rx Queue 3 Interrupt */
+#define EITR_TX_QUEUE0 0x00000100 /* Tx Queue 0 Interrupt */
+#define EITR_TX_QUEUE1 0x00000200 /* Tx Queue 1 Interrupt */
+#define EITR_TX_QUEUE2 0x00000400 /* Tx Queue 2 Interrupt */
+#define EITR_TX_QUEUE3 0x00000800 /* Tx Queue 3 Interrupt */
+#define EITR_TCP_TIMER 0x40000000 /* TCP Timer */
+#define EITR_OTHER     0x80000000 /* Interrupt Cause Active */
+
+#define WMREG_EITR(x)  (0x01680 + (0x4 * (x)))
+#define EITR_ITR_INT_MASK      0x0000ffff
+
 #define        WMREG_TXDMAC    0x3000  /* Transfer DMA Control */
 #define        TXDMAC_DPP      (1U << 0)       /* disable packet prefetch */
 
@@ -622,6 +682,8 @@
 #define        RXCSUM_TUOFL    (1U << 9)       /* TCP/UDP checksum offload */
 #define        RXCSUM_IPV6OFL  (1U << 10)      /* IPv6 checksum offload */
 
+#define WMREG_RLPML    0x5004  /* Rx Long Packet Max Length */
+
 #define        WMREG_RXERRC    0x400C  /* receive error Count - R/clr */
 #define        WMREG_COLC      0x4028  /* collision Count - R/clr */
 #define        WMREG_XONRXC    0x4048  /* XON Rx Count - R/clr */
@@ -662,6 +724,10 @@
 
 #define        WMREG_MANC2H    0x5860  /* Managment Control To Host - RW */
 
+#define WMREG_CCMCTL   0x5b48  /* CCM Control Register */
+#define WMREG_GIOCTL   0x5b44  /* GIO Analog Control Register */
+#define WMREG_SCCTL    0x5b4c  /* PCIc PLL Configuration Register */
+
 #define        WMREG_SWSM      0x5b50  /* SW Semaphore */
 #define        SWSM_SMBI       0x00000001      /* Driver Semaphore bit */
 #define        SWSM_SWESMBI    0x00000002      /* FW Semaphore bit */


--- if_wm.c     2009/04/14 12:33:48     1.3
+++ if_wm.c     2009/12/07 14:37:24
@@ -253,6 +253,7 @@
        WM_T_ICH8,                      /* ICH8 LAN */
        WM_T_ICH9,                      /* ICH9 LAN */
        WM_T_ICH10,                     /* ICH10 LAN */
+       WM_T_82575,                     /* i82575 */
 } wm_chip_type;
 
 #define WM_LINKUP_TIMEOUT      50
@@ -561,6 +562,9 @@
 static int     wm_gmii_i82544_readreg(struct device *, int, int);
 static void    wm_gmii_i82544_writereg(struct device *, int, int, int);
 
+static int     wm_gmii_i82575_readreg(struct device *, int, int);
+static void    wm_gmii_i82575_writereg(struct device *, int, int, int);
+
 static int     wm_gmii_i80003_readreg(struct device *, int, int);
 static void    wm_gmii_i80003_writereg(struct device *, int, int, int);
 
@@ -894,6 +898,20 @@
        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801J_D_BM_LF,
          "i82801J (LF) LAN Controller",
          WM_T_ICH10,           WMP_F_1000T },
+       { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82575EB_COPPER,
+         "i82575EB dual-1000baseT Ethernet",
+         WM_T_82575,           WMP_F_1000T },
+#if 0 /* not shure if WMP_F_1000X or WMP_F_SERDES - we do not have it - so 
disabled for now .. */
+       { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82575EB_FIBER_SERDES,
+         "i82575EB dual-1000baseX Ethernet (SERDES)",
+         WM_T_82575,           WMP_F_SERDES },
+#endif
+       { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82575GB_QUAD_COPPER,
+         "i82575GB Quad-1000baseT Ethernet",
+         WM_T_82575,           WMP_F_1000T },
+       { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82575GB_QUAD_COPPER_PM,
+         "i82575GB Quad-1000baseT Ethernet (PM)",
+         WM_T_82575,           WMP_F_1000T },
        { 0,                    0,
          NULL,
          0,                    0 },
@@ -955,6 +973,26 @@
        return (0);
 }
 
+static inline void _82575_write_8bit_ctlr_reg(struct wm_softc *sc, uint32_t 
reg, uint32_t off, uint32_t data)
+{
+  uint32_t regval = (data & SCTL_CTL_DATA_MASK) | (off << SCTL_CTL_ADDR_SHIFT);
+  int i;
+
+  CSR_WRITE(sc, reg, regval);
+
+  for (i = 0; i < SCTL_CTL_POLL_TIMEOUT; i++)
+    {
+      delay(5);
+      if (CSR_READ(sc, reg) & SCTL_CTL_READY)
+       break;
+    }
+  if (i == SCTL_CTL_POLL_TIMEOUT)
+    {
+      aprint_error("%s: WARNING: i82575 reg 0x%08x setup did not indicate 
ready\n",
+       sc->sc_dev.dv_xname, reg);
+    }
+}
+
 static void
 wm_attach(struct device *parent, struct device *self, void *aux)
 {
@@ -1300,6 +1338,38 @@
        wm_reset(sc);
 
        switch (sc->sc_type) {
+       case WM_T_82575:
+               reg = CSR_READ(sc, WMREG_EECD);
+               if ((reg & EECD_EE_PRES) == 0) {
+                       /* special case - for 82575 - need to do manual init 
... */
+                       /* remark: this is untested code - we have no board 
without EEPROM
+                        *         same setup as mentioned int the freeBSD 
driver for the i82575
+                        */
+                       sc->sc_flags |= WM_F_EEPROM_INVALID; /* mark no EEPROM 
present ... */
+
+                       /* SerDes configuration via SERDESCTRL */
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_SCTL, 0x00, 0x0C);
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_SCTL, 0x01, 0x78);
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_SCTL, 0x1B, 0x23);
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_SCTL, 0x23, 0x15);
+
+                       /* CCM configuration via CCMCTL register */
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_CCMCTL, 0x14, 
0x00);
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_CCMCTL, 0x10, 
0x00);
+
+                       /* PCIe lanes configuration */
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_GIOCTL, 0x00, 
0xEC);
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_GIOCTL, 0x61, 
0xDF);
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_GIOCTL, 0x34, 
0x05);
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_GIOCTL, 0x2F, 
0x81);
+
+                       /* PCIe PLL Configuration */
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x02, 0x47);
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x14, 0x00);
+                       _82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x10, 0x00);
+
+               }
+               /* fall throught ... */
        case WM_T_82571:
        case WM_T_82572:
        case WM_T_82573:
@@ -1346,6 +1416,8 @@
                sc->sc_flags |= WM_F_EEPROM_EERDEEWR;
        else if (sc->sc_type > WM_T_82544)
                sc->sc_flags |= WM_F_EEPROM_HANDSHAKE;
+       else if (sc->sc_type == WM_T_82575)
+               sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_SWFW_SYNC; /* XXXX 
just like 80003 .... just a guess ... */
 
        if (sc->sc_type <= WM_T_82544)
                sc->sc_ee_addrbits = 6;
@@ -1365,7 +1437,7 @@
        } else if ((sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574) &&
            (wm_is_onboard_nvm_eeprom(sc) == 0)) {
                sc->sc_flags |= WM_F_EEPROM_FLASH;
-       } else {
+       } else if (!(sc->sc_flags & WM_F_EEPROM_INVALID)) {
                /* Assume everything else is SPI. */
                reg = CSR_READ(sc, WMREG_EECD);
                sc->sc_flags |= WM_F_EEPROM_SPI;
@@ -1382,7 +1454,7 @@
         * Validate the EEPROM checksum. If the checksum fails, flag this for
         * later, so we can fail future reads from the EEPROM.
         */
-       if (wm_validate_eeprom_checksum(sc)) {
+       if (!(sc->sc_flags & WM_F_EEPROM_INVALID) && 
wm_validate_eeprom_checksum(sc)) {
                /*
                 * Read twice again because some PCI-e parts fail the first
                 * check due to the link being in sleep state.
@@ -1434,7 +1506,8 @@
         * of the dual port controller.
         */
        if (sc->sc_type == WM_T_82546 || sc->sc_type == WM_T_82546_3
-           || sc->sc_type ==  WM_T_82571 || sc->sc_type == WM_T_80003) {
+           || sc->sc_type ==  WM_T_82571 || sc->sc_type == WM_T_80003
+           || sc->sc_type ==  WM_T_82575) {
                if ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1)
                        enaddr[5] ^= 1;
        }
@@ -1547,6 +1620,21 @@
            || sc->sc_type == WM_T_82574) {
                /* STATUS_TBIMODE reserved/reused, can't rely on it */
                wm_gmii_mediainit(sc);
+       } else if (sc->sc_type >= WM_T_82575) {
+               reg = CSR_READ(sc, WMREG_CTRL_EXT);
+               if ((reg & CTRL_EXT_LINK_MODE_MASK) == 
CTRL_EXT_LINK_MODE_SERDES) {
+                       reg |= CTRL_EXT_I2C_ENA;
+aprint_error("%s: CTRL_EXT 0x%08x - WARNING - internal SERDES - still not 
supported ...\n", sc->sc_dev.dv_xname, reg);
+wm_reset(sc); goto fail_5;
+               } else if (reg & CTRL_EXT_LINK_MODE_SGMII) {
+                       reg |= CTRL_EXT_I2C_ENA;
+aprint_error("%s: CTRL_EXT 0x%08x - WARNING - SGMII - still not supported 
...\n", sc->sc_dev.dv_xname, reg);
+wm_reset(sc); goto fail_5;
+               } else {
+                       reg &= ~CTRL_EXT_I2C_ENA;
+               }
+               CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+               wm_gmii_mediainit(sc);
        } else if (sc->sc_type < WM_T_82543 ||
            (CSR_READ(sc, WMREG_STATUS) & STATUS_TBIMODE) != 0) {
                if (wmp->wmp_flags & WMP_F_1000T)
@@ -3011,6 +3099,7 @@
        case WM_T_82571:
        case WM_T_82572:                
        case WM_T_80003:                
+       case WM_T_82575:                /* XXXX not 100% shure, but set in 
freebsd driver  .. */
                sc->sc_pba = PBA_32K;
                break;
        case WM_T_82573:
@@ -3038,7 +3127,7 @@
                sc->sc_ctrl |= CTRL_GIO_M_DIS;
                CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
 
-               while (timeout) {
+               while (timeout--) {
                        if ((CSR_READ(sc, WMREG_STATUS) & STATUS_GIO_M_ENA) == 
0)
                                break;
                        delay(100);
@@ -3202,6 +3291,7 @@
        case WM_T_ICH8:
        case WM_T_ICH9:
        case WM_T_ICH10:
+       case WM_T_82575:
                if (wm_check_mng_mode(sc) != 0)
                        wm_get_hw_control(sc);
                break;
@@ -3232,10 +3322,15 @@
                CSR_WRITE(sc, WMREG_TIDV, 375);         /* ITR / 4 */
                CSR_WRITE(sc, WMREG_TADV, 375);         /* should be same */
 
-               CSR_WRITE(sc, WMREG_TXDCTL, TXDCTL_PTHRESH(0) |
-                   TXDCTL_HTHRESH(0) | TXDCTL_WTHRESH(0));
-               CSR_WRITE(sc, WMREG_RXDCTL, RXDCTL_PTHRESH(0) |
-                   RXDCTL_HTHRESH(0) | RXDCTL_WTHRESH(1));
+               if (sc->sc_type < WM_T_82575) {
+                       CSR_WRITE(sc, WMREG_TXDCTL, TXDCTL_PTHRESH(0) |
+                           TXDCTL_HTHRESH(0) | TXDCTL_WTHRESH(0));
+                       CSR_WRITE(sc, WMREG_RXDCTL, RXDCTL_PTHRESH(0) |
+                           RXDCTL_HTHRESH(0) | RXDCTL_WTHRESH(1));
+               } else { /* remark: not shure if RX-part can be initialized 
here - better to it below ... */
+                       CSR_WRITE(sc, WMREG_TXDCTL, TXDCTL_QUEUE_ENABLE | 
TXDCTL_PTHRESH(0) |
+                           TXDCTL_HTHRESH(0) | TXDCTL_WTHRESH(0));
+               }
        }
        CSR_WRITE(sc, WMREG_TQSA_LO, 0);
        CSR_WRITE(sc, WMREG_TQSA_HI, 0);
@@ -3269,10 +3364,25 @@
                CSR_WRITE(sc, WMREG_RDBAH, WM_CDRXADDR_HI(sc, 0));
                CSR_WRITE(sc, WMREG_RDBAL, WM_CDRXADDR_LO(sc, 0));
                CSR_WRITE(sc, WMREG_RDLEN, sizeof(sc->sc_rxdescs));
-               CSR_WRITE(sc, WMREG_RDH, 0);
-               CSR_WRITE(sc, WMREG_RDT, 0);
-               CSR_WRITE(sc, WMREG_RDTR, 375 | RDTR_FPD);      /* ITR/4 */
-               CSR_WRITE(sc, WMREG_RADV, 375);         /* MUST be same */
+               if (sc->sc_type >= WM_T_82575) {
+                       /* setup interupt moderation for the all used interrupt 
queues ... */
+                       CSR_WRITE(sc, WMREG_EITR(0), 450); /* default 
igb_ave_latency from freebsd-driver ... - not shure if this makes any sence */
+                       if (MCLBYTES & ((1 << SRRCTL_BSIZEPKT_SHIFT) - 1))
+                               panic("wm_init: MCLBYTES %d unsupported for 
82575", MCLBYTES);
+                       CSR_WRITE(sc, WMREG_SRRCTL, SRRCTL_DESCTYPE_LEGACY | 
(MCLBYTES >> SRRCTL_BSIZEPKT_SHIFT));
+#if 1 /* values from freebsd - not shure if they are good ... */
+                       CSR_WRITE(sc, WMREG_RXDCTL, RXDCTL_QUEUE_ENABLE | 
RXDCTL_PTHRESH(16) |
+                           RXDCTL_HTHRESH(8) | RXDCTL_WTHRESH(1));
+#else
+                       CSR_WRITE(sc, WMREG_RXDCTL, RXDCTL_QUEUE_ENABLE | 
RXDCTL_PTHRESH(0) |
+                           RXDCTL_HTHRESH(0) | RXDCTL_WTHRESH(1));
+#endif
+               } else { /* some registers that are no longer present, have 
different semantics or must be set later on 82575 and later ... */
+                       CSR_WRITE(sc, WMREG_RDH, 0);
+                       CSR_WRITE(sc, WMREG_RDT, 0);
+                       CSR_WRITE(sc, WMREG_RDTR, 375 | RDTR_FPD);      /* 
ITR/4 */
+                       CSR_WRITE(sc, WMREG_RADV, 375);         /* MUST be same 
*/
+               }
        }
        for (i = 0; i < WM_NRXDESC; i++) {
                rxs = &sc->sc_rxsoft[i];
@@ -3288,7 +3398,7 @@
                                wm_rxdrain(sc);
                                goto out;
                        }
-               } else
+               } else if (sc->sc_type < WM_T_82575) /* need to enable reciever 
prior setting RDT on 82575 and later */
                        WM_INIT_RXDESC(sc, i);
        }
        sc->sc_rxptr = 0;
@@ -3331,7 +3441,8 @@
 
        /* Write the control registers. */
        CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
-       if (sc->sc_type >= WM_T_80003 && (sc->sc_flags & WM_F_HAS_MII)) {
+       if (sc->sc_type>= WM_T_82575) { /* cannot fill in RDT - even if the 
EN-bit is set in RXDCTL, it is ignored until EN in RCTL is set ... */
+       } else if (sc->sc_type >= WM_T_80003 && (sc->sc_flags & WM_F_HAS_MII)) {
                int val;
                val = CSR_READ(sc, WMREG_CTRL_EXT);
                val &= ~CTRL_EXT_LINK_MODE_MASK;
@@ -3424,6 +3535,7 @@
            TCTL_COLD(TX_COLLISION_DISTANCE_FDX);
        if (sc->sc_type >= WM_T_82571)
                sc->sc_tctl |= TCTL_MULR;
+/* XXXX - order of WM_T_xxxx entries - the 82575 falls in here - this is 
correct here - freebsd-driver does it too ... */
        if (sc->sc_type >= WM_T_80003)
                sc->sc_tctl |= TCTL_RTLC;
        CSR_WRITE(sc, WMREG_TCTL, sc->sc_tctl);
@@ -3443,8 +3555,12 @@
        sc->sc_rctl = RCTL_EN | RCTL_LBM_NONE | RCTL_RDMTS_1_2 | RCTL_DPF
            | RCTL_MO(sc->sc_mchash_type);
 
+       if (sc->sc_type >= WM_T_82575) {
+               sc->sc_rctl |= RCTL_LPE;
+               CSR_WRITE(sc, WMREG_RLPML, ETHER_MAX_LEN_JUMBO);
+       }
        /* 82573 doesn't support jumbo frame */
-       if (sc->sc_type != WM_T_82573 && sc->sc_type != WM_T_82574 &&
+       else if (sc->sc_type != WM_T_82573 && sc->sc_type != WM_T_82574 &&
            sc->sc_type != WM_T_ICH8)
                sc->sc_rctl |= RCTL_LPE;
 
@@ -3472,6 +3588,11 @@
 
        /* Set the receive filter. */
        wm_set_filter(sc);
+       if (sc->sc_type>= WM_T_82575) { /* now fill in RDT - RCTL EN-bit has 
been set in the last function ... */
+               CSR_WRITE(sc, WMREG_RDH, 0); /* this is read-only on 82576, but 
freebsd driver write it too ... */
+               for (i = 0; i < WM_NRXDESC; i++)
+                       WM_INIT_RXDESC(sc, i);
+       }
 
        /* Start the one second link check clock. */
        callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc);
@@ -3540,6 +3661,7 @@
        /* Stop the transmit and receive processes. */
        CSR_WRITE(sc, WMREG_TCTL, 0);
        CSR_WRITE(sc, WMREG_RCTL, 0);
+       sc->sc_rctl &= ~RCTL_EN; /* clear EN bit again - needed for 82575 and 
later */
 
        /*
         * Clear the interrupt mask to ensure the device cannot assert its
@@ -3583,6 +3705,7 @@
        case WM_T_ICH8:
        case WM_T_ICH9:
        case WM_T_ICH10:
+       case WM_T_82575:
                for (i = 10; i > 0; i--) {
                        if (CSR_READ(sc, WMREG_EECD) & EECD_EE_AUTORD)
                                break;
@@ -3599,7 +3722,8 @@
        }
 
        /* Phy configuration starts after EECD_AUTO_RD is set */
-       if (sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574)
+/* XXXX - should the 82575 go here too ? - added for security reasons ... */
+       if (sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574 || 
sc->sc_type == WM_T_82575)
                delay(25000);
 }
 
@@ -3996,7 +4120,9 @@
        bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0,
            rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
 
-       WM_INIT_RXDESC(sc, idx);
+       if (sc->sc_type < WM_T_82575 || (sc->sc_rctl & RCTL_EN)) { /* on 575 
and later set RDT only if RX enabled... */
+               WM_INIT_RXDESC(sc, idx);
+       }
 
        return (0);
 }
@@ -4463,7 +4589,7 @@
                        return;
                }
        }
-       if (sc->sc_type == WM_T_80003) {
+       if (sc->sc_type == WM_T_80003 || sc->sc_type == WM_T_82575) {  /* XXXXX 
is this OK ??? - looks good to me */
                func = (CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1;
                if (wm_get_swfw_semaphore(sc,
                    func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
@@ -4508,7 +4634,7 @@
        if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
            || (sc->sc_type == WM_T_ICH10))
                wm_put_swfwhw_semaphore(sc);
-       if (sc->sc_type == WM_T_80003)
+       if (sc->sc_type == WM_T_80003 || sc->sc_type == WM_T_82575) /* XXXXX 
see above ... */
                wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
 }
 
@@ -4525,7 +4651,9 @@
        /* We have MII. */
        sc->sc_flags |= WM_F_HAS_MII;
 
-       if (sc->sc_type >= WM_T_80003)
+       if (sc->sc_type >= WM_T_82575) /* XXXX free bsd-driver sets normal 
default values here - but it does it for ich-chips too ... */
+               sc->sc_tipg = TIPG_1000T_DFLT;
+       else if (sc->sc_type >= WM_T_80003)
                sc->sc_tipg =  TIPG_1000T_80003_DFLT;
        else
                sc->sc_tipg = TIPG_1000T_DFLT;
@@ -4545,6 +4673,9 @@
        if (sc->sc_type == WM_T_ICH10) {
                sc->sc_mii.mii_readreg = wm_gmii_bm_readreg;
                sc->sc_mii.mii_writereg = wm_gmii_bm_writereg;
+       } else if (sc->sc_type >= WM_T_82575) {
+               sc->sc_mii.mii_readreg = wm_gmii_i82575_readreg;
+               sc->sc_mii.mii_writereg = wm_gmii_i82575_writereg;
        } else if (sc->sc_type >= WM_T_80003) {
                sc->sc_mii.mii_readreg = wm_gmii_i80003_readreg;
                sc->sc_mii.mii_writereg = wm_gmii_i80003_writereg;
@@ -4812,6 +4943,91 @@
 }
 
 /*
+ * wm_gmii_i82575_readreg:     [mii interface function]
+ *
+ *     Read a PHY register on the GMII.
+ */
+static int
+wm_gmii_i82575_readreg(struct device *self, int phy, int reg)
+{
+       struct wm_softc *sc = (void *) self;
+       uint32_t mdic = 0;
+       int i, rv;
+       int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+
+       if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+               aprint_error("%s: failed to get semaphore\n", 
sc->sc_dev.dv_xname);
+               return 0;
+       }
+
+       CSR_WRITE(sc, WMREG_MDIC, MDIC_OP_READ | MDIC_PHYADD(phy) |
+           MDIC_REGADD(reg));
+
+       for (i = 0; i < 320; i++) {
+               mdic = CSR_READ(sc, WMREG_MDIC);
+               if (mdic & MDIC_READY)
+                       break;
+               delay(10);
+       }
+
+       if ((mdic & MDIC_READY) == 0) {
+               log(LOG_WARNING, "%s: MDIC read timed out: phy %d reg %d\n",
+                   sc->sc_dev.dv_xname, phy, reg);
+               rv = 0;
+       } else if (mdic & MDIC_E) {
+#if 0 /* This is normal if no PHY is present. */
+               log(LOG_WARNING, "%s: MDIC read error: phy %d reg %d\n",
+                   sc->sc_dev.dv_xname, phy, reg);
+#endif
+               rv = 0;
+       } else {
+               rv = MDIC_DATA(mdic);
+               if (rv == 0xffff)
+                       rv = 0;
+       }
+
+       wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+       return (rv);
+}
+
+/*
+ * wm_gmii_i82575_writereg:    [mii interface function]
+ *
+ *     Write a PHY register on the GMII.
+ */
+static void
+wm_gmii_i82575_writereg(struct device *self, int phy, int reg, int val)
+{
+       struct wm_softc *sc = (void *) self;
+       uint32_t mdic = 0;
+       int i;
+       int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+
+       if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+               aprint_error("%s: failed to get semaphore\n", 
sc->sc_dev.dv_xname);
+               return;
+       }
+
+       CSR_WRITE(sc, WMREG_MDIC, MDIC_OP_WRITE | MDIC_PHYADD(phy) |
+           MDIC_REGADD(reg) | MDIC_DATA(val));
+
+       for (i = 0; i < 320; i++) {
+               mdic = CSR_READ(sc, WMREG_MDIC);
+               if (mdic & MDIC_READY)
+                       break;
+               delay(10);
+       }
+
+       if ((mdic & MDIC_READY) == 0)
+               log(LOG_WARNING, "%s: MDIC write timed out: phy %d reg %d\n",
+                   sc->sc_dev.dv_xname, phy, reg);
+       else if (mdic & MDIC_E)
+               log(LOG_WARNING, "%s: MDIC write error: phy %d reg %d\n",
+                   sc->sc_dev.dv_xname, phy, reg);
+       wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+}
+
+/*
  * wm_gmii_i80003_readreg:     [mii interface function]
  *
  *     Read a PHY register on the kumeran
@@ -5511,6 +5727,7 @@
        case WM_T_82572:
        case WM_T_82573:
        case WM_T_80003:
+       case WM_T_82575:
                rv = wm_check_mng_mode_generic(sc);
                break;
        default:
@@ -5586,6 +5803,7 @@
        case WM_T_ICH8:
        case WM_T_ICH9:
        case WM_T_ICH10:
+       case WM_T_82575:
                reg = CSR_READ(sc, WMREG_CTRL_EXT);
                CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_DRV_LOAD);
                break;

>Unformatted:
        
        


Home | Main Index | Thread Index | Old Index