ice_ptp_lock() conditionally retains ctrl_pf_lock for read when it successfully acquires the hardware semaphore. The matching unlock occurs in ice_ptp_unlock(). Describe this cross-function handoff with context analysis annotations so static analysis can verify callers. Signed-off-by: Sergey Temerkhanov Reviewed-by: Przemyslaw Korba --- drivers/net/ethernet/intel/ice/ice.h | 12 ++++++++++ drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 26 +++++++++++++-------- drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 6 +++-- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index c454f19a2cb2..8b7891ac25b0 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -1179,4 +1179,16 @@ static inline struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf) rcu_dereference_check(pf->adapter->ctrl_pf, lockdep_is_held(&pf->adapter->ctrl_pf_lock)); } + +/* container_of() expands to a statement expression, which clang cannot parse + * inside a context analysis attribute argument, so open-code the cast here. + */ +#define ice_hw_ctrl_pf_lock(_hw) \ + (&((struct ice_pf *)((void *)(_hw) - \ + offsetof(struct ice_pf, hw)))->adapter->ctrl_pf_lock) + +bool ice_ptp_lock(struct ice_hw *hw) + __cond_acquires_shared(true, ice_hw_ctrl_pf_lock(hw)); +void ice_ptp_unlock(struct ice_hw *hw) + __releases_shared(ice_hw_ctrl_pf_lock(hw)); #endif /* _ICE_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index a85aa8f99057..eb7fdd000cf2 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -5361,15 +5361,16 @@ static void ice_ptp_init_phy_e830(struct ice_ptp_hw *ptp) bool ice_ptp_lock(struct ice_hw *hw) { struct ice_pf *pf = container_of(hw, struct ice_pf, hw); + struct ice_hw *pri_hw = hw; u32 hw_lock; int i; - down_read(&pf->adapter->ctrl_pf_lock); + down_read(ice_hw_ctrl_pf_lock(hw)); if (!ice_is_primary(hw)) { - hw = ice_get_primary_hw(pf); - if (!hw) { - up_read(&pf->adapter->ctrl_pf_lock); + pri_hw = ice_get_primary_hw(pf); + if (!pri_hw) { + up_read(ice_hw_ctrl_pf_lock(hw)); return false; } } @@ -5377,7 +5378,8 @@ bool ice_ptp_lock(struct ice_hw *hw) #define MAX_TRIES 15 for (i = 0; i < MAX_TRIES; i++) { - hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id)); + hw_lock = rd32(pri_hw, + PFTSYN_SEM + (PFTSYN_SEM_BYTES * pri_hw->pf_id)); hw_lock = hw_lock & PFTSYN_SEM_BUSY_M; if (hw_lock) { /* Somebody is holding the lock */ @@ -5389,7 +5391,7 @@ bool ice_ptp_lock(struct ice_hw *hw) } if (hw_lock) - up_read(&pf->adapter->ctrl_pf_lock); + up_read(ice_hw_ctrl_pf_lock(hw)); return !hw_lock; } @@ -5404,14 +5406,18 @@ bool ice_ptp_lock(struct ice_hw *hw) void ice_ptp_unlock(struct ice_hw *hw) { struct ice_pf *pf = container_of(hw, struct ice_pf, hw); + struct ice_hw *pri_hw = hw; - lockdep_assert_held(&pf->adapter->ctrl_pf_lock); + lockdep_assert_held(ice_hw_ctrl_pf_lock(hw)); + /* ctrl_pf cannot be cleared while ctrl_pf_lock is held for read, so a + * successful ice_ptp_lock() guarantees a primary hw is still there. + */ if (!ice_is_primary(hw)) - hw = ice_get_primary_hw(pf); + pri_hw = ice_get_primary_hw(pf); - wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0); - up_read(&pf->adapter->ctrl_pf_lock); + wr32(pri_hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * pri_hw->pf_id), 0); + up_read(ice_hw_ctrl_pf_lock(hw)); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index 16b1988e993d..ce8eb0672e71 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -293,8 +293,10 @@ extern const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD]; /* Device agnostic functions */ u8 ice_get_ptp_src_clock_index(struct ice_hw *hw); -bool ice_ptp_lock(struct ice_hw *hw); -void ice_ptp_unlock(struct ice_hw *hw); +/* ice_ptp_lock()/ice_ptp_unlock() are declared in ice.h, where struct ice_pf + * and struct ice_adapter are complete and ice_hw_ctrl_pf_lock() can be used + * in their context analysis annotations. + */ void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd); int ice_ptp_init_time(struct ice_hw *hw, u64 time); int ice_ptp_write_incval(struct ice_hw *hw, u64 incval); -- 2.53.0