diff options
author | Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> | 2019-02-28 18:24:24 -0500 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2019-04-18 11:38:47 -0400 |
commit | 7b9ffc76bf5998aad8feaa26d9d3fcb65ec7a21b (patch) | |
tree | 9935f6c7b53786d7f9ce06d804aa4a42ce541ec4 /drivers/net/ethernet/intel/ice/ice_dcb_lib.c | |
parent | 0ebd3ff13ccad2940516ba522ca8d21cea4f56f6 (diff) |
ice: Add code for DCB initialization part 3/4
This patch adds a new function ice_pf_dcb_cfg (and related helpers)
which applies the DCB configuration obtained from the firmware. As
part of this, VSIs/netdevs are updated with traffic class information.
This patch requires a bit of a refactor of existing code.
1. For a MIB change event, the associated VSI is closed and brought up
again. The gap between closing and opening the VSI can cause a race
condition. Fix this by grabbing the rtnl_lock prior to closing the
VSI and then only free it after re-opening the VSI during a MIB
change event.
2. ice_sched_query_elem is used in ice_sched.c and with this patch, in
ice_dcb.c as well. However, ice_dcb.c is not built when CONFIG_DCB is
unset. This results in namespace warnings (ice_sched.o: Externally
defined symbols with no external references) when CONFIG_DCB is unset.
To avoid this move ice_sched_query_elem from ice_sched.c to
ice_common.c.
Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_dcb_lib.c')
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 204 |
1 files changed, 203 insertions, 1 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index f2dd41408652..210487a0671d 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c | |||
@@ -4,6 +4,189 @@ | |||
4 | #include "ice_dcb_lib.h" | 4 | #include "ice_dcb_lib.h" |
5 | 5 | ||
6 | /** | 6 | /** |
7 | * ice_dcb_get_ena_tc - return bitmap of enabled TCs | ||
8 | * @dcbcfg: DCB config to evaluate for enabled TCs | ||
9 | */ | ||
10 | u8 ice_dcb_get_ena_tc(struct ice_dcbx_cfg *dcbcfg) | ||
11 | { | ||
12 | u8 i, num_tc, ena_tc = 1; | ||
13 | |||
14 | num_tc = ice_dcb_get_num_tc(dcbcfg); | ||
15 | |||
16 | for (i = 0; i < num_tc; i++) | ||
17 | ena_tc |= BIT(i); | ||
18 | |||
19 | return ena_tc; | ||
20 | } | ||
21 | |||
22 | /** | ||
23 | * ice_dcb_get_num_tc - Get the number of TCs from DCBX config | ||
24 | * @dcbcfg: config to retrieve number of TCs from | ||
25 | */ | ||
26 | u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg *dcbcfg) | ||
27 | { | ||
28 | bool tc_unused = false; | ||
29 | u8 num_tc = 0; | ||
30 | u8 ret = 0; | ||
31 | int i; | ||
32 | |||
33 | /* Scan the ETS Config Priority Table to find traffic classes | ||
34 | * enabled and create a bitmask of enabled TCs | ||
35 | */ | ||
36 | for (i = 0; i < CEE_DCBX_MAX_PRIO; i++) | ||
37 | num_tc |= BIT(dcbcfg->etscfg.prio_table[i]); | ||
38 | |||
39 | /* Scan bitmask for contiguous TCs starting with TC0 */ | ||
40 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | ||
41 | if (num_tc & BIT(i)) { | ||
42 | if (!tc_unused) { | ||
43 | ret++; | ||
44 | } else { | ||
45 | pr_err("Non-contiguous TCs - Disabling DCB\n"); | ||
46 | return 1; | ||
47 | } | ||
48 | } else { | ||
49 | tc_unused = true; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | /* There is always at least 1 TC */ | ||
54 | if (!ret) | ||
55 | ret = 1; | ||
56 | |||
57 | return ret; | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * ice_pf_dcb_recfg - Reconfigure all VEBs and VSIs | ||
62 | * @pf: pointer to the PF struct | ||
63 | * | ||
64 | * Assumed caller has already disabled all VSIs before | ||
65 | * calling this function. Reconfiguring DCB based on | ||
66 | * local_dcbx_cfg. | ||
67 | */ | ||
68 | static void ice_pf_dcb_recfg(struct ice_pf *pf) | ||
69 | { | ||
70 | struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg; | ||
71 | u8 tc_map = 0; | ||
72 | int v, ret; | ||
73 | |||
74 | /* Update each VSI */ | ||
75 | ice_for_each_vsi(pf, v) { | ||
76 | if (!pf->vsi[v]) | ||
77 | continue; | ||
78 | |||
79 | if (pf->vsi[v]->type == ICE_VSI_PF) | ||
80 | tc_map = ice_dcb_get_ena_tc(dcbcfg); | ||
81 | else | ||
82 | tc_map = ICE_DFLT_TRAFFIC_CLASS; | ||
83 | |||
84 | ret = ice_vsi_cfg_tc(pf->vsi[v], tc_map); | ||
85 | if (ret) | ||
86 | dev_err(&pf->pdev->dev, | ||
87 | "Failed to config TC for VSI index: %d\n", | ||
88 | pf->vsi[v]->idx); | ||
89 | else | ||
90 | ice_vsi_map_rings_to_vectors(pf->vsi[v]); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * ice_pf_dcb_cfg - Apply new DCB configuration | ||
96 | * @pf: pointer to the PF struct | ||
97 | * @new_cfg: DCBX config to apply | ||
98 | */ | ||
99 | static int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg) | ||
100 | { | ||
101 | struct ice_dcbx_cfg *old_cfg, *curr_cfg; | ||
102 | struct ice_aqc_port_ets_elem buf = { 0 }; | ||
103 | int ret = 0; | ||
104 | |||
105 | curr_cfg = &pf->hw.port_info->local_dcbx_cfg; | ||
106 | |||
107 | /* Enable DCB tagging only when more than one TC */ | ||
108 | if (ice_dcb_get_num_tc(new_cfg) > 1) { | ||
109 | dev_dbg(&pf->pdev->dev, "DCB tagging enabled (num TC > 1)\n"); | ||
110 | set_bit(ICE_FLAG_DCB_ENA, pf->flags); | ||
111 | } else { | ||
112 | dev_dbg(&pf->pdev->dev, "DCB tagging disabled (num TC = 1)\n"); | ||
113 | clear_bit(ICE_FLAG_DCB_ENA, pf->flags); | ||
114 | } | ||
115 | |||
116 | if (!memcmp(new_cfg, curr_cfg, sizeof(*new_cfg))) { | ||
117 | dev_dbg(&pf->pdev->dev, "No change in DCB config required\n"); | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | /* Store old config in case FW config fails */ | ||
122 | old_cfg = devm_kzalloc(&pf->pdev->dev, sizeof(*old_cfg), GFP_KERNEL); | ||
123 | memcpy(old_cfg, curr_cfg, sizeof(*old_cfg)); | ||
124 | |||
125 | /* avoid race conditions by holding the lock while disabling and | ||
126 | * re-enabling the VSI | ||
127 | */ | ||
128 | rtnl_lock(); | ||
129 | ice_pf_dis_all_vsi(pf, true); | ||
130 | |||
131 | memcpy(curr_cfg, new_cfg, sizeof(*curr_cfg)); | ||
132 | memcpy(&curr_cfg->etsrec, &curr_cfg->etscfg, sizeof(curr_cfg->etsrec)); | ||
133 | |||
134 | /* Only send new config to HW if we are in SW LLDP mode. Otherwise, | ||
135 | * the new config came from the HW in the first place. | ||
136 | */ | ||
137 | if (pf->hw.port_info->is_sw_lldp) { | ||
138 | ret = ice_set_dcb_cfg(pf->hw.port_info); | ||
139 | if (ret) { | ||
140 | dev_err(&pf->pdev->dev, "Set DCB Config failed\n"); | ||
141 | /* Restore previous settings to local config */ | ||
142 | memcpy(curr_cfg, old_cfg, sizeof(*curr_cfg)); | ||
143 | goto out; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); | ||
148 | if (ret) { | ||
149 | dev_err(&pf->pdev->dev, "Query Port ETS failed\n"); | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | ice_pf_dcb_recfg(pf); | ||
154 | |||
155 | out: | ||
156 | ice_pf_ena_all_vsi(pf, true); | ||
157 | rtnl_unlock(); | ||
158 | devm_kfree(&pf->pdev->dev, old_cfg); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | /** | ||
163 | * ice_dcb_init_cfg - set the initial DCB config in SW | ||
164 | * @pf: pf to apply config to | ||
165 | */ | ||
166 | static int ice_dcb_init_cfg(struct ice_pf *pf) | ||
167 | { | ||
168 | struct ice_dcbx_cfg *newcfg; | ||
169 | struct ice_port_info *pi; | ||
170 | int ret = 0; | ||
171 | |||
172 | pi = pf->hw.port_info; | ||
173 | newcfg = devm_kzalloc(&pf->pdev->dev, sizeof(*newcfg), GFP_KERNEL); | ||
174 | if (!newcfg) | ||
175 | return -ENOMEM; | ||
176 | |||
177 | memcpy(newcfg, &pi->local_dcbx_cfg, sizeof(*newcfg)); | ||
178 | memset(&pi->local_dcbx_cfg, 0, sizeof(*newcfg)); | ||
179 | |||
180 | dev_info(&pf->pdev->dev, "Configuring initial DCB values\n"); | ||
181 | if (ice_pf_dcb_cfg(pf, newcfg)) | ||
182 | ret = -EINVAL; | ||
183 | |||
184 | devm_kfree(&pf->pdev->dev, newcfg); | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | /** | ||
7 | * ice_init_pf_dcb - initialize DCB for a PF | 190 | * ice_init_pf_dcb - initialize DCB for a PF |
8 | * @pf: pf to initiialize DCB for | 191 | * @pf: pf to initiialize DCB for |
9 | */ | 192 | */ |
@@ -12,6 +195,7 @@ int ice_init_pf_dcb(struct ice_pf *pf) | |||
12 | struct device *dev = &pf->pdev->dev; | 195 | struct device *dev = &pf->pdev->dev; |
13 | struct ice_port_info *port_info; | 196 | struct ice_port_info *port_info; |
14 | struct ice_hw *hw = &pf->hw; | 197 | struct ice_hw *hw = &pf->hw; |
198 | int err; | ||
15 | 199 | ||
16 | port_info = hw->port_info; | 200 | port_info = hw->port_info; |
17 | 201 | ||
@@ -38,5 +222,23 @@ int ice_init_pf_dcb(struct ice_pf *pf) | |||
38 | ice_aq_start_stop_dcbx(hw, true, &dcbx_status, NULL); | 222 | ice_aq_start_stop_dcbx(hw, true, &dcbx_status, NULL); |
39 | } | 223 | } |
40 | 224 | ||
41 | return ice_init_dcb(hw); | 225 | err = ice_init_dcb(hw); |
226 | if (err) | ||
227 | goto dcb_init_err; | ||
228 | |||
229 | /* DCBX in FW and LLDP enabled in FW */ | ||
230 | pf->dcbx_cap = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_IEEE; | ||
231 | |||
232 | set_bit(ICE_FLAG_DCB_CAPABLE, pf->flags); | ||
233 | |||
234 | err = ice_dcb_init_cfg(pf); | ||
235 | if (err) | ||
236 | goto dcb_init_err; | ||
237 | |||
238 | dev_info(&pf->pdev->dev, "DCBX offload supported\n"); | ||
239 | return err; | ||
240 | |||
241 | dcb_init_err: | ||
242 | dev_err(dev, "DCB init failed\n"); | ||
243 | return err; | ||
42 | } | 244 | } |