lkml.org 
[lkml]   [2022]   [Jul]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.18 084/158] net: lan966x: Fix taking rtnl_lock while holding spin_lock
    Date
    From: Horatiu Vultur <horatiu.vultur@microchip.com>

    [ Upstream commit 45533a534a45cb12c20c81615d17306176cb1c57 ]

    When the HW deletes an entry in MAC table then it generates an
    interrupt. The SW will go through it's own list of MAC entries and if it
    is not found then it would notify the listeners about this. The problem
    is that when the SW will go through it's own list it would take a spin
    lock(lan966x->mac_lock) and when it notifies that the entry is deleted.
    But to notify the listeners it taking the rtnl_lock which is illegal.

    This is fixed by instead of notifying right away that the entry is
    deleted, move the entry on a temp list and once, it checks all the
    entries then just notify that the entries from temp list are deleted.

    Fixes: 5ccd66e01cbe ("net: lan966x: add support for interrupts from analyzer")
    Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
    Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
    Signed-off-by: Jakub Kicinski <kuba@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    .../ethernet/microchip/lan966x/lan966x_mac.c | 27 ++++++++++++-------
    1 file changed, 18 insertions(+), 9 deletions(-)

    diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_mac.c b/drivers/net/ethernet/microchip/lan966x/lan966x_mac.c
    index 005e56ea5da1..2d2b83c03796 100644
    --- a/drivers/net/ethernet/microchip/lan966x/lan966x_mac.c
    +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_mac.c
    @@ -325,10 +325,13 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
    {
    struct lan966x_mac_entry *mac_entry, *tmp;
    unsigned char mac[ETH_ALEN] __aligned(2);
    + struct list_head mac_deleted_entries;
    u32 dest_idx;
    u32 column;
    u16 vid;

    + INIT_LIST_HEAD(&mac_deleted_entries);
    +
    spin_lock(&lan966x->mac_lock);
    list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries, list) {
    bool found = false;
    @@ -362,20 +365,26 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
    }

    if (!found) {
    - /* Notify the bridge that the entry doesn't exist
    - * anymore in the HW and remove the entry from the SW
    - * list
    - */
    - lan966x_mac_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
    - mac_entry->mac, mac_entry->vid,
    - lan966x->ports[mac_entry->port_index]->dev);
    -
    list_del(&mac_entry->list);
    - kfree(mac_entry);
    + /* Move the entry from SW list to a tmp list such that
    + * it would be deleted later
    + */
    + list_add_tail(&mac_entry->list, &mac_deleted_entries);
    }
    }
    spin_unlock(&lan966x->mac_lock);

    + list_for_each_entry_safe(mac_entry, tmp, &mac_deleted_entries, list) {
    + /* Notify the bridge that the entry doesn't exist
    + * anymore in the HW
    + */
    + lan966x_mac_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
    + mac_entry->mac, mac_entry->vid,
    + lan966x->ports[mac_entry->port_index]->dev);
    + list_del(&mac_entry->list);
    + kfree(mac_entry);
    + }
    +
    /* Now go to the list of columns and see if any entry was not in the SW
    * list, then that means that the entry is new so it needs to notify the
    * bridge.
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-07-27 19:39    [W:2.192 / U:0.144 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site