xref: /openbmc/linux/drivers/uio/uio_hv_generic.c (revision 2e6ae11dd0d1c37f44cec51a58fb2092e55ed0f5)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * uio_hv_generic - generic UIO driver for VMBus
4  *
5  * Copyright (c) 2013-2016 Brocade Communications Systems, Inc.
6  * Copyright (c) 2016, Microsoft Corporation.
7  *
8  * Since the driver does not declare any device ids, you must allocate
9  * id and bind the device to the driver yourself.  For example:
10  *
11  * Associate Network GUID with UIO device
12  * # echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" \
13  *    > /sys/bus/vmbus/drivers/uio_hv_generic/new_id
14  * Then rebind
15  * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \
16  *    > /sys/bus/vmbus/drivers/hv_netvsc/unbind
17  * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \
18  *    > /sys/bus/vmbus/drivers/uio_hv_generic/bind
19  */
20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21 
22 #include <linux/device.h>
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/uio_driver.h>
26 #include <linux/netdevice.h>
27 #include <linux/if_ether.h>
28 #include <linux/skbuff.h>
29 #include <linux/hyperv.h>
30 #include <linux/vmalloc.h>
31 #include <linux/slab.h>
32 
33 #include "../hv/hyperv_vmbus.h"
34 
35 #define DRIVER_VERSION	"0.02.1"
36 #define DRIVER_AUTHOR	"Stephen Hemminger <sthemmin at microsoft.com>"
37 #define DRIVER_DESC	"Generic UIO driver for VMBus devices"
38 
39 #define HV_RING_SIZE	 512	/* pages */
40 #define SEND_BUFFER_SIZE (16 * 1024 * 1024)
41 #define RECV_BUFFER_SIZE (31 * 1024 * 1024)
42 
43 /*
44  * List of resources to be mapped to user space
45  * can be extended up to MAX_UIO_MAPS(5) items
46  */
47 enum hv_uio_map {
48 	TXRX_RING_MAP = 0,
49 	INT_PAGE_MAP,
50 	MON_PAGE_MAP,
51 	RECV_BUF_MAP,
52 	SEND_BUF_MAP
53 };
54 
55 struct hv_uio_private_data {
56 	struct uio_info info;
57 	struct hv_device *device;
58 
59 	void	*recv_buf;
60 	u32	recv_gpadl;
61 	char	recv_name[32];	/* "recv_4294967295" */
62 
63 	void	*send_buf;
64 	u32	send_gpadl;
65 	char	send_name[32];
66 };
67 
68 /*
69  * This is the irqcontrol callback to be registered to uio_info.
70  * It can be used to disable/enable interrupt from user space processes.
71  *
72  * @param info
73  *  pointer to uio_info.
74  * @param irq_state
75  *  state value. 1 to enable interrupt, 0 to disable interrupt.
76  */
77 static int
78 hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
79 {
80 	struct hv_uio_private_data *pdata = info->priv;
81 	struct hv_device *dev = pdata->device;
82 
83 	dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state;
84 	virt_mb();
85 
86 	return 0;
87 }
88 
89 /*
90  * Callback from vmbus_event when something is in inbound ring.
91  */
92 static void hv_uio_channel_cb(void *context)
93 {
94 	struct vmbus_channel *chan = context;
95 	struct hv_device *hv_dev = chan->device_obj;
96 	struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
97 
98 	chan->inbound.ring_buffer->interrupt_mask = 1;
99 	virt_mb();
100 
101 	uio_event_notify(&pdata->info);
102 }
103 
104 /*
105  * Callback from vmbus_event when channel is rescinded.
106  */
107 static void hv_uio_rescind(struct vmbus_channel *channel)
108 {
109 	struct hv_device *hv_dev = channel->primary_channel->device_obj;
110 	struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
111 
112 	/*
113 	 * Turn off the interrupt file handle
114 	 * Next read for event will return -EIO
115 	 */
116 	pdata->info.irq = 0;
117 
118 	/* Wake up reader */
119 	uio_event_notify(&pdata->info);
120 }
121 
122 /* Sysfs API to allow mmap of the ring buffers
123  * The ring buffer is allocated as contiguous memory by vmbus_open
124  */
125 static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj,
126 			    struct bin_attribute *attr,
127 			    struct vm_area_struct *vma)
128 {
129 	struct vmbus_channel *channel
130 		= container_of(kobj, struct vmbus_channel, kobj);
131 	struct hv_device *dev = channel->primary_channel->device_obj;
132 	u16 q_idx = channel->offermsg.offer.sub_channel_index;
133 
134 	dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n",
135 		q_idx, vma_pages(vma), vma->vm_pgoff);
136 
137 	return vm_iomap_memory(vma, virt_to_phys(channel->ringbuffer_pages),
138 			       channel->ringbuffer_pagecount << PAGE_SHIFT);
139 }
140 
141 static const struct bin_attribute ring_buffer_bin_attr = {
142 	.attr = {
143 		.name = "ring",
144 		.mode = 0600,
145 	},
146 	.size = 2 * HV_RING_SIZE * PAGE_SIZE,
147 	.mmap = hv_uio_ring_mmap,
148 };
149 
150 /* Callback from VMBUS subsystem when new channel created. */
151 static void
152 hv_uio_new_channel(struct vmbus_channel *new_sc)
153 {
154 	struct hv_device *hv_dev = new_sc->primary_channel->device_obj;
155 	struct device *device = &hv_dev->device;
156 	const size_t ring_bytes = HV_RING_SIZE * PAGE_SIZE;
157 	int ret;
158 
159 	/* Create host communication ring */
160 	ret = vmbus_open(new_sc, ring_bytes, ring_bytes, NULL, 0,
161 			 hv_uio_channel_cb, new_sc);
162 	if (ret) {
163 		dev_err(device, "vmbus_open subchannel failed: %d\n", ret);
164 		return;
165 	}
166 
167 	/* Disable interrupts on sub channel */
168 	new_sc->inbound.ring_buffer->interrupt_mask = 1;
169 	set_channel_read_mode(new_sc, HV_CALL_ISR);
170 
171 	ret = sysfs_create_bin_file(&new_sc->kobj, &ring_buffer_bin_attr);
172 	if (ret) {
173 		dev_err(device, "sysfs create ring bin file failed; %d\n", ret);
174 		vmbus_close(new_sc);
175 	}
176 }
177 
178 static void
179 hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata)
180 {
181 	if (pdata->send_gpadl)
182 		vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl);
183 	vfree(pdata->send_buf);
184 
185 	if (pdata->recv_gpadl)
186 		vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl);
187 	vfree(pdata->recv_buf);
188 }
189 
190 static int
191 hv_uio_probe(struct hv_device *dev,
192 	     const struct hv_vmbus_device_id *dev_id)
193 {
194 	struct hv_uio_private_data *pdata;
195 	int ret;
196 
197 	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
198 	if (!pdata)
199 		return -ENOMEM;
200 
201 	ret = vmbus_open(dev->channel, HV_RING_SIZE * PAGE_SIZE,
202 			 HV_RING_SIZE * PAGE_SIZE, NULL, 0,
203 			 hv_uio_channel_cb, dev->channel);
204 	if (ret)
205 		goto fail;
206 
207 	/* Communicating with host has to be via shared memory not hypercall */
208 	if (!dev->channel->offermsg.monitor_allocated) {
209 		dev_err(&dev->device, "vmbus channel requires hypercall\n");
210 		ret = -ENOTSUPP;
211 		goto fail_close;
212 	}
213 
214 	dev->channel->inbound.ring_buffer->interrupt_mask = 1;
215 	set_channel_read_mode(dev->channel, HV_CALL_ISR);
216 
217 	/* Fill general uio info */
218 	pdata->info.name = "uio_hv_generic";
219 	pdata->info.version = DRIVER_VERSION;
220 	pdata->info.irqcontrol = hv_uio_irqcontrol;
221 	pdata->info.irq = UIO_IRQ_CUSTOM;
222 
223 	/* mem resources */
224 	pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings";
225 	pdata->info.mem[TXRX_RING_MAP].addr
226 		= (uintptr_t)dev->channel->ringbuffer_pages;
227 	pdata->info.mem[TXRX_RING_MAP].size
228 		= dev->channel->ringbuffer_pagecount << PAGE_SHIFT;
229 	pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL;
230 
231 	pdata->info.mem[INT_PAGE_MAP].name = "int_page";
232 	pdata->info.mem[INT_PAGE_MAP].addr
233 		= (uintptr_t)vmbus_connection.int_page;
234 	pdata->info.mem[INT_PAGE_MAP].size = PAGE_SIZE;
235 	pdata->info.mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL;
236 
237 	pdata->info.mem[MON_PAGE_MAP].name = "monitor_page";
238 	pdata->info.mem[MON_PAGE_MAP].addr
239 		= (uintptr_t)vmbus_connection.monitor_pages[1];
240 	pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE;
241 	pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL;
242 
243 	pdata->recv_buf = vzalloc(RECV_BUFFER_SIZE);
244 	if (pdata->recv_buf == NULL) {
245 		ret = -ENOMEM;
246 		goto fail_close;
247 	}
248 
249 	ret = vmbus_establish_gpadl(dev->channel, pdata->recv_buf,
250 				    RECV_BUFFER_SIZE, &pdata->recv_gpadl);
251 	if (ret)
252 		goto fail_close;
253 
254 	/* put Global Physical Address Label in name */
255 	snprintf(pdata->recv_name, sizeof(pdata->recv_name),
256 		 "recv:%u", pdata->recv_gpadl);
257 	pdata->info.mem[RECV_BUF_MAP].name = pdata->recv_name;
258 	pdata->info.mem[RECV_BUF_MAP].addr
259 		= (uintptr_t)pdata->recv_buf;
260 	pdata->info.mem[RECV_BUF_MAP].size = RECV_BUFFER_SIZE;
261 	pdata->info.mem[RECV_BUF_MAP].memtype = UIO_MEM_VIRTUAL;
262 
263 
264 	pdata->send_buf = vzalloc(SEND_BUFFER_SIZE);
265 	if (pdata->send_buf == NULL) {
266 		ret = -ENOMEM;
267 		goto fail_close;
268 	}
269 
270 	ret = vmbus_establish_gpadl(dev->channel, pdata->send_buf,
271 				    SEND_BUFFER_SIZE, &pdata->send_gpadl);
272 	if (ret)
273 		goto fail_close;
274 
275 	snprintf(pdata->send_name, sizeof(pdata->send_name),
276 		 "send:%u", pdata->send_gpadl);
277 	pdata->info.mem[SEND_BUF_MAP].name = pdata->send_name;
278 	pdata->info.mem[SEND_BUF_MAP].addr
279 		= (uintptr_t)pdata->send_buf;
280 	pdata->info.mem[SEND_BUF_MAP].size = SEND_BUFFER_SIZE;
281 	pdata->info.mem[SEND_BUF_MAP].memtype = UIO_MEM_VIRTUAL;
282 
283 	pdata->info.priv = pdata;
284 	pdata->device = dev;
285 
286 	ret = uio_register_device(&dev->device, &pdata->info);
287 	if (ret) {
288 		dev_err(&dev->device, "hv_uio register failed\n");
289 		goto fail_close;
290 	}
291 
292 	vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind);
293 	vmbus_set_sc_create_callback(dev->channel, hv_uio_new_channel);
294 
295 	ret = sysfs_create_bin_file(&dev->channel->kobj, &ring_buffer_bin_attr);
296 	if (ret)
297 		dev_notice(&dev->device,
298 			   "sysfs create ring bin file failed; %d\n", ret);
299 
300 	hv_set_drvdata(dev, pdata);
301 
302 	return 0;
303 
304 fail_close:
305 	hv_uio_cleanup(dev, pdata);
306 	vmbus_close(dev->channel);
307 fail:
308 	kfree(pdata);
309 
310 	return ret;
311 }
312 
313 static int
314 hv_uio_remove(struct hv_device *dev)
315 {
316 	struct hv_uio_private_data *pdata = hv_get_drvdata(dev);
317 
318 	if (!pdata)
319 		return 0;
320 
321 	uio_unregister_device(&pdata->info);
322 	hv_uio_cleanup(dev, pdata);
323 	hv_set_drvdata(dev, NULL);
324 	vmbus_close(dev->channel);
325 	kfree(pdata);
326 	return 0;
327 }
328 
329 static struct hv_driver hv_uio_drv = {
330 	.name = "uio_hv_generic",
331 	.id_table = NULL, /* only dynamic id's */
332 	.probe = hv_uio_probe,
333 	.remove = hv_uio_remove,
334 };
335 
336 static int __init
337 hyperv_module_init(void)
338 {
339 	return vmbus_driver_register(&hv_uio_drv);
340 }
341 
342 static void __exit
343 hyperv_module_exit(void)
344 {
345 	vmbus_driver_unregister(&hv_uio_drv);
346 }
347 
348 module_init(hyperv_module_init);
349 module_exit(hyperv_module_exit);
350 
351 MODULE_VERSION(DRIVER_VERSION);
352 MODULE_LICENSE("GPL v2");
353 MODULE_AUTHOR(DRIVER_AUTHOR);
354 MODULE_DESCRIPTION(DRIVER_DESC);
355