xref: /linux/drivers/hv/mshv_portid_table.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/types.h>
3 #include <linux/mm.h>
4 #include <linux/slab.h>
5 #include <linux/idr.h>
6 #include <asm/mshyperv.h>
7 
8 #include "mshv.h"
9 #include "mshv_root.h"
10 
11 /*
12  * Ports and connections are hypervisor struct used for inter-partition
13  * communication. Port represents the source and connection represents
14  * the destination. Partitions are responsible for managing the port and
15  * connection ids.
16  *
17  */
18 
19 #define PORTID_MIN	1
20 #define PORTID_MAX	INT_MAX
21 
22 static DEFINE_IDR(port_table_idr);
23 
24 void
25 mshv_port_table_fini(void)
26 {
27 	struct port_table_info *port_info;
28 	unsigned long i, tmp;
29 
30 	idr_lock(&port_table_idr);
31 	if (!idr_is_empty(&port_table_idr)) {
32 		idr_for_each_entry_ul(&port_table_idr, port_info, tmp, i) {
33 			port_info = idr_remove(&port_table_idr, i);
34 			kfree_rcu(port_info, portbl_rcu);
35 		}
36 	}
37 	idr_unlock(&port_table_idr);
38 }
39 
40 int
41 mshv_portid_alloc(struct port_table_info *info)
42 {
43 	int ret;
44 
45 	idr_preload(GFP_KERNEL);
46 	idr_lock(&port_table_idr);
47 	ret = idr_alloc(&port_table_idr, info, PORTID_MIN,
48 			PORTID_MAX, GFP_NOWAIT);
49 	idr_unlock(&port_table_idr);
50 	idr_preload_end();
51 
52 	return ret;
53 }
54 
55 void
56 mshv_portid_free(int port_id)
57 {
58 	struct port_table_info *info;
59 
60 	idr_lock(&port_table_idr);
61 	info = idr_remove(&port_table_idr, port_id);
62 	WARN_ON(!info);
63 	idr_unlock(&port_table_idr);
64 
65 	kfree_rcu(info, portbl_rcu);
66 }
67 
68 int
69 mshv_portid_lookup(int port_id, struct port_table_info *info)
70 {
71 	struct port_table_info *_info;
72 	int ret = -ENOENT;
73 
74 	rcu_read_lock();
75 	_info = idr_find(&port_table_idr, port_id);
76 	rcu_read_unlock();
77 
78 	if (_info) {
79 		*info = *_info;
80 		ret = 0;
81 	}
82 
83 	return ret;
84 }
85