Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ice: enable initial devlink support

Begin implementing support for the devlink interface with the ice
driver.

The pf structure is currently memory managed through devres, via
a devm_alloc. To mimic this behavior, after allocating the devlink
pointer, use devm_add_action to add a teardown action for releasing the
devlink memory on exit.

The ice hardware is a multi-function PCIe device. Thus, each physical
function will get its own devlink instance. This means that each
function will be treated independently, with its own parameters and
configuration. This is done because the ice driver loads a separate
instance for each function.

Due to this, the implementation does not enable devlink to manage
device-wide resources or configuration, as each physical function will
be treated independently. This is done for simplicity, as managing
a devlink instance across multiple driver instances would significantly
increase the complexity for minimal gain.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>

authored by

Jacob Keller and committed by
Jeff Kirsher
1adf7ead 84a24798

+166 -4
+1
drivers/net/ethernet/intel/Kconfig
··· 294 294 tristate "Intel(R) Ethernet Connection E800 Series Support" 295 295 default n 296 296 depends on PCI_MSI 297 + select NET_DEVLINK 297 298 ---help--- 298 299 This driver supports Intel(R) Ethernet Connection E800 Series of 299 300 devices. For more information on how to identify your adapter, go
+1
drivers/net/ethernet/intel/ice/Makefile
··· 19 19 ice_txrx.o \ 20 20 ice_flex_pipe.o \ 21 21 ice_flow.o \ 22 + ice_devlink.o \ 22 23 ice_ethtool.o 23 24 ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o 24 25 ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+4
drivers/net/ethernet/intel/ice/ice.h
··· 34 34 #include <linux/ctype.h> 35 35 #include <linux/bpf.h> 36 36 #include <linux/avf/virtchnl.h> 37 + #include <net/devlink.h> 37 38 #include <net/ipv6.h> 38 39 #include <net/xdp_sock.h> 39 40 #include "ice_devids.h" ··· 347 346 348 347 struct ice_pf { 349 348 struct pci_dev *pdev; 349 + 350 + /* devlink port data */ 351 + struct devlink_port devlink_port; 350 352 351 353 /* OS reserved IRQ details */ 352 354 struct msix_entry *msix_entries;
+117
drivers/net/ethernet/intel/ice/ice_devlink.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2020, Intel Corporation. */ 3 + 4 + #include "ice.h" 5 + #include "ice_devlink.h" 6 + 7 + static const struct devlink_ops ice_devlink_ops = { 8 + }; 9 + 10 + static void ice_devlink_free(void *devlink_ptr) 11 + { 12 + devlink_free((struct devlink *)devlink_ptr); 13 + } 14 + 15 + /** 16 + * ice_allocate_pf - Allocate devlink and return PF structure pointer 17 + * @dev: the device to allocate for 18 + * 19 + * Allocate a devlink instance for this device and return the private area as 20 + * the PF structure. The devlink memory is kept track of through devres by 21 + * adding an action to remove it when unwinding. 22 + */ 23 + struct ice_pf *ice_allocate_pf(struct device *dev) 24 + { 25 + struct devlink *devlink; 26 + 27 + devlink = devlink_alloc(&ice_devlink_ops, sizeof(struct ice_pf)); 28 + if (!devlink) 29 + return NULL; 30 + 31 + /* Add an action to teardown the devlink when unwinding the driver */ 32 + if (devm_add_action(dev, ice_devlink_free, devlink)) { 33 + devlink_free(devlink); 34 + return NULL; 35 + } 36 + 37 + return devlink_priv(devlink); 38 + } 39 + 40 + /** 41 + * ice_devlink_register - Register devlink interface for this PF 42 + * @pf: the PF to register the devlink for. 43 + * 44 + * Register the devlink instance associated with this physical function. 45 + * 46 + * Return: zero on success or an error code on failure. 47 + */ 48 + int ice_devlink_register(struct ice_pf *pf) 49 + { 50 + struct devlink *devlink = priv_to_devlink(pf); 51 + struct device *dev = ice_pf_to_dev(pf); 52 + int err; 53 + 54 + err = devlink_register(devlink, dev); 55 + if (err) { 56 + dev_err(dev, "devlink registration failed: %d\n", err); 57 + return err; 58 + } 59 + 60 + return 0; 61 + } 62 + 63 + /** 64 + * ice_devlink_unregister - Unregister devlink resources for this PF. 65 + * @pf: the PF structure to cleanup 66 + * 67 + * Releases resources used by devlink and cleans up associated memory. 68 + */ 69 + void ice_devlink_unregister(struct ice_pf *pf) 70 + { 71 + devlink_unregister(priv_to_devlink(pf)); 72 + } 73 + 74 + /** 75 + * ice_devlink_create_port - Create a devlink port for this PF 76 + * @pf: the PF to create a port for 77 + * 78 + * Create and register a devlink_port for this PF. Note that although each 79 + * physical function is connected to a separate devlink instance, the port 80 + * will still be numbered according to the physical function id. 81 + * 82 + * Return: zero on success or an error code on failure. 83 + */ 84 + int ice_devlink_create_port(struct ice_pf *pf) 85 + { 86 + struct devlink *devlink = priv_to_devlink(pf); 87 + struct ice_vsi *vsi = ice_get_main_vsi(pf); 88 + struct device *dev = ice_pf_to_dev(pf); 89 + int err; 90 + 91 + if (!vsi) { 92 + dev_err(dev, "%s: unable to find main VSI\n", __func__); 93 + return -EIO; 94 + } 95 + 96 + devlink_port_attrs_set(&pf->devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL, 97 + pf->hw.pf_id, false, 0, NULL, 0); 98 + err = devlink_port_register(devlink, &pf->devlink_port, pf->hw.pf_id); 99 + if (err) { 100 + dev_err(dev, "devlink_port_register failed: %d\n", err); 101 + return err; 102 + } 103 + 104 + return 0; 105 + } 106 + 107 + /** 108 + * ice_devlink_destroy_port - Destroy the devlink_port for this PF 109 + * @pf: the PF to cleanup 110 + * 111 + * Unregisters the devlink_port structure associated with this PF. 112 + */ 113 + void ice_devlink_destroy_port(struct ice_pf *pf) 114 + { 115 + devlink_port_type_clear(&pf->devlink_port); 116 + devlink_port_unregister(&pf->devlink_port); 117 + }
+14
drivers/net/ethernet/intel/ice/ice_devlink.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (c) 2019, Intel Corporation. */ 3 + 4 + #ifndef _ICE_DEVLINK_H_ 5 + #define _ICE_DEVLINK_H_ 6 + 7 + struct ice_pf *ice_allocate_pf(struct device *dev); 8 + 9 + int ice_devlink_register(struct ice_pf *pf); 10 + void ice_devlink_unregister(struct ice_pf *pf); 11 + int ice_devlink_create_port(struct ice_pf *pf); 12 + void ice_devlink_destroy_port(struct ice_pf *pf); 13 + 14 + #endif /* _ICE_DEVLINK_H_ */
+29 -4
drivers/net/ethernet/intel/ice/ice_main.c
··· 10 10 #include "ice_lib.h" 11 11 #include "ice_dcb_lib.h" 12 12 #include "ice_dcb_nl.h" 13 + #include "ice_devlink.h" 13 14 14 15 #define DRV_VERSION_MAJOR 0 15 16 #define DRV_VERSION_MINOR 8 ··· 2372 2371 u8 mac_addr[ETH_ALEN]; 2373 2372 int err; 2374 2373 2374 + err = ice_devlink_create_port(pf); 2375 + if (err) 2376 + return err; 2377 + 2375 2378 netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq, 2376 2379 vsi->alloc_rxq); 2377 - if (!netdev) 2378 - return -ENOMEM; 2380 + if (!netdev) { 2381 + err = -ENOMEM; 2382 + goto err_destroy_devlink_port; 2383 + } 2379 2384 2380 2385 vsi->netdev = netdev; 2381 2386 np = netdev_priv(netdev); ··· 2411 2404 2412 2405 err = register_netdev(vsi->netdev); 2413 2406 if (err) 2414 - return err; 2407 + goto err_destroy_devlink_port; 2408 + 2409 + devlink_port_type_eth_set(&pf->devlink_port, vsi->netdev); 2415 2410 2416 2411 netif_carrier_off(vsi->netdev); 2417 2412 ··· 2421 2412 netif_tx_stop_all_queues(vsi->netdev); 2422 2413 2423 2414 return 0; 2415 + 2416 + err_destroy_devlink_port: 2417 + ice_devlink_destroy_port(pf); 2418 + 2419 + return err; 2424 2420 } 2425 2421 2426 2422 /** ··· 3198 3184 return err; 3199 3185 } 3200 3186 3201 - pf = devm_kzalloc(dev, sizeof(*pf), GFP_KERNEL); 3187 + pf = ice_allocate_pf(dev); 3202 3188 if (!pf) 3203 3189 return -ENOMEM; 3204 3190 ··· 3235 3221 ice_set_ctrlq_len(hw); 3236 3222 3237 3223 pf->msg_enable = netif_msg_init(debug, ICE_DFLT_NETIF_M); 3224 + 3225 + err = ice_devlink_register(pf); 3226 + if (err) { 3227 + dev_err(dev, "ice_devlink_register failed: %d\n", err); 3228 + goto err_exit_unroll; 3229 + } 3238 3230 3239 3231 #ifndef CONFIG_DYNAMIC_DEBUG 3240 3232 if (debug < -1) ··· 3374 3354 return 0; 3375 3355 3376 3356 err_alloc_sw_unroll: 3357 + ice_devlink_destroy_port(pf); 3377 3358 set_bit(__ICE_SERVICE_DIS, pf->state); 3378 3359 set_bit(__ICE_DOWN, pf->state); 3379 3360 devm_kfree(dev, pf->first_sw); ··· 3387 3366 ice_deinit_pf(pf); 3388 3367 ice_deinit_hw(hw); 3389 3368 err_exit_unroll: 3369 + ice_devlink_unregister(pf); 3390 3370 pci_disable_pcie_error_reporting(pdev); 3391 3371 return err; 3392 3372 } ··· 3418 3396 set_bit(__ICE_DOWN, pf->state); 3419 3397 ice_service_task_stop(pf); 3420 3398 3399 + ice_devlink_destroy_port(pf); 3421 3400 ice_vsi_release_all(pf); 3422 3401 ice_free_irq_msix_misc(pf); 3423 3402 ice_for_each_vsi(pf, i) { ··· 3428 3405 } 3429 3406 ice_deinit_pf(pf); 3430 3407 ice_deinit_hw(&pf->hw); 3408 + ice_devlink_unregister(pf); 3409 + 3431 3410 /* Issue a PFR as part of the prescribed driver unload flow. Do not 3432 3411 * do it via ice_schedule_reset() since there is no need to rebuild 3433 3412 * and the service task is already stopped.