mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-01 00:58:39 +02:00 
			
		
		
		
	net/smc: implement DMB-related operations of loopback-ism
This implements DMB (un)registration and data move operations of loopback-ism device. Signed-off-by: Wen Gu <guwen@linux.alibaba.com> Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com> Reviewed-and-tested-by: Jan Karcher <jaka@linux.ibm.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
		
							parent
							
								
									45783ee85b
								
							
						
					
					
						commit
						f7a22071db
					
				
					 2 changed files with 139 additions and 3 deletions
				
			
		|  | @ -15,10 +15,12 @@ | ||||||
| #include <linux/types.h> | #include <linux/types.h> | ||||||
| #include <net/smc.h> | #include <net/smc.h> | ||||||
| 
 | 
 | ||||||
|  | #include "smc_cdc.h" | ||||||
| #include "smc_ism.h" | #include "smc_ism.h" | ||||||
| #include "smc_loopback.h" | #include "smc_loopback.h" | ||||||
| 
 | 
 | ||||||
| #define SMC_LO_V2_CAPABLE	0x1 /* loopback-ism acts as ISMv2 */ | #define SMC_LO_V2_CAPABLE	0x1 /* loopback-ism acts as ISMv2 */ | ||||||
|  | #define SMC_DMA_ADDR_INVALID	(~(dma_addr_t)0) | ||||||
| 
 | 
 | ||||||
| static const char smc_lo_dev_name[] = "loopback-ism"; | static const char smc_lo_dev_name[] = "loopback-ism"; | ||||||
| static struct smc_lo_dev *lo_dev; | static struct smc_lo_dev *lo_dev; | ||||||
|  | @ -48,6 +50,125 @@ static int smc_lo_query_rgid(struct smcd_dev *smcd, struct smcd_gid *rgid, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb, | ||||||
|  | 			       void *client_priv) | ||||||
|  | { | ||||||
|  | 	struct smc_lo_dmb_node *dmb_node, *tmp_node; | ||||||
|  | 	struct smc_lo_dev *ldev = smcd->priv; | ||||||
|  | 	int sba_idx, rc; | ||||||
|  | 
 | ||||||
|  | 	/* check space for new dmb */ | ||||||
|  | 	for_each_clear_bit(sba_idx, ldev->sba_idx_mask, SMC_LO_MAX_DMBS) { | ||||||
|  | 		if (!test_and_set_bit(sba_idx, ldev->sba_idx_mask)) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 	if (sba_idx == SMC_LO_MAX_DMBS) | ||||||
|  | 		return -ENOSPC; | ||||||
|  | 
 | ||||||
|  | 	dmb_node = kzalloc(sizeof(*dmb_node), GFP_KERNEL); | ||||||
|  | 	if (!dmb_node) { | ||||||
|  | 		rc = -ENOMEM; | ||||||
|  | 		goto err_bit; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	dmb_node->sba_idx = sba_idx; | ||||||
|  | 	dmb_node->len = dmb->dmb_len; | ||||||
|  | 	dmb_node->cpu_addr = kzalloc(dmb_node->len, GFP_KERNEL | | ||||||
|  | 				     __GFP_NOWARN | __GFP_NORETRY | | ||||||
|  | 				     __GFP_NOMEMALLOC); | ||||||
|  | 	if (!dmb_node->cpu_addr) { | ||||||
|  | 		rc = -ENOMEM; | ||||||
|  | 		goto err_node; | ||||||
|  | 	} | ||||||
|  | 	dmb_node->dma_addr = SMC_DMA_ADDR_INVALID; | ||||||
|  | 
 | ||||||
|  | again: | ||||||
|  | 	/* add new dmb into hash table */ | ||||||
|  | 	get_random_bytes(&dmb_node->token, sizeof(dmb_node->token)); | ||||||
|  | 	write_lock_bh(&ldev->dmb_ht_lock); | ||||||
|  | 	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_node->token) { | ||||||
|  | 		if (tmp_node->token == dmb_node->token) { | ||||||
|  | 			write_unlock_bh(&ldev->dmb_ht_lock); | ||||||
|  | 			goto again; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	hash_add(ldev->dmb_ht, &dmb_node->list, dmb_node->token); | ||||||
|  | 	write_unlock_bh(&ldev->dmb_ht_lock); | ||||||
|  | 
 | ||||||
|  | 	dmb->sba_idx = dmb_node->sba_idx; | ||||||
|  | 	dmb->dmb_tok = dmb_node->token; | ||||||
|  | 	dmb->cpu_addr = dmb_node->cpu_addr; | ||||||
|  | 	dmb->dma_addr = dmb_node->dma_addr; | ||||||
|  | 	dmb->dmb_len = dmb_node->len; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | 
 | ||||||
|  | err_node: | ||||||
|  | 	kfree(dmb_node); | ||||||
|  | err_bit: | ||||||
|  | 	clear_bit(sba_idx, ldev->sba_idx_mask); | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int smc_lo_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb) | ||||||
|  | { | ||||||
|  | 	struct smc_lo_dmb_node *dmb_node = NULL, *tmp_node; | ||||||
|  | 	struct smc_lo_dev *ldev = smcd->priv; | ||||||
|  | 
 | ||||||
|  | 	/* remove dmb from hash table */ | ||||||
|  | 	write_lock_bh(&ldev->dmb_ht_lock); | ||||||
|  | 	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) { | ||||||
|  | 		if (tmp_node->token == dmb->dmb_tok) { | ||||||
|  | 			dmb_node = tmp_node; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (!dmb_node) { | ||||||
|  | 		write_unlock_bh(&ldev->dmb_ht_lock); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 	hash_del(&dmb_node->list); | ||||||
|  | 	write_unlock_bh(&ldev->dmb_ht_lock); | ||||||
|  | 
 | ||||||
|  | 	clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask); | ||||||
|  | 	kfree(dmb_node->cpu_addr); | ||||||
|  | 	kfree(dmb_node); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int smc_lo_move_data(struct smcd_dev *smcd, u64 dmb_tok, | ||||||
|  | 			    unsigned int idx, bool sf, unsigned int offset, | ||||||
|  | 			    void *data, unsigned int size) | ||||||
|  | { | ||||||
|  | 	struct smc_lo_dmb_node *rmb_node = NULL, *tmp_node; | ||||||
|  | 	struct smc_lo_dev *ldev = smcd->priv; | ||||||
|  | 	struct smc_connection *conn; | ||||||
|  | 
 | ||||||
|  | 	read_lock_bh(&ldev->dmb_ht_lock); | ||||||
|  | 	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_tok) { | ||||||
|  | 		if (tmp_node->token == dmb_tok) { | ||||||
|  | 			rmb_node = tmp_node; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (!rmb_node) { | ||||||
|  | 		read_unlock_bh(&ldev->dmb_ht_lock); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 	memcpy((char *)rmb_node->cpu_addr + offset, data, size); | ||||||
|  | 	read_unlock_bh(&ldev->dmb_ht_lock); | ||||||
|  | 
 | ||||||
|  | 	if (sf) { | ||||||
|  | 		conn = smcd->conn[rmb_node->sba_idx]; | ||||||
|  | 		if (conn && !conn->killed) | ||||||
|  | 			tasklet_schedule(&conn->rx_tsklet); | ||||||
|  | 		else | ||||||
|  | 			return -EPIPE; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int smc_lo_supports_v2(void) | static int smc_lo_supports_v2(void) | ||||||
| { | { | ||||||
| 	return SMC_LO_V2_CAPABLE; | 	return SMC_LO_V2_CAPABLE; | ||||||
|  | @ -74,14 +195,14 @@ static struct device *smc_lo_get_dev(struct smcd_dev *smcd) | ||||||
| 
 | 
 | ||||||
| static const struct smcd_ops lo_ops = { | static const struct smcd_ops lo_ops = { | ||||||
| 	.query_remote_gid = smc_lo_query_rgid, | 	.query_remote_gid = smc_lo_query_rgid, | ||||||
| 	.register_dmb		= NULL, | 	.register_dmb = smc_lo_register_dmb, | ||||||
| 	.unregister_dmb		= NULL, | 	.unregister_dmb = smc_lo_unregister_dmb, | ||||||
| 	.add_vlan_id		= NULL, | 	.add_vlan_id		= NULL, | ||||||
| 	.del_vlan_id		= NULL, | 	.del_vlan_id		= NULL, | ||||||
| 	.set_vlan_required	= NULL, | 	.set_vlan_required	= NULL, | ||||||
| 	.reset_vlan_required	= NULL, | 	.reset_vlan_required	= NULL, | ||||||
| 	.signal_event		= NULL, | 	.signal_event		= NULL, | ||||||
| 	.move_data		= NULL, | 	.move_data = smc_lo_move_data, | ||||||
| 	.supports_v2 = smc_lo_supports_v2, | 	.supports_v2 = smc_lo_supports_v2, | ||||||
| 	.get_local_gid = smc_lo_get_local_gid, | 	.get_local_gid = smc_lo_get_local_gid, | ||||||
| 	.get_chid = smc_lo_get_chid, | 	.get_chid = smc_lo_get_chid, | ||||||
|  | @ -146,6 +267,8 @@ static void smcd_lo_unregister_dev(struct smc_lo_dev *ldev) | ||||||
| static int smc_lo_dev_init(struct smc_lo_dev *ldev) | static int smc_lo_dev_init(struct smc_lo_dev *ldev) | ||||||
| { | { | ||||||
| 	smc_lo_generate_ids(ldev); | 	smc_lo_generate_ids(ldev); | ||||||
|  | 	rwlock_init(&ldev->dmb_ht_lock); | ||||||
|  | 	hash_init(ldev->dmb_ht); | ||||||
| 	return smcd_lo_register_dev(ldev); | 	return smcd_lo_register_dev(ldev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,13 +20,26 @@ | ||||||
| 
 | 
 | ||||||
| #if IS_ENABLED(CONFIG_SMC_LO) | #if IS_ENABLED(CONFIG_SMC_LO) | ||||||
| #define SMC_LO_MAX_DMBS		5000 | #define SMC_LO_MAX_DMBS		5000 | ||||||
|  | #define SMC_LO_DMBS_HASH_BITS	12 | ||||||
| #define SMC_LO_RESERVED_CHID	0xFFFF | #define SMC_LO_RESERVED_CHID	0xFFFF | ||||||
| 
 | 
 | ||||||
|  | struct smc_lo_dmb_node { | ||||||
|  | 	struct hlist_node list; | ||||||
|  | 	u64 token; | ||||||
|  | 	u32 len; | ||||||
|  | 	u32 sba_idx; | ||||||
|  | 	void *cpu_addr; | ||||||
|  | 	dma_addr_t dma_addr; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct smc_lo_dev { | struct smc_lo_dev { | ||||||
| 	struct smcd_dev *smcd; | 	struct smcd_dev *smcd; | ||||||
| 	struct device dev; | 	struct device dev; | ||||||
| 	u16 chid; | 	u16 chid; | ||||||
| 	struct smcd_gid local_gid; | 	struct smcd_gid local_gid; | ||||||
|  | 	rwlock_t dmb_ht_lock; | ||||||
|  | 	DECLARE_BITMAP(sba_idx_mask, SMC_LO_MAX_DMBS); | ||||||
|  | 	DECLARE_HASHTABLE(dmb_ht, SMC_LO_DMBS_HASH_BITS); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int smc_loopback_init(void); | int smc_loopback_init(void); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Wen Gu
						Wen Gu