2 * uio_hv_generic - generic UIO driver for VMBus
4 * Copyright (c) 2013-2016 Brocade Communications Systems, Inc.
5 * Copyright (c) 2016, Microsoft Corporation.
8 * This work is licensed under the terms of the GNU GPL, version 2.
10 * Since the driver does not declare any device ids, you must allocate
11 * id and bind the device to the driver yourself. For example:
13 * Associate Network GUID with UIO device
14 * # echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" \
15 * > /sys/bus/vmbus/drivers/uio_hv_generic/new_id
17 * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \
18 * > /sys/bus/vmbus/drivers/hv_netvsc/unbind
19 * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \
20 * > /sys/bus/vmbus/drivers/uio_hv_generic/bind
23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25 #include <linux/device.h>
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/uio_driver.h>
29 #include <linux/netdevice.h>
30 #include <linux/if_ether.h>
31 #include <linux/skbuff.h>
32 #include <linux/hyperv.h>
33 #include <linux/vmalloc.h>
34 #include <linux/slab.h>
36 #include "../hv/hyperv_vmbus.h"
38 #define DRIVER_VERSION "0.02.0"
39 #define DRIVER_AUTHOR "Stephen Hemminger <sthemmin at microsoft.com>"
40 #define DRIVER_DESC "Generic UIO driver for VMBus devices"
42 #define HV_RING_SIZE 512 /* pages */
43 #define SEND_BUFFER_SIZE (15 * 1024 * 1024)
44 #define RECV_BUFFER_SIZE (15 * 1024 * 1024)
47 * List of resources to be mapped to user space
48 * can be extended up to MAX_UIO_MAPS(5) items
58 struct hv_uio_private_data
{
60 struct hv_device
*device
;
64 char recv_name
[32]; /* "recv_4294967295" */
72 * This is the irqcontrol callback to be registered to uio_info.
73 * It can be used to disable/enable interrupt from user space processes.
76 * pointer to uio_info.
78 * state value. 1 to enable interrupt, 0 to disable interrupt.
81 hv_uio_irqcontrol(struct uio_info
*info
, s32 irq_state
)
83 struct hv_uio_private_data
*pdata
= info
->priv
;
84 struct hv_device
*dev
= pdata
->device
;
86 dev
->channel
->inbound
.ring_buffer
->interrupt_mask
= !irq_state
;
93 * Callback from vmbus_event when something is in inbound ring.
95 static void hv_uio_channel_cb(void *context
)
97 struct hv_uio_private_data
*pdata
= context
;
98 struct hv_device
*dev
= pdata
->device
;
100 dev
->channel
->inbound
.ring_buffer
->interrupt_mask
= 1;
103 uio_event_notify(&pdata
->info
);
107 * Callback from vmbus_event when channel is rescinded.
109 static void hv_uio_rescind(struct vmbus_channel
*channel
)
111 struct hv_device
*hv_dev
= channel
->primary_channel
->device_obj
;
112 struct hv_uio_private_data
*pdata
= hv_get_drvdata(hv_dev
);
115 * Turn off the interrupt file handle
116 * Next read for event will return -EIO
121 uio_event_notify(&pdata
->info
);
125 hv_uio_cleanup(struct hv_device
*dev
, struct hv_uio_private_data
*pdata
)
127 if (pdata
->send_gpadl
)
128 vmbus_teardown_gpadl(dev
->channel
, pdata
->send_gpadl
);
129 vfree(pdata
->send_buf
);
131 if (pdata
->recv_gpadl
)
132 vmbus_teardown_gpadl(dev
->channel
, pdata
->recv_gpadl
);
133 vfree(pdata
->recv_buf
);
137 hv_uio_probe(struct hv_device
*dev
,
138 const struct hv_vmbus_device_id
*dev_id
)
140 struct hv_uio_private_data
*pdata
;
143 pdata
= kzalloc(sizeof(*pdata
), GFP_KERNEL
);
147 ret
= vmbus_open(dev
->channel
, HV_RING_SIZE
* PAGE_SIZE
,
148 HV_RING_SIZE
* PAGE_SIZE
, NULL
, 0,
149 hv_uio_channel_cb
, pdata
);
153 /* Communicating with host has to be via shared memory not hypercall */
154 if (!dev
->channel
->offermsg
.monitor_allocated
) {
155 dev_err(&dev
->device
, "vmbus channel requires hypercall\n");
160 dev
->channel
->inbound
.ring_buffer
->interrupt_mask
= 1;
161 set_channel_read_mode(dev
->channel
, HV_CALL_ISR
);
163 /* Fill general uio info */
164 pdata
->info
.name
= "uio_hv_generic";
165 pdata
->info
.version
= DRIVER_VERSION
;
166 pdata
->info
.irqcontrol
= hv_uio_irqcontrol
;
167 pdata
->info
.irq
= UIO_IRQ_CUSTOM
;
170 pdata
->info
.mem
[TXRX_RING_MAP
].name
= "txrx_rings";
171 pdata
->info
.mem
[TXRX_RING_MAP
].addr
172 = (uintptr_t)dev
->channel
->ringbuffer_pages
;
173 pdata
->info
.mem
[TXRX_RING_MAP
].size
174 = dev
->channel
->ringbuffer_pagecount
<< PAGE_SHIFT
;
175 pdata
->info
.mem
[TXRX_RING_MAP
].memtype
= UIO_MEM_LOGICAL
;
177 pdata
->info
.mem
[INT_PAGE_MAP
].name
= "int_page";
178 pdata
->info
.mem
[INT_PAGE_MAP
].addr
179 = (uintptr_t)vmbus_connection
.int_page
;
180 pdata
->info
.mem
[INT_PAGE_MAP
].size
= PAGE_SIZE
;
181 pdata
->info
.mem
[INT_PAGE_MAP
].memtype
= UIO_MEM_LOGICAL
;
183 pdata
->info
.mem
[MON_PAGE_MAP
].name
= "monitor_page";
184 pdata
->info
.mem
[MON_PAGE_MAP
].addr
185 = (uintptr_t)vmbus_connection
.monitor_pages
[1];
186 pdata
->info
.mem
[MON_PAGE_MAP
].size
= PAGE_SIZE
;
187 pdata
->info
.mem
[MON_PAGE_MAP
].memtype
= UIO_MEM_LOGICAL
;
189 pdata
->recv_buf
= vzalloc(RECV_BUFFER_SIZE
);
190 if (pdata
->recv_buf
== NULL
) {
195 ret
= vmbus_establish_gpadl(dev
->channel
, pdata
->recv_buf
,
196 RECV_BUFFER_SIZE
, &pdata
->recv_gpadl
);
200 /* put Global Physical Address Label in name */
201 snprintf(pdata
->recv_name
, sizeof(pdata
->recv_name
),
202 "recv:%u", pdata
->recv_gpadl
);
203 pdata
->info
.mem
[RECV_BUF_MAP
].name
= pdata
->recv_name
;
204 pdata
->info
.mem
[RECV_BUF_MAP
].addr
205 = (uintptr_t)pdata
->recv_buf
;
206 pdata
->info
.mem
[RECV_BUF_MAP
].size
= RECV_BUFFER_SIZE
;
207 pdata
->info
.mem
[RECV_BUF_MAP
].memtype
= UIO_MEM_VIRTUAL
;
210 pdata
->send_buf
= vzalloc(SEND_BUFFER_SIZE
);
211 if (pdata
->send_buf
== NULL
) {
216 ret
= vmbus_establish_gpadl(dev
->channel
, pdata
->send_buf
,
217 SEND_BUFFER_SIZE
, &pdata
->send_gpadl
);
221 snprintf(pdata
->send_name
, sizeof(pdata
->send_name
),
222 "send:%u", pdata
->send_gpadl
);
223 pdata
->info
.mem
[SEND_BUF_MAP
].name
= pdata
->send_name
;
224 pdata
->info
.mem
[SEND_BUF_MAP
].addr
225 = (uintptr_t)pdata
->send_buf
;
226 pdata
->info
.mem
[SEND_BUF_MAP
].size
= SEND_BUFFER_SIZE
;
227 pdata
->info
.mem
[SEND_BUF_MAP
].memtype
= UIO_MEM_VIRTUAL
;
229 pdata
->info
.priv
= pdata
;
232 ret
= uio_register_device(&dev
->device
, &pdata
->info
);
234 dev_err(&dev
->device
, "hv_uio register failed\n");
238 vmbus_set_chn_rescind_callback(dev
->channel
, hv_uio_rescind
);
240 hv_set_drvdata(dev
, pdata
);
245 hv_uio_cleanup(dev
, pdata
);
246 vmbus_close(dev
->channel
);
254 hv_uio_remove(struct hv_device
*dev
)
256 struct hv_uio_private_data
*pdata
= hv_get_drvdata(dev
);
261 uio_unregister_device(&pdata
->info
);
262 hv_uio_cleanup(dev
, pdata
);
263 hv_set_drvdata(dev
, NULL
);
264 vmbus_close(dev
->channel
);
269 static struct hv_driver hv_uio_drv
= {
270 .name
= "uio_hv_generic",
271 .id_table
= NULL
, /* only dynamic id's */
272 .probe
= hv_uio_probe
,
273 .remove
= hv_uio_remove
,
277 hyperv_module_init(void)
279 return vmbus_driver_register(&hv_uio_drv
);
283 hyperv_module_exit(void)
285 vmbus_driver_unregister(&hv_uio_drv
);
288 module_init(hyperv_module_init
);
289 module_exit(hyperv_module_exit
);
291 MODULE_VERSION(DRIVER_VERSION
);
292 MODULE_LICENSE("GPL v2");
293 MODULE_AUTHOR(DRIVER_AUTHOR
);
294 MODULE_DESCRIPTION(DRIVER_DESC
);