diff options
| author | Andrea Parri (Microsoft) <parri.andrea@gmail.com> | 2022-04-19 14:23:23 +0200 | 
|---|---|---|
| committer | Wei Liu <wei.liu@kernel.org> | 2022-04-25 15:51:12 +0000 | 
| commit | 0aadb6a7bb811554cf39318b5d18e8ec50dd9f02 (patch) | |
| tree | 747313f405d50341346381763ff44215f294ebd7 | |
| parent | b03afa57c65e1e045e02df49777e953742745f4c (diff) | |
Drivers: hv: vmbus: Introduce vmbus_request_addr_match()
The function can be used to retrieve and clear/remove a transation ID
from a channel requestor, provided the memory address corresponding to
the ID equals a specified address.  The function, and its 'lockless'
variant __vmbus_request_addr_match(), will be used by hv_pci.
Refactor vmbus_request_addr() to reuse the 'newly' introduced code.
No functional change.
Suggested-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Link: https://lore.kernel.org/r/20220419122325.10078-5-parri.andrea@gmail.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
| -rw-r--r-- | drivers/hv/channel.c | 65 | ||||
| -rw-r--r-- | include/linux/hyperv.h | 5 | 
2 files changed, 52 insertions, 18 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 585a8084848b..49f10a603a09 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -1279,17 +1279,11 @@ u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr)  }  EXPORT_SYMBOL_GPL(vmbus_next_request_id); -/* - * vmbus_request_addr - Returns the memory address stored at @trans_id - * in @rqstor. Uses a spin lock to avoid race conditions. - * @channel: Pointer to the VMbus channel struct - * @trans_id: Request id sent back from Hyper-V. Becomes the requestor's - * next request id. - */ -u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id) +/* As in vmbus_request_addr_match() but without the requestor lock */ +u64 __vmbus_request_addr_match(struct vmbus_channel *channel, u64 trans_id, +			       u64 rqst_addr)  {  	struct vmbus_requestor *rqstor = &channel->requestor; -	unsigned long flags;  	u64 req_addr;  	/* Check rqstor has been initialized */ @@ -1300,25 +1294,60 @@ u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id)  	if (!trans_id)  		return VMBUS_RQST_ERROR; -	spin_lock_irqsave(&rqstor->req_lock, flags); -  	/* Data corresponding to trans_id is stored at trans_id - 1 */  	trans_id--;  	/* Invalid trans_id */ -	if (trans_id >= rqstor->size || !test_bit(trans_id, rqstor->req_bitmap)) { -		spin_unlock_irqrestore(&rqstor->req_lock, flags); +	if (trans_id >= rqstor->size || !test_bit(trans_id, rqstor->req_bitmap))  		return VMBUS_RQST_ERROR; -	}  	req_addr = rqstor->req_arr[trans_id]; -	rqstor->req_arr[trans_id] = rqstor->next_request_id; -	rqstor->next_request_id = trans_id; +	if (rqst_addr == VMBUS_RQST_ADDR_ANY || req_addr == rqst_addr) { +		rqstor->req_arr[trans_id] = rqstor->next_request_id; +		rqstor->next_request_id = trans_id; -	/* The already held spin lock provides atomicity */ -	bitmap_clear(rqstor->req_bitmap, trans_id, 1); +		/* The already held spin lock provides atomicity */ +		bitmap_clear(rqstor->req_bitmap, trans_id, 1); +	} + +	return req_addr; +} +EXPORT_SYMBOL_GPL(__vmbus_request_addr_match); + +/* + * vmbus_request_addr_match - Clears/removes @trans_id from the @channel's + * requestor, provided the memory address stored at @trans_id equals @rqst_addr + * (or provided @rqst_addr matches the sentinel value VMBUS_RQST_ADDR_ANY). + * + * Returns the memory address stored at @trans_id, or VMBUS_RQST_ERROR if + * @trans_id is not contained in the requestor. + * + * Acquires and releases the requestor spin lock. + */ +u64 vmbus_request_addr_match(struct vmbus_channel *channel, u64 trans_id, +			     u64 rqst_addr) +{ +	struct vmbus_requestor *rqstor = &channel->requestor; +	unsigned long flags; +	u64 req_addr; +	spin_lock_irqsave(&rqstor->req_lock, flags); +	req_addr = __vmbus_request_addr_match(channel, trans_id, rqst_addr);  	spin_unlock_irqrestore(&rqstor->req_lock, flags); +  	return req_addr;  } +EXPORT_SYMBOL_GPL(vmbus_request_addr_match); + +/* + * vmbus_request_addr - Returns the memory address stored at @trans_id + * in @rqstor. Uses a spin lock to avoid race conditions. + * @channel: Pointer to the VMbus channel struct + * @trans_id: Request id sent back from Hyper-V. Becomes the requestor's + * next request id. + */ +u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id) +{ +	return vmbus_request_addr_match(channel, trans_id, VMBUS_RQST_ADDR_ANY); +}  EXPORT_SYMBOL_GPL(vmbus_request_addr); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 7cb8718825ee..2e4962a2fbec 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -788,6 +788,7 @@ struct vmbus_requestor {  #define VMBUS_NO_RQSTOR U64_MAX  #define VMBUS_RQST_ERROR (U64_MAX - 1) +#define VMBUS_RQST_ADDR_ANY U64_MAX  /* NetVSC-specific */  #define VMBUS_RQST_ID_NO_RESPONSE (U64_MAX - 2)  /* StorVSC-specific */ @@ -1042,6 +1043,10 @@ struct vmbus_channel {  };  u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr); +u64 __vmbus_request_addr_match(struct vmbus_channel *channel, u64 trans_id, +			       u64 rqst_addr); +u64 vmbus_request_addr_match(struct vmbus_channel *channel, u64 trans_id, +			     u64 rqst_addr);  u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id);  static inline bool is_hvsock_channel(const struct vmbus_channel *c)  | 
