diff options
author | Jesse Brandeburg <jesse.brandeburg@intel.com> | 2008-09-11 22:55:32 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-09-24 18:54:49 -0400 |
commit | cf8280ee7be3aaf44d32e389f15c725b850e5e32 (patch) | |
tree | 3511ef0b19370597c7bd5fbe43a74d563522adeb /drivers/net/ixgbe/ixgbe_main.c | |
parent | ce94bf469edf84228771b58489944cf654aeb496 (diff) |
ixgbe: Update watchdog thread to accomodate longerlink_up events
This patch updates the link_up code and watchdog thread so that link_up
doesn't cause stack overflows due to long waits in interrupt context.
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_main.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 129 |
1 files changed, 86 insertions, 43 deletions
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 904819586e2a..036393e5383e 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
@@ -902,6 +902,20 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) | |||
902 | return; | 902 | return; |
903 | } | 903 | } |
904 | 904 | ||
905 | |||
906 | static void ixgbe_check_lsc(struct ixgbe_adapter *adapter) | ||
907 | { | ||
908 | struct ixgbe_hw *hw = &adapter->hw; | ||
909 | |||
910 | adapter->lsc_int++; | ||
911 | adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; | ||
912 | adapter->link_check_timeout = jiffies; | ||
913 | if (!test_bit(__IXGBE_DOWN, &adapter->state)) { | ||
914 | IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); | ||
915 | schedule_work(&adapter->watchdog_task); | ||
916 | } | ||
917 | } | ||
918 | |||
905 | static irqreturn_t ixgbe_msix_lsc(int irq, void *data) | 919 | static irqreturn_t ixgbe_msix_lsc(int irq, void *data) |
906 | { | 920 | { |
907 | struct net_device *netdev = data; | 921 | struct net_device *netdev = data; |
@@ -909,11 +923,8 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) | |||
909 | struct ixgbe_hw *hw = &adapter->hw; | 923 | struct ixgbe_hw *hw = &adapter->hw; |
910 | u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); | 924 | u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); |
911 | 925 | ||
912 | if (eicr & IXGBE_EICR_LSC) { | 926 | if (eicr & IXGBE_EICR_LSC) |
913 | adapter->lsc_int++; | 927 | ixgbe_check_lsc(adapter); |
914 | if (!test_bit(__IXGBE_DOWN, &adapter->state)) | ||
915 | mod_timer(&adapter->watchdog_timer, jiffies); | ||
916 | } | ||
917 | 928 | ||
918 | if (!test_bit(__IXGBE_DOWN, &adapter->state)) | 929 | if (!test_bit(__IXGBE_DOWN, &adapter->state)) |
919 | IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); | 930 | IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); |
@@ -1237,12 +1248,8 @@ static irqreturn_t ixgbe_intr(int irq, void *data) | |||
1237 | if (!eicr) | 1248 | if (!eicr) |
1238 | return IRQ_NONE; /* Not our interrupt */ | 1249 | return IRQ_NONE; /* Not our interrupt */ |
1239 | 1250 | ||
1240 | if (eicr & IXGBE_EICR_LSC) { | 1251 | if (eicr & IXGBE_EICR_LSC) |
1241 | adapter->lsc_int++; | 1252 | ixgbe_check_lsc(adapter); |
1242 | if (!test_bit(__IXGBE_DOWN, &adapter->state)) | ||
1243 | mod_timer(&adapter->watchdog_timer, jiffies); | ||
1244 | } | ||
1245 | |||
1246 | 1253 | ||
1247 | if (netif_rx_schedule_prep(netdev, &adapter->q_vector[0].napi)) { | 1254 | if (netif_rx_schedule_prep(netdev, &adapter->q_vector[0].napi)) { |
1248 | adapter->tx_ring[0].total_packets = 0; | 1255 | adapter->tx_ring[0].total_packets = 0; |
@@ -1897,6 +1904,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) | |||
1897 | 1904 | ||
1898 | /* bring the link up in the watchdog, this could race with our first | 1905 | /* bring the link up in the watchdog, this could race with our first |
1899 | * link up interrupt but shouldn't be a problem */ | 1906 | * link up interrupt but shouldn't be a problem */ |
1907 | adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; | ||
1908 | adapter->link_check_timeout = jiffies; | ||
1900 | mod_timer(&adapter->watchdog_timer, jiffies); | 1909 | mod_timer(&adapter->watchdog_timer, jiffies); |
1901 | return 0; | 1910 | return 0; |
1902 | } | 1911 | } |
@@ -2098,6 +2107,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter) | |||
2098 | 2107 | ||
2099 | ixgbe_napi_disable_all(adapter); | 2108 | ixgbe_napi_disable_all(adapter); |
2100 | del_timer_sync(&adapter->watchdog_timer); | 2109 | del_timer_sync(&adapter->watchdog_timer); |
2110 | cancel_work_sync(&adapter->watchdog_task); | ||
2101 | 2111 | ||
2102 | netif_carrier_off(netdev); | 2112 | netif_carrier_off(netdev); |
2103 | netif_tx_stop_all_queues(netdev); | 2113 | netif_tx_stop_all_queues(netdev); |
@@ -3010,27 +3020,74 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) | |||
3010 | static void ixgbe_watchdog(unsigned long data) | 3020 | static void ixgbe_watchdog(unsigned long data) |
3011 | { | 3021 | { |
3012 | struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; | 3022 | struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; |
3013 | struct net_device *netdev = adapter->netdev; | 3023 | struct ixgbe_hw *hw = &adapter->hw; |
3014 | bool link_up; | 3024 | |
3015 | u32 link_speed = 0; | 3025 | /* Do the watchdog outside of interrupt context due to the lovely |
3026 | * delays that some of the newer hardware requires */ | ||
3027 | if (!test_bit(__IXGBE_DOWN, &adapter->state)) { | ||
3028 | /* Cause software interrupt to ensure rx rings are cleaned */ | ||
3029 | if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { | ||
3030 | u32 eics = | ||
3031 | (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1; | ||
3032 | IXGBE_WRITE_REG(hw, IXGBE_EICS, eics); | ||
3033 | } else { | ||
3034 | /* For legacy and MSI interrupts don't set any bits that | ||
3035 | * are enabled for EIAM, because this operation would | ||
3036 | * set *both* EIMS and EICS for any bit in EIAM */ | ||
3037 | IXGBE_WRITE_REG(hw, IXGBE_EICS, | ||
3038 | (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); | ||
3039 | } | ||
3040 | /* Reset the timer */ | ||
3041 | mod_timer(&adapter->watchdog_timer, | ||
3042 | round_jiffies(jiffies + 2 * HZ)); | ||
3043 | } | ||
3016 | 3044 | ||
3017 | adapter->hw.mac.ops.check_link(&adapter->hw, &(link_speed), &link_up); | 3045 | schedule_work(&adapter->watchdog_task); |
3046 | } | ||
3047 | |||
3048 | /** | ||
3049 | * ixgbe_watchdog_task - worker thread to bring link up | ||
3050 | * @work: pointer to work_struct containing our data | ||
3051 | **/ | ||
3052 | static void ixgbe_watchdog_task(struct work_struct *work) | ||
3053 | { | ||
3054 | struct ixgbe_adapter *adapter = container_of(work, | ||
3055 | struct ixgbe_adapter, | ||
3056 | watchdog_task); | ||
3057 | struct net_device *netdev = adapter->netdev; | ||
3058 | struct ixgbe_hw *hw = &adapter->hw; | ||
3059 | u32 link_speed = adapter->link_speed; | ||
3060 | bool link_up = adapter->link_up; | ||
3061 | |||
3062 | adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; | ||
3063 | |||
3064 | if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { | ||
3065 | hw->mac.ops.check_link(hw, &link_speed, &link_up, false); | ||
3066 | if (link_up || | ||
3067 | time_after(jiffies, (adapter->link_check_timeout + | ||
3068 | IXGBE_TRY_LINK_TIMEOUT))) { | ||
3069 | IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); | ||
3070 | adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; | ||
3071 | } | ||
3072 | adapter->link_up = link_up; | ||
3073 | adapter->link_speed = link_speed; | ||
3074 | } | ||
3018 | 3075 | ||
3019 | if (link_up) { | 3076 | if (link_up) { |
3020 | if (!netif_carrier_ok(netdev)) { | 3077 | if (!netif_carrier_ok(netdev)) { |
3021 | u32 frctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); | 3078 | u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); |
3022 | u32 rmcs = IXGBE_READ_REG(&adapter->hw, IXGBE_RMCS); | 3079 | u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); |
3023 | #define FLOW_RX (frctl & IXGBE_FCTRL_RFCE) | 3080 | #define FLOW_RX (frctl & IXGBE_FCTRL_RFCE) |
3024 | #define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X) | 3081 | #define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X) |
3025 | DPRINTK(LINK, INFO, "NIC Link is Up %s, " | 3082 | DPRINTK(LINK, INFO, "NIC Link is Up %s, " |
3026 | "Flow Control: %s\n", | 3083 | "Flow Control: %s\n", |
3027 | (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? | 3084 | (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? |
3028 | "10 Gbps" : | 3085 | "10 Gbps" : |
3029 | (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? | 3086 | (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? |
3030 | "1 Gbps" : "unknown speed")), | 3087 | "1 Gbps" : "unknown speed")), |
3031 | ((FLOW_RX && FLOW_TX) ? "RX/TX" : | 3088 | ((FLOW_RX && FLOW_TX) ? "RX/TX" : |
3032 | (FLOW_RX ? "RX" : | 3089 | (FLOW_RX ? "RX" : |
3033 | (FLOW_TX ? "TX" : "None")))); | 3090 | (FLOW_TX ? "TX" : "None")))); |
3034 | 3091 | ||
3035 | netif_carrier_on(netdev); | 3092 | netif_carrier_on(netdev); |
3036 | netif_tx_wake_all_queues(netdev); | 3093 | netif_tx_wake_all_queues(netdev); |
@@ -3039,6 +3096,8 @@ static void ixgbe_watchdog(unsigned long data) | |||
3039 | adapter->detect_tx_hung = true; | 3096 | adapter->detect_tx_hung = true; |
3040 | } | 3097 | } |
3041 | } else { | 3098 | } else { |
3099 | adapter->link_up = false; | ||
3100 | adapter->link_speed = 0; | ||
3042 | if (netif_carrier_ok(netdev)) { | 3101 | if (netif_carrier_ok(netdev)) { |
3043 | DPRINTK(LINK, INFO, "NIC Link is Down\n"); | 3102 | DPRINTK(LINK, INFO, "NIC Link is Down\n"); |
3044 | netif_carrier_off(netdev); | 3103 | netif_carrier_off(netdev); |
@@ -3047,24 +3106,7 @@ static void ixgbe_watchdog(unsigned long data) | |||
3047 | } | 3106 | } |
3048 | 3107 | ||
3049 | ixgbe_update_stats(adapter); | 3108 | ixgbe_update_stats(adapter); |
3050 | 3109 | adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; | |
3051 | if (!test_bit(__IXGBE_DOWN, &adapter->state)) { | ||
3052 | /* Cause software interrupt to ensure rx rings are cleaned */ | ||
3053 | if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { | ||
3054 | u32 eics = | ||
3055 | (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1; | ||
3056 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, eics); | ||
3057 | } else { | ||
3058 | /* for legacy and MSI interrupts don't set any bits that | ||
3059 | * are enabled for EIAM, because this operation would | ||
3060 | * set *both* EIMS and EICS for any bit in EIAM */ | ||
3061 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, | ||
3062 | (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); | ||
3063 | } | ||
3064 | /* Reset the timer */ | ||
3065 | mod_timer(&adapter->watchdog_timer, | ||
3066 | round_jiffies(jiffies + 2 * HZ)); | ||
3067 | } | ||
3068 | } | 3110 | } |
3069 | 3111 | ||
3070 | static int ixgbe_tso(struct ixgbe_adapter *adapter, | 3112 | static int ixgbe_tso(struct ixgbe_adapter *adapter, |
@@ -3707,6 +3749,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, | |||
3707 | adapter->watchdog_timer.data = (unsigned long)adapter; | 3749 | adapter->watchdog_timer.data = (unsigned long)adapter; |
3708 | 3750 | ||
3709 | INIT_WORK(&adapter->reset_task, ixgbe_reset_task); | 3751 | INIT_WORK(&adapter->reset_task, ixgbe_reset_task); |
3752 | INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task); | ||
3710 | 3753 | ||
3711 | err = ixgbe_init_interrupt_scheme(adapter); | 3754 | err = ixgbe_init_interrupt_scheme(adapter); |
3712 | if (err) | 3755 | if (err) |