diff options
author | Akeem G Abodunrin <akeem.g.abodunrin@intel.com> | 2019-02-26 19:35:14 -0500 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2019-03-22 11:19:17 -0400 |
commit | 5eda8afd6bcc89d4e4aa5d56b5f54276f63158ae (patch) | |
tree | 44a9e13481cd5aa025b5f576a09f93fa943bb9fa /drivers/net/ethernet/intel/ice/ice_switch.c | |
parent | e1ca65a3cceacc94dd9cde388016422ca2e15a54 (diff) |
ice: Add support for PF/VF promiscuous mode
Implement support for VF promiscuous mode, MAC/VLAN/MAC_VLAN and PF
multicast MAC/VLAN/MAC_VLAN promiscuous mode.
Signed-off-by: Akeem G Abodunrin <akeem.g.abodunrin@intel.com>
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_switch.c')
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_switch.c | 291 |
1 files changed, 289 insertions, 2 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index ed87361f6112..64e9e0cb61ce 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c | |||
@@ -2190,6 +2190,291 @@ ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, | |||
2190 | } | 2190 | } |
2191 | 2191 | ||
2192 | /** | 2192 | /** |
2193 | * ice_determine_promisc_mask | ||
2194 | * @fi: filter info to parse | ||
2195 | * | ||
2196 | * Helper function to determine which ICE_PROMISC_ mask corresponds | ||
2197 | * to given filter into. | ||
2198 | */ | ||
2199 | static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi) | ||
2200 | { | ||
2201 | u16 vid = fi->l_data.mac_vlan.vlan_id; | ||
2202 | u8 *macaddr = fi->l_data.mac.mac_addr; | ||
2203 | bool is_tx_fltr = false; | ||
2204 | u8 promisc_mask = 0; | ||
2205 | |||
2206 | if (fi->flag == ICE_FLTR_TX) | ||
2207 | is_tx_fltr = true; | ||
2208 | |||
2209 | if (is_broadcast_ether_addr(macaddr)) | ||
2210 | promisc_mask |= is_tx_fltr ? | ||
2211 | ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX; | ||
2212 | else if (is_multicast_ether_addr(macaddr)) | ||
2213 | promisc_mask |= is_tx_fltr ? | ||
2214 | ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX; | ||
2215 | else if (is_unicast_ether_addr(macaddr)) | ||
2216 | promisc_mask |= is_tx_fltr ? | ||
2217 | ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX; | ||
2218 | if (vid) | ||
2219 | promisc_mask |= is_tx_fltr ? | ||
2220 | ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX; | ||
2221 | |||
2222 | return promisc_mask; | ||
2223 | } | ||
2224 | |||
2225 | /** | ||
2226 | * ice_remove_promisc - Remove promisc based filter rules | ||
2227 | * @hw: pointer to the hardware structure | ||
2228 | * @recp_id: recipe id for which the rule needs to removed | ||
2229 | * @v_list: list of promisc entries | ||
2230 | */ | ||
2231 | static enum ice_status | ||
2232 | ice_remove_promisc(struct ice_hw *hw, u8 recp_id, | ||
2233 | struct list_head *v_list) | ||
2234 | { | ||
2235 | struct ice_fltr_list_entry *v_list_itr, *tmp; | ||
2236 | |||
2237 | list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { | ||
2238 | v_list_itr->status = | ||
2239 | ice_remove_rule_internal(hw, recp_id, v_list_itr); | ||
2240 | if (v_list_itr->status) | ||
2241 | return v_list_itr->status; | ||
2242 | } | ||
2243 | return 0; | ||
2244 | } | ||
2245 | |||
2246 | /** | ||
2247 | * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI | ||
2248 | * @hw: pointer to the hardware structure | ||
2249 | * @vsi_handle: VSI handle to clear mode | ||
2250 | * @promisc_mask: mask of promiscuous config bits to clear | ||
2251 | * @vid: VLAN ID to clear VLAN promiscuous | ||
2252 | */ | ||
2253 | enum ice_status | ||
2254 | ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, | ||
2255 | u16 vid) | ||
2256 | { | ||
2257 | struct ice_switch_info *sw = hw->switch_info; | ||
2258 | struct ice_fltr_list_entry *fm_entry, *tmp; | ||
2259 | struct list_head remove_list_head; | ||
2260 | struct ice_fltr_mgmt_list_entry *itr; | ||
2261 | struct list_head *rule_head; | ||
2262 | struct mutex *rule_lock; /* Lock to protect filter rule list */ | ||
2263 | enum ice_status status = 0; | ||
2264 | u8 recipe_id; | ||
2265 | |||
2266 | if (!ice_is_vsi_valid(hw, vsi_handle)) | ||
2267 | return ICE_ERR_PARAM; | ||
2268 | |||
2269 | if (vid) | ||
2270 | recipe_id = ICE_SW_LKUP_PROMISC_VLAN; | ||
2271 | else | ||
2272 | recipe_id = ICE_SW_LKUP_PROMISC; | ||
2273 | |||
2274 | rule_head = &sw->recp_list[recipe_id].filt_rules; | ||
2275 | rule_lock = &sw->recp_list[recipe_id].filt_rule_lock; | ||
2276 | |||
2277 | INIT_LIST_HEAD(&remove_list_head); | ||
2278 | |||
2279 | mutex_lock(rule_lock); | ||
2280 | list_for_each_entry(itr, rule_head, list_entry) { | ||
2281 | u8 fltr_promisc_mask = 0; | ||
2282 | |||
2283 | if (!ice_vsi_uses_fltr(itr, vsi_handle)) | ||
2284 | continue; | ||
2285 | |||
2286 | fltr_promisc_mask |= | ||
2287 | ice_determine_promisc_mask(&itr->fltr_info); | ||
2288 | |||
2289 | /* Skip if filter is not completely specified by given mask */ | ||
2290 | if (fltr_promisc_mask & ~promisc_mask) | ||
2291 | continue; | ||
2292 | |||
2293 | status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, | ||
2294 | &remove_list_head, | ||
2295 | &itr->fltr_info); | ||
2296 | if (status) { | ||
2297 | mutex_unlock(rule_lock); | ||
2298 | goto free_fltr_list; | ||
2299 | } | ||
2300 | } | ||
2301 | mutex_unlock(rule_lock); | ||
2302 | |||
2303 | status = ice_remove_promisc(hw, recipe_id, &remove_list_head); | ||
2304 | |||
2305 | free_fltr_list: | ||
2306 | list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { | ||
2307 | list_del(&fm_entry->list_entry); | ||
2308 | devm_kfree(ice_hw_to_dev(hw), fm_entry); | ||
2309 | } | ||
2310 | |||
2311 | return status; | ||
2312 | } | ||
2313 | |||
2314 | /** | ||
2315 | * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s) | ||
2316 | * @hw: pointer to the hardware structure | ||
2317 | * @vsi_handle: VSI handle to configure | ||
2318 | * @promisc_mask: mask of promiscuous config bits | ||
2319 | * @vid: VLAN ID to set VLAN promiscuous | ||
2320 | */ | ||
2321 | enum ice_status | ||
2322 | ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid) | ||
2323 | { | ||
2324 | enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR }; | ||
2325 | struct ice_fltr_list_entry f_list_entry; | ||
2326 | struct ice_fltr_info new_fltr; | ||
2327 | enum ice_status status = 0; | ||
2328 | bool is_tx_fltr; | ||
2329 | u16 hw_vsi_id; | ||
2330 | int pkt_type; | ||
2331 | u8 recipe_id; | ||
2332 | |||
2333 | if (!ice_is_vsi_valid(hw, vsi_handle)) | ||
2334 | return ICE_ERR_PARAM; | ||
2335 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); | ||
2336 | |||
2337 | memset(&new_fltr, 0, sizeof(new_fltr)); | ||
2338 | |||
2339 | if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) { | ||
2340 | new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN; | ||
2341 | new_fltr.l_data.mac_vlan.vlan_id = vid; | ||
2342 | recipe_id = ICE_SW_LKUP_PROMISC_VLAN; | ||
2343 | } else { | ||
2344 | new_fltr.lkup_type = ICE_SW_LKUP_PROMISC; | ||
2345 | recipe_id = ICE_SW_LKUP_PROMISC; | ||
2346 | } | ||
2347 | |||
2348 | /* Separate filters must be set for each direction/packet type | ||
2349 | * combination, so we will loop over the mask value, store the | ||
2350 | * individual type, and clear it out in the input mask as it | ||
2351 | * is found. | ||
2352 | */ | ||
2353 | while (promisc_mask) { | ||
2354 | u8 *mac_addr; | ||
2355 | |||
2356 | pkt_type = 0; | ||
2357 | is_tx_fltr = false; | ||
2358 | |||
2359 | if (promisc_mask & ICE_PROMISC_UCAST_RX) { | ||
2360 | promisc_mask &= ~ICE_PROMISC_UCAST_RX; | ||
2361 | pkt_type = UCAST_FLTR; | ||
2362 | } else if (promisc_mask & ICE_PROMISC_UCAST_TX) { | ||
2363 | promisc_mask &= ~ICE_PROMISC_UCAST_TX; | ||
2364 | pkt_type = UCAST_FLTR; | ||
2365 | is_tx_fltr = true; | ||
2366 | } else if (promisc_mask & ICE_PROMISC_MCAST_RX) { | ||
2367 | promisc_mask &= ~ICE_PROMISC_MCAST_RX; | ||
2368 | pkt_type = MCAST_FLTR; | ||
2369 | } else if (promisc_mask & ICE_PROMISC_MCAST_TX) { | ||
2370 | promisc_mask &= ~ICE_PROMISC_MCAST_TX; | ||
2371 | pkt_type = MCAST_FLTR; | ||
2372 | is_tx_fltr = true; | ||
2373 | } else if (promisc_mask & ICE_PROMISC_BCAST_RX) { | ||
2374 | promisc_mask &= ~ICE_PROMISC_BCAST_RX; | ||
2375 | pkt_type = BCAST_FLTR; | ||
2376 | } else if (promisc_mask & ICE_PROMISC_BCAST_TX) { | ||
2377 | promisc_mask &= ~ICE_PROMISC_BCAST_TX; | ||
2378 | pkt_type = BCAST_FLTR; | ||
2379 | is_tx_fltr = true; | ||
2380 | } | ||
2381 | |||
2382 | /* Check for VLAN promiscuous flag */ | ||
2383 | if (promisc_mask & ICE_PROMISC_VLAN_RX) { | ||
2384 | promisc_mask &= ~ICE_PROMISC_VLAN_RX; | ||
2385 | } else if (promisc_mask & ICE_PROMISC_VLAN_TX) { | ||
2386 | promisc_mask &= ~ICE_PROMISC_VLAN_TX; | ||
2387 | is_tx_fltr = true; | ||
2388 | } | ||
2389 | |||
2390 | /* Set filter DA based on packet type */ | ||
2391 | mac_addr = new_fltr.l_data.mac.mac_addr; | ||
2392 | if (pkt_type == BCAST_FLTR) { | ||
2393 | eth_broadcast_addr(mac_addr); | ||
2394 | } else if (pkt_type == MCAST_FLTR || | ||
2395 | pkt_type == UCAST_FLTR) { | ||
2396 | /* Use the dummy ether header DA */ | ||
2397 | ether_addr_copy(mac_addr, dummy_eth_header); | ||
2398 | if (pkt_type == MCAST_FLTR) | ||
2399 | mac_addr[0] |= 0x1; /* Set multicast bit */ | ||
2400 | } | ||
2401 | |||
2402 | /* Need to reset this to zero for all iterations */ | ||
2403 | new_fltr.flag = 0; | ||
2404 | if (is_tx_fltr) { | ||
2405 | new_fltr.flag |= ICE_FLTR_TX; | ||
2406 | new_fltr.src = hw_vsi_id; | ||
2407 | } else { | ||
2408 | new_fltr.flag |= ICE_FLTR_RX; | ||
2409 | new_fltr.src = hw->port_info->lport; | ||
2410 | } | ||
2411 | |||
2412 | new_fltr.fltr_act = ICE_FWD_TO_VSI; | ||
2413 | new_fltr.vsi_handle = vsi_handle; | ||
2414 | new_fltr.fwd_id.hw_vsi_id = hw_vsi_id; | ||
2415 | f_list_entry.fltr_info = new_fltr; | ||
2416 | |||
2417 | status = ice_add_rule_internal(hw, recipe_id, &f_list_entry); | ||
2418 | if (status) | ||
2419 | goto set_promisc_exit; | ||
2420 | } | ||
2421 | |||
2422 | set_promisc_exit: | ||
2423 | return status; | ||
2424 | } | ||
2425 | |||
2426 | /** | ||
2427 | * ice_set_vlan_vsi_promisc | ||
2428 | * @hw: pointer to the hardware structure | ||
2429 | * @vsi_handle: VSI handle to configure | ||
2430 | * @promisc_mask: mask of promiscuous config bits | ||
2431 | * @rm_vlan_promisc: Clear VLANs VSI promisc mode | ||
2432 | * | ||
2433 | * Configure VSI with all associated VLANs to given promiscuous mode(s) | ||
2434 | */ | ||
2435 | enum ice_status | ||
2436 | ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, | ||
2437 | bool rm_vlan_promisc) | ||
2438 | { | ||
2439 | struct ice_switch_info *sw = hw->switch_info; | ||
2440 | struct ice_fltr_list_entry *list_itr, *tmp; | ||
2441 | struct list_head vsi_list_head; | ||
2442 | struct list_head *vlan_head; | ||
2443 | struct mutex *vlan_lock; /* Lock to protect filter rule list */ | ||
2444 | enum ice_status status; | ||
2445 | u16 vlan_id; | ||
2446 | |||
2447 | INIT_LIST_HEAD(&vsi_list_head); | ||
2448 | vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; | ||
2449 | vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; | ||
2450 | mutex_lock(vlan_lock); | ||
2451 | status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head, | ||
2452 | &vsi_list_head); | ||
2453 | mutex_unlock(vlan_lock); | ||
2454 | if (status) | ||
2455 | goto free_fltr_list; | ||
2456 | |||
2457 | list_for_each_entry(list_itr, &vsi_list_head, list_entry) { | ||
2458 | vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id; | ||
2459 | if (rm_vlan_promisc) | ||
2460 | status = ice_clear_vsi_promisc(hw, vsi_handle, | ||
2461 | promisc_mask, vlan_id); | ||
2462 | else | ||
2463 | status = ice_set_vsi_promisc(hw, vsi_handle, | ||
2464 | promisc_mask, vlan_id); | ||
2465 | if (status) | ||
2466 | break; | ||
2467 | } | ||
2468 | |||
2469 | free_fltr_list: | ||
2470 | list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) { | ||
2471 | list_del(&list_itr->list_entry); | ||
2472 | devm_kfree(ice_hw_to_dev(hw), list_itr); | ||
2473 | } | ||
2474 | return status; | ||
2475 | } | ||
2476 | |||
2477 | /** | ||
2193 | * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI | 2478 | * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI |
2194 | * @hw: pointer to the hardware structure | 2479 | * @hw: pointer to the hardware structure |
2195 | * @vsi_handle: VSI handle to remove filters from | 2480 | * @vsi_handle: VSI handle to remove filters from |
@@ -2224,12 +2509,14 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle, | |||
2224 | case ICE_SW_LKUP_VLAN: | 2509 | case ICE_SW_LKUP_VLAN: |
2225 | ice_remove_vlan(hw, &remove_list_head); | 2510 | ice_remove_vlan(hw, &remove_list_head); |
2226 | break; | 2511 | break; |
2512 | case ICE_SW_LKUP_PROMISC: | ||
2513 | case ICE_SW_LKUP_PROMISC_VLAN: | ||
2514 | ice_remove_promisc(hw, lkup, &remove_list_head); | ||
2515 | break; | ||
2227 | case ICE_SW_LKUP_MAC_VLAN: | 2516 | case ICE_SW_LKUP_MAC_VLAN: |
2228 | case ICE_SW_LKUP_ETHERTYPE: | 2517 | case ICE_SW_LKUP_ETHERTYPE: |
2229 | case ICE_SW_LKUP_ETHERTYPE_MAC: | 2518 | case ICE_SW_LKUP_ETHERTYPE_MAC: |
2230 | case ICE_SW_LKUP_PROMISC: | ||
2231 | case ICE_SW_LKUP_DFLT: | 2519 | case ICE_SW_LKUP_DFLT: |
2232 | case ICE_SW_LKUP_PROMISC_VLAN: | ||
2233 | case ICE_SW_LKUP_LAST: | 2520 | case ICE_SW_LKUP_LAST: |
2234 | default: | 2521 | default: |
2235 | ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup); | 2522 | ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup); |