struct iavf_adapter::crit_section is a bit-lock container indexed by values from enum iavf_critical_section_t (__IAVF_IN_REMOVE_TASK). It is manipulated exclusively through the kernel atomic bitops API: set_bit(), clear_bit(), test_bit(), test_and_set_bit().
It is declared as a bare 'unsigned long' and every call site passes '&adapter->crit_section'. That is functionally correct -- the bit index is a compile-time enum value well below BITS_PER_LONG so BIT_WORD(nr) is always 0 and only the singleton word is ever touched -- but it relies on layout coincidence rather than on the documented contract of the bitops API, which is defined in terms of 'unsigned long *' arrays. Static analyzers that model the same contract flag every such call site with ARRAY_VS_SINGLETON because the address of a scalar is passed where an array pointer is expected. Convert the field to a proper bitmap using DECLARE_BITMAP() sized by a new sentinel __IAVF_CRIT_SECTION_NBITS at the end of the enum. The underlying storage is unchanged (a single unsigned long word on every architecture Linux supports), so there is no functional or ABI change; the type simply becomes 'unsigned long[1]' which matches what the bitops API expects and silences the analyzer warnings permanently. Drop the leading '&' at every call site, since arrays decay to pointers. No functional change intended. Suggested-by: Arkadiusz Kubalewski <[email protected]> Signed-off-by: Aleksandr Loktionov <[email protected]> --- drivers/net/ethernet/intel/iavf/iavf.h | 3 ++- drivers/net/ethernet/intel/iavf/iavf_main.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index 050f824..ba9ad63 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -213,6 +213,7 @@ enum iavf_state_t { enum iavf_critical_section_t { __IAVF_IN_REMOVE_TASK, /* device being removed */ + __IAVF_CRIT_SECTION_NBITS /* must be last */ }; #define IAVF_CLOUD_FIELD_OMAC 0x01 @@ -389,7 +390,7 @@ struct iavf_adapter { enum iavf_state_t state; enum iavf_state_t last_state; - unsigned long crit_section; + DECLARE_BITMAP(crit_section, __IAVF_CRIT_SECTION_NBITS); struct delayed_work watchdog_task; bool link_up; diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index d2914c5..b3332ca 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -264,7 +264,7 @@ void iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem) **/ void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags) { - if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section) && + if (!test_bit(__IAVF_IN_REMOVE_TASK, adapter->crit_section) && !(adapter->flags & (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) { adapter->flags |= flags; @@ -1355,7 +1355,7 @@ void iavf_down(struct iavf_adapter *adapter) if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) return; - if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) { + if (!test_bit(__IAVF_IN_REMOVE_TASK, adapter->crit_section)) { /* cancel any current operation */ adapter->current_op = VIRTCHNL_OP_UNKNOWN; /* Schedule operations to close down the HW. Don't wait @@ -1960,7 +1960,7 @@ static void iavf_finish_config(struct work_struct *work) if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) && adapter->netdev->reg_state == NETREG_REGISTERED && - !test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) { + !test_bit(__IAVF_IN_REMOVE_TASK, adapter->crit_section)) { netdev_update_features(adapter->netdev); adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES; } @@ -2016,7 +2016,7 @@ static void iavf_finish_config(struct work_struct *work) **/ void iavf_schedule_finish_config(struct iavf_adapter *adapter) { - if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) + if (!test_bit(__IAVF_IN_REMOVE_TASK, adapter->crit_section)) queue_work(adapter->wq, &adapter->finish_config); } @@ -2870,7 +2870,7 @@ static int iavf_watchdog_step(struct iavf_adapter *adapter) return 1; case __IAVF_INIT_FAILED: if (test_bit(__IAVF_IN_REMOVE_TASK, - &adapter->crit_section)) { + adapter->crit_section)) { /* Do not update the state and do not reschedule * watchdog task, iavf_remove should handle this state * as it can loop forever @@ -2889,7 +2889,7 @@ static int iavf_watchdog_step(struct iavf_adapter *adapter) return 1000; case __IAVF_COMM_FAILED: if (test_bit(__IAVF_IN_REMOVE_TASK, - &adapter->crit_section)) { + adapter->crit_section)) { /* Set state to __IAVF_INIT_FAILED and perform remove * steps. Remove IAVF_FLAG_PF_COMMS_FAILED so the task * doesn't bring the state back to __IAVF_COMM_FAILED. @@ -3771,7 +3771,7 @@ static int __iavf_setup_tc(struct net_device *netdev, void *type_data) } } exit: - if (test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) + if (test_bit(__IAVF_IN_REMOVE_TASK, adapter->crit_section)) return 0; netif_set_real_num_rx_queues(netdev, total_qps); @@ -5513,7 +5513,7 @@ static void iavf_remove(struct pci_dev *pdev) adapter = iavf_pdev_to_adapter(pdev); hw = &adapter->hw; - if (test_and_set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) + if (test_and_set_bit(__IAVF_IN_REMOVE_TASK, adapter->crit_section)) return; /* Wait until port initialization is complete. -- 2.52.0
