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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'mlx5-updates-2021-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

Saeed Mahameed says:

====================
mlx5 subfunction support

Parav Pandit says:

This patchset introduces support for mlx5 subfunction (SF).

A subfunction is a lightweight function that has a parent PCI function on
which it is deployed. mlx5 subfunction has its own function capabilities
and its own resources. This means a subfunction has its own dedicated
queues(txq, rxq, cq, eq). These queues are neither shared nor stolen from
the parent PCI function.

When subfunction is RDMA capable, it has its own QP1, GID table and rdma
resources neither shared nor stolen from the parent PCI function.

A subfunction has dedicated window in PCI BAR space that is not shared
with the other subfunctions or parent PCI function. This ensures that all
class devices of the subfunction accesses only assigned PCI BAR space.

A Subfunction supports eswitch representation through which it supports tc
offloads. User must configure eswitch to send/receive packets from/to
subfunction port.

Subfunctions share PCI level resources such as PCI MSI-X IRQs with
their other subfunctions and/or with its parent PCI function.

Subfunction support is discussed in detail in RFC [1] and [2].
RFC [1] and extension [2] describes requirements, design and proposed
plumbing using devlink, auxiliary bus and sysfs for systemd/udev
support. Functionality of this patchset is best explained using real
examples further below.

overview:
--------
A subfunction can be created and deleted by a user using devlink port
add/delete interface.

A subfunction can be configured using devlink port function attribute
before its activated.

When a subfunction is activated, it results in an auxiliary device on
the host PCI device where it is deployed. A driver binds to the
auxiliary device that further creates supported class devices.

example subfunction usage sequence:
-----------------------------------
Change device to switchdev mode:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev

Add a devlink port of subfunction flavour:
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88

Configure mac address of the port function:
$ devlink port function set ens2f0npf0sf88 hw_addr 00:00:00:00:88:88

Now activate the function:
$ devlink port function set ens2f0npf0sf88 state active

Now use the auxiliary device and class devices:
$ devlink dev show
pci/0000:06:00.0
auxiliary/mlx5_core.sf.4

$ ip link show
127: ens2f0np0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 24:8a:07:b3:d1:12 brd ff:ff:ff:ff:ff:ff
altname enp6s0f0np0
129: p0sf88: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:00:00:88:88 brd ff:ff:ff:ff:ff:ff

$ rdma dev show
43: rdmap6s0f0: node_type ca fw 16.29.0550 node_guid 248a:0703:00b3:d112 sys_image_guid 248a:0703:00b3:d112
44: mlx5_0: node_type ca fw 16.29.0550 node_guid 0000:00ff:fe00:8888 sys_image_guid 248a:0703:00b3:d112

After use inactivate the function:
$ devlink port function set ens2f0npf0sf88 state inactive

Now delete the subfunction port:
$ devlink port del ens2f0npf0sf88

[1] https://lore.kernel.org/netdev/20200519092258.GF4655@nanopsycho/
[2] https://marc.info/?l=linux-netdev&m=158555928517777&w=2

=================

* tag 'mlx5-updates-2021-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux:
net/mlx5: Add devlink subfunction port documentation
devlink: Extend devlink port documentation for subfunctions
devlink: Add devlink port documentation
net/mlx5: SF, Port function state change support
net/mlx5: SF, Add port add delete functionality
net/mlx5: E-switch, Add eswitch helpers for SF vport
net/mlx5: E-switch, Prepare eswitch to handle SF vport
net/mlx5: SF, Add auxiliary device driver
net/mlx5: SF, Add auxiliary device support
net/mlx5: Introduce vhca state event notifier
devlink: Support get and set state of port function
devlink: Support add and delete devlink port
devlink: Introduce PCI SF port flavour and port attribute
devlink: Prepare code to fill multiple port function attributes
====================

Link: https://lore.kernel.org/r/20210122193658.282884-1-saeed@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+2917 -47
+2
Documentation/driver-api/auxiliary_bus.rst
··· 1 1 .. SPDX-License-Identifier: GPL-2.0-only 2 2 3 + .. _auxiliary_bus: 4 + 3 5 ============= 4 6 Auxiliary Bus 5 7 =============
+215
Documentation/networking/device_drivers/ethernet/mellanox/mlx5.rst
··· 12 12 - `Enabling the driver and kconfig options`_ 13 13 - `Devlink info`_ 14 14 - `Devlink parameters`_ 15 + - `mlx5 subfunction`_ 16 + - `mlx5 port function`_ 15 17 - `Devlink health reporters`_ 16 18 - `mlx5 tracepoints`_ 17 19 ··· 99 97 100 98 | Provides low-level InfiniBand/RDMA and `RoCE <https://community.mellanox.com/s/article/recommended-network-configuration-examples-for-roce-deployment>`_ support. 101 99 100 + **CONFIG_MLX5_SF=(y/n)** 101 + 102 + | Build support for subfunction. 103 + | Subfunctons are more light weight than PCI SRIOV VFs. Choosing this option 104 + | will enable support for creating subfunction devices. 102 105 103 106 **External options** ( Choose if the corresponding mlx5 feature is required ) 104 107 ··· 182 175 name enable_roce type generic 183 176 values: 184 177 cmode driverinit value true 178 + 179 + mlx5 subfunction 180 + ================ 181 + mlx5 supports subfunction management using devlink port (see :ref:`Documentation/networking/devlink/devlink-port.rst <devlink_port>`) interface. 182 + 183 + A Subfunction has its own function capabilities and its own resources. This 184 + means a subfunction has its own dedicated queues (txq, rxq, cq, eq). These 185 + queues are neither shared nor stolen from the parent PCI function. 186 + 187 + When a subfunction is RDMA capable, it has its own QP1, GID table and rdma 188 + resources neither shared nor stolen from the parent PCI function. 189 + 190 + A subfunction has a dedicated window in PCI BAR space that is not shared 191 + with ther other subfunctions or the parent PCI function. This ensures that all 192 + devices (netdev, rdma, vdpa etc.) of the subfunction accesses only assigned 193 + PCI BAR space. 194 + 195 + A Subfunction supports eswitch representation through which it supports tc 196 + offloads. The user configures eswitch to send/receive packets from/to 197 + the subfunction port. 198 + 199 + Subfunctions share PCI level resources such as PCI MSI-X IRQs with 200 + other subfunctions and/or with its parent PCI function. 201 + 202 + Example mlx5 software, system and device view:: 203 + 204 + _______ 205 + | admin | 206 + | user |---------- 207 + |_______| | 208 + | | 209 + ____|____ __|______ _________________ 210 + | | | | | | 211 + | devlink | | tc tool | | user | 212 + | tool | |_________| | applications | 213 + |_________| | |_________________| 214 + | | | | 215 + | | | | Userspace 216 + +---------|-------------|-------------------|----------|--------------------+ 217 + | | +----------+ +----------+ Kernel 218 + | | | netdev | | rdma dev | 219 + | | +----------+ +----------+ 220 + (devlink port add/del | ^ ^ 221 + port function set) | | | 222 + | | +---------------| 223 + _____|___ | | _______|_______ 224 + | | | | | mlx5 class | 225 + | devlink | +------------+ | | drivers | 226 + | kernel | | rep netdev | | |(mlx5_core,ib) | 227 + |_________| +------------+ | |_______________| 228 + | | | ^ 229 + (devlink ops) | | (probe/remove) 230 + _________|________ | | ____|________ 231 + | subfunction | | +---------------+ | subfunction | 232 + | management driver|----- | subfunction |---| driver | 233 + | (mlx5_core) | | auxiliary dev | | (mlx5_core) | 234 + |__________________| +---------------+ |_____________| 235 + | ^ 236 + (sf add/del, vhca events) | 237 + | (device add/del) 238 + _____|____ ____|________ 239 + | | | subfunction | 240 + | PCI NIC |---- activate/deactive events---->| host driver | 241 + |__________| | (mlx5_core) | 242 + |_____________| 243 + 244 + Subfunction is created using devlink port interface. 245 + 246 + - Change device to switchdev mode:: 247 + 248 + $ devlink dev eswitch set pci/0000:06:00.0 mode switchdev 249 + 250 + - Add a devlink port of subfunction flaovur:: 251 + 252 + $ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88 253 + pci/0000:06:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false 254 + function: 255 + hw_addr 00:00:00:00:00:00 state inactive opstate detached 256 + 257 + - Show a devlink port of the subfunction:: 258 + 259 + $ devlink port show pci/0000:06:00.0/32768 260 + pci/0000:06:00.0/32768: type eth netdev enp6s0pf0sf88 flavour pcisf pfnum 0 sfnum 88 261 + function: 262 + hw_addr 00:00:00:00:00:00 state inactive opstate detached 263 + 264 + - Delete a devlink port of subfunction after use:: 265 + 266 + $ devlink port del pci/0000:06:00.0/32768 267 + 268 + mlx5 function attributes 269 + ======================== 270 + The mlx5 driver provides a mechanism to setup PCI VF/SF function attributes in 271 + a unified way for SmartNIC and non-SmartNIC. 272 + 273 + This is supported only when the eswitch mode is set to switchdev. Port function 274 + configuration of the PCI VF/SF is supported through devlink eswitch port. 275 + 276 + Port function attributes should be set before PCI VF/SF is enumerated by the 277 + driver. 278 + 279 + MAC address setup 280 + ----------------- 281 + mlx5 driver provides mechanism to setup the MAC address of the PCI VF/SF. 282 + 283 + The configured MAC address of the PCI VF/SF will be used by netdevice and rdma 284 + device created for the PCI VF/SF. 285 + 286 + - Get the MAC address of the VF identified by its unique devlink port index:: 287 + 288 + $ devlink port show pci/0000:06:00.0/2 289 + pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 290 + function: 291 + hw_addr 00:00:00:00:00:00 292 + 293 + - Set the MAC address of the VF identified by its unique devlink port index:: 294 + 295 + $ devlink port function set pci/0000:06:00.0/2 hw_addr 00:11:22:33:44:55 296 + 297 + $ devlink port show pci/0000:06:00.0/2 298 + pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 299 + function: 300 + hw_addr 00:11:22:33:44:55 301 + 302 + - Get the MAC address of the SF identified by its unique devlink port index:: 303 + 304 + $ devlink port show pci/0000:06:00.0/32768 305 + pci/0000:06:00.0/32768: type eth netdev enp6s0pf0sf88 flavour pcisf pfnum 0 sfnum 88 306 + function: 307 + hw_addr 00:00:00:00:00:00 308 + 309 + - Set the MAC address of the VF identified by its unique devlink port index:: 310 + 311 + $ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 312 + 313 + $ devlink port show pci/0000:06:00.0/32768 314 + pci/0000:06:00.0/32768: type eth netdev enp6s0pf0sf88 flavour pcivf pfnum 0 sfnum 88 315 + function: 316 + hw_addr 00:00:00:00:88:88 317 + 318 + SF state setup 319 + -------------- 320 + To use the SF, the user must active the SF using the SF function state 321 + attribute. 322 + 323 + - Get the state of the SF identified by its unique devlink port index:: 324 + 325 + $ devlink port show ens2f0npf0sf88 326 + pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false 327 + function: 328 + hw_addr 00:00:00:00:88:88 state inactive opstate detached 329 + 330 + - Activate the function and verify its state is active:: 331 + 332 + $ devlink port function set ens2f0npf0sf88 state active 333 + 334 + $ devlink port show ens2f0npf0sf88 335 + pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false 336 + function: 337 + hw_addr 00:00:00:00:88:88 state active opstate detached 338 + 339 + Upon function activation, the PF driver instance gets the event from the device 340 + that a particular SF was activated. It's the cue to put the device on bus, probe 341 + it and instantiate the devlink instance and class specific auxiliary devices 342 + for it. 343 + 344 + - Show the auxiliary device and port of the subfunction:: 345 + 346 + $ devlink dev show 347 + devlink dev show auxiliary/mlx5_core.sf.4 348 + 349 + $ devlink port show auxiliary/mlx5_core.sf.4/1 350 + auxiliary/mlx5_core.sf.4/1: type eth netdev p0sf88 flavour virtual port 0 splittable false 351 + 352 + $ rdma link show mlx5_0/1 353 + link mlx5_0/1 state ACTIVE physical_state LINK_UP netdev p0sf88 354 + 355 + $ rdma dev show 356 + 8: rocep6s0f1: node_type ca fw 16.29.0550 node_guid 248a:0703:00b3:d113 sys_image_guid 248a:0703:00b3:d112 357 + 13: mlx5_0: node_type ca fw 16.29.0550 node_guid 0000:00ff:fe00:8888 sys_image_guid 248a:0703:00b3:d112 358 + 359 + - Subfunction auxiliary device and class device hierarchy:: 360 + 361 + mlx5_core.sf.4 362 + (subfunction auxiliary device) 363 + /\ 364 + / \ 365 + / \ 366 + / \ 367 + / \ 368 + mlx5_core.eth.4 mlx5_core.rdma.4 369 + (sf eth aux dev) (sf rdma aux dev) 370 + | | 371 + | | 372 + p0sf88 mlx5_0 373 + (sf netdev) (sf rdma device) 374 + 375 + Additionally, the SF port also gets the event when the driver attaches to the 376 + auxiliary device of the subfunction. This results in changing the operational 377 + state of the function. This provides visiblity to the user to decide when is it 378 + safe to delete the SF port for graceful termination of the subfunction. 379 + 380 + - Show the SF port operational state:: 381 + 382 + $ devlink port show ens2f0npf0sf88 383 + pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false 384 + function: 385 + hw_addr 00:00:00:00:88:88 state active opstate attached 185 386 186 387 Devlink health reporters 187 388 ========================
+1
Documentation/networking/devlink/index.rst
··· 18 18 devlink-info 19 19 devlink-flash 20 20 devlink-params 21 + devlink-port 21 22 devlink-region 22 23 devlink-resource 23 24 devlink-reload
+19
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
··· 203 203 default y 204 204 help 205 205 Build support for software-managed steering in the NIC. 206 + 207 + config MLX5_SF 208 + bool "Mellanox Technologies subfunction device support using auxiliary device" 209 + depends on MLX5_CORE && MLX5_CORE_EN 210 + default n 211 + help 212 + Build support for subfuction device in the NIC. A Mellanox subfunction 213 + device can support RDMA, netdevice and vdpa device. 214 + It is similar to a SRIOV VF but it doesn't require SRIOV support. 215 + 216 + config MLX5_SF_MANAGER 217 + bool 218 + depends on MLX5_SF && MLX5_ESWITCH 219 + default y 220 + help 221 + Build support for subfuction port in the NIC. A Mellanox subfunction 222 + port is managed through devlink. A subfunction supports RDMA, netdevice 223 + and vdpa device. It is similar to a SRIOV VF but it doesn't require 224 + SRIOV support.
+9
drivers/net/ethernet/mellanox/mlx5/core/Makefile
··· 88 88 steering/dr_ste_v0.o \ 89 89 steering/dr_cmd.o steering/dr_fw.o \ 90 90 steering/dr_action.o steering/fs_dr.o 91 + # 92 + # SF device 93 + # 94 + mlx5_core-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o 95 + 96 + # 97 + # SF manager 98 + # 99 + mlx5_core-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o
+8
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
··· 333 333 case MLX5_CMD_OP_DEALLOC_MEMIC: 334 334 case MLX5_CMD_OP_PAGE_FAULT_RESUME: 335 335 case MLX5_CMD_OP_QUERY_ESW_FUNCTIONS: 336 + case MLX5_CMD_OP_DEALLOC_SF: 336 337 return MLX5_CMD_STAT_OK; 337 338 338 339 case MLX5_CMD_OP_QUERY_HCA_CAP: ··· 465 464 case MLX5_CMD_OP_ALLOC_MEMIC: 466 465 case MLX5_CMD_OP_MODIFY_XRQ: 467 466 case MLX5_CMD_OP_RELEASE_XRQ_ERROR: 467 + case MLX5_CMD_OP_QUERY_VHCA_STATE: 468 + case MLX5_CMD_OP_MODIFY_VHCA_STATE: 469 + case MLX5_CMD_OP_ALLOC_SF: 468 470 *status = MLX5_DRIVER_STATUS_ABORTED; 469 471 *synd = MLX5_DRIVER_SYND; 470 472 return -EIO; ··· 661 657 MLX5_COMMAND_STR_CASE(DESTROY_UMEM); 662 658 MLX5_COMMAND_STR_CASE(RELEASE_XRQ_ERROR); 663 659 MLX5_COMMAND_STR_CASE(MODIFY_XRQ); 660 + MLX5_COMMAND_STR_CASE(QUERY_VHCA_STATE); 661 + MLX5_COMMAND_STR_CASE(MODIFY_VHCA_STATE); 662 + MLX5_COMMAND_STR_CASE(ALLOC_SF); 663 + MLX5_COMMAND_STR_CASE(DEALLOC_SF); 664 664 default: return "unknown command opcode"; 665 665 } 666 666 }
+19
drivers/net/ethernet/mellanox/mlx5/core/devlink.c
··· 7 7 #include "fw_reset.h" 8 8 #include "fs_core.h" 9 9 #include "eswitch.h" 10 + #include "sf/dev/dev.h" 11 + #include "sf/sf.h" 10 12 11 13 static int mlx5_devlink_flash_update(struct devlink *devlink, 12 14 struct devlink_flash_update_params *params, ··· 129 127 struct netlink_ext_ack *extack) 130 128 { 131 129 struct mlx5_core_dev *dev = devlink_priv(devlink); 130 + bool sf_dev_allocated; 131 + 132 + sf_dev_allocated = mlx5_sf_dev_allocated(dev); 133 + if (sf_dev_allocated) { 134 + /* Reload results in deleting SF device which further results in 135 + * unregistering devlink instance while holding devlink_mutext. 136 + * Hence, do not support reload. 137 + */ 138 + NL_SET_ERR_MSG_MOD(extack, "reload is unsupported when SFs are allocated\n"); 139 + return -EOPNOTSUPP; 140 + } 132 141 133 142 switch (action) { 134 143 case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: ··· 276 263 .eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get, 277 264 .port_function_hw_addr_get = mlx5_devlink_port_function_hw_addr_get, 278 265 .port_function_hw_addr_set = mlx5_devlink_port_function_hw_addr_set, 266 + #endif 267 + #ifdef CONFIG_MLX5_SF_MANAGER 268 + .port_new = mlx5_devlink_sf_port_new, 269 + .port_del = mlx5_devlink_sf_port_del, 270 + .port_fn_state_get = mlx5_devlink_sf_port_fn_state_get, 271 + .port_fn_state_set = mlx5_devlink_sf_port_fn_state_set, 279 272 #endif 280 273 .flash_update = mlx5_devlink_flash_update, 281 274 .info_get = mlx5_devlink_info_get,
+4 -1
drivers/net/ethernet/mellanox/mlx5/core/eq.c
··· 467 467 for (i = 0; i < MLX5_EVENT_TYPE_MAX; i++) 468 468 ATOMIC_INIT_NOTIFIER_HEAD(&eq_table->nh[i]); 469 469 470 - eq_table->irq_table = dev->priv.irq_table; 470 + eq_table->irq_table = mlx5_irq_table_get(dev); 471 471 return 0; 472 472 } 473 473 ··· 594 594 if (mlx5_eswitch_is_funcs_handler(dev)) 595 595 async_event_mask |= 596 596 (1ull << MLX5_EVENT_TYPE_ESW_FUNCTIONS_CHANGED); 597 + 598 + if (MLX5_CAP_GEN_MAX(dev, vhca_state)) 599 + async_event_mask |= (1ull << MLX5_EVENT_TYPE_VHCA_STATE_CHANGE); 597 600 598 601 mask[0] = async_event_mask; 599 602
+1 -1
drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_ofld.c
··· 150 150 151 151 static bool esw_acl_egress_needed(const struct mlx5_eswitch *esw, u16 vport_num) 152 152 { 153 - return mlx5_eswitch_is_vf_vport(esw, vport_num); 153 + return mlx5_eswitch_is_vf_vport(esw, vport_num) || mlx5_esw_is_sf_vport(esw, vport_num); 154 154 } 155 155 156 156 int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+40 -8
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
··· 1272 1272 esw_vport_cleanup_acl(esw, vport); 1273 1273 } 1274 1274 1275 - static int esw_enable_vport(struct mlx5_eswitch *esw, u16 vport_num, 1276 - enum mlx5_eswitch_vport_event enabled_events) 1275 + int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, u16 vport_num, 1276 + enum mlx5_eswitch_vport_event enabled_events) 1277 1277 { 1278 1278 struct mlx5_vport *vport; 1279 1279 int ret; ··· 1309 1309 return ret; 1310 1310 } 1311 1311 1312 - static void esw_disable_vport(struct mlx5_eswitch *esw, u16 vport_num) 1312 + void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, u16 vport_num) 1313 1313 { 1314 1314 struct mlx5_vport *vport; 1315 1315 ··· 1365 1365 { 1366 1366 int outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out); 1367 1367 u32 in[MLX5_ST_SZ_DW(query_esw_functions_in)] = {}; 1368 + u16 max_sf_vports; 1368 1369 u32 *out; 1369 1370 int err; 1371 + 1372 + max_sf_vports = mlx5_sf_max_functions(dev); 1373 + /* Device interface is array of 64-bits */ 1374 + if (max_sf_vports) 1375 + outlen += DIV_ROUND_UP(max_sf_vports, BITS_PER_TYPE(__be64)) * sizeof(__be64); 1370 1376 1371 1377 out = kvzalloc(outlen, GFP_KERNEL); 1372 1378 if (!out) ··· 1381 1375 MLX5_SET(query_esw_functions_in, in, opcode, 1382 1376 MLX5_CMD_OP_QUERY_ESW_FUNCTIONS); 1383 1377 1384 - err = mlx5_cmd_exec_inout(dev, query_esw_functions, in, out); 1378 + err = mlx5_cmd_exec(dev, in, sizeof(in), out, outlen); 1385 1379 if (!err) 1386 1380 return out; 1387 1381 ··· 1431 1425 { 1432 1426 int err; 1433 1427 1434 - err = esw_enable_vport(esw, vport_num, enabled_events); 1428 + err = mlx5_esw_vport_enable(esw, vport_num, enabled_events); 1435 1429 if (err) 1436 1430 return err; 1437 1431 ··· 1442 1436 return err; 1443 1437 1444 1438 err_rep: 1445 - esw_disable_vport(esw, vport_num); 1439 + mlx5_esw_vport_disable(esw, vport_num); 1446 1440 return err; 1447 1441 } 1448 1442 1449 1443 void mlx5_eswitch_unload_vport(struct mlx5_eswitch *esw, u16 vport_num) 1450 1444 { 1451 1445 esw_offloads_unload_rep(esw, vport_num); 1452 - esw_disable_vport(esw, vport_num); 1446 + mlx5_esw_vport_disable(esw, vport_num); 1453 1447 } 1454 1448 1455 1449 void mlx5_eswitch_unload_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs) ··· 1599 1593 kvfree(out); 1600 1594 } 1601 1595 1596 + static void mlx5_esw_mode_change_notify(struct mlx5_eswitch *esw, u16 mode) 1597 + { 1598 + struct mlx5_esw_event_info info = {}; 1599 + 1600 + info.new_mode = mode; 1601 + 1602 + blocking_notifier_call_chain(&esw->n_head, 0, &info); 1603 + } 1604 + 1602 1605 /** 1603 1606 * mlx5_eswitch_enable_locked - Enable eswitch 1604 1607 * @esw: Pointer to eswitch ··· 1668 1653 mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS", 1669 1654 esw->esw_funcs.num_vfs, esw->enabled_vports); 1670 1655 1656 + mlx5_esw_mode_change_notify(esw, mode); 1657 + 1671 1658 return 0; 1672 1659 1673 1660 abort: ··· 1725 1708 esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n", 1726 1709 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS", 1727 1710 esw->esw_funcs.num_vfs, esw->enabled_vports); 1711 + 1712 + /* Notify eswitch users that it is exiting from current mode. 1713 + * So that it can do necessary cleanup before the eswitch is disabled. 1714 + */ 1715 + mlx5_esw_mode_change_notify(esw, MLX5_ESWITCH_NONE); 1728 1716 1729 1717 mlx5_eswitch_event_handlers_unregister(esw); 1730 1718 ··· 1831 1809 esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE; 1832 1810 1833 1811 dev->priv.eswitch = esw; 1812 + BLOCKING_INIT_NOTIFIER_HEAD(&esw->n_head); 1834 1813 return 0; 1835 1814 abort: 1836 1815 if (esw->work_queue) ··· 1921 1898 is_port_function_supported(const struct mlx5_eswitch *esw, u16 vport_num) 1922 1899 { 1923 1900 return vport_num == MLX5_VPORT_PF || 1924 - mlx5_eswitch_is_vf_vport(esw, vport_num); 1901 + mlx5_eswitch_is_vf_vport(esw, vport_num) || 1902 + mlx5_esw_is_sf_vport(esw, vport_num); 1925 1903 } 1926 1904 1927 1905 int mlx5_devlink_port_function_hw_addr_get(struct devlink *devlink, ··· 2523 2499 dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS); 2524 2500 } 2525 2501 2502 + int mlx5_esw_event_notifier_register(struct mlx5_eswitch *esw, struct notifier_block *nb) 2503 + { 2504 + return blocking_notifier_chain_register(&esw->n_head, nb); 2505 + } 2526 2506 2507 + void mlx5_esw_event_notifier_unregister(struct mlx5_eswitch *esw, struct notifier_block *nb) 2508 + { 2509 + blocking_notifier_chain_unregister(&esw->n_head, nb); 2510 + }
+78
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
··· 43 43 #include <linux/mlx5/fs.h> 44 44 #include "lib/mpfs.h" 45 45 #include "lib/fs_chains.h" 46 + #include "sf/sf.h" 46 47 #include "en/tc_ct.h" 47 48 48 49 #ifdef CONFIG_MLX5_ESWITCH ··· 278 277 struct { 279 278 u32 large_group_num; 280 279 } params; 280 + struct blocking_notifier_head n_head; 281 281 }; 282 282 283 283 void esw_offloads_disable(struct mlx5_eswitch *esw); ··· 501 499 MLX5_VPORT_PF : MLX5_VPORT_FIRST_VF; 502 500 } 503 501 502 + static inline int mlx5_esw_sf_start_idx(const struct mlx5_eswitch *esw) 503 + { 504 + /* PF and VF vports indices start from 0 to max_vfs */ 505 + return MLX5_VPORT_PF_PLACEHOLDER + mlx5_core_max_vfs(esw->dev); 506 + } 507 + 508 + static inline int mlx5_esw_sf_end_idx(const struct mlx5_eswitch *esw) 509 + { 510 + return mlx5_esw_sf_start_idx(esw) + mlx5_sf_max_functions(esw->dev); 511 + } 512 + 513 + static inline int 514 + mlx5_esw_sf_vport_num_to_index(const struct mlx5_eswitch *esw, u16 vport_num) 515 + { 516 + return vport_num - mlx5_sf_start_function_id(esw->dev) + 517 + MLX5_VPORT_PF_PLACEHOLDER + mlx5_core_max_vfs(esw->dev); 518 + } 519 + 520 + static inline u16 521 + mlx5_esw_sf_vport_index_to_num(const struct mlx5_eswitch *esw, int idx) 522 + { 523 + return mlx5_sf_start_function_id(esw->dev) + idx - 524 + (MLX5_VPORT_PF_PLACEHOLDER + mlx5_core_max_vfs(esw->dev)); 525 + } 526 + 527 + static inline bool 528 + mlx5_esw_is_sf_vport(const struct mlx5_eswitch *esw, u16 vport_num) 529 + { 530 + return mlx5_sf_supported(esw->dev) && 531 + vport_num >= mlx5_sf_start_function_id(esw->dev) && 532 + (vport_num < (mlx5_sf_start_function_id(esw->dev) + 533 + mlx5_sf_max_functions(esw->dev))); 534 + } 535 + 504 536 static inline bool mlx5_eswitch_is_funcs_handler(const struct mlx5_core_dev *dev) 505 537 { 506 538 return mlx5_core_is_ecpf_esw_manager(dev); ··· 563 527 if (vport_num == MLX5_VPORT_UPLINK) 564 528 return mlx5_eswitch_uplink_idx(esw); 565 529 530 + if (mlx5_esw_is_sf_vport(esw, vport_num)) 531 + return mlx5_esw_sf_vport_num_to_index(esw, vport_num); 532 + 533 + /* PF and VF vports start from 0 to max_vfs */ 566 534 return vport_num; 567 535 } 568 536 ··· 580 540 if (index == mlx5_eswitch_uplink_idx(esw)) 581 541 return MLX5_VPORT_UPLINK; 582 542 543 + /* SF vports indices are after VFs and before ECPF */ 544 + if (mlx5_sf_supported(esw->dev) && 545 + index > mlx5_core_max_vfs(esw->dev)) 546 + return mlx5_esw_sf_vport_index_to_num(esw, index); 547 + 548 + /* PF and VF vports start from 0 to max_vfs */ 583 549 return index; 584 550 } 585 551 ··· 671 625 for ((vport) = (nvfs); \ 672 626 (vport) >= (esw)->first_host_vport; (vport)--) 673 627 628 + #define mlx5_esw_for_each_sf_rep(esw, i, rep) \ 629 + for ((i) = mlx5_esw_sf_start_idx(esw); \ 630 + (rep) = &(esw)->offloads.vport_reps[(i)], \ 631 + (i) < mlx5_esw_sf_end_idx(esw); (i++)) 632 + 674 633 struct mlx5_eswitch *mlx5_devlink_eswitch_get(struct devlink *devlink); 675 634 struct mlx5_vport *__must_check 676 635 mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num); ··· 688 637 mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, 689 638 enum mlx5_eswitch_vport_event enabled_events); 690 639 void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw); 640 + 641 + int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, u16 vport_num, 642 + enum mlx5_eswitch_vport_event enabled_events); 643 + void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, u16 vport_num); 691 644 692 645 int 693 646 esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw, ··· 711 656 int esw_offloads_load_rep(struct mlx5_eswitch *esw, u16 vport_num); 712 657 void esw_offloads_unload_rep(struct mlx5_eswitch *esw, u16 vport_num); 713 658 659 + int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num); 660 + void mlx5_esw_offloads_rep_unload(struct mlx5_eswitch *esw, u16 vport_num); 661 + 714 662 int mlx5_eswitch_load_vport(struct mlx5_eswitch *esw, u16 vport_num, 715 663 enum mlx5_eswitch_vport_event enabled_events); 716 664 void mlx5_eswitch_unload_vport(struct mlx5_eswitch *esw, u16 vport_num); ··· 725 667 int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num); 726 668 void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, u16 vport_num); 727 669 struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num); 670 + 671 + int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port, 672 + u16 vport_num, u32 sfnum); 673 + void mlx5_esw_devlink_sf_port_unregister(struct mlx5_eswitch *esw, u16 vport_num); 674 + 675 + int mlx5_esw_offloads_sf_vport_enable(struct mlx5_eswitch *esw, struct devlink_port *dl_port, 676 + u16 vport_num, u32 sfnum); 677 + void mlx5_esw_offloads_sf_vport_disable(struct mlx5_eswitch *esw, u16 vport_num); 678 + 679 + /** 680 + * mlx5_esw_event_info - Indicates eswitch mode changed/changing. 681 + * 682 + * @new_mode: New mode of eswitch. 683 + */ 684 + struct mlx5_esw_event_info { 685 + u16 new_mode; 686 + }; 687 + 688 + int mlx5_esw_event_notifier_register(struct mlx5_eswitch *esw, struct notifier_block *n); 689 + void mlx5_esw_event_notifier_unregister(struct mlx5_eswitch *esw, struct notifier_block *n); 728 690 #else /* CONFIG_MLX5_ESWITCH */ 729 691 /* eswitch API stubs */ 730 692 static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
+45 -2
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
··· 1800 1800 esw->offloads.rep_ops[rep_type]->unload(rep); 1801 1801 } 1802 1802 1803 + static void __unload_reps_sf_vport(struct mlx5_eswitch *esw, u8 rep_type) 1804 + { 1805 + struct mlx5_eswitch_rep *rep; 1806 + int i; 1807 + 1808 + mlx5_esw_for_each_sf_rep(esw, i, rep) 1809 + __esw_offloads_unload_rep(esw, rep, rep_type); 1810 + } 1811 + 1803 1812 static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type) 1804 1813 { 1805 1814 struct mlx5_eswitch_rep *rep; 1806 1815 int i; 1816 + 1817 + __unload_reps_sf_vport(esw, rep_type); 1807 1818 1808 1819 mlx5_esw_for_each_vf_rep_reverse(esw, i, rep, esw->esw_funcs.num_vfs) 1809 1820 __esw_offloads_unload_rep(esw, rep, rep_type); ··· 1833 1822 __esw_offloads_unload_rep(esw, rep, rep_type); 1834 1823 } 1835 1824 1836 - static int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num) 1825 + int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num) 1837 1826 { 1838 1827 struct mlx5_eswitch_rep *rep; 1839 1828 int rep_type; ··· 1857 1846 return err; 1858 1847 } 1859 1848 1860 - static void mlx5_esw_offloads_rep_unload(struct mlx5_eswitch *esw, u16 vport_num) 1849 + void mlx5_esw_offloads_rep_unload(struct mlx5_eswitch *esw, u16 vport_num) 1861 1850 { 1862 1851 struct mlx5_eswitch_rep *rep; 1863 1852 int rep_type; ··· 2835 2824 return vport->metadata << (32 - ESW_SOURCE_PORT_METADATA_BITS); 2836 2825 } 2837 2826 EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_match); 2827 + 2828 + int mlx5_esw_offloads_sf_vport_enable(struct mlx5_eswitch *esw, struct devlink_port *dl_port, 2829 + u16 vport_num, u32 sfnum) 2830 + { 2831 + int err; 2832 + 2833 + err = mlx5_esw_vport_enable(esw, vport_num, MLX5_VPORT_UC_ADDR_CHANGE); 2834 + if (err) 2835 + return err; 2836 + 2837 + err = mlx5_esw_devlink_sf_port_register(esw, dl_port, vport_num, sfnum); 2838 + if (err) 2839 + goto devlink_err; 2840 + 2841 + err = mlx5_esw_offloads_rep_load(esw, vport_num); 2842 + if (err) 2843 + goto rep_err; 2844 + return 0; 2845 + 2846 + rep_err: 2847 + mlx5_esw_devlink_sf_port_unregister(esw, vport_num); 2848 + devlink_err: 2849 + mlx5_esw_vport_disable(esw, vport_num); 2850 + return err; 2851 + } 2852 + 2853 + void mlx5_esw_offloads_sf_vport_disable(struct mlx5_eswitch *esw, u16 vport_num) 2854 + { 2855 + mlx5_esw_offloads_rep_unload(esw, vport_num); 2856 + mlx5_esw_devlink_sf_port_unregister(esw, vport_num); 2857 + mlx5_esw_vport_disable(esw, vport_num); 2858 + }
+7
drivers/net/ethernet/mellanox/mlx5/core/events.c
··· 112 112 return "MLX5_EVENT_TYPE_CMD"; 113 113 case MLX5_EVENT_TYPE_ESW_FUNCTIONS_CHANGED: 114 114 return "MLX5_EVENT_TYPE_ESW_FUNCTIONS_CHANGED"; 115 + case MLX5_EVENT_TYPE_VHCA_STATE_CHANGE: 116 + return "MLX5_EVENT_TYPE_VHCA_STATE_CHANGE"; 115 117 case MLX5_EVENT_TYPE_PAGE_REQUEST: 116 118 return "MLX5_EVENT_TYPE_PAGE_REQUEST"; 117 119 case MLX5_EVENT_TYPE_PAGE_FAULT: ··· 435 433 struct mlx5_events *events = dev->priv.events; 436 434 437 435 return blocking_notifier_call_chain(&events->sw_nh, event, data); 436 + } 437 + 438 + void mlx5_events_work_enqueue(struct mlx5_core_dev *dev, struct work_struct *work) 439 + { 440 + queue_work(dev->priv.events->wq, work); 438 441 }
+57 -3
drivers/net/ethernet/mellanox/mlx5/core/main.c
··· 73 73 #include "ecpf.h" 74 74 #include "lib/hv_vhca.h" 75 75 #include "diag/rsc_dump.h" 76 + #include "sf/vhca_event.h" 77 + #include "sf/dev/dev.h" 78 + #include "sf/sf.h" 76 79 77 80 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); 78 81 MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver"); ··· 85 82 module_param_named(debug_mask, mlx5_core_debug_mask, uint, 0644); 86 83 MODULE_PARM_DESC(debug_mask, "debug mask: 1 = dump cmd data, 2 = dump cmd exec time, 3 = both. Default=0"); 87 84 88 - #define MLX5_DEFAULT_PROF 2 89 85 static unsigned int prof_sel = MLX5_DEFAULT_PROF; 90 86 module_param_named(prof_sel, prof_sel, uint, 0444); 91 87 MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2"); ··· 569 567 if (MLX5_CAP_GEN_MAX(dev, mkey_by_name)) 570 568 MLX5_SET(cmd_hca_cap, set_hca_cap, mkey_by_name, 1); 571 569 570 + mlx5_vhca_state_cap_handle(dev, set_hca_cap); 571 + 572 572 return set_caps(dev, set_ctx, MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE); 573 573 } 574 574 ··· 888 884 goto err_eswitch_cleanup; 889 885 } 890 886 887 + err = mlx5_vhca_event_init(dev); 888 + if (err) { 889 + mlx5_core_err(dev, "Failed to init vhca event notifier %d\n", err); 890 + goto err_fpga_cleanup; 891 + } 892 + 893 + err = mlx5_sf_hw_table_init(dev); 894 + if (err) { 895 + mlx5_core_err(dev, "Failed to init SF HW table %d\n", err); 896 + goto err_sf_hw_table_cleanup; 897 + } 898 + 899 + err = mlx5_sf_table_init(dev); 900 + if (err) { 901 + mlx5_core_err(dev, "Failed to init SF table %d\n", err); 902 + goto err_sf_table_cleanup; 903 + } 904 + 891 905 dev->dm = mlx5_dm_create(dev); 892 906 if (IS_ERR(dev->dm)) 893 907 mlx5_core_warn(dev, "Failed to init device memory%d\n", err); ··· 916 894 917 895 return 0; 918 896 897 + err_sf_table_cleanup: 898 + mlx5_sf_hw_table_cleanup(dev); 899 + err_sf_hw_table_cleanup: 900 + mlx5_vhca_event_cleanup(dev); 901 + err_fpga_cleanup: 902 + mlx5_fpga_cleanup(dev); 919 903 err_eswitch_cleanup: 920 904 mlx5_eswitch_cleanup(dev->priv.eswitch); 921 905 err_sriov_cleanup: ··· 953 925 mlx5_hv_vhca_destroy(dev->hv_vhca); 954 926 mlx5_fw_tracer_destroy(dev->tracer); 955 927 mlx5_dm_cleanup(dev); 928 + mlx5_sf_table_cleanup(dev); 929 + mlx5_sf_hw_table_cleanup(dev); 930 + mlx5_vhca_event_cleanup(dev); 956 931 mlx5_fpga_cleanup(dev); 957 932 mlx5_eswitch_cleanup(dev->priv.eswitch); 958 933 mlx5_sriov_cleanup(dev); ··· 1160 1129 goto err_sriov; 1161 1130 } 1162 1131 1132 + mlx5_vhca_event_start(dev); 1133 + 1134 + err = mlx5_sf_hw_table_create(dev); 1135 + if (err) { 1136 + mlx5_core_err(dev, "sf table create failed %d\n", err); 1137 + goto err_vhca; 1138 + } 1139 + 1163 1140 err = mlx5_ec_init(dev); 1164 1141 if (err) { 1165 1142 mlx5_core_err(dev, "Failed to init embedded CPU\n"); ··· 1180 1141 goto err_sriov; 1181 1142 } 1182 1143 1144 + mlx5_sf_dev_table_create(dev); 1145 + 1183 1146 return 0; 1184 1147 1185 1148 err_sriov: 1186 1149 mlx5_ec_cleanup(dev); 1187 1150 err_ec: 1151 + mlx5_sf_hw_table_destroy(dev); 1152 + err_vhca: 1153 + mlx5_vhca_event_stop(dev); 1188 1154 mlx5_cleanup_fs(dev); 1189 1155 err_fs: 1190 1156 mlx5_accel_tls_cleanup(dev); ··· 1215 1171 1216 1172 static void mlx5_unload(struct mlx5_core_dev *dev) 1217 1173 { 1174 + mlx5_sf_dev_table_destroy(dev); 1218 1175 mlx5_sriov_detach(dev); 1219 1176 mlx5_ec_cleanup(dev); 1177 + mlx5_sf_hw_table_destroy(dev); 1178 + mlx5_vhca_event_stop(dev); 1220 1179 mlx5_cleanup_fs(dev); 1221 1180 mlx5_accel_ipsec_cleanup(dev); 1222 1181 mlx5_accel_tls_cleanup(dev); ··· 1330 1283 mutex_unlock(&dev->intf_state_mutex); 1331 1284 } 1332 1285 1333 - static int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) 1286 + int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) 1334 1287 { 1335 1288 struct mlx5_priv *priv = &dev->priv; 1336 1289 int err; ··· 1382 1335 return err; 1383 1336 } 1384 1337 1385 - static void mlx5_mdev_uninit(struct mlx5_core_dev *dev) 1338 + void mlx5_mdev_uninit(struct mlx5_core_dev *dev) 1386 1339 { 1387 1340 struct mlx5_priv *priv = &dev->priv; 1388 1341 ··· 1725 1678 if (err) 1726 1679 goto err_debug; 1727 1680 1681 + err = mlx5_sf_driver_register(); 1682 + if (err) 1683 + goto err_sf; 1684 + 1728 1685 #ifdef CONFIG_MLX5_CORE_EN 1729 1686 err = mlx5e_init(); 1730 1687 if (err) { ··· 1739 1688 1740 1689 return 0; 1741 1690 1691 + err_sf: 1692 + pci_unregister_driver(&mlx5_core_driver); 1742 1693 err_debug: 1743 1694 mlx5_unregister_debugfs(); 1744 1695 return err; ··· 1751 1698 #ifdef CONFIG_MLX5_CORE_EN 1752 1699 mlx5e_cleanup(); 1753 1700 #endif 1701 + mlx5_sf_driver_unregister(); 1754 1702 pci_unregister_driver(&mlx5_core_driver); 1755 1703 mlx5_unregister_debugfs(); 1756 1704 }
+12
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
··· 117 117 MLX5_SEMAPHORE_SW_RESET = 0x20, 118 118 }; 119 119 120 + #define MLX5_DEFAULT_PROF 2 121 + 120 122 int mlx5_query_hca_caps(struct mlx5_core_dev *dev); 121 123 int mlx5_query_board_id(struct mlx5_core_dev *dev); 122 124 int mlx5_cmd_init(struct mlx5_core_dev *dev); ··· 178 176 mlx5_irq_get_affinity_mask(struct mlx5_irq_table *irq_table, int vecidx); 179 177 struct cpu_rmap *mlx5_irq_get_rmap(struct mlx5_irq_table *table); 180 178 int mlx5_irq_get_num_comp(struct mlx5_irq_table *table); 179 + struct mlx5_irq_table *mlx5_irq_table_get(struct mlx5_core_dev *dev); 181 180 182 181 int mlx5_events_init(struct mlx5_core_dev *dev); 183 182 void mlx5_events_cleanup(struct mlx5_core_dev *dev); ··· 260 257 u8 mlx5_get_nic_state(struct mlx5_core_dev *dev); 261 258 void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state); 262 259 260 + static inline bool mlx5_core_is_sf(const struct mlx5_core_dev *dev) 261 + { 262 + return dev->coredev_type == MLX5_COREDEV_SF; 263 + } 264 + 265 + int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx); 266 + void mlx5_mdev_uninit(struct mlx5_core_dev *dev); 263 267 void mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup); 264 268 int mlx5_load_one(struct mlx5_core_dev *dev, bool boot); 269 + 270 + void mlx5_events_work_enqueue(struct mlx5_core_dev *dev, struct work_struct *work); 265 271 #endif /* __MLX5_CORE_H__ */
+20
drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
··· 30 30 { 31 31 struct mlx5_irq_table *irq_table; 32 32 33 + if (mlx5_core_is_sf(dev)) 34 + return 0; 35 + 33 36 irq_table = kvzalloc(sizeof(*irq_table), GFP_KERNEL); 34 37 if (!irq_table) 35 38 return -ENOMEM; ··· 43 40 44 41 void mlx5_irq_table_cleanup(struct mlx5_core_dev *dev) 45 42 { 43 + if (mlx5_core_is_sf(dev)) 44 + return; 45 + 46 46 kvfree(dev->priv.irq_table); 47 47 } 48 48 ··· 274 268 int nvec; 275 269 int err; 276 270 271 + if (mlx5_core_is_sf(dev)) 272 + return 0; 273 + 277 274 nvec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() + 278 275 MLX5_IRQ_VEC_COMP_BASE; 279 276 nvec = min_t(int, nvec, num_eqs); ··· 328 319 struct mlx5_irq_table *table = dev->priv.irq_table; 329 320 int i; 330 321 322 + if (mlx5_core_is_sf(dev)) 323 + return; 324 + 331 325 /* free_irq requires that affinity and rmap will be cleared 332 326 * before calling it. This is why there is asymmetry with set_rmap 333 327 * which should be called after alloc_irq but before request_irq. ··· 344 332 kfree(table->irq); 345 333 } 346 334 335 + struct mlx5_irq_table *mlx5_irq_table_get(struct mlx5_core_dev *dev) 336 + { 337 + #ifdef CONFIG_MLX5_SF 338 + if (mlx5_core_is_sf(dev)) 339 + return dev->priv.parent_mdev->priv.irq_table; 340 + #endif 341 + return dev->priv.irq_table; 342 + }
+49
drivers/net/ethernet/mellanox/mlx5/core/sf/cmd.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #include <linux/mlx5/driver.h> 5 + #include "priv.h" 6 + 7 + int mlx5_cmd_alloc_sf(struct mlx5_core_dev *dev, u16 function_id) 8 + { 9 + u32 out[MLX5_ST_SZ_DW(alloc_sf_out)] = {}; 10 + u32 in[MLX5_ST_SZ_DW(alloc_sf_in)] = {}; 11 + 12 + MLX5_SET(alloc_sf_in, in, opcode, MLX5_CMD_OP_ALLOC_SF); 13 + MLX5_SET(alloc_sf_in, in, function_id, function_id); 14 + 15 + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 16 + } 17 + 18 + int mlx5_cmd_dealloc_sf(struct mlx5_core_dev *dev, u16 function_id) 19 + { 20 + u32 out[MLX5_ST_SZ_DW(dealloc_sf_out)] = {}; 21 + u32 in[MLX5_ST_SZ_DW(dealloc_sf_in)] = {}; 22 + 23 + MLX5_SET(dealloc_sf_in, in, opcode, MLX5_CMD_OP_DEALLOC_SF); 24 + MLX5_SET(dealloc_sf_in, in, function_id, function_id); 25 + 26 + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 27 + } 28 + 29 + int mlx5_cmd_sf_enable_hca(struct mlx5_core_dev *dev, u16 func_id) 30 + { 31 + u32 out[MLX5_ST_SZ_DW(enable_hca_out)] = {}; 32 + u32 in[MLX5_ST_SZ_DW(enable_hca_in)] = {}; 33 + 34 + MLX5_SET(enable_hca_in, in, opcode, MLX5_CMD_OP_ENABLE_HCA); 35 + MLX5_SET(enable_hca_in, in, function_id, func_id); 36 + MLX5_SET(enable_hca_in, in, embedded_cpu_function, 0); 37 + return mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 38 + } 39 + 40 + int mlx5_cmd_sf_disable_hca(struct mlx5_core_dev *dev, u16 func_id) 41 + { 42 + u32 out[MLX5_ST_SZ_DW(disable_hca_out)] = {}; 43 + u32 in[MLX5_ST_SZ_DW(disable_hca_in)] = {}; 44 + 45 + MLX5_SET(disable_hca_in, in, opcode, MLX5_CMD_OP_DISABLE_HCA); 46 + MLX5_SET(disable_hca_in, in, function_id, func_id); 47 + MLX5_SET(enable_hca_in, in, embedded_cpu_function, 0); 48 + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 49 + }
+275
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #include <linux/mlx5/driver.h> 5 + #include <linux/mlx5/device.h> 6 + #include "mlx5_core.h" 7 + #include "dev.h" 8 + #include "sf/vhca_event.h" 9 + #include "sf/sf.h" 10 + #include "sf/mlx5_ifc_vhca_event.h" 11 + #include "ecpf.h" 12 + 13 + struct mlx5_sf_dev_table { 14 + struct xarray devices; 15 + unsigned int max_sfs; 16 + phys_addr_t base_address; 17 + u64 sf_bar_length; 18 + struct notifier_block nb; 19 + struct mlx5_core_dev *dev; 20 + }; 21 + 22 + static bool mlx5_sf_dev_supported(const struct mlx5_core_dev *dev) 23 + { 24 + return MLX5_CAP_GEN(dev, sf) && mlx5_vhca_event_supported(dev); 25 + } 26 + 27 + bool mlx5_sf_dev_allocated(const struct mlx5_core_dev *dev) 28 + { 29 + struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table; 30 + 31 + if (!mlx5_sf_dev_supported(dev)) 32 + return false; 33 + 34 + return !xa_empty(&table->devices); 35 + } 36 + 37 + static ssize_t sfnum_show(struct device *dev, struct device_attribute *attr, char *buf) 38 + { 39 + struct auxiliary_device *adev = container_of(dev, struct auxiliary_device, dev); 40 + struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); 41 + 42 + return scnprintf(buf, PAGE_SIZE, "%u\n", sf_dev->sfnum); 43 + } 44 + static DEVICE_ATTR_RO(sfnum); 45 + 46 + static struct attribute *sf_device_attrs[] = { 47 + &dev_attr_sfnum.attr, 48 + NULL, 49 + }; 50 + 51 + static const struct attribute_group sf_attr_group = { 52 + .attrs = sf_device_attrs, 53 + }; 54 + 55 + static const struct attribute_group *sf_attr_groups[2] = { 56 + &sf_attr_group, 57 + NULL 58 + }; 59 + 60 + static void mlx5_sf_dev_release(struct device *device) 61 + { 62 + struct auxiliary_device *adev = container_of(device, struct auxiliary_device, dev); 63 + struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); 64 + 65 + mlx5_adev_idx_free(adev->id); 66 + kfree(sf_dev); 67 + } 68 + 69 + static void mlx5_sf_dev_remove(struct mlx5_sf_dev *sf_dev) 70 + { 71 + auxiliary_device_delete(&sf_dev->adev); 72 + auxiliary_device_uninit(&sf_dev->adev); 73 + } 74 + 75 + static void mlx5_sf_dev_add(struct mlx5_core_dev *dev, u16 sf_index, u32 sfnum) 76 + { 77 + struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table; 78 + struct mlx5_sf_dev *sf_dev; 79 + struct pci_dev *pdev; 80 + int err; 81 + int id; 82 + 83 + id = mlx5_adev_idx_alloc(); 84 + if (id < 0) { 85 + err = id; 86 + goto add_err; 87 + } 88 + 89 + sf_dev = kzalloc(sizeof(*sf_dev), GFP_KERNEL); 90 + if (!sf_dev) { 91 + mlx5_adev_idx_free(id); 92 + err = -ENOMEM; 93 + goto add_err; 94 + } 95 + pdev = dev->pdev; 96 + sf_dev->adev.id = id; 97 + sf_dev->adev.name = MLX5_SF_DEV_ID_NAME; 98 + sf_dev->adev.dev.release = mlx5_sf_dev_release; 99 + sf_dev->adev.dev.parent = &pdev->dev; 100 + sf_dev->adev.dev.groups = sf_attr_groups; 101 + sf_dev->sfnum = sfnum; 102 + sf_dev->parent_mdev = dev; 103 + 104 + if (!table->max_sfs) { 105 + mlx5_adev_idx_free(id); 106 + kfree(sf_dev); 107 + err = -EOPNOTSUPP; 108 + goto add_err; 109 + } 110 + sf_dev->bar_base_addr = table->base_address + (sf_index * table->sf_bar_length); 111 + 112 + err = auxiliary_device_init(&sf_dev->adev); 113 + if (err) { 114 + mlx5_adev_idx_free(id); 115 + kfree(sf_dev); 116 + goto add_err; 117 + } 118 + 119 + err = auxiliary_device_add(&sf_dev->adev); 120 + if (err) { 121 + put_device(&sf_dev->adev.dev); 122 + goto add_err; 123 + } 124 + 125 + err = xa_insert(&table->devices, sf_index, sf_dev, GFP_KERNEL); 126 + if (err) 127 + goto xa_err; 128 + return; 129 + 130 + xa_err: 131 + mlx5_sf_dev_remove(sf_dev); 132 + add_err: 133 + mlx5_core_err(dev, "SF DEV: fail device add for index=%d sfnum=%d err=%d\n", 134 + sf_index, sfnum, err); 135 + } 136 + 137 + static void mlx5_sf_dev_del(struct mlx5_core_dev *dev, struct mlx5_sf_dev *sf_dev, u16 sf_index) 138 + { 139 + struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table; 140 + 141 + xa_erase(&table->devices, sf_index); 142 + mlx5_sf_dev_remove(sf_dev); 143 + } 144 + 145 + static int 146 + mlx5_sf_dev_state_change_handler(struct notifier_block *nb, unsigned long event_code, void *data) 147 + { 148 + struct mlx5_sf_dev_table *table = container_of(nb, struct mlx5_sf_dev_table, nb); 149 + const struct mlx5_vhca_state_event *event = data; 150 + struct mlx5_sf_dev *sf_dev; 151 + u16 sf_index; 152 + 153 + sf_index = event->function_id - MLX5_CAP_GEN(table->dev, sf_base_id); 154 + sf_dev = xa_load(&table->devices, sf_index); 155 + switch (event->new_vhca_state) { 156 + case MLX5_VHCA_STATE_ALLOCATED: 157 + if (sf_dev) 158 + mlx5_sf_dev_del(table->dev, sf_dev, sf_index); 159 + break; 160 + case MLX5_VHCA_STATE_TEARDOWN_REQUEST: 161 + if (sf_dev) 162 + mlx5_sf_dev_del(table->dev, sf_dev, sf_index); 163 + else 164 + mlx5_core_err(table->dev, 165 + "SF DEV: teardown state for invalid dev index=%d fn_id=0x%x\n", 166 + sf_index, event->sw_function_id); 167 + break; 168 + case MLX5_VHCA_STATE_ACTIVE: 169 + if (!sf_dev) 170 + mlx5_sf_dev_add(table->dev, sf_index, event->sw_function_id); 171 + break; 172 + default: 173 + break; 174 + } 175 + return 0; 176 + } 177 + 178 + static int mlx5_sf_dev_vhca_arm_all(struct mlx5_sf_dev_table *table) 179 + { 180 + struct mlx5_core_dev *dev = table->dev; 181 + u16 max_functions; 182 + u16 function_id; 183 + int err = 0; 184 + bool ecpu; 185 + int i; 186 + 187 + max_functions = mlx5_sf_max_functions(dev); 188 + function_id = MLX5_CAP_GEN(dev, sf_base_id); 189 + ecpu = mlx5_read_embedded_cpu(dev); 190 + /* Arm the vhca context as the vhca event notifier */ 191 + for (i = 0; i < max_functions; i++) { 192 + err = mlx5_vhca_event_arm(dev, function_id, ecpu); 193 + if (err) 194 + return err; 195 + 196 + function_id++; 197 + } 198 + return 0; 199 + } 200 + 201 + void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev) 202 + { 203 + struct mlx5_sf_dev_table *table; 204 + unsigned int max_sfs; 205 + int err; 206 + 207 + if (!mlx5_sf_dev_supported(dev) || !mlx5_vhca_event_supported(dev)) 208 + return; 209 + 210 + table = kzalloc(sizeof(*table), GFP_KERNEL); 211 + if (!table) { 212 + err = -ENOMEM; 213 + goto table_err; 214 + } 215 + 216 + table->nb.notifier_call = mlx5_sf_dev_state_change_handler; 217 + table->dev = dev; 218 + if (MLX5_CAP_GEN(dev, max_num_sf)) 219 + max_sfs = MLX5_CAP_GEN(dev, max_num_sf); 220 + else 221 + max_sfs = 1 << MLX5_CAP_GEN(dev, log_max_sf); 222 + table->sf_bar_length = 1 << (MLX5_CAP_GEN(dev, log_min_sf_size) + 12); 223 + table->base_address = pci_resource_start(dev->pdev, 2); 224 + table->max_sfs = max_sfs; 225 + xa_init(&table->devices); 226 + dev->priv.sf_dev_table = table; 227 + 228 + err = mlx5_vhca_event_notifier_register(dev, &table->nb); 229 + if (err) 230 + goto vhca_err; 231 + err = mlx5_sf_dev_vhca_arm_all(table); 232 + if (err) 233 + goto arm_err; 234 + mlx5_core_dbg(dev, "SF DEV: max sf devices=%d\n", max_sfs); 235 + return; 236 + 237 + arm_err: 238 + mlx5_vhca_event_notifier_unregister(dev, &table->nb); 239 + vhca_err: 240 + table->max_sfs = 0; 241 + kfree(table); 242 + dev->priv.sf_dev_table = NULL; 243 + table_err: 244 + mlx5_core_err(dev, "SF DEV table create err = %d\n", err); 245 + } 246 + 247 + static void mlx5_sf_dev_destroy_all(struct mlx5_sf_dev_table *table) 248 + { 249 + struct mlx5_sf_dev *sf_dev; 250 + unsigned long index; 251 + 252 + xa_for_each(&table->devices, index, sf_dev) { 253 + xa_erase(&table->devices, index); 254 + mlx5_sf_dev_remove(sf_dev); 255 + } 256 + } 257 + 258 + void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev) 259 + { 260 + struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table; 261 + 262 + if (!table) 263 + return; 264 + 265 + mlx5_vhca_event_notifier_unregister(dev, &table->nb); 266 + 267 + /* Now that event handler is not running, it is safe to destroy 268 + * the sf device without race. 269 + */ 270 + mlx5_sf_dev_destroy_all(table); 271 + 272 + WARN_ON(!xa_empty(&table->devices)); 273 + kfree(table); 274 + dev->priv.sf_dev_table = NULL; 275 + }
+55
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #ifndef __MLX5_SF_DEV_H__ 5 + #define __MLX5_SF_DEV_H__ 6 + 7 + #ifdef CONFIG_MLX5_SF 8 + 9 + #include <linux/auxiliary_bus.h> 10 + 11 + #define MLX5_SF_DEV_ID_NAME "sf" 12 + 13 + struct mlx5_sf_dev { 14 + struct auxiliary_device adev; 15 + struct mlx5_core_dev *parent_mdev; 16 + struct mlx5_core_dev *mdev; 17 + phys_addr_t bar_base_addr; 18 + u32 sfnum; 19 + }; 20 + 21 + void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev); 22 + void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev); 23 + 24 + int mlx5_sf_driver_register(void); 25 + void mlx5_sf_driver_unregister(void); 26 + 27 + bool mlx5_sf_dev_allocated(const struct mlx5_core_dev *dev); 28 + 29 + #else 30 + 31 + static inline void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev) 32 + { 33 + } 34 + 35 + static inline void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev) 36 + { 37 + } 38 + 39 + static inline int mlx5_sf_driver_register(void) 40 + { 41 + return 0; 42 + } 43 + 44 + static inline void mlx5_sf_driver_unregister(void) 45 + { 46 + } 47 + 48 + static inline bool mlx5_sf_dev_allocated(const struct mlx5_core_dev *dev) 49 + { 50 + return 0; 51 + } 52 + 53 + #endif 54 + 55 + #endif
+101
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #include <linux/mlx5/driver.h> 5 + #include <linux/mlx5/device.h> 6 + #include "mlx5_core.h" 7 + #include "dev.h" 8 + #include "devlink.h" 9 + 10 + static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id) 11 + { 12 + struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); 13 + struct mlx5_core_dev *mdev; 14 + struct devlink *devlink; 15 + int err; 16 + 17 + devlink = mlx5_devlink_alloc(); 18 + if (!devlink) 19 + return -ENOMEM; 20 + 21 + mdev = devlink_priv(devlink); 22 + mdev->device = &adev->dev; 23 + mdev->pdev = sf_dev->parent_mdev->pdev; 24 + mdev->bar_addr = sf_dev->bar_base_addr; 25 + mdev->iseg_base = sf_dev->bar_base_addr; 26 + mdev->coredev_type = MLX5_COREDEV_SF; 27 + mdev->priv.parent_mdev = sf_dev->parent_mdev; 28 + mdev->priv.adev_idx = adev->id; 29 + sf_dev->mdev = mdev; 30 + 31 + err = mlx5_mdev_init(mdev, MLX5_DEFAULT_PROF); 32 + if (err) { 33 + mlx5_core_warn(mdev, "mlx5_mdev_init on err=%d\n", err); 34 + goto mdev_err; 35 + } 36 + 37 + mdev->iseg = ioremap(mdev->iseg_base, sizeof(*mdev->iseg)); 38 + if (!mdev->iseg) { 39 + mlx5_core_warn(mdev, "remap error\n"); 40 + goto remap_err; 41 + } 42 + 43 + err = mlx5_load_one(mdev, true); 44 + if (err) { 45 + mlx5_core_warn(mdev, "mlx5_load_one err=%d\n", err); 46 + goto load_one_err; 47 + } 48 + return 0; 49 + 50 + load_one_err: 51 + iounmap(mdev->iseg); 52 + remap_err: 53 + mlx5_mdev_uninit(mdev); 54 + mdev_err: 55 + mlx5_devlink_free(devlink); 56 + return err; 57 + } 58 + 59 + static void mlx5_sf_dev_remove(struct auxiliary_device *adev) 60 + { 61 + struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); 62 + struct devlink *devlink; 63 + 64 + devlink = priv_to_devlink(sf_dev->mdev); 65 + mlx5_unload_one(sf_dev->mdev, true); 66 + iounmap(sf_dev->mdev->iseg); 67 + mlx5_mdev_uninit(sf_dev->mdev); 68 + mlx5_devlink_free(devlink); 69 + } 70 + 71 + static void mlx5_sf_dev_shutdown(struct auxiliary_device *adev) 72 + { 73 + struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); 74 + 75 + mlx5_unload_one(sf_dev->mdev, false); 76 + } 77 + 78 + static const struct auxiliary_device_id mlx5_sf_dev_id_table[] = { 79 + { .name = MLX5_ADEV_NAME "." MLX5_SF_DEV_ID_NAME, }, 80 + { }, 81 + }; 82 + 83 + MODULE_DEVICE_TABLE(auxiliary, mlx5_sf_dev_id_table); 84 + 85 + static struct auxiliary_driver mlx5_sf_driver = { 86 + .name = MLX5_SF_DEV_ID_NAME, 87 + .probe = mlx5_sf_dev_probe, 88 + .remove = mlx5_sf_dev_remove, 89 + .shutdown = mlx5_sf_dev_shutdown, 90 + .id_table = mlx5_sf_dev_id_table, 91 + }; 92 + 93 + int mlx5_sf_driver_register(void) 94 + { 95 + return auxiliary_driver_register(&mlx5_sf_driver); 96 + } 97 + 98 + void mlx5_sf_driver_unregister(void) 99 + { 100 + auxiliary_driver_unregister(&mlx5_sf_driver); 101 + }
+556
drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #include <linux/mlx5/driver.h> 5 + #include "eswitch.h" 6 + #include "priv.h" 7 + #include "sf/dev/dev.h" 8 + #include "mlx5_ifc_vhca_event.h" 9 + #include "vhca_event.h" 10 + #include "ecpf.h" 11 + 12 + struct mlx5_sf { 13 + struct devlink_port dl_port; 14 + unsigned int port_index; 15 + u16 id; 16 + u16 hw_fn_id; 17 + u16 hw_state; 18 + }; 19 + 20 + struct mlx5_sf_table { 21 + struct mlx5_core_dev *dev; /* To refer from notifier context. */ 22 + struct xarray port_indices; /* port index based lookup. */ 23 + refcount_t refcount; 24 + struct completion disable_complete; 25 + struct mutex sf_state_lock; /* Serializes sf state among user cmds & vhca event handler. */ 26 + struct notifier_block esw_nb; 27 + struct notifier_block vhca_nb; 28 + u8 ecpu: 1; 29 + }; 30 + 31 + static struct mlx5_sf * 32 + mlx5_sf_lookup_by_index(struct mlx5_sf_table *table, unsigned int port_index) 33 + { 34 + return xa_load(&table->port_indices, port_index); 35 + } 36 + 37 + static struct mlx5_sf * 38 + mlx5_sf_lookup_by_function_id(struct mlx5_sf_table *table, unsigned int fn_id) 39 + { 40 + unsigned long index; 41 + struct mlx5_sf *sf; 42 + 43 + xa_for_each(&table->port_indices, index, sf) { 44 + if (sf->hw_fn_id == fn_id) 45 + return sf; 46 + } 47 + return NULL; 48 + } 49 + 50 + static int mlx5_sf_id_insert(struct mlx5_sf_table *table, struct mlx5_sf *sf) 51 + { 52 + return xa_insert(&table->port_indices, sf->port_index, sf, GFP_KERNEL); 53 + } 54 + 55 + static void mlx5_sf_id_erase(struct mlx5_sf_table *table, struct mlx5_sf *sf) 56 + { 57 + xa_erase(&table->port_indices, sf->port_index); 58 + } 59 + 60 + static struct mlx5_sf * 61 + mlx5_sf_alloc(struct mlx5_sf_table *table, u32 sfnum, struct netlink_ext_ack *extack) 62 + { 63 + unsigned int dl_port_index; 64 + struct mlx5_sf *sf; 65 + u16 hw_fn_id; 66 + int id_err; 67 + int err; 68 + 69 + id_err = mlx5_sf_hw_table_sf_alloc(table->dev, sfnum); 70 + if (id_err < 0) { 71 + err = id_err; 72 + goto id_err; 73 + } 74 + 75 + sf = kzalloc(sizeof(*sf), GFP_KERNEL); 76 + if (!sf) { 77 + err = -ENOMEM; 78 + goto alloc_err; 79 + } 80 + sf->id = id_err; 81 + hw_fn_id = mlx5_sf_sw_to_hw_id(table->dev, sf->id); 82 + dl_port_index = mlx5_esw_vport_to_devlink_port_index(table->dev, hw_fn_id); 83 + sf->port_index = dl_port_index; 84 + sf->hw_fn_id = hw_fn_id; 85 + sf->hw_state = MLX5_VHCA_STATE_ALLOCATED; 86 + 87 + err = mlx5_sf_id_insert(table, sf); 88 + if (err) 89 + goto insert_err; 90 + 91 + return sf; 92 + 93 + insert_err: 94 + kfree(sf); 95 + alloc_err: 96 + mlx5_sf_hw_table_sf_free(table->dev, id_err); 97 + id_err: 98 + if (err == -EEXIST) 99 + NL_SET_ERR_MSG_MOD(extack, "SF already exist. Choose different sfnum"); 100 + return ERR_PTR(err); 101 + } 102 + 103 + static void mlx5_sf_free(struct mlx5_sf_table *table, struct mlx5_sf *sf) 104 + { 105 + mlx5_sf_id_erase(table, sf); 106 + mlx5_sf_hw_table_sf_free(table->dev, sf->id); 107 + kfree(sf); 108 + } 109 + 110 + static struct mlx5_sf_table *mlx5_sf_table_try_get(struct mlx5_core_dev *dev) 111 + { 112 + struct mlx5_sf_table *table = dev->priv.sf_table; 113 + 114 + if (!table) 115 + return NULL; 116 + 117 + return refcount_inc_not_zero(&table->refcount) ? table : NULL; 118 + } 119 + 120 + static void mlx5_sf_table_put(struct mlx5_sf_table *table) 121 + { 122 + if (refcount_dec_and_test(&table->refcount)) 123 + complete(&table->disable_complete); 124 + } 125 + 126 + static enum devlink_port_fn_state mlx5_sf_to_devlink_state(u8 hw_state) 127 + { 128 + switch (hw_state) { 129 + case MLX5_VHCA_STATE_ACTIVE: 130 + case MLX5_VHCA_STATE_IN_USE: 131 + case MLX5_VHCA_STATE_TEARDOWN_REQUEST: 132 + return DEVLINK_PORT_FN_STATE_ACTIVE; 133 + case MLX5_VHCA_STATE_INVALID: 134 + case MLX5_VHCA_STATE_ALLOCATED: 135 + default: 136 + return DEVLINK_PORT_FN_STATE_INACTIVE; 137 + } 138 + } 139 + 140 + static enum devlink_port_fn_opstate mlx5_sf_to_devlink_opstate(u8 hw_state) 141 + { 142 + switch (hw_state) { 143 + case MLX5_VHCA_STATE_IN_USE: 144 + case MLX5_VHCA_STATE_TEARDOWN_REQUEST: 145 + return DEVLINK_PORT_FN_OPSTATE_ATTACHED; 146 + case MLX5_VHCA_STATE_INVALID: 147 + case MLX5_VHCA_STATE_ALLOCATED: 148 + case MLX5_VHCA_STATE_ACTIVE: 149 + default: 150 + return DEVLINK_PORT_FN_OPSTATE_DETACHED; 151 + } 152 + } 153 + 154 + static bool mlx5_sf_is_active(const struct mlx5_sf *sf) 155 + { 156 + return sf->hw_state == MLX5_VHCA_STATE_ACTIVE || sf->hw_state == MLX5_VHCA_STATE_IN_USE; 157 + } 158 + 159 + int mlx5_devlink_sf_port_fn_state_get(struct devlink *devlink, struct devlink_port *dl_port, 160 + enum devlink_port_fn_state *state, 161 + enum devlink_port_fn_opstate *opstate, 162 + struct netlink_ext_ack *extack) 163 + { 164 + struct mlx5_core_dev *dev = devlink_priv(devlink); 165 + struct mlx5_sf_table *table; 166 + struct mlx5_sf *sf; 167 + int err = 0; 168 + 169 + table = mlx5_sf_table_try_get(dev); 170 + if (!table) 171 + return -EOPNOTSUPP; 172 + 173 + sf = mlx5_sf_lookup_by_index(table, dl_port->index); 174 + if (!sf) { 175 + err = -EOPNOTSUPP; 176 + goto sf_err; 177 + } 178 + mutex_lock(&table->sf_state_lock); 179 + *state = mlx5_sf_to_devlink_state(sf->hw_state); 180 + *opstate = mlx5_sf_to_devlink_opstate(sf->hw_state); 181 + mutex_unlock(&table->sf_state_lock); 182 + sf_err: 183 + mlx5_sf_table_put(table); 184 + return err; 185 + } 186 + 187 + static int mlx5_sf_activate(struct mlx5_core_dev *dev, struct mlx5_sf *sf) 188 + { 189 + int err; 190 + 191 + if (mlx5_sf_is_active(sf)) 192 + return 0; 193 + if (sf->hw_state != MLX5_VHCA_STATE_ALLOCATED) 194 + return -EINVAL; 195 + 196 + err = mlx5_cmd_sf_enable_hca(dev, sf->hw_fn_id); 197 + if (err) 198 + return err; 199 + 200 + sf->hw_state = MLX5_VHCA_STATE_ACTIVE; 201 + return 0; 202 + } 203 + 204 + static int mlx5_sf_deactivate(struct mlx5_core_dev *dev, struct mlx5_sf *sf) 205 + { 206 + int err; 207 + 208 + if (!mlx5_sf_is_active(sf)) 209 + return 0; 210 + 211 + err = mlx5_cmd_sf_disable_hca(dev, sf->hw_fn_id); 212 + if (err) 213 + return err; 214 + 215 + sf->hw_state = MLX5_VHCA_STATE_TEARDOWN_REQUEST; 216 + return 0; 217 + } 218 + 219 + static int mlx5_sf_state_set(struct mlx5_core_dev *dev, struct mlx5_sf_table *table, 220 + struct mlx5_sf *sf, 221 + enum devlink_port_fn_state state) 222 + { 223 + int err = 0; 224 + 225 + mutex_lock(&table->sf_state_lock); 226 + if (state == mlx5_sf_to_devlink_state(sf->hw_state)) 227 + goto out; 228 + if (state == DEVLINK_PORT_FN_STATE_ACTIVE) 229 + err = mlx5_sf_activate(dev, sf); 230 + else if (state == DEVLINK_PORT_FN_STATE_INACTIVE) 231 + err = mlx5_sf_deactivate(dev, sf); 232 + else 233 + err = -EINVAL; 234 + out: 235 + mutex_unlock(&table->sf_state_lock); 236 + return err; 237 + } 238 + 239 + int mlx5_devlink_sf_port_fn_state_set(struct devlink *devlink, struct devlink_port *dl_port, 240 + enum devlink_port_fn_state state, 241 + struct netlink_ext_ack *extack) 242 + { 243 + struct mlx5_core_dev *dev = devlink_priv(devlink); 244 + struct mlx5_sf_table *table; 245 + struct mlx5_sf *sf; 246 + int err; 247 + 248 + table = mlx5_sf_table_try_get(dev); 249 + if (!table) { 250 + NL_SET_ERR_MSG_MOD(extack, 251 + "Port state set is only supported in eswitch switchdev mode or SF ports are disabled."); 252 + return -EOPNOTSUPP; 253 + } 254 + sf = mlx5_sf_lookup_by_index(table, dl_port->index); 255 + if (!sf) { 256 + err = -ENODEV; 257 + goto out; 258 + } 259 + 260 + err = mlx5_sf_state_set(dev, table, sf, state); 261 + out: 262 + mlx5_sf_table_put(table); 263 + return err; 264 + } 265 + 266 + static int mlx5_sf_add(struct mlx5_core_dev *dev, struct mlx5_sf_table *table, 267 + const struct devlink_port_new_attrs *new_attr, 268 + struct netlink_ext_ack *extack, 269 + unsigned int *new_port_index) 270 + { 271 + struct mlx5_eswitch *esw = dev->priv.eswitch; 272 + struct mlx5_sf *sf; 273 + u16 hw_fn_id; 274 + int err; 275 + 276 + sf = mlx5_sf_alloc(table, new_attr->sfnum, extack); 277 + if (IS_ERR(sf)) 278 + return PTR_ERR(sf); 279 + 280 + hw_fn_id = mlx5_sf_sw_to_hw_id(dev, sf->id); 281 + err = mlx5_esw_offloads_sf_vport_enable(esw, &sf->dl_port, hw_fn_id, new_attr->sfnum); 282 + if (err) 283 + goto esw_err; 284 + *new_port_index = sf->port_index; 285 + return 0; 286 + 287 + esw_err: 288 + mlx5_sf_free(table, sf); 289 + return err; 290 + } 291 + 292 + static int 293 + mlx5_sf_new_check_attr(struct mlx5_core_dev *dev, const struct devlink_port_new_attrs *new_attr, 294 + struct netlink_ext_ack *extack) 295 + { 296 + if (new_attr->flavour != DEVLINK_PORT_FLAVOUR_PCI_SF) { 297 + NL_SET_ERR_MSG_MOD(extack, "Driver supports only SF port addition"); 298 + return -EOPNOTSUPP; 299 + } 300 + if (new_attr->port_index_valid) { 301 + NL_SET_ERR_MSG_MOD(extack, 302 + "Driver does not support user defined port index assignment"); 303 + return -EOPNOTSUPP; 304 + } 305 + if (!new_attr->sfnum_valid) { 306 + NL_SET_ERR_MSG_MOD(extack, 307 + "User must provide unique sfnum. Driver does not support auto assignment"); 308 + return -EOPNOTSUPP; 309 + } 310 + if (new_attr->controller_valid && new_attr->controller) { 311 + NL_SET_ERR_MSG_MOD(extack, "External controller is unsupported"); 312 + return -EOPNOTSUPP; 313 + } 314 + if (new_attr->pfnum != PCI_FUNC(dev->pdev->devfn)) { 315 + NL_SET_ERR_MSG_MOD(extack, "Invalid pfnum supplied"); 316 + return -EOPNOTSUPP; 317 + } 318 + return 0; 319 + } 320 + 321 + int mlx5_devlink_sf_port_new(struct devlink *devlink, 322 + const struct devlink_port_new_attrs *new_attr, 323 + struct netlink_ext_ack *extack, 324 + unsigned int *new_port_index) 325 + { 326 + struct mlx5_core_dev *dev = devlink_priv(devlink); 327 + struct mlx5_sf_table *table; 328 + int err; 329 + 330 + err = mlx5_sf_new_check_attr(dev, new_attr, extack); 331 + if (err) 332 + return err; 333 + 334 + table = mlx5_sf_table_try_get(dev); 335 + if (!table) { 336 + NL_SET_ERR_MSG_MOD(extack, 337 + "Port add is only supported in eswitch switchdev mode or SF ports are disabled."); 338 + return -EOPNOTSUPP; 339 + } 340 + err = mlx5_sf_add(dev, table, new_attr, extack, new_port_index); 341 + mlx5_sf_table_put(table); 342 + return err; 343 + } 344 + 345 + static void mlx5_sf_dealloc(struct mlx5_sf_table *table, struct mlx5_sf *sf) 346 + { 347 + if (sf->hw_state == MLX5_VHCA_STATE_ALLOCATED) { 348 + mlx5_sf_free(table, sf); 349 + } else if (mlx5_sf_is_active(sf)) { 350 + /* Even if its active, it is treated as in_use because by the time, 351 + * it is disabled here, it may getting used. So it is safe to 352 + * always look for the event to ensure that it is recycled only after 353 + * firmware gives confirmation that it is detached by the driver. 354 + */ 355 + mlx5_cmd_sf_disable_hca(table->dev, sf->hw_fn_id); 356 + mlx5_sf_hw_table_sf_deferred_free(table->dev, sf->id); 357 + kfree(sf); 358 + } else { 359 + mlx5_sf_hw_table_sf_deferred_free(table->dev, sf->id); 360 + kfree(sf); 361 + } 362 + } 363 + 364 + int mlx5_devlink_sf_port_del(struct devlink *devlink, unsigned int port_index, 365 + struct netlink_ext_ack *extack) 366 + { 367 + struct mlx5_core_dev *dev = devlink_priv(devlink); 368 + struct mlx5_eswitch *esw = dev->priv.eswitch; 369 + struct mlx5_sf_table *table; 370 + struct mlx5_sf *sf; 371 + int err = 0; 372 + 373 + table = mlx5_sf_table_try_get(dev); 374 + if (!table) { 375 + NL_SET_ERR_MSG_MOD(extack, 376 + "Port del is only supported in eswitch switchdev mode or SF ports are disabled."); 377 + return -EOPNOTSUPP; 378 + } 379 + sf = mlx5_sf_lookup_by_index(table, port_index); 380 + if (!sf) { 381 + err = -ENODEV; 382 + goto sf_err; 383 + } 384 + 385 + mlx5_esw_offloads_sf_vport_disable(esw, sf->hw_fn_id); 386 + mlx5_sf_id_erase(table, sf); 387 + 388 + mutex_lock(&table->sf_state_lock); 389 + mlx5_sf_dealloc(table, sf); 390 + mutex_unlock(&table->sf_state_lock); 391 + sf_err: 392 + mlx5_sf_table_put(table); 393 + return err; 394 + } 395 + 396 + static bool mlx5_sf_state_update_check(const struct mlx5_sf *sf, u8 new_state) 397 + { 398 + if (sf->hw_state == MLX5_VHCA_STATE_ACTIVE && new_state == MLX5_VHCA_STATE_IN_USE) 399 + return true; 400 + 401 + if (sf->hw_state == MLX5_VHCA_STATE_IN_USE && new_state == MLX5_VHCA_STATE_ACTIVE) 402 + return true; 403 + 404 + if (sf->hw_state == MLX5_VHCA_STATE_TEARDOWN_REQUEST && 405 + new_state == MLX5_VHCA_STATE_ALLOCATED) 406 + return true; 407 + 408 + return false; 409 + } 410 + 411 + static int mlx5_sf_vhca_event(struct notifier_block *nb, unsigned long opcode, void *data) 412 + { 413 + struct mlx5_sf_table *table = container_of(nb, struct mlx5_sf_table, vhca_nb); 414 + const struct mlx5_vhca_state_event *event = data; 415 + bool update = false; 416 + struct mlx5_sf *sf; 417 + 418 + table = mlx5_sf_table_try_get(table->dev); 419 + if (!table) 420 + return 0; 421 + 422 + mutex_lock(&table->sf_state_lock); 423 + sf = mlx5_sf_lookup_by_function_id(table, event->function_id); 424 + if (!sf) 425 + goto sf_err; 426 + 427 + /* When driver is attached or detached to a function, an event 428 + * notifies such state change. 429 + */ 430 + update = mlx5_sf_state_update_check(sf, event->new_vhca_state); 431 + if (update) 432 + sf->hw_state = event->new_vhca_state; 433 + sf_err: 434 + mutex_unlock(&table->sf_state_lock); 435 + mlx5_sf_table_put(table); 436 + return 0; 437 + } 438 + 439 + static void mlx5_sf_table_enable(struct mlx5_sf_table *table) 440 + { 441 + if (!mlx5_sf_max_functions(table->dev)) 442 + return; 443 + 444 + init_completion(&table->disable_complete); 445 + refcount_set(&table->refcount, 1); 446 + } 447 + 448 + static void mlx5_sf_deactivate_all(struct mlx5_sf_table *table) 449 + { 450 + struct mlx5_eswitch *esw = table->dev->priv.eswitch; 451 + unsigned long index; 452 + struct mlx5_sf *sf; 453 + 454 + /* At this point, no new user commands can start and no vhca event can 455 + * arrive. It is safe to destroy all user created SFs. 456 + */ 457 + xa_for_each(&table->port_indices, index, sf) { 458 + mlx5_esw_offloads_sf_vport_disable(esw, sf->hw_fn_id); 459 + mlx5_sf_id_erase(table, sf); 460 + mlx5_sf_dealloc(table, sf); 461 + } 462 + } 463 + 464 + static void mlx5_sf_table_disable(struct mlx5_sf_table *table) 465 + { 466 + if (!mlx5_sf_max_functions(table->dev)) 467 + return; 468 + 469 + if (!refcount_read(&table->refcount)) 470 + return; 471 + 472 + /* Balances with refcount_set; drop the reference so that new user cmd cannot start 473 + * and new vhca event handler cannnot run. 474 + */ 475 + mlx5_sf_table_put(table); 476 + wait_for_completion(&table->disable_complete); 477 + 478 + mlx5_sf_deactivate_all(table); 479 + } 480 + 481 + static int mlx5_sf_esw_event(struct notifier_block *nb, unsigned long event, void *data) 482 + { 483 + struct mlx5_sf_table *table = container_of(nb, struct mlx5_sf_table, esw_nb); 484 + const struct mlx5_esw_event_info *mode = data; 485 + 486 + switch (mode->new_mode) { 487 + case MLX5_ESWITCH_OFFLOADS: 488 + mlx5_sf_table_enable(table); 489 + break; 490 + case MLX5_ESWITCH_NONE: 491 + mlx5_sf_table_disable(table); 492 + break; 493 + default: 494 + break; 495 + }; 496 + 497 + return 0; 498 + } 499 + 500 + static bool mlx5_sf_table_supported(const struct mlx5_core_dev *dev) 501 + { 502 + return dev->priv.eswitch && MLX5_ESWITCH_MANAGER(dev) && mlx5_sf_supported(dev); 503 + } 504 + 505 + int mlx5_sf_table_init(struct mlx5_core_dev *dev) 506 + { 507 + struct mlx5_sf_table *table; 508 + int err; 509 + 510 + if (!mlx5_sf_table_supported(dev) || !mlx5_vhca_event_supported(dev)) 511 + return 0; 512 + 513 + table = kzalloc(sizeof(*table), GFP_KERNEL); 514 + if (!table) 515 + return -ENOMEM; 516 + 517 + mutex_init(&table->sf_state_lock); 518 + table->dev = dev; 519 + xa_init(&table->port_indices); 520 + dev->priv.sf_table = table; 521 + refcount_set(&table->refcount, 0); 522 + table->esw_nb.notifier_call = mlx5_sf_esw_event; 523 + err = mlx5_esw_event_notifier_register(dev->priv.eswitch, &table->esw_nb); 524 + if (err) 525 + goto reg_err; 526 + 527 + table->vhca_nb.notifier_call = mlx5_sf_vhca_event; 528 + err = mlx5_vhca_event_notifier_register(table->dev, &table->vhca_nb); 529 + if (err) 530 + goto vhca_err; 531 + 532 + return 0; 533 + 534 + vhca_err: 535 + mlx5_esw_event_notifier_unregister(dev->priv.eswitch, &table->esw_nb); 536 + reg_err: 537 + mutex_destroy(&table->sf_state_lock); 538 + kfree(table); 539 + dev->priv.sf_table = NULL; 540 + return err; 541 + } 542 + 543 + void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev) 544 + { 545 + struct mlx5_sf_table *table = dev->priv.sf_table; 546 + 547 + if (!table) 548 + return; 549 + 550 + mlx5_vhca_event_notifier_unregister(table->dev, &table->vhca_nb); 551 + mlx5_esw_event_notifier_unregister(dev->priv.eswitch, &table->esw_nb); 552 + WARN_ON(refcount_read(&table->refcount)); 553 + mutex_destroy(&table->sf_state_lock); 554 + WARN_ON(!xa_empty(&table->port_indices)); 555 + kfree(table); 556 + }
+233
drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + #include <linux/mlx5/driver.h> 4 + #include "vhca_event.h" 5 + #include "priv.h" 6 + #include "sf.h" 7 + #include "mlx5_ifc_vhca_event.h" 8 + #include "vhca_event.h" 9 + #include "ecpf.h" 10 + 11 + struct mlx5_sf_hw { 12 + u32 usr_sfnum; 13 + u8 allocated: 1; 14 + u8 pending_delete: 1; 15 + }; 16 + 17 + struct mlx5_sf_hw_table { 18 + struct mlx5_core_dev *dev; 19 + struct mlx5_sf_hw *sfs; 20 + int max_local_functions; 21 + u8 ecpu: 1; 22 + struct mutex table_lock; /* Serializes sf deletion and vhca state change handler. */ 23 + struct notifier_block vhca_nb; 24 + }; 25 + 26 + u16 mlx5_sf_sw_to_hw_id(const struct mlx5_core_dev *dev, u16 sw_id) 27 + { 28 + return sw_id + mlx5_sf_start_function_id(dev); 29 + } 30 + 31 + static u16 mlx5_sf_hw_to_sw_id(const struct mlx5_core_dev *dev, u16 hw_id) 32 + { 33 + return hw_id - mlx5_sf_start_function_id(dev); 34 + } 35 + 36 + int mlx5_sf_hw_table_sf_alloc(struct mlx5_core_dev *dev, u32 usr_sfnum) 37 + { 38 + struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table; 39 + int sw_id = -ENOSPC; 40 + u16 hw_fn_id; 41 + int err; 42 + int i; 43 + 44 + if (!table->max_local_functions) 45 + return -EOPNOTSUPP; 46 + 47 + mutex_lock(&table->table_lock); 48 + /* Check if sf with same sfnum already exists or not. */ 49 + for (i = 0; i < table->max_local_functions; i++) { 50 + if (table->sfs[i].allocated && table->sfs[i].usr_sfnum == usr_sfnum) { 51 + err = -EEXIST; 52 + goto exist_err; 53 + } 54 + } 55 + 56 + /* Find the free entry and allocate the entry from the array */ 57 + for (i = 0; i < table->max_local_functions; i++) { 58 + if (!table->sfs[i].allocated) { 59 + table->sfs[i].usr_sfnum = usr_sfnum; 60 + table->sfs[i].allocated = true; 61 + sw_id = i; 62 + break; 63 + } 64 + } 65 + if (sw_id == -ENOSPC) { 66 + err = -ENOSPC; 67 + goto err; 68 + } 69 + 70 + hw_fn_id = mlx5_sf_sw_to_hw_id(table->dev, sw_id); 71 + err = mlx5_cmd_alloc_sf(table->dev, hw_fn_id); 72 + if (err) 73 + goto err; 74 + 75 + err = mlx5_modify_vhca_sw_id(dev, hw_fn_id, table->ecpu, usr_sfnum); 76 + if (err) 77 + goto vhca_err; 78 + 79 + mutex_unlock(&table->table_lock); 80 + return sw_id; 81 + 82 + vhca_err: 83 + mlx5_cmd_dealloc_sf(table->dev, hw_fn_id); 84 + err: 85 + table->sfs[i].allocated = false; 86 + exist_err: 87 + mutex_unlock(&table->table_lock); 88 + return err; 89 + } 90 + 91 + static void _mlx5_sf_hw_id_free(struct mlx5_core_dev *dev, u16 id) 92 + { 93 + struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table; 94 + u16 hw_fn_id; 95 + 96 + hw_fn_id = mlx5_sf_sw_to_hw_id(table->dev, id); 97 + mlx5_cmd_dealloc_sf(table->dev, hw_fn_id); 98 + table->sfs[id].allocated = false; 99 + table->sfs[id].pending_delete = false; 100 + } 101 + 102 + void mlx5_sf_hw_table_sf_free(struct mlx5_core_dev *dev, u16 id) 103 + { 104 + struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table; 105 + 106 + mutex_lock(&table->table_lock); 107 + _mlx5_sf_hw_id_free(dev, id); 108 + mutex_unlock(&table->table_lock); 109 + } 110 + 111 + void mlx5_sf_hw_table_sf_deferred_free(struct mlx5_core_dev *dev, u16 id) 112 + { 113 + struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table; 114 + u32 out[MLX5_ST_SZ_DW(query_vhca_state_out)] = {}; 115 + u16 hw_fn_id; 116 + u8 state; 117 + int err; 118 + 119 + hw_fn_id = mlx5_sf_sw_to_hw_id(dev, id); 120 + mutex_lock(&table->table_lock); 121 + err = mlx5_cmd_query_vhca_state(dev, hw_fn_id, table->ecpu, out, sizeof(out)); 122 + if (err) 123 + goto err; 124 + state = MLX5_GET(query_vhca_state_out, out, vhca_state_context.vhca_state); 125 + if (state == MLX5_VHCA_STATE_ALLOCATED) { 126 + mlx5_cmd_dealloc_sf(table->dev, hw_fn_id); 127 + table->sfs[id].allocated = false; 128 + } else { 129 + table->sfs[id].pending_delete = true; 130 + } 131 + err: 132 + mutex_unlock(&table->table_lock); 133 + } 134 + 135 + static void mlx5_sf_hw_dealloc_all(struct mlx5_sf_hw_table *table) 136 + { 137 + int i; 138 + 139 + for (i = 0; i < table->max_local_functions; i++) { 140 + if (table->sfs[i].allocated) 141 + _mlx5_sf_hw_id_free(table->dev, i); 142 + } 143 + } 144 + 145 + int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev) 146 + { 147 + struct mlx5_sf_hw_table *table; 148 + struct mlx5_sf_hw *sfs; 149 + int max_functions; 150 + 151 + if (!mlx5_sf_supported(dev) || !mlx5_vhca_event_supported(dev)) 152 + return 0; 153 + 154 + max_functions = mlx5_sf_max_functions(dev); 155 + table = kzalloc(sizeof(*table), GFP_KERNEL); 156 + if (!table) 157 + return -ENOMEM; 158 + 159 + sfs = kcalloc(max_functions, sizeof(*sfs), GFP_KERNEL); 160 + if (!sfs) 161 + goto table_err; 162 + 163 + mutex_init(&table->table_lock); 164 + table->dev = dev; 165 + table->sfs = sfs; 166 + table->max_local_functions = max_functions; 167 + table->ecpu = mlx5_read_embedded_cpu(dev); 168 + dev->priv.sf_hw_table = table; 169 + mlx5_core_dbg(dev, "SF HW table: max sfs = %d\n", max_functions); 170 + return 0; 171 + 172 + table_err: 173 + kfree(table); 174 + return -ENOMEM; 175 + } 176 + 177 + void mlx5_sf_hw_table_cleanup(struct mlx5_core_dev *dev) 178 + { 179 + struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table; 180 + 181 + if (!table) 182 + return; 183 + 184 + mutex_destroy(&table->table_lock); 185 + kfree(table->sfs); 186 + kfree(table); 187 + } 188 + 189 + static int mlx5_sf_hw_vhca_event(struct notifier_block *nb, unsigned long opcode, void *data) 190 + { 191 + struct mlx5_sf_hw_table *table = container_of(nb, struct mlx5_sf_hw_table, vhca_nb); 192 + const struct mlx5_vhca_state_event *event = data; 193 + struct mlx5_sf_hw *sf_hw; 194 + u16 sw_id; 195 + 196 + if (event->new_vhca_state != MLX5_VHCA_STATE_ALLOCATED) 197 + return 0; 198 + 199 + sw_id = mlx5_sf_hw_to_sw_id(table->dev, event->function_id); 200 + sf_hw = &table->sfs[sw_id]; 201 + 202 + mutex_lock(&table->table_lock); 203 + /* SF driver notified through firmware that SF is finally detached. 204 + * Hence recycle the sf hardware id for reuse. 205 + */ 206 + if (sf_hw->allocated && sf_hw->pending_delete) 207 + _mlx5_sf_hw_id_free(table->dev, sw_id); 208 + mutex_unlock(&table->table_lock); 209 + return 0; 210 + } 211 + 212 + int mlx5_sf_hw_table_create(struct mlx5_core_dev *dev) 213 + { 214 + struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table; 215 + 216 + if (!table) 217 + return 0; 218 + 219 + table->vhca_nb.notifier_call = mlx5_sf_hw_vhca_event; 220 + return mlx5_vhca_event_notifier_register(table->dev, &table->vhca_nb); 221 + } 222 + 223 + void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev) 224 + { 225 + struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table; 226 + 227 + if (!table) 228 + return; 229 + 230 + mlx5_vhca_event_notifier_unregister(table->dev, &table->vhca_nb); 231 + /* Dealloc SFs whose firmware event has been missed. */ 232 + mlx5_sf_hw_dealloc_all(table); 233 + }
+82
drivers/net/ethernet/mellanox/mlx5/core/sf/mlx5_ifc_vhca_event.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #ifndef __MLX5_IFC_VHCA_EVENT_H__ 5 + #define __MLX5_IFC_VHCA_EVENT_H__ 6 + 7 + enum mlx5_ifc_vhca_state { 8 + MLX5_VHCA_STATE_INVALID = 0x0, 9 + MLX5_VHCA_STATE_ALLOCATED = 0x1, 10 + MLX5_VHCA_STATE_ACTIVE = 0x2, 11 + MLX5_VHCA_STATE_IN_USE = 0x3, 12 + MLX5_VHCA_STATE_TEARDOWN_REQUEST = 0x4, 13 + }; 14 + 15 + struct mlx5_ifc_vhca_state_context_bits { 16 + u8 arm_change_event[0x1]; 17 + u8 reserved_at_1[0xb]; 18 + u8 vhca_state[0x4]; 19 + u8 reserved_at_10[0x10]; 20 + 21 + u8 sw_function_id[0x20]; 22 + 23 + u8 reserved_at_40[0x80]; 24 + }; 25 + 26 + struct mlx5_ifc_query_vhca_state_out_bits { 27 + u8 status[0x8]; 28 + u8 reserved_at_8[0x18]; 29 + 30 + u8 syndrome[0x20]; 31 + 32 + u8 reserved_at_40[0x40]; 33 + 34 + struct mlx5_ifc_vhca_state_context_bits vhca_state_context; 35 + }; 36 + 37 + struct mlx5_ifc_query_vhca_state_in_bits { 38 + u8 opcode[0x10]; 39 + u8 uid[0x10]; 40 + 41 + u8 reserved_at_20[0x10]; 42 + u8 op_mod[0x10]; 43 + 44 + u8 embedded_cpu_function[0x1]; 45 + u8 reserved_at_41[0xf]; 46 + u8 function_id[0x10]; 47 + 48 + u8 reserved_at_60[0x20]; 49 + }; 50 + 51 + struct mlx5_ifc_vhca_state_field_select_bits { 52 + u8 reserved_at_0[0x1e]; 53 + u8 sw_function_id[0x1]; 54 + u8 arm_change_event[0x1]; 55 + }; 56 + 57 + struct mlx5_ifc_modify_vhca_state_out_bits { 58 + u8 status[0x8]; 59 + u8 reserved_at_8[0x18]; 60 + 61 + u8 syndrome[0x20]; 62 + 63 + u8 reserved_at_40[0x40]; 64 + }; 65 + 66 + struct mlx5_ifc_modify_vhca_state_in_bits { 67 + u8 opcode[0x10]; 68 + u8 uid[0x10]; 69 + 70 + u8 reserved_at_20[0x10]; 71 + u8 op_mod[0x10]; 72 + 73 + u8 embedded_cpu_function[0x1]; 74 + u8 reserved_at_41[0xf]; 75 + u8 function_id[0x10]; 76 + 77 + struct mlx5_ifc_vhca_state_field_select_bits vhca_state_field_select; 78 + 79 + struct mlx5_ifc_vhca_state_context_bits vhca_state_context; 80 + }; 81 + 82 + #endif
+21
drivers/net/ethernet/mellanox/mlx5/core/sf/priv.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #ifndef __MLX5_SF_PRIV_H__ 5 + #define __MLX5_SF_PRIV_H__ 6 + 7 + #include <linux/mlx5/driver.h> 8 + 9 + int mlx5_cmd_alloc_sf(struct mlx5_core_dev *dev, u16 function_id); 10 + int mlx5_cmd_dealloc_sf(struct mlx5_core_dev *dev, u16 function_id); 11 + 12 + int mlx5_cmd_sf_enable_hca(struct mlx5_core_dev *dev, u16 func_id); 13 + int mlx5_cmd_sf_disable_hca(struct mlx5_core_dev *dev, u16 func_id); 14 + 15 + u16 mlx5_sf_sw_to_hw_id(const struct mlx5_core_dev *dev, u16 sw_id); 16 + 17 + int mlx5_sf_hw_table_sf_alloc(struct mlx5_core_dev *dev, u32 usr_sfnum); 18 + void mlx5_sf_hw_table_sf_free(struct mlx5_core_dev *dev, u16 id); 19 + void mlx5_sf_hw_table_sf_deferred_free(struct mlx5_core_dev *dev, u16 id); 20 + 21 + #endif
+100
drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #ifndef __MLX5_SF_H__ 5 + #define __MLX5_SF_H__ 6 + 7 + #include <linux/mlx5/driver.h> 8 + 9 + static inline u16 mlx5_sf_start_function_id(const struct mlx5_core_dev *dev) 10 + { 11 + return MLX5_CAP_GEN(dev, sf_base_id); 12 + } 13 + 14 + #ifdef CONFIG_MLX5_SF 15 + 16 + static inline bool mlx5_sf_supported(const struct mlx5_core_dev *dev) 17 + { 18 + return MLX5_CAP_GEN(dev, sf); 19 + } 20 + 21 + static inline u16 mlx5_sf_max_functions(const struct mlx5_core_dev *dev) 22 + { 23 + if (!mlx5_sf_supported(dev)) 24 + return 0; 25 + if (MLX5_CAP_GEN(dev, max_num_sf)) 26 + return MLX5_CAP_GEN(dev, max_num_sf); 27 + else 28 + return 1 << MLX5_CAP_GEN(dev, log_max_sf); 29 + } 30 + 31 + #else 32 + 33 + static inline bool mlx5_sf_supported(const struct mlx5_core_dev *dev) 34 + { 35 + return false; 36 + } 37 + 38 + static inline u16 mlx5_sf_max_functions(const struct mlx5_core_dev *dev) 39 + { 40 + return 0; 41 + } 42 + 43 + #endif 44 + 45 + #ifdef CONFIG_MLX5_SF_MANAGER 46 + 47 + int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev); 48 + void mlx5_sf_hw_table_cleanup(struct mlx5_core_dev *dev); 49 + 50 + int mlx5_sf_hw_table_create(struct mlx5_core_dev *dev); 51 + void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev); 52 + 53 + int mlx5_sf_table_init(struct mlx5_core_dev *dev); 54 + void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev); 55 + 56 + int mlx5_devlink_sf_port_new(struct devlink *devlink, 57 + const struct devlink_port_new_attrs *add_attr, 58 + struct netlink_ext_ack *extack, 59 + unsigned int *new_port_index); 60 + int mlx5_devlink_sf_port_del(struct devlink *devlink, unsigned int port_index, 61 + struct netlink_ext_ack *extack); 62 + int mlx5_devlink_sf_port_fn_state_get(struct devlink *devlink, struct devlink_port *dl_port, 63 + enum devlink_port_fn_state *state, 64 + enum devlink_port_fn_opstate *opstate, 65 + struct netlink_ext_ack *extack); 66 + int mlx5_devlink_sf_port_fn_state_set(struct devlink *devlink, struct devlink_port *dl_port, 67 + enum devlink_port_fn_state state, 68 + struct netlink_ext_ack *extack); 69 + #else 70 + 71 + static inline int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev) 72 + { 73 + return 0; 74 + } 75 + 76 + static inline void mlx5_sf_hw_table_cleanup(struct mlx5_core_dev *dev) 77 + { 78 + } 79 + 80 + static inline int mlx5_sf_hw_table_create(struct mlx5_core_dev *dev) 81 + { 82 + return 0; 83 + } 84 + 85 + static inline void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev) 86 + { 87 + } 88 + 89 + static inline int mlx5_sf_table_init(struct mlx5_core_dev *dev) 90 + { 91 + return 0; 92 + } 93 + 94 + static inline void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev) 95 + { 96 + } 97 + 98 + #endif 99 + 100 + #endif
+189
drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #include <linux/mlx5/driver.h> 5 + #include "mlx5_ifc_vhca_event.h" 6 + #include "mlx5_core.h" 7 + #include "vhca_event.h" 8 + #include "ecpf.h" 9 + 10 + struct mlx5_vhca_state_notifier { 11 + struct mlx5_core_dev *dev; 12 + struct mlx5_nb nb; 13 + struct blocking_notifier_head n_head; 14 + }; 15 + 16 + struct mlx5_vhca_event_work { 17 + struct work_struct work; 18 + struct mlx5_vhca_state_notifier *notifier; 19 + struct mlx5_vhca_state_event event; 20 + }; 21 + 22 + int mlx5_cmd_query_vhca_state(struct mlx5_core_dev *dev, u16 function_id, 23 + bool ecpu, u32 *out, u32 outlen) 24 + { 25 + u32 in[MLX5_ST_SZ_DW(query_vhca_state_in)] = {}; 26 + 27 + MLX5_SET(query_vhca_state_in, in, opcode, MLX5_CMD_OP_QUERY_VHCA_STATE); 28 + MLX5_SET(query_vhca_state_in, in, function_id, function_id); 29 + MLX5_SET(query_vhca_state_in, in, embedded_cpu_function, ecpu); 30 + 31 + return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen); 32 + } 33 + 34 + static int mlx5_cmd_modify_vhca_state(struct mlx5_core_dev *dev, u16 function_id, 35 + bool ecpu, u32 *in, u32 inlen) 36 + { 37 + u32 out[MLX5_ST_SZ_DW(modify_vhca_state_out)] = {}; 38 + 39 + MLX5_SET(modify_vhca_state_in, in, opcode, MLX5_CMD_OP_MODIFY_VHCA_STATE); 40 + MLX5_SET(modify_vhca_state_in, in, function_id, function_id); 41 + MLX5_SET(modify_vhca_state_in, in, embedded_cpu_function, ecpu); 42 + 43 + return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); 44 + } 45 + 46 + int mlx5_modify_vhca_sw_id(struct mlx5_core_dev *dev, u16 function_id, bool ecpu, u32 sw_fn_id) 47 + { 48 + u32 out[MLX5_ST_SZ_DW(modify_vhca_state_out)] = {}; 49 + u32 in[MLX5_ST_SZ_DW(modify_vhca_state_in)] = {}; 50 + 51 + MLX5_SET(modify_vhca_state_in, in, opcode, MLX5_CMD_OP_MODIFY_VHCA_STATE); 52 + MLX5_SET(modify_vhca_state_in, in, function_id, function_id); 53 + MLX5_SET(modify_vhca_state_in, in, embedded_cpu_function, ecpu); 54 + MLX5_SET(modify_vhca_state_in, in, vhca_state_field_select.sw_function_id, 1); 55 + MLX5_SET(modify_vhca_state_in, in, vhca_state_context.sw_function_id, sw_fn_id); 56 + 57 + return mlx5_cmd_exec_inout(dev, modify_vhca_state, in, out); 58 + } 59 + 60 + int mlx5_vhca_event_arm(struct mlx5_core_dev *dev, u16 function_id, bool ecpu) 61 + { 62 + u32 in[MLX5_ST_SZ_DW(modify_vhca_state_in)] = {}; 63 + 64 + MLX5_SET(modify_vhca_state_in, in, vhca_state_context.arm_change_event, 1); 65 + MLX5_SET(modify_vhca_state_in, in, vhca_state_field_select.arm_change_event, 1); 66 + 67 + return mlx5_cmd_modify_vhca_state(dev, function_id, ecpu, in, sizeof(in)); 68 + } 69 + 70 + static void 71 + mlx5_vhca_event_notify(struct mlx5_core_dev *dev, struct mlx5_vhca_state_event *event) 72 + { 73 + u32 out[MLX5_ST_SZ_DW(query_vhca_state_out)] = {}; 74 + int err; 75 + 76 + err = mlx5_cmd_query_vhca_state(dev, event->function_id, event->ecpu, out, sizeof(out)); 77 + if (err) 78 + return; 79 + 80 + event->sw_function_id = MLX5_GET(query_vhca_state_out, out, 81 + vhca_state_context.sw_function_id); 82 + event->new_vhca_state = MLX5_GET(query_vhca_state_out, out, 83 + vhca_state_context.vhca_state); 84 + 85 + mlx5_vhca_event_arm(dev, event->function_id, event->ecpu); 86 + 87 + blocking_notifier_call_chain(&dev->priv.vhca_state_notifier->n_head, 0, event); 88 + } 89 + 90 + static void mlx5_vhca_state_work_handler(struct work_struct *_work) 91 + { 92 + struct mlx5_vhca_event_work *work = container_of(_work, struct mlx5_vhca_event_work, work); 93 + struct mlx5_vhca_state_notifier *notifier = work->notifier; 94 + struct mlx5_core_dev *dev = notifier->dev; 95 + 96 + mlx5_vhca_event_notify(dev, &work->event); 97 + } 98 + 99 + static int 100 + mlx5_vhca_state_change_notifier(struct notifier_block *nb, unsigned long type, void *data) 101 + { 102 + struct mlx5_vhca_state_notifier *notifier = 103 + mlx5_nb_cof(nb, struct mlx5_vhca_state_notifier, nb); 104 + struct mlx5_vhca_event_work *work; 105 + struct mlx5_eqe *eqe = data; 106 + 107 + work = kzalloc(sizeof(*work), GFP_ATOMIC); 108 + if (!work) 109 + return NOTIFY_DONE; 110 + INIT_WORK(&work->work, &mlx5_vhca_state_work_handler); 111 + work->notifier = notifier; 112 + work->event.function_id = be16_to_cpu(eqe->data.vhca_state.function_id); 113 + work->event.ecpu = be16_to_cpu(eqe->data.vhca_state.ec_function); 114 + mlx5_events_work_enqueue(notifier->dev, &work->work); 115 + return NOTIFY_OK; 116 + } 117 + 118 + void mlx5_vhca_state_cap_handle(struct mlx5_core_dev *dev, void *set_hca_cap) 119 + { 120 + if (!mlx5_vhca_event_supported(dev)) 121 + return; 122 + 123 + MLX5_SET(cmd_hca_cap, set_hca_cap, vhca_state, 1); 124 + MLX5_SET(cmd_hca_cap, set_hca_cap, event_on_vhca_state_allocated, 1); 125 + MLX5_SET(cmd_hca_cap, set_hca_cap, event_on_vhca_state_active, 1); 126 + MLX5_SET(cmd_hca_cap, set_hca_cap, event_on_vhca_state_in_use, 1); 127 + MLX5_SET(cmd_hca_cap, set_hca_cap, event_on_vhca_state_teardown_request, 1); 128 + } 129 + 130 + int mlx5_vhca_event_init(struct mlx5_core_dev *dev) 131 + { 132 + struct mlx5_vhca_state_notifier *notifier; 133 + 134 + if (!mlx5_vhca_event_supported(dev)) 135 + return 0; 136 + 137 + notifier = kzalloc(sizeof(*notifier), GFP_KERNEL); 138 + if (!notifier) 139 + return -ENOMEM; 140 + 141 + dev->priv.vhca_state_notifier = notifier; 142 + notifier->dev = dev; 143 + BLOCKING_INIT_NOTIFIER_HEAD(&notifier->n_head); 144 + MLX5_NB_INIT(&notifier->nb, mlx5_vhca_state_change_notifier, VHCA_STATE_CHANGE); 145 + return 0; 146 + } 147 + 148 + void mlx5_vhca_event_cleanup(struct mlx5_core_dev *dev) 149 + { 150 + if (!mlx5_vhca_event_supported(dev)) 151 + return; 152 + 153 + kfree(dev->priv.vhca_state_notifier); 154 + dev->priv.vhca_state_notifier = NULL; 155 + } 156 + 157 + void mlx5_vhca_event_start(struct mlx5_core_dev *dev) 158 + { 159 + struct mlx5_vhca_state_notifier *notifier; 160 + 161 + if (!dev->priv.vhca_state_notifier) 162 + return; 163 + 164 + notifier = dev->priv.vhca_state_notifier; 165 + mlx5_eq_notifier_register(dev, &notifier->nb); 166 + } 167 + 168 + void mlx5_vhca_event_stop(struct mlx5_core_dev *dev) 169 + { 170 + struct mlx5_vhca_state_notifier *notifier; 171 + 172 + if (!dev->priv.vhca_state_notifier) 173 + return; 174 + 175 + notifier = dev->priv.vhca_state_notifier; 176 + mlx5_eq_notifier_unregister(dev, &notifier->nb); 177 + } 178 + 179 + int mlx5_vhca_event_notifier_register(struct mlx5_core_dev *dev, struct notifier_block *nb) 180 + { 181 + if (!dev->priv.vhca_state_notifier) 182 + return -EOPNOTSUPP; 183 + return blocking_notifier_chain_register(&dev->priv.vhca_state_notifier->n_head, nb); 184 + } 185 + 186 + void mlx5_vhca_event_notifier_unregister(struct mlx5_core_dev *dev, struct notifier_block *nb) 187 + { 188 + blocking_notifier_chain_unregister(&dev->priv.vhca_state_notifier->n_head, nb); 189 + }
+57
drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 2 + /* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 + 4 + #ifndef __MLX5_VHCA_EVENT_H__ 5 + #define __MLX5_VHCA_EVENT_H__ 6 + 7 + #ifdef CONFIG_MLX5_SF 8 + 9 + struct mlx5_vhca_state_event { 10 + u16 function_id; 11 + u16 sw_function_id; 12 + u8 new_vhca_state; 13 + bool ecpu; 14 + }; 15 + 16 + static inline bool mlx5_vhca_event_supported(const struct mlx5_core_dev *dev) 17 + { 18 + return MLX5_CAP_GEN_MAX(dev, vhca_state); 19 + } 20 + 21 + void mlx5_vhca_state_cap_handle(struct mlx5_core_dev *dev, void *set_hca_cap); 22 + int mlx5_vhca_event_init(struct mlx5_core_dev *dev); 23 + void mlx5_vhca_event_cleanup(struct mlx5_core_dev *dev); 24 + void mlx5_vhca_event_start(struct mlx5_core_dev *dev); 25 + void mlx5_vhca_event_stop(struct mlx5_core_dev *dev); 26 + int mlx5_vhca_event_notifier_register(struct mlx5_core_dev *dev, struct notifier_block *nb); 27 + void mlx5_vhca_event_notifier_unregister(struct mlx5_core_dev *dev, struct notifier_block *nb); 28 + int mlx5_modify_vhca_sw_id(struct mlx5_core_dev *dev, u16 function_id, bool ecpu, u32 sw_fn_id); 29 + int mlx5_vhca_event_arm(struct mlx5_core_dev *dev, u16 function_id, bool ecpu); 30 + int mlx5_cmd_query_vhca_state(struct mlx5_core_dev *dev, u16 function_id, 31 + bool ecpu, u32 *out, u32 outlen); 32 + #else 33 + 34 + static inline void mlx5_vhca_state_cap_handle(struct mlx5_core_dev *dev, void *set_hca_cap) 35 + { 36 + } 37 + 38 + static inline int mlx5_vhca_event_init(struct mlx5_core_dev *dev) 39 + { 40 + return 0; 41 + } 42 + 43 + static inline void mlx5_vhca_event_cleanup(struct mlx5_core_dev *dev) 44 + { 45 + } 46 + 47 + static inline void mlx5_vhca_event_start(struct mlx5_core_dev *dev) 48 + { 49 + } 50 + 51 + static inline void mlx5_vhca_event_stop(struct mlx5_core_dev *dev) 52 + { 53 + } 54 + 55 + #endif 56 + 57 + #endif
+2 -1
drivers/net/ethernet/mellanox/mlx5/core/vport.c
··· 36 36 #include <linux/mlx5/vport.h> 37 37 #include <linux/mlx5/eswitch.h> 38 38 #include "mlx5_core.h" 39 + #include "sf/sf.h" 39 40 40 41 /* Mutex to hold while enabling or disabling RoCE */ 41 42 static DEFINE_MUTEX(mlx5_roce_en_lock); ··· 1161 1160 */ 1162 1161 u16 mlx5_eswitch_get_total_vports(const struct mlx5_core_dev *dev) 1163 1162 { 1164 - return MLX5_SPECIAL_VPORTS(dev) + mlx5_core_max_vfs(dev); 1163 + return MLX5_SPECIAL_VPORTS(dev) + mlx5_core_max_vfs(dev) + mlx5_sf_max_functions(dev); 1165 1164 } 1166 1165 EXPORT_SYMBOL_GPL(mlx5_eswitch_get_total_vports);
+15 -1
include/linux/mlx5/driver.h
··· 193 193 194 194 enum mlx5_coredev_type { 195 195 MLX5_COREDEV_PF, 196 - MLX5_COREDEV_VF 196 + MLX5_COREDEV_VF, 197 + MLX5_COREDEV_SF, 197 198 }; 198 199 199 200 struct mlx5_field_desc { ··· 508 507 struct mlx5_fw_reset; 509 508 struct mlx5_eq_table; 510 509 struct mlx5_irq_table; 510 + struct mlx5_vhca_state_notifier; 511 + struct mlx5_sf_dev_table; 512 + struct mlx5_sf_hw_table; 513 + struct mlx5_sf_table; 511 514 512 515 struct mlx5_rate_limit { 513 516 u32 rate; ··· 609 604 610 605 struct mlx5_bfreg_data bfregs; 611 606 struct mlx5_uars_page *uar; 607 + #ifdef CONFIG_MLX5_SF 608 + struct mlx5_vhca_state_notifier *vhca_state_notifier; 609 + struct mlx5_sf_dev_table *sf_dev_table; 610 + struct mlx5_core_dev *parent_mdev; 611 + #endif 612 + #ifdef CONFIG_MLX5_SF_MANAGER 613 + struct mlx5_sf_hw_table *sf_hw_table; 614 + struct mlx5_sf_table *sf_table; 615 + #endif 612 616 }; 613 617 614 618 enum mlx5_device_state {
+100
include/net/devlink.h
··· 94 94 }; 95 95 96 96 /** 97 + * struct devlink_port_pci_sf_attrs - devlink port's PCI SF attributes 98 + * @controller: Associated controller number 99 + * @sf: Associated PCI SF for of the PCI PF for this port. 100 + * @pf: Associated PCI PF number for this port. 101 + */ 102 + struct devlink_port_pci_sf_attrs { 103 + u32 controller; 104 + u32 sf; 105 + u16 pf; 106 + }; 107 + 108 + /** 97 109 * struct devlink_port_attrs - devlink port object 98 110 * @flavour: flavour of the port 99 111 * @split: indicates if this is split port ··· 115 103 * @phys: physical port attributes 116 104 * @pci_pf: PCI PF port attributes 117 105 * @pci_vf: PCI VF port attributes 106 + * @pci_sf: PCI SF port attributes 118 107 */ 119 108 struct devlink_port_attrs { 120 109 u8 split:1, ··· 127 114 struct devlink_port_phys_attrs phys; 128 115 struct devlink_port_pci_pf_attrs pci_pf; 129 116 struct devlink_port_pci_vf_attrs pci_vf; 117 + struct devlink_port_pci_sf_attrs pci_sf; 130 118 }; 131 119 }; 132 120 ··· 150 136 struct delayed_work type_warn_dw; 151 137 struct list_head reporter_list; 152 138 struct mutex reporters_lock; /* Protects reporter_list */ 139 + }; 140 + 141 + struct devlink_port_new_attrs { 142 + enum devlink_port_flavour flavour; 143 + unsigned int port_index; 144 + u32 controller; 145 + u32 sfnum; 146 + u16 pfnum; 147 + u8 port_index_valid:1, 148 + controller_valid:1, 149 + sfnum_valid:1; 153 150 }; 154 151 155 152 struct devlink_sb_pool_info { ··· 1378 1353 int (*port_function_hw_addr_set)(struct devlink *devlink, struct devlink_port *port, 1379 1354 const u8 *hw_addr, int hw_addr_len, 1380 1355 struct netlink_ext_ack *extack); 1356 + /** 1357 + * port_new() - Add a new port function of a specified flavor 1358 + * @devlink: Devlink instance 1359 + * @attrs: attributes of the new port 1360 + * @extack: extack for reporting error messages 1361 + * @new_port_index: index of the new port 1362 + * 1363 + * Devlink core will call this device driver function upon user request 1364 + * to create a new port function of a specified flavor and optional 1365 + * attributes 1366 + * 1367 + * Notes: 1368 + * - Called without devlink instance lock being held. Drivers must 1369 + * implement own means of synchronization 1370 + * - On success, drivers must register a port with devlink core 1371 + * 1372 + * Return: 0 on success, negative value otherwise. 1373 + */ 1374 + int (*port_new)(struct devlink *devlink, 1375 + const struct devlink_port_new_attrs *attrs, 1376 + struct netlink_ext_ack *extack, 1377 + unsigned int *new_port_index); 1378 + /** 1379 + * port_del() - Delete a port function 1380 + * @devlink: Devlink instance 1381 + * @port_index: port function index to delete 1382 + * @extack: extack for reporting error messages 1383 + * 1384 + * Devlink core will call this device driver function upon user request 1385 + * to delete a previously created port function 1386 + * 1387 + * Notes: 1388 + * - Called without devlink instance lock being held. Drivers must 1389 + * implement own means of synchronization 1390 + * - On success, drivers must unregister the corresponding devlink 1391 + * port 1392 + * 1393 + * Return: 0 on success, negative value otherwise. 1394 + */ 1395 + int (*port_del)(struct devlink *devlink, unsigned int port_index, 1396 + struct netlink_ext_ack *extack); 1397 + /** 1398 + * port_fn_state_get() - Get the state of a port function 1399 + * @devlink: Devlink instance 1400 + * @port: The devlink port 1401 + * @state: Admin configured state 1402 + * @opstate: Current operational state 1403 + * @extack: extack for reporting error messages 1404 + * 1405 + * Reports the admin and operational state of a devlink port function 1406 + * 1407 + * Return: 0 on success, negative value otherwise. 1408 + */ 1409 + int (*port_fn_state_get)(struct devlink *devlink, 1410 + struct devlink_port *port, 1411 + enum devlink_port_fn_state *state, 1412 + enum devlink_port_fn_opstate *opstate, 1413 + struct netlink_ext_ack *extack); 1414 + /** 1415 + * port_fn_state_set() - Set the admin state of a port function 1416 + * @devlink: Devlink instance 1417 + * @port: The devlink port 1418 + * @state: Admin state 1419 + * @extack: extack for reporting error messages 1420 + * 1421 + * Set the admin state of a devlink port function 1422 + * 1423 + * Return: 0 on success, negative value otherwise. 1424 + */ 1425 + int (*port_fn_state_set)(struct devlink *devlink, 1426 + struct devlink_port *port, 1427 + enum devlink_port_fn_state state, 1428 + struct netlink_ext_ack *extack); 1381 1429 }; 1382 1430 1383 1431 static inline void *devlink_priv(struct devlink *devlink) ··· 1507 1409 u16 pf, bool external); 1508 1410 void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller, 1509 1411 u16 pf, u16 vf, bool external); 1412 + void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, 1413 + u32 controller, u16 pf, u32 sf); 1510 1414 int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, 1511 1415 u32 size, u16 ingress_pools_count, 1512 1416 u16 egress_pools_count, u16 ingress_tc_count,
+25
include/uapi/linux/devlink.h
··· 200 200 DEVLINK_PORT_FLAVOUR_UNUSED, /* Port which exists in the switch, but 201 201 * is not used in any way. 202 202 */ 203 + DEVLINK_PORT_FLAVOUR_PCI_SF, /* Represents eswitch port 204 + * for the PCI SF. It is an internal 205 + * port that faces the PCI SF. 206 + */ 203 207 }; 204 208 205 209 enum devlink_param_cmode { ··· 533 529 DEVLINK_ATTR_RELOAD_ACTION_INFO, /* nested */ 534 530 DEVLINK_ATTR_RELOAD_ACTION_STATS, /* nested */ 535 531 532 + DEVLINK_ATTR_PORT_PCI_SF_NUMBER, /* u32 */ 536 533 /* add new attributes above here, update the policy in devlink.c */ 537 534 538 535 __DEVLINK_ATTR_MAX, ··· 583 578 enum devlink_port_function_attr { 584 579 DEVLINK_PORT_FUNCTION_ATTR_UNSPEC, 585 580 DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, /* binary */ 581 + DEVLINK_PORT_FN_ATTR_STATE, /* u8 */ 582 + DEVLINK_PORT_FN_ATTR_OPSTATE, /* u8 */ 586 583 587 584 __DEVLINK_PORT_FUNCTION_ATTR_MAX, 588 585 DEVLINK_PORT_FUNCTION_ATTR_MAX = __DEVLINK_PORT_FUNCTION_ATTR_MAX - 1 586 + }; 587 + 588 + enum devlink_port_fn_state { 589 + DEVLINK_PORT_FN_STATE_INACTIVE, 590 + DEVLINK_PORT_FN_STATE_ACTIVE, 591 + }; 592 + 593 + /** 594 + * enum devlink_port_fn_opstate - indicates operational state of the function 595 + * @DEVLINK_PORT_FN_OPSTATE_ATTACHED: Driver is attached to the function. 596 + * For graceful tear down of the function, after inactivation of the 597 + * function, user should wait for operational state to turn DETACHED. 598 + * @DEVLINK_PORT_FN_OPSTATE_DETACHED: Driver is detached from the function. 599 + * It is safe to delete the port. 600 + */ 601 + enum devlink_port_fn_opstate { 602 + DEVLINK_PORT_FN_OPSTATE_DETACHED, 603 + DEVLINK_PORT_FN_OPSTATE_ATTACHED, 589 604 }; 590 605 591 606 #endif /* _UAPI_LINUX_DEVLINK_H_ */
+280 -30
net/core/devlink.c
··· 87 87 88 88 static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = { 89 89 [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY }, 90 + [DEVLINK_PORT_FN_ATTR_STATE] = 91 + NLA_POLICY_RANGE(NLA_U8, DEVLINK_PORT_FN_STATE_INACTIVE, 92 + DEVLINK_PORT_FN_STATE_ACTIVE), 90 93 }; 91 94 92 95 static LIST_HEAD(devlink_list); ··· 693 690 if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_vf.external)) 694 691 return -EMSGSIZE; 695 692 break; 693 + case DEVLINK_PORT_FLAVOUR_PCI_SF: 694 + if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, 695 + attrs->pci_sf.controller) || 696 + nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, 697 + attrs->pci_sf.pf) || 698 + nla_put_u32(msg, DEVLINK_ATTR_PORT_PCI_SF_NUMBER, 699 + attrs->pci_sf.sf)) 700 + return -EMSGSIZE; 701 + break; 696 702 case DEVLINK_PORT_FLAVOUR_PHYSICAL: 697 703 case DEVLINK_PORT_FLAVOUR_CPU: 698 704 case DEVLINK_PORT_FLAVOUR_DSA: ··· 725 713 } 726 714 727 715 static int 716 + devlink_port_fn_hw_addr_fill(struct devlink *devlink, const struct devlink_ops *ops, 717 + struct devlink_port *port, struct sk_buff *msg, 718 + struct netlink_ext_ack *extack, bool *msg_updated) 719 + { 720 + u8 hw_addr[MAX_ADDR_LEN]; 721 + int hw_addr_len; 722 + int err; 723 + 724 + if (!ops->port_function_hw_addr_get) 725 + return 0; 726 + 727 + err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack); 728 + if (err) { 729 + if (err == -EOPNOTSUPP) 730 + return 0; 731 + return err; 732 + } 733 + err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr); 734 + if (err) 735 + return err; 736 + *msg_updated = true; 737 + return 0; 738 + } 739 + 740 + static bool 741 + devlink_port_fn_state_valid(enum devlink_port_fn_state state) 742 + { 743 + return state == DEVLINK_PORT_FN_STATE_INACTIVE || 744 + state == DEVLINK_PORT_FN_STATE_ACTIVE; 745 + } 746 + 747 + static bool 748 + devlink_port_fn_opstate_valid(enum devlink_port_fn_opstate opstate) 749 + { 750 + return opstate == DEVLINK_PORT_FN_OPSTATE_DETACHED || 751 + opstate == DEVLINK_PORT_FN_OPSTATE_ATTACHED; 752 + } 753 + 754 + static int 755 + devlink_port_fn_state_fill(struct devlink *devlink, 756 + const struct devlink_ops *ops, 757 + struct devlink_port *port, struct sk_buff *msg, 758 + struct netlink_ext_ack *extack, 759 + bool *msg_updated) 760 + { 761 + enum devlink_port_fn_opstate opstate; 762 + enum devlink_port_fn_state state; 763 + int err; 764 + 765 + if (!ops->port_fn_state_get) 766 + return 0; 767 + 768 + err = ops->port_fn_state_get(devlink, port, &state, &opstate, extack); 769 + if (err) { 770 + if (err == -EOPNOTSUPP) 771 + return 0; 772 + return err; 773 + } 774 + if (!devlink_port_fn_state_valid(state)) { 775 + WARN_ON_ONCE(1); 776 + NL_SET_ERR_MSG_MOD(extack, "Invalid state read from driver"); 777 + return -EINVAL; 778 + } 779 + if (!devlink_port_fn_opstate_valid(opstate)) { 780 + WARN_ON_ONCE(1); 781 + NL_SET_ERR_MSG_MOD(extack, 782 + "Invalid operational state read from driver"); 783 + return -EINVAL; 784 + } 785 + if (nla_put_u8(msg, DEVLINK_PORT_FN_ATTR_STATE, state) || 786 + nla_put_u8(msg, DEVLINK_PORT_FN_ATTR_OPSTATE, opstate)) 787 + return -EMSGSIZE; 788 + *msg_updated = true; 789 + return 0; 790 + } 791 + 792 + static int 728 793 devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port, 729 794 struct netlink_ext_ack *extack) 730 795 { 731 796 struct devlink *devlink = port->devlink; 732 797 const struct devlink_ops *ops; 733 798 struct nlattr *function_attr; 734 - bool empty_nest = true; 735 - int err = 0; 799 + bool msg_updated = false; 800 + int err; 736 801 737 802 function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION); 738 803 if (!function_attr) 739 804 return -EMSGSIZE; 740 805 741 806 ops = devlink->ops; 742 - if (ops->port_function_hw_addr_get) { 743 - int hw_addr_len; 744 - u8 hw_addr[MAX_ADDR_LEN]; 745 - 746 - err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack); 747 - if (err == -EOPNOTSUPP) { 748 - /* Port function attributes are optional for a port. If port doesn't 749 - * support function attribute, returning -EOPNOTSUPP is not an error. 750 - */ 751 - err = 0; 752 - goto out; 753 - } else if (err) { 754 - goto out; 755 - } 756 - err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr); 757 - if (err) 758 - goto out; 759 - empty_nest = false; 760 - } 761 - 807 + err = devlink_port_fn_hw_addr_fill(devlink, ops, port, msg, 808 + extack, &msg_updated); 809 + if (err) 810 + goto out; 811 + err = devlink_port_fn_state_fill(devlink, ops, port, msg, extack, 812 + &msg_updated); 762 813 out: 763 - if (err || empty_nest) 814 + if (err || !msg_updated) 764 815 nla_nest_cancel(msg, function_attr); 765 816 else 766 817 nla_nest_end(msg, function_attr); ··· 1061 986 const struct devlink_ops *ops; 1062 987 const u8 *hw_addr; 1063 988 int hw_addr_len; 1064 - int err; 1065 989 1066 990 hw_addr = nla_data(attr); 1067 991 hw_addr_len = nla_len(attr); ··· 1085 1011 return -EOPNOTSUPP; 1086 1012 } 1087 1013 1088 - err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack); 1089 - if (err) 1090 - return err; 1014 + return ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack); 1015 + } 1091 1016 1092 - devlink_port_notify(port, DEVLINK_CMD_PORT_NEW); 1093 - return 0; 1017 + static int devlink_port_fn_state_set(struct devlink *devlink, 1018 + struct devlink_port *port, 1019 + const struct nlattr *attr, 1020 + struct netlink_ext_ack *extack) 1021 + { 1022 + enum devlink_port_fn_state state; 1023 + const struct devlink_ops *ops; 1024 + 1025 + state = nla_get_u8(attr); 1026 + ops = devlink->ops; 1027 + if (!ops->port_fn_state_set) { 1028 + NL_SET_ERR_MSG_MOD(extack, 1029 + "Function does not support state setting"); 1030 + return -EOPNOTSUPP; 1031 + } 1032 + return ops->port_fn_state_set(devlink, port, state, extack); 1094 1033 } 1095 1034 1096 1035 static int ··· 1121 1034 } 1122 1035 1123 1036 attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]; 1124 - if (attr) 1037 + if (attr) { 1125 1038 err = devlink_port_function_hw_addr_set(devlink, port, attr, extack); 1039 + if (err) 1040 + return err; 1041 + } 1042 + /* Keep this as the last function attribute set, so that when 1043 + * multiple port function attributes are set along with state, 1044 + * Those can be applied first before activating the state. 1045 + */ 1046 + attr = tb[DEVLINK_PORT_FN_ATTR_STATE]; 1047 + if (attr) 1048 + err = devlink_port_fn_state_set(devlink, port, attr, extack); 1126 1049 1050 + if (!err) 1051 + devlink_port_notify(port, DEVLINK_CMD_PORT_NEW); 1127 1052 return err; 1128 1053 } 1129 1054 ··· 1233 1134 1234 1135 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 1235 1136 return devlink_port_unsplit(devlink, port_index, info->extack); 1137 + } 1138 + 1139 + static int devlink_port_new_notifiy(struct devlink *devlink, 1140 + unsigned int port_index, 1141 + struct genl_info *info) 1142 + { 1143 + struct devlink_port *devlink_port; 1144 + struct sk_buff *msg; 1145 + int err; 1146 + 1147 + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1148 + if (!msg) 1149 + return -ENOMEM; 1150 + 1151 + mutex_lock(&devlink->lock); 1152 + devlink_port = devlink_port_get_by_index(devlink, port_index); 1153 + if (!devlink_port) { 1154 + err = -ENODEV; 1155 + goto out; 1156 + } 1157 + 1158 + err = devlink_nl_port_fill(msg, devlink, devlink_port, 1159 + DEVLINK_CMD_NEW, info->snd_portid, 1160 + info->snd_seq, 0, NULL); 1161 + if (err) 1162 + goto out; 1163 + 1164 + err = genlmsg_reply(msg, info); 1165 + mutex_unlock(&devlink->lock); 1166 + return err; 1167 + 1168 + out: 1169 + mutex_unlock(&devlink->lock); 1170 + nlmsg_free(msg); 1171 + return err; 1172 + } 1173 + 1174 + static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, 1175 + struct genl_info *info) 1176 + { 1177 + struct netlink_ext_ack *extack = info->extack; 1178 + struct devlink_port_new_attrs new_attrs = {}; 1179 + struct devlink *devlink = info->user_ptr[0]; 1180 + unsigned int new_port_index; 1181 + int err; 1182 + 1183 + if (!devlink->ops->port_new || !devlink->ops->port_del) 1184 + return -EOPNOTSUPP; 1185 + 1186 + if (!info->attrs[DEVLINK_ATTR_PORT_FLAVOUR] || 1187 + !info->attrs[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) { 1188 + NL_SET_ERR_MSG_MOD(extack, "Port flavour or PCI PF are not specified"); 1189 + return -EINVAL; 1190 + } 1191 + new_attrs.flavour = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_FLAVOUR]); 1192 + new_attrs.pfnum = 1193 + nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]); 1194 + 1195 + if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 1196 + /* Port index of the new port being created by driver. */ 1197 + new_attrs.port_index = 1198 + nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 1199 + new_attrs.port_index_valid = true; 1200 + } 1201 + if (info->attrs[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]) { 1202 + new_attrs.controller = 1203 + nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]); 1204 + new_attrs.controller_valid = true; 1205 + } 1206 + if (new_attrs.flavour == DEVLINK_PORT_FLAVOUR_PCI_SF && 1207 + info->attrs[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]) { 1208 + new_attrs.sfnum = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]); 1209 + new_attrs.sfnum_valid = true; 1210 + } 1211 + 1212 + err = devlink->ops->port_new(devlink, &new_attrs, extack, 1213 + &new_port_index); 1214 + if (err) 1215 + return err; 1216 + 1217 + err = devlink_port_new_notifiy(devlink, new_port_index, info); 1218 + if (err && err != -ENODEV) { 1219 + /* Fail to send the response; destroy newly created port. */ 1220 + devlink->ops->port_del(devlink, new_port_index, extack); 1221 + } 1222 + return err; 1223 + } 1224 + 1225 + static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb, 1226 + struct genl_info *info) 1227 + { 1228 + struct netlink_ext_ack *extack = info->extack; 1229 + struct devlink *devlink = info->user_ptr[0]; 1230 + unsigned int port_index; 1231 + 1232 + if (!devlink->ops->port_del) 1233 + return -EOPNOTSUPP; 1234 + 1235 + if (!info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 1236 + NL_SET_ERR_MSG_MOD(extack, "Port index is not specified"); 1237 + return -EINVAL; 1238 + } 1239 + port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 1240 + 1241 + return devlink->ops->port_del(devlink, port_index, extack); 1236 1242 } 1237 1243 1238 1244 static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, ··· 7798 7594 [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, 7799 7595 DEVLINK_RELOAD_ACTION_MAX), 7800 7596 [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK), 7597 + [DEVLINK_ATTR_PORT_FLAVOUR] = { .type = NLA_U16 }, 7598 + [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16 }, 7599 + [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 }, 7600 + [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 }, 7801 7601 }; 7802 7602 7803 7603 static const struct genl_small_ops devlink_nl_ops[] = { ··· 7838 7630 .cmd = DEVLINK_CMD_PORT_UNSPLIT, 7839 7631 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 7840 7632 .doit = devlink_nl_cmd_port_unsplit_doit, 7633 + .flags = GENL_ADMIN_PERM, 7634 + .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, 7635 + }, 7636 + { 7637 + .cmd = DEVLINK_CMD_PORT_NEW, 7638 + .doit = devlink_nl_cmd_port_new_doit, 7639 + .flags = GENL_ADMIN_PERM, 7640 + .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, 7641 + }, 7642 + { 7643 + .cmd = DEVLINK_CMD_PORT_DEL, 7644 + .doit = devlink_nl_cmd_port_del_doit, 7841 7645 .flags = GENL_ADMIN_PERM, 7842 7646 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, 7843 7647 }, ··· 8592 8372 } 8593 8373 EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set); 8594 8374 8375 + /** 8376 + * devlink_port_attrs_pci_sf_set - Set PCI SF port attributes 8377 + * 8378 + * @devlink_port: devlink port 8379 + * @controller: associated controller number for the devlink port instance 8380 + * @pf: associated PF for the devlink port instance 8381 + * @sf: associated SF of a PF for the devlink port instance 8382 + */ 8383 + void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 controller, 8384 + u16 pf, u32 sf) 8385 + { 8386 + struct devlink_port_attrs *attrs = &devlink_port->attrs; 8387 + int ret; 8388 + 8389 + if (WARN_ON(devlink_port->registered)) 8390 + return; 8391 + ret = __devlink_port_attrs_set(devlink_port, 8392 + DEVLINK_PORT_FLAVOUR_PCI_SF); 8393 + if (ret) 8394 + return; 8395 + attrs->pci_sf.controller = controller; 8396 + attrs->pci_sf.pf = pf; 8397 + attrs->pci_sf.sf = sf; 8398 + } 8399 + EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_sf_set); 8400 + 8595 8401 static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, 8596 8402 char *name, size_t len) 8597 8403 { ··· 8665 8419 } 8666 8420 n = snprintf(name, len, "pf%uvf%u", 8667 8421 attrs->pci_vf.pf, attrs->pci_vf.vf); 8422 + break; 8423 + case DEVLINK_PORT_FLAVOUR_PCI_SF: 8424 + n = snprintf(name, len, "pf%usf%u", attrs->pci_sf.pf, 8425 + attrs->pci_sf.sf); 8668 8426 break; 8669 8427 } 8670 8428