Skip to content

Conversation

@madhuchittim
Copy link
Owner

@madhuchittim madhuchittim commented Apr 18, 2024

This series converts the idpf driver to use the auxiliary bus.

The main motivation for this patch series is to address the following topics:

  1. The auxiliary bus is preferred in the Linux community.
  2. Upstreaming of dynamic vports and ADI functionality requires driver
    separation into PCIe and Ethernet driver component.
  3. IDPF PCIe driver supports multiple sub functions like RDMA, ethernet etc.

First 5 patches are in preparation for enabling the code changes for auxiliary
bus plug in. They are only refactoring the existing code to different files. The
similar functionality is accomodated into different files. This enables separating
the ethernet functionality for future patches.

Patch 6 introduces the IDC shared header file. This file is for inter device
communication.

Patch 7 creates logical separation of ethernet portion of the code, but it is
still a global single adapter for all the vports.

Patch 8 makes it multi-instance driver like each vport will have its own adapter instance.
Patch 9 moves the ethernet functionality into eth directory.
And finally Patch 10 connect the ethernet portion of the driver to the auxiliary bus.

@madhuchittim madhuchittim force-pushed the aux_bus branch 6 times, most recently from 41df721 to a156d88 Compare April 18, 2024 20:05

extern struct idpf_eth_idc_auxiliary_driver *idpf_eth_get_driver(void);
/**
* idpf_eth_idc_get_driver - returns eth driver ops

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please check all the comment headers. Many places there is a mismatch...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if I missed something. Needs review.

}

do_memcpy:
memcpy(rss_data->rss_key, recv_rk->key_flex, rss_data->rss_key_size);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recv_rk memory is leaked here unless I am missing something.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what leak is referred here. The driver loads fine and I didn't see any issue with the driver.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I referred specifically to recv_rk. If you examine the function, I don't see it being freed. Loading of driver has nothng to do with a few memory blocks leaking.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will keep the original code as it as that is not the purpose of this PR . The other issues (non aux related changes) can be addressed with a separate PR.

@@ -1,18 +1,29 @@
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (C) 2023 Intel Corporation
# Copyright (C) 2024 Intel Corporation

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copyright year is year of coding, not year of modification.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pavan had a comment on this to be changed. @plinga1 Can you please confirm on this.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a comment when we upstreamed IDPF to update the copyright year to the current year the driver makes into the upstream. Couldnt find the comment but you may consult Tony for additional info.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See here is my past experience with Copyright. When the file is first coded, the copyright line shows that year e.g.
Copyright (C) 2021 Rafał Miłecki rafal@milecki.pl

Now suppose above file is modified again in 2022, the copyright should be
Copyright (C) 2021-2022 Rafał Miłecki rafal@milecki.pl

Then the file gets modified in 2024 (means not modified in 2023), the copyright should read:
Copyright (C) 2021-2022, 2024 Rafał Miłecki rafal@milecki.pl

Essentially, every year that you modify the file should be listed via range (using dash) or explicitly

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially talked to Tony about it, and I had left it to the original code date of this driver based on the feedback from him. I will ask him again about it.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have caused a problem here.. some of the files I moved the year based on Pavan's comments so some of them would end up showing as 2024

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worry, I will fix them again.

dev_info = adapter->dev_info;
eth_shared = idpf_eth_adapter_shared(adapter);
pdev = eth_shared->pdev;
adapter->req_tx_splitq = true;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove these flags if they are always true ? Or is there some mechanism to make it false

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is part of original code. I don't want to divert from the definition of this PR for making further changes to this PR.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How the OOT is doing? I am not sure why it is there in first place? Will it ever need in future?

@tksingh-amr tksingh-amr force-pushed the aux_bus branch 6 times, most recently from 614edb3 to 4c367cb Compare May 6, 2024 12:26
@tksingh-amr tksingh-amr force-pushed the aux_bus branch 7 times, most recently from a97a5dc to 4d486cf Compare May 10, 2024 17:28
Repository owner deleted a comment from burra006 May 10, 2024
@tksingh-amr tksingh-amr force-pushed the aux_bus branch 2 times, most recently from 37f6713 to 621bcfc Compare May 13, 2024 12:24
* idpf_eth_device_post_init_task - Delayed ethernet post initialization task
* @work: work_struct handle to ethernet adapter data
*/
static void idpf_eth_device_post_init_task(struct work_struct *work)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why this is a task. There is nothing blocking here. So why spawn a task ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see this flag "adapter->start_post_init" in this function. It is a blocking factor to re spawn.

return -ENOMEM;

/* Initialize dev_info */
adapter->dev_info = &eth_dev->eth_info;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assignment to dev_info can be deleted . IT is being done below.

u32 tx_timeout_count;
bool req_tx_splitq;
bool req_rx_splitq;
u32 *vport_ids;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this plural and pointer ? I think there is only one vport_id for one ethernet adapter

Added new files 'idpf_eth_idc.c', idpf_eth.c, idpf_eth.h, and
'idpf_eth_common.h'

Added new 'struct idpf_eth_adapter' to make ethernet device's
logical separation from main driver. Moved all ethernet related
members into this new structure, and corresponding functions
into new files 'idpf_eth.c' and 'idpf_eth.h'. Added inter device
communication (idc) functions in new file 'idpf_eth_idc.c'. The
idc file contains all the necessary hooks to communicate with
separated logical device (eth). Many ethernet device code function
argumets are now changed from idpf_adapter to idpf_eth_adapter
in corresponding ethernet code files.

Added 'struct idpf_eth_idc_auxiliary_dev' for tracking eth device
creation and deletion. The eth device information is stored in
idpf_eth_shared structure for easy access in both lower and upper
layers.

A new 'struct idpf_eth_idc_dev_info' is added to pass device init
parameters like queue, capabilities etc. to ethernet device from
main driver. The capabilities (caps) macros are moved into the
file 'idpf_eth_idc.h', so that both main and ethernet drivers can
access these macros.

After the primary pci device's reset and initialization flow, a
new task 'idc_eth_init_task' is scheduled. This new task creates
ethernet device structure information, allocates ethernet adapter
structure, and initializes eth portion of the driver which now
takes over the processing of vports of ethernet device (eth).

This patch impliments ethernet device as a single ethernet device
adapter having default single or multiple vport(s).

Ethernet device initialization is a two part process through
functions idpf_eth_device_pre_init(), and idpf_eth_device_post_init().
Pre init runs task idpf_eth_device_pre_init_task() which
checks to see if all vports devices are pre-initialized and ready
for moving on to post init step. Post init step enables the vport's
availability into the system.

Added events for propagating the information from main driver to
ethernet portion of the driver.Added 'enum idpf_eth_idc_event_type'
to indicate whether an event is for all vports/ethernet adapters or
single vport/ethernet adapter.

Added a local flags declaration into 'struct idpf_eth_adapter', and
corresponding 'enum idpf_eth_flags' for keeping lower level events
information.

Removed reference or dependency of 'struct idpf_adapter' i.e. the
header file 'idpf.h' from all the files related to ethernet
operations. These files are: idpf_eth.c/h, idpf_mac.c/h,
idpf_netdev.c/h, idpf_vport.c/h, idpf_vport_config.c,
idpf_vport_q.c, idpf_txrx.c, and idpf_singleq_txrx.c. These files
now include idpf_eth.h instead of idpf.h.

Renamed variable 'vport_ctrl_lock' to 'reset_lock' and associated
function to reflect its usage nature. Removed main driver's lock
dependency into the ethernet drivers. Ethernet driver code now
refers to local version og 'vport_ctrl_lock' and flags in
eth_adapter to take decisions. The local flags information is
updated via events from main driver.

In function idpf_decfg_netdev(), added a netdev register check
before unregistering.

The content of 'idpf_virtchnl.h' are moved into 'idpf_eth_common.h'
as they are common for both, and file 'idpf_virtchnl.h' has been
removed.

Signed-off-by: Tarun K Singh <tarun.k.singh@intel.com>
Signed-off-by: Shailendra Bhatnagar <shailendra.bhatnagar@intel.com>
Added capability to allocate multiple adapter instance based on
number of vports. Most of the double pointers into 'struct
idpf_eth_adapter'are converted into single pointer to hold data
structure for vport, netdev, vport_config, vport_params_reqd, and
vport_params_recvd.

Removed unused following function(s) while making these changes:
idpf_get_free_slot(), idpf_vport_params_buf_alloc(),
idpf_vid_to_vport(), and few others.

In 'struct idpf_eth_adapter' removed pre_init_task, pre_init_wq,
members vport_ids, next_vport, and num_alloc_vports. They are not
required into the multi instance adapter implementation.

In 'struct idpf_eth_idc_dev_info' a new member
'bool start_probe_post_init' is added so that the probe post init
can be triggered concurrently. Added new event to trigger the post
initialization part of ethernet probe.

Added new function idpf_eth_idc_vid_to_dev_info() to retrieve the
device instance based on vport id associated with it.

Signed-off-by: Tarun K Singh <tarun.k.singh@intel.com>
Signed-off-by: Shailendra Bhatnagar <shailendra.bhatnagar@intel.com>
Created new directory 'eth' to separate the ethernet driver files.

Following files are now part of 'eth' and represents ethernet
portion of the driver.
Files:idpf_txrx.c, idpf_txrx.h, idpf_singleq_txrx.c, idpf_ethtool.c,
idpf_mac.c, idpf_mac.h, idpf_netdev.c, idpf_netdev.h, idpf_vport.c
idpf_vport.h, idpf_vport_config.c, idpf_vport_q.c, idpf_eth.c, and
idpf_eth.h

Makefile modification are done to include directory name 'eth' for
above moved 'c' files, and a flag.

Signed-off-by: Tarun K Singh <tarun.k.singh@intel.com>
It now uses the auxiliary bus to manage ethernet part of driver and
its devices.

In 'struct idpf_eth_idc_auxiliary_driver' added new member to save
signature, and another member 'struct auxiliary_driver adrv' to keep
auxiliary device information. Renamed function idpf_eth_device_add()
to idpf_eth_probe() to reflect auxiliary device probe.

Added new function 'idpf_eth_idc_driver_register()' to register
auxiliary driver. And added corespondig call to unregister the
auxiliary driver in function 'idpf_eth_idc_driver_unregister()'.

Added module_init(idpf_driver_register), and
module_exit(idpf_driver_unregister) to register/unregister the
auxiliary device information.

Added management auxiliary call 'auxiliary_device_init()' and
'auxiliary_device_add()' to initialize the device and to request the
system to start the probe for device(s).

Added new function 'idpf_eth_idc_device_deinit()' to manage the
delete and uninit the auxuliary devices.

Removed unused function after conversion idpf_eth_unregister(), and
removed variables idpf_context, and eth_context as they are not
required. In this new model those are retrieved from the system
devices references now on need basis.

Signed-off-by: Tarun K Singh <tarun.k.singh@intel.com>
Signed-off-by: Shailendra Bhatnagar <shailendra.bhatnagar@intel.com>
*/
struct idpf_adapter {
/* Do not move eth_shared location */
struct idpf_eth_shared eth_shared;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static_assert(offsetof(...) == 0) can be used here

azaki1 pushed a commit that referenced this pull request Feb 15, 2025
We have recently seen reports of lockdep circular lock dependency warnings
when loading the iAVF driver:

[ 1504.790308] ======================================================
[ 1504.790309] WARNING: possible circular locking dependency detected
[ 1504.790310] 6.13.0 #net_next_rt.c2933b2befe2.el9 Not tainted
[ 1504.790311] ------------------------------------------------------
[ 1504.790312] kworker/u128:0/13566 is trying to acquire lock:
[ 1504.790313] ffff97d0e4738f18 (&dev->lock){+.+.}-{4:4}, at: register_netdevice+0x52c/0x710
[ 1504.790320]
[ 1504.790320] but task is already holding lock:
[ 1504.790321] ffff97d0e47392e8 (&adapter->crit_lock){+.+.}-{4:4}, at: iavf_finish_config+0x37/0x240 [iavf]
[ 1504.790330]
[ 1504.790330] which lock already depends on the new lock.
[ 1504.790330]
[ 1504.790330]
[ 1504.790330] the existing dependency chain (in reverse order) is:
[ 1504.790331]
[ 1504.790331] -> #1 (&adapter->crit_lock){+.+.}-{4:4}:
[ 1504.790333]        __lock_acquire+0x52d/0xbb0
[ 1504.790337]        lock_acquire+0xd9/0x330
[ 1504.790338]        mutex_lock_nested+0x4b/0xb0
[ 1504.790341]        iavf_finish_config+0x37/0x240 [iavf]
[ 1504.790347]        process_one_work+0x248/0x6d0
[ 1504.790350]        worker_thread+0x18d/0x330
[ 1504.790352]        kthread+0x10e/0x250
[ 1504.790354]        ret_from_fork+0x30/0x50
[ 1504.790357]        ret_from_fork_asm+0x1a/0x30
[ 1504.790361]
[ 1504.790361] -> #0 (&dev->lock){+.+.}-{4:4}:
[ 1504.790364]        check_prev_add+0xf1/0xce0
[ 1504.790366]        validate_chain+0x46a/0x570
[ 1504.790368]        __lock_acquire+0x52d/0xbb0
[ 1504.790370]        lock_acquire+0xd9/0x330
[ 1504.790371]        mutex_lock_nested+0x4b/0xb0
[ 1504.790372]        register_netdevice+0x52c/0x710
[ 1504.790374]        iavf_finish_config+0xfa/0x240 [iavf]
[ 1504.790379]        process_one_work+0x248/0x6d0
[ 1504.790381]        worker_thread+0x18d/0x330
[ 1504.790383]        kthread+0x10e/0x250
[ 1504.790385]        ret_from_fork+0x30/0x50
[ 1504.790387]        ret_from_fork_asm+0x1a/0x30
[ 1504.790389]
[ 1504.790389] other info that might help us debug this:
[ 1504.790389]
[ 1504.790389]  Possible unsafe locking scenario:
[ 1504.790389]
[ 1504.790390]        CPU0                    CPU1
[ 1504.790391]        ----                    ----
[ 1504.790391]   lock(&adapter->crit_lock);
[ 1504.790393]                                lock(&dev->lock);
[ 1504.790394]                                lock(&adapter->crit_lock);
[ 1504.790395]   lock(&dev->lock);
[ 1504.790397]
[ 1504.790397]  *** DEADLOCK ***

This appears to be caused by the change in commit 5fda3f3 ("net: make
netdev_lock() protect netdev->reg_state"), which added a netdev_lock() in
register_netdevice.

The iAVF driver calls register_netdevice() from iavf_finish_config(), as a
final stage of its state machine post-probe. It currently takes the RTNL
lock, then the netdev lock, and then the device critical lock. This pattern
is used throughout the driver. Thus there is a strong dependency that the
crit_lock should not be acquired before the net device lock. The change to
register_netdevice creates an ABBA lock order violation because the iAVF
driver is holding the crit_lock while calling register_netdevice, which
then takes the netdev_lock.

It seems likely that future refactors could result in netdev APIs which
hold the netdev_lock while calling into the driver. This means that we
should not re-order the locks so that netdev_lock is acquired after the
device private crit_lock.

Instead, notice that we already release the netdev_lock prior to calling
the register_netdevice. This flow only happens during the early driver
initialization as we transition through the __IAVF_STARTUP,
__IAVF_INIT_VERSION_CHECK, __IAVF_INIT_GET_RESOURCES, etc.

Analyzing the places where we take crit_lock in the driver there are two
sources:

a) several of the work queue tasks including adminq_task, watchdog_task,
reset_task, and the finish_config task.

b) various callbacks which ultimately stem back to .ndo operations or
ethtool operations.

The latter cannot be triggered until after the netdevice registration is
completed successfully.

The iAVF driver uses alloc_ordered_workqueue, which is an unbound workqueue
that has a max limit of 1, and thus guarantees that only a single work item
on the queue is executing at any given time, so none of the other work
threads could be executing due to the ordered workqueue guarantees.

The iavf_finish_config() function also does not do anything else after
register_netdevice, unless it fails. It seems unlikely that the driver
private crit_lock is protecting anything that register_netdevice() itself
touches.

Thus, to fix this ABBA lock violation, lets simply release the
adapter->crit_lock as well as netdev_lock prior to calling
register_netdevice(). We do still keep holding the RTNL lock as required by
the function. If we do fail to register the netdevice, then we re-acquire
the adapter critical lock to finish the transition back to
__IAVF_INIT_CONFIG_ADAPTER.

This ensures every call where both netdev_lock and the adapter->crit_lock
are acquired under the same ordering.

Fixes: afc6649 ("eth: iavf: extend the netdev_lock usage")
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Jakub Kicinski <kuba@kernel.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.