i40e: reduce stack usage in i40e_set_fc
authorArnd Bergmann <arnd@arndb.de>
Mon, 15 Jul 2019 12:35:07 +0000 (14:35 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Jan 2020 13:51:06 +0000 (14:51 +0100)
[ Upstream commit 33b165684ab70867d4545643f550a5d48d3ddc57 ]

The functions i40e_aq_get_phy_abilities_resp() and i40e_set_fc() both
have giant structure on the stack, which makes each one use stack frames
larger than 500 bytes.

As clang decides one function into the other, we get a warning for
exceeding the frame size limit on 32-bit architectures:

drivers/net/ethernet/intel/i40e/i40e_common.c:1654:23: error: stack frame size of 1116 bytes in function 'i40e_set_fc' [-Werror,-Wframe-larger-than=]

When building with gcc, the inlining does not happen, but i40e_set_fc()
calls i40e_aq_get_phy_abilities_resp() anyway, so they add up on the
kernel stack just as much.

The parts that actually use large stacks don't overlap, so make sure
each one is a separate function, and mark them as noinline_for_stack to
prevent the compilers from combining them again.

Fixes: 0a862b43acc6 ("i40e/i40evf: Add module_types and update_link_info")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/intel/i40e/i40e_common.c

index 85f75b5..eb0ae6a 100644 (file)
@@ -1668,25 +1668,15 @@ enum i40e_status_code i40e_aq_set_phy_config(struct i40e_hw *hw,
        return status;
 }
 
-/**
- * i40e_set_fc
- * @hw: pointer to the hw struct
- * @aq_failures: buffer to return AdminQ failure information
- * @atomic_restart: whether to enable atomic link restart
- *
- * Set the requested flow control mode using set_phy_config.
- **/
-enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures,
-                                 bool atomic_restart)
+static noinline_for_stack enum i40e_status_code
+i40e_set_fc_status(struct i40e_hw *hw,
+                  struct i40e_aq_get_phy_abilities_resp *abilities,
+                  bool atomic_restart)
 {
-       enum i40e_fc_mode fc_mode = hw->fc.requested_mode;
-       struct i40e_aq_get_phy_abilities_resp abilities;
        struct i40e_aq_set_phy_config config;
-       enum i40e_status_code status;
+       enum i40e_fc_mode fc_mode = hw->fc.requested_mode;
        u8 pause_mask = 0x0;
 
-       *aq_failures = 0x0;
-
        switch (fc_mode) {
        case I40E_FC_FULL:
                pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_TX;
@@ -1702,6 +1692,48 @@ enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures,
                break;
        }
 
+       memset(&config, 0, sizeof(struct i40e_aq_set_phy_config));
+       /* clear the old pause settings */
+       config.abilities = abilities->abilities & ~(I40E_AQ_PHY_FLAG_PAUSE_TX) &
+                          ~(I40E_AQ_PHY_FLAG_PAUSE_RX);
+       /* set the new abilities */
+       config.abilities |= pause_mask;
+       /* If the abilities have changed, then set the new config */
+       if (config.abilities == abilities->abilities)
+               return 0;
+
+       /* Auto restart link so settings take effect */
+       if (atomic_restart)
+               config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+       /* Copy over all the old settings */
+       config.phy_type = abilities->phy_type;
+       config.phy_type_ext = abilities->phy_type_ext;
+       config.link_speed = abilities->link_speed;
+       config.eee_capability = abilities->eee_capability;
+       config.eeer = abilities->eeer_val;
+       config.low_power_ctrl = abilities->d3_lpan;
+       config.fec_config = abilities->fec_cfg_curr_mod_ext_info &
+                           I40E_AQ_PHY_FEC_CONFIG_MASK;
+
+       return i40e_aq_set_phy_config(hw, &config, NULL);
+}
+
+/**
+ * i40e_set_fc
+ * @hw: pointer to the hw struct
+ * @aq_failures: buffer to return AdminQ failure information
+ * @atomic_restart: whether to enable atomic link restart
+ *
+ * Set the requested flow control mode using set_phy_config.
+ **/
+enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures,
+                                 bool atomic_restart)
+{
+       struct i40e_aq_get_phy_abilities_resp abilities;
+       enum i40e_status_code status;
+
+       *aq_failures = 0x0;
+
        /* Get the current phy config */
        status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
                                              NULL);
@@ -1710,31 +1742,10 @@ enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures,
                return status;
        }
 
-       memset(&config, 0, sizeof(struct i40e_aq_set_phy_config));
-       /* clear the old pause settings */
-       config.abilities = abilities.abilities & ~(I40E_AQ_PHY_FLAG_PAUSE_TX) &
-                          ~(I40E_AQ_PHY_FLAG_PAUSE_RX);
-       /* set the new abilities */
-       config.abilities |= pause_mask;
-       /* If the abilities have changed, then set the new config */
-       if (config.abilities != abilities.abilities) {
-               /* Auto restart link so settings take effect */
-               if (atomic_restart)
-                       config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
-               /* Copy over all the old settings */
-               config.phy_type = abilities.phy_type;
-               config.phy_type_ext = abilities.phy_type_ext;
-               config.link_speed = abilities.link_speed;
-               config.eee_capability = abilities.eee_capability;
-               config.eeer = abilities.eeer_val;
-               config.low_power_ctrl = abilities.d3_lpan;
-               config.fec_config = abilities.fec_cfg_curr_mod_ext_info &
-                                   I40E_AQ_PHY_FEC_CONFIG_MASK;
-               status = i40e_aq_set_phy_config(hw, &config, NULL);
+       status = i40e_set_fc_status(hw, &abilities, atomic_restart);
+       if (status)
+               *aq_failures |= I40E_SET_FC_AQ_FAIL_SET;
 
-               if (status)
-                       *aq_failures |= I40E_SET_FC_AQ_FAIL_SET;
-       }
        /* Update the link info */
        status = i40e_update_link_info(hw);
        if (status) {
@@ -2563,7 +2574,7 @@ i40e_status i40e_get_link_status(struct i40e_hw *hw, bool *link_up)
  * i40e_updatelink_status - update status of the HW network link
  * @hw: pointer to the hw struct
  **/
-i40e_status i40e_update_link_info(struct i40e_hw *hw)
+noinline_for_stack i40e_status i40e_update_link_info(struct i40e_hw *hw)
 {
        struct i40e_aq_get_phy_abilities_resp abilities;
        i40e_status status = 0;