ixgbe:add support for a new 82599 10G Base-T device
authorMallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com>
Fri, 21 May 2010 06:07:06 +0000 (23:07 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 21 May 2010 06:07:06 +0000 (23:07 -0700)
This adds support for a new copper device for 82599, device id 0x151c.
This 82599 10GBase-T device uses the PHY's internal temperature sensor
to guard against over-temp conditions. In this scenario the PHY will be
put in a low power mode and link will no longer be able to transmit or
receive any data. When this occurs, the over-temp interrupt is latched
and driver logs this error message. A HW reset or power cycle is
required to clear this status.

Signed-off-by: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_82598.c
drivers/net/ixgbe/ixgbe_82599.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_phy.c
drivers/net/ixgbe/ixgbe_phy.h
drivers/net/ixgbe/ixgbe_type.h

index d0ea3d6dea95f6f26b2fe3f9534c8b445c810cc6..ffae480587ae909fa482dda292f8802ca15565c8 100644 (file)
@@ -360,6 +360,7 @@ struct ixgbe_adapter {
        u32 flags2;
 #define IXGBE_FLAG2_RSC_CAPABLE                 (u32)(1)
 #define IXGBE_FLAG2_RSC_ENABLED                 (u32)(1 << 1)
+#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE         (u32)(1 << 2)
 /* default to trying for four seconds */
 #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ)
 
@@ -407,6 +408,8 @@ struct ixgbe_adapter {
        u16 eeprom_version;
 
        int node;
+       struct work_struct check_overtemp_task;
+       u32 interrupt_event;
 
        /* SR-IOV */
        DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
index f2b7ff44215b52b3f9608d6593d22792273727f5..9c02d6014cc43856fa405d8b0c0cc140aef63dde 100644 (file)
@@ -1236,6 +1236,7 @@ static struct ixgbe_phy_operations phy_ops_82598 = {
        .setup_link             = &ixgbe_setup_phy_link_generic,
        .setup_link_speed       = &ixgbe_setup_phy_link_speed_generic,
        .read_i2c_eeprom        = &ixgbe_read_i2c_eeprom_82598,
+       .check_overtemp   = &ixgbe_tn_check_overtemp,
 };
 
 struct ixgbe_info ixgbe_82598_info = {
index e9706eb8e4ff58fdb805e12094438a3e14437bb9..a4e2901f2f08e5bc585fb5889c174d754a2672e3 100644 (file)
@@ -2395,6 +2395,7 @@ static struct ixgbe_phy_operations phy_ops_82599 = {
        .write_i2c_byte         = &ixgbe_write_i2c_byte_generic,
        .read_i2c_eeprom        = &ixgbe_read_i2c_eeprom_generic,
        .write_i2c_eeprom       = &ixgbe_write_i2c_eeprom_generic,
+       .check_overtemp         = &ixgbe_tn_check_overtemp,
 };
 
 struct ixgbe_info ixgbe_82599_info = {
index 9551cbb7bf01f532e3a5705f9e54e45d0cf8ae6e..d571d101de08fb4c183af77cb9b64d10904d10a7 100644 (file)
@@ -108,6 +108,8 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
         board_82599 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4),
         board_82599 },
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM),
+        board_82599 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE),
         board_82599 },
 
@@ -1618,6 +1620,48 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
        }
 }
 
+/**
+ * ixgbe_check_overtemp_task - worker thread to check over tempurature
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbe_check_overtemp_task(struct work_struct *work)
+{
+       struct ixgbe_adapter *adapter = container_of(work,
+                                                    struct ixgbe_adapter,
+                                                    check_overtemp_task);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 eicr = adapter->interrupt_event;
+
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
+               switch (hw->device_id) {
+               case IXGBE_DEV_ID_82599_T3_LOM: {
+                       u32 autoneg;
+                       bool link_up = false;
+
+                       if (hw->mac.ops.check_link)
+                               hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
+
+                       if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
+                           (eicr & IXGBE_EICR_LSC))
+                               /* Check if this is due to overtemp */
+                               if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP)
+                                       break;
+                       }
+                       return;
+               default:
+                       if (!(eicr & IXGBE_EICR_GPI_SDP0))
+                               return;
+                       break;
+               }
+               DPRINTK(DRV, ERR, "Network adapter has been stopped because it "
+                       "has over heated. Restart the computer. If the problem "
+                       "persists, power off the system and replace the "
+                       "adapter\n");
+               /* write to clear the interrupt */
+               IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
+       }
+}
+
 static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
 {
        struct ixgbe_hw *hw = &adapter->hw;
@@ -1689,6 +1733,10 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
 
        if (hw->mac.type == ixgbe_mac_82599EB) {
                ixgbe_check_sfp_event(adapter, eicr);
+               adapter->interrupt_event = eicr;
+               if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+                   ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC)))
+                       schedule_work(&adapter->check_overtemp_task);
 
                /* Handle Flow Director Full threshold interrupt */
                if (eicr & IXGBE_EICR_FLOW_DIR) {
@@ -2190,6 +2238,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
        u32 mask;
 
        mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
+               mask |= IXGBE_EIMS_GPI_SDP0;
        if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
                mask |= IXGBE_EIMS_GPI_SDP1;
        if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
@@ -2250,6 +2300,9 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
                ixgbe_check_sfp_event(adapter, eicr);
 
        ixgbe_check_fan_failure(adapter, eicr);
+       if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+           ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC)))
+               schedule_work(&adapter->check_overtemp_task);
 
        if (napi_schedule_prep(&(q_vector->napi))) {
                adapter->tx_ring[0]->total_packets = 0;
@@ -3265,6 +3318,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
        }
 
+       /* Enable Thermal over heat sensor interrupt */
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
+               gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+               gpie |= IXGBE_SDP0_GPIEN;
+               IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+       }
+
        /* Enable fan failure interrupt if media type is copper */
        if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
                gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
@@ -3666,6 +3726,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
            adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
                cancel_work_sync(&adapter->fdir_reinit_task);
 
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
+               cancel_work_sync(&adapter->check_overtemp_task);
+
        /* disable transmits in the hardware now that interrupts are off */
        for (i = 0; i < adapter->num_tx_queues; i++) {
                j = adapter->tx_ring[i]->reg_idx;
@@ -4645,6 +4708,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
                adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
                adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
                adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
+               if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM)
+                       adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
                if (dev->features & NETIF_F_NTUPLE) {
                        /* Flow Director perfect filter enabled */
                        adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
@@ -6561,7 +6626,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        }
 
        /* reset_hw fills in the perm_addr as well */
+       hw->phy.reset_if_overtemp = true;
        err = hw->mac.ops.reset_hw(hw);
+       hw->phy.reset_if_overtemp = false;
        if (err == IXGBE_ERR_SFP_NOT_PRESENT &&
            hw->mac.type == ixgbe_mac_82598EB) {
                /*
@@ -6730,6 +6797,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
            adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
                INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task);
 
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
+               INIT_WORK(&adapter->check_overtemp_task, ixgbe_check_overtemp_task);
 #ifdef CONFIG_IXGBE_DCA
        if (dca_add_requester(&pdev->dev) == 0) {
                adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
index 22d21af1478326b7c332f72b7c2759566addb43c..09e1911ff510474ecda600446a51330d057647e3 100644 (file)
@@ -135,6 +135,11 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
  **/
 s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
 {
+       /* Don't reset PHY if it's shut down due to overtemp. */
+       if (!hw->phy.reset_if_overtemp &&
+           (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw)))
+               return 0;
+
        /*
         * Perform soft PHY reset to the PHY_XS.
         * This will cause a soft reset to the PHY
@@ -1345,3 +1350,28 @@ s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw,
        return status;
 }
 
+/**
+ *  ixgbe_tn_check_overtemp - Checks if an overtemp occured.
+ *  @hw: pointer to hardware structure
+ *
+ *  Checks if the LASI temp alarm status was triggered due to overtemp
+ **/
+s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
+{
+       s32 status = 0;
+       u16 phy_data = 0;
+
+       if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
+               goto out;
+
+       /* Check that the LASI temp alarm status was triggered */
+       hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
+                            MDIO_MMD_PMAPMD, &phy_data);
+
+       if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM))
+               goto out;
+
+       status = IXGBE_ERR_OVERTEMP;
+out:
+       return status;
+}
index c9c545941407fa5f09964c20040f52b5b78bef2f..ef4ba834c593e81220dfa78a9174646cb4289502 100644 (file)
@@ -80,6 +80,8 @@
 #define IXGBE_I2C_T_SU_STO  4
 #define IXGBE_I2C_T_BUF     5
 
+#define IXGBE_TN_LASI_STATUS_REG        0x9005
+#define IXGBE_TN_LASI_STATUS_TEMP_ALARM 0x0008
 
 s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw);
 s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw);
@@ -106,6 +108,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw);
 s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
                                         u16 *list_offset,
                                         u16 *data_offset);
+s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw);
 s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
                                 u8 dev_addr, u8 *data);
 s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
index 39b9be897439b1d745e7c739c5c0089d0b43bf0c..2eb6e151016cac10ca15eadfd9311283361e09b9 100644 (file)
@@ -51,6 +51,7 @@
 #define IXGBE_DEV_ID_82599_KX4           0x10F7
 #define IXGBE_DEV_ID_82599_KX4_MEZZ      0x1514
 #define IXGBE_DEV_ID_82599_KR            0x1517
+#define IXGBE_DEV_ID_82599_T3_LOM        0x151C
 #define IXGBE_DEV_ID_82599_CX4           0x10F9
 #define IXGBE_DEV_ID_82599_SFP           0x10FB
 #define IXGBE_DEV_ID_82599_SFP_EM        0x1507
@@ -2470,6 +2471,7 @@ struct ixgbe_phy_operations {
        s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8);
        s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *);
        s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8);
+       s32 (*check_overtemp)(struct ixgbe_hw *);
 };
 
 struct ixgbe_eeprom_info {
@@ -2518,6 +2520,7 @@ struct ixgbe_phy_info {
        enum ixgbe_smart_speed          smart_speed;
        bool                            smart_speed_active;
        bool                            multispeed_fiber;
+       bool                            reset_if_overtemp;
 };
 
 #include "ixgbe_mbx.h"
@@ -2605,6 +2608,7 @@ struct ixgbe_info {
 #define IXGBE_ERR_FDIR_REINIT_FAILED            -23
 #define IXGBE_ERR_EEPROM_VERSION                -24
 #define IXGBE_ERR_NO_SPACE                      -25
+#define IXGBE_ERR_OVERTEMP                      -26
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
 #endif /* _IXGBE_TYPE_H_ */