|
4 | 4 | #include "ice_common.h" |
5 | 5 | #include "ice.h" |
6 | 6 | #include "ice_ddp.h" |
| 7 | +#include "ice_sched.h" |
7 | 8 |
|
8 | 9 | /* For supporting double VLAN mode, it is necessary to enable or disable certain |
9 | 10 | * boost tcam entries. The metadata labels names that match the following |
@@ -2272,3 +2273,211 @@ enum ice_ddp_state ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, |
2272 | 2273 |
|
2273 | 2274 | return state; |
2274 | 2275 | } |
| 2276 | + |
| 2277 | +/** |
| 2278 | + * ice_get_set_tx_topo - get or set Tx topology |
| 2279 | + * @hw: pointer to the HW struct |
| 2280 | + * @buf: pointer to Tx topology buffer |
| 2281 | + * @buf_size: buffer size |
| 2282 | + * @cd: pointer to command details structure or NULL |
| 2283 | + * @flags: pointer to descriptor flags |
| 2284 | + * @set: 0-get, 1-set topology |
| 2285 | + * |
| 2286 | + * The function will get or set Tx topology |
| 2287 | + * |
| 2288 | + * Return: zero when set was successful, negative values otherwise. |
| 2289 | + */ |
| 2290 | +static int |
| 2291 | +ice_get_set_tx_topo(struct ice_hw *hw, u8 *buf, u16 buf_size, |
| 2292 | + struct ice_sq_cd *cd, u8 *flags, bool set) |
| 2293 | +{ |
| 2294 | + struct ice_aqc_get_set_tx_topo *cmd; |
| 2295 | + struct ice_aq_desc desc; |
| 2296 | + int status; |
| 2297 | + |
| 2298 | + cmd = &desc.params.get_set_tx_topo; |
| 2299 | + if (set) { |
| 2300 | + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_tx_topo); |
| 2301 | + cmd->set_flags = ICE_AQC_TX_TOPO_FLAGS_ISSUED; |
| 2302 | + /* requested to update a new topology, not a default topology */ |
| 2303 | + if (buf) |
| 2304 | + cmd->set_flags |= ICE_AQC_TX_TOPO_FLAGS_SRC_RAM | |
| 2305 | + ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW; |
| 2306 | + |
| 2307 | + if (ice_is_e825c(hw)) |
| 2308 | + desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); |
| 2309 | + } else { |
| 2310 | + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_tx_topo); |
| 2311 | + cmd->get_flags = ICE_AQC_TX_TOPO_GET_RAM; |
| 2312 | + } |
| 2313 | + |
| 2314 | + if (!ice_is_e825c(hw)) |
| 2315 | + desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); |
| 2316 | + |
| 2317 | + status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); |
| 2318 | + if (status) |
| 2319 | + return status; |
| 2320 | + /* read the return flag values (first byte) for get operation */ |
| 2321 | + if (!set && flags) |
| 2322 | + *flags = desc.params.get_set_tx_topo.set_flags; |
| 2323 | + |
| 2324 | + return 0; |
| 2325 | +} |
| 2326 | + |
| 2327 | +/** |
| 2328 | + * ice_cfg_tx_topo - Initialize new Tx topology if available |
| 2329 | + * @hw: pointer to the HW struct |
| 2330 | + * @buf: pointer to Tx topology buffer |
| 2331 | + * @len: buffer size |
| 2332 | + * |
| 2333 | + * The function will apply the new Tx topology from the package buffer |
| 2334 | + * if available. |
| 2335 | + * |
| 2336 | + * Return: zero when update was successful, negative values otherwise. |
| 2337 | + */ |
| 2338 | +int ice_cfg_tx_topo(struct ice_hw *hw, u8 *buf, u32 len) |
| 2339 | +{ |
| 2340 | + u8 *current_topo, *new_topo = NULL; |
| 2341 | + struct ice_run_time_cfg_seg *seg; |
| 2342 | + struct ice_buf_hdr *section; |
| 2343 | + struct ice_pkg_hdr *pkg_hdr; |
| 2344 | + enum ice_ddp_state state; |
| 2345 | + u16 offset, size = 0; |
| 2346 | + u32 reg = 0; |
| 2347 | + int status; |
| 2348 | + u8 flags; |
| 2349 | + |
| 2350 | + if (!buf || !len) |
| 2351 | + return -EINVAL; |
| 2352 | + |
| 2353 | + /* Does FW support new Tx topology mode ? */ |
| 2354 | + if (!hw->func_caps.common_cap.tx_sched_topo_comp_mode_en) { |
| 2355 | + ice_debug(hw, ICE_DBG_INIT, "FW doesn't support compatibility mode\n"); |
| 2356 | + return -EOPNOTSUPP; |
| 2357 | + } |
| 2358 | + |
| 2359 | + current_topo = kzalloc(ICE_AQ_MAX_BUF_LEN, GFP_KERNEL); |
| 2360 | + if (!current_topo) |
| 2361 | + return -ENOMEM; |
| 2362 | + |
| 2363 | + /* Get the current Tx topology */ |
| 2364 | + status = ice_get_set_tx_topo(hw, current_topo, ICE_AQ_MAX_BUF_LEN, NULL, |
| 2365 | + &flags, false); |
| 2366 | + |
| 2367 | + kfree(current_topo); |
| 2368 | + |
| 2369 | + if (status) { |
| 2370 | + ice_debug(hw, ICE_DBG_INIT, "Get current topology is failed\n"); |
| 2371 | + return status; |
| 2372 | + } |
| 2373 | + |
| 2374 | + /* Is default topology already applied ? */ |
| 2375 | + if (!(flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) && |
| 2376 | + hw->num_tx_sched_layers == ICE_SCHED_9_LAYERS) { |
| 2377 | + ice_debug(hw, ICE_DBG_INIT, "Default topology already applied\n"); |
| 2378 | + return -EEXIST; |
| 2379 | + } |
| 2380 | + |
| 2381 | + /* Is new topology already applied ? */ |
| 2382 | + if ((flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) && |
| 2383 | + hw->num_tx_sched_layers == ICE_SCHED_5_LAYERS) { |
| 2384 | + ice_debug(hw, ICE_DBG_INIT, "New topology already applied\n"); |
| 2385 | + return -EEXIST; |
| 2386 | + } |
| 2387 | + |
| 2388 | + /* Setting topology already issued? */ |
| 2389 | + if (flags & ICE_AQC_TX_TOPO_FLAGS_ISSUED) { |
| 2390 | + ice_debug(hw, ICE_DBG_INIT, "Update Tx topology was done by another PF\n"); |
| 2391 | + /* Add a small delay before exiting */ |
| 2392 | + msleep(2000); |
| 2393 | + return -EEXIST; |
| 2394 | + } |
| 2395 | + |
| 2396 | + /* Change the topology from new to default (5 to 9) */ |
| 2397 | + if (!(flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) && |
| 2398 | + hw->num_tx_sched_layers == ICE_SCHED_5_LAYERS) { |
| 2399 | + ice_debug(hw, ICE_DBG_INIT, "Change topology from 5 to 9 layers\n"); |
| 2400 | + goto update_topo; |
| 2401 | + } |
| 2402 | + |
| 2403 | + pkg_hdr = (struct ice_pkg_hdr *)buf; |
| 2404 | + state = ice_verify_pkg(pkg_hdr, len); |
| 2405 | + if (state) { |
| 2406 | + ice_debug(hw, ICE_DBG_INIT, "Failed to verify pkg (err: %d)\n", |
| 2407 | + state); |
| 2408 | + return -EIO; |
| 2409 | + } |
| 2410 | + |
| 2411 | + /* Find runtime configuration segment */ |
| 2412 | + seg = (struct ice_run_time_cfg_seg *) |
| 2413 | + ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE_RUN_TIME_CFG, pkg_hdr); |
| 2414 | + if (!seg) { |
| 2415 | + ice_debug(hw, ICE_DBG_INIT, "5 layer topology segment is missing\n"); |
| 2416 | + return -EIO; |
| 2417 | + } |
| 2418 | + |
| 2419 | + if (le32_to_cpu(seg->buf_table.buf_count) < ICE_MIN_S_COUNT) { |
| 2420 | + ice_debug(hw, ICE_DBG_INIT, "5 layer topology segment count(%d) is wrong\n", |
| 2421 | + seg->buf_table.buf_count); |
| 2422 | + return -EIO; |
| 2423 | + } |
| 2424 | + |
| 2425 | + section = ice_pkg_val_buf(seg->buf_table.buf_array); |
| 2426 | + if (!section || le32_to_cpu(section->section_entry[0].type) != |
| 2427 | + ICE_SID_TX_5_LAYER_TOPO) { |
| 2428 | + ice_debug(hw, ICE_DBG_INIT, "5 layer topology section type is wrong\n"); |
| 2429 | + return -EIO; |
| 2430 | + } |
| 2431 | + |
| 2432 | + size = le16_to_cpu(section->section_entry[0].size); |
| 2433 | + offset = le16_to_cpu(section->section_entry[0].offset); |
| 2434 | + if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ) { |
| 2435 | + ice_debug(hw, ICE_DBG_INIT, "5 layer topology section size is wrong\n"); |
| 2436 | + return -EIO; |
| 2437 | + } |
| 2438 | + |
| 2439 | + /* Make sure the section fits in the buffer */ |
| 2440 | + if (offset + size > ICE_PKG_BUF_SIZE) { |
| 2441 | + ice_debug(hw, ICE_DBG_INIT, "5 layer topology buffer > 4K\n"); |
| 2442 | + return -EIO; |
| 2443 | + } |
| 2444 | + |
| 2445 | + /* Get the new topology buffer */ |
| 2446 | + new_topo = ((u8 *)section) + offset; |
| 2447 | + |
| 2448 | +update_topo: |
| 2449 | + /* Acquire global lock to make sure that set topology issued |
| 2450 | + * by one PF. |
| 2451 | + */ |
| 2452 | + status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, ICE_RES_WRITE, |
| 2453 | + ICE_GLOBAL_CFG_LOCK_TIMEOUT); |
| 2454 | + if (status) { |
| 2455 | + ice_debug(hw, ICE_DBG_INIT, "Failed to acquire global lock\n"); |
| 2456 | + return status; |
| 2457 | + } |
| 2458 | + |
| 2459 | + /* Check if reset was triggered already. */ |
| 2460 | + reg = rd32(hw, GLGEN_RSTAT); |
| 2461 | + if (reg & GLGEN_RSTAT_DEVSTATE_M) { |
| 2462 | + /* Reset is in progress, re-init the HW again */ |
| 2463 | + ice_debug(hw, ICE_DBG_INIT, "Reset is in progress. Layer topology might be applied already\n"); |
| 2464 | + ice_check_reset(hw); |
| 2465 | + return 0; |
| 2466 | + } |
| 2467 | + |
| 2468 | + /* Set new topology */ |
| 2469 | + status = ice_get_set_tx_topo(hw, new_topo, size, NULL, NULL, true); |
| 2470 | + if (status) { |
| 2471 | + ice_debug(hw, ICE_DBG_INIT, "Failed setting Tx topology\n"); |
| 2472 | + return status; |
| 2473 | + } |
| 2474 | + |
| 2475 | + /* New topology is updated, delay 1 second before issuing the CORER */ |
| 2476 | + msleep(1000); |
| 2477 | + ice_reset(hw, ICE_RESET_CORER); |
| 2478 | + /* CORER will clear the global lock, so no explicit call |
| 2479 | + * required for release. |
| 2480 | + */ |
| 2481 | + |
| 2482 | + return 0; |
| 2483 | +} |
0 commit comments