diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 13:31:17 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 13:31:17 -0500 |
commit | f6cff79f1d122f78a4b35bf4b2f0112afcd89ea4 (patch) | |
tree | cf3a38576f9adbb3860982c25f72aebed2bb541a /drivers/uio | |
parent | 47fcc0360cfb3fe82e4daddacad3c1cd80b0b75d (diff) | |
parent | 9ff6576e124b1227c27c1da43fe5f8ee908263e0 (diff) |
Merge tag 'char-misc-4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH:
"Here is the big pull request for char/misc drivers for 4.16-rc1.
There's a lot of stuff in here. Three new driver subsystems were added
for various types of hardware busses:
- siox
- slimbus
- soundwire
as well as a new vboxguest subsystem for the VirtualBox hypervisor
drivers.
There's also big updates from the FPGA subsystem, lots of Android
binder fixes, the usual handful of hyper-v updates, and lots of other
smaller driver updates.
All of these have been in linux-next for a long time, with no reported
issues"
* tag 'char-misc-4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (155 commits)
char: lp: use true or false for boolean values
android: binder: use VM_ALLOC to get vm area
android: binder: Use true and false for boolean values
lkdtm: fix handle_irq_event symbol for INT_HW_IRQ_EN
EISA: Delete error message for a failed memory allocation in eisa_probe()
EISA: Whitespace cleanup
misc: remove AVR32 dependencies
virt: vbox: Add error mapping for VERR_INVALID_NAME and VERR_NO_MORE_FILES
soundwire: Fix a signedness bug
uio_hv_generic: fix new type mismatch warnings
uio_hv_generic: fix type mismatch warnings
auxdisplay: img-ascii-lcd: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
uio_hv_generic: add rescind support
uio_hv_generic: check that host supports monitor page
uio_hv_generic: create send and receive buffers
uio: document uio_hv_generic regions
doc: fix documentation about uio_hv_generic
vmbus: add monitor_id and subchannel_id to sysfs per channel
vmbus: fix ABI documentation
uio_hv_generic: use ISR callback method
...
Diffstat (limited to 'drivers/uio')
-rw-r--r-- | drivers/uio/uio_hv_generic.c | 138 |
1 files changed, 107 insertions, 31 deletions
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 48d5327d38d4..8ca549032c27 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c | |||
@@ -10,11 +10,13 @@ | |||
10 | * Since the driver does not declare any device ids, you must allocate | 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: | 11 | * id and bind the device to the driver yourself. For example: |
12 | * | 12 | * |
13 | * Associate Network GUID with UIO device | ||
13 | * # echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" \ | 14 | * # echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" \ |
14 | * > /sys/bus/vmbus/drivers/uio_hv_generic | 15 | * > /sys/bus/vmbus/drivers/uio_hv_generic/new_id |
15 | * # echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 \ | 16 | * Then rebind |
17 | * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \ | ||
16 | * > /sys/bus/vmbus/drivers/hv_netvsc/unbind | 18 | * > /sys/bus/vmbus/drivers/hv_netvsc/unbind |
17 | * # echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 \ | 19 | * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \ |
18 | * > /sys/bus/vmbus/drivers/uio_hv_generic/bind | 20 | * > /sys/bus/vmbus/drivers/uio_hv_generic/bind |
19 | */ | 21 | */ |
20 | 22 | ||
@@ -37,6 +39,10 @@ | |||
37 | #define DRIVER_AUTHOR "Stephen Hemminger <sthemmin at microsoft.com>" | 39 | #define DRIVER_AUTHOR "Stephen Hemminger <sthemmin at microsoft.com>" |
38 | #define DRIVER_DESC "Generic UIO driver for VMBus devices" | 40 | #define DRIVER_DESC "Generic UIO driver for VMBus devices" |
39 | 41 | ||
42 | #define HV_RING_SIZE 512 /* pages */ | ||
43 | #define SEND_BUFFER_SIZE (15 * 1024 * 1024) | ||
44 | #define RECV_BUFFER_SIZE (15 * 1024 * 1024) | ||
45 | |||
40 | /* | 46 | /* |
41 | * List of resources to be mapped to user space | 47 | * List of resources to be mapped to user space |
42 | * can be extended up to MAX_UIO_MAPS(5) items | 48 | * can be extended up to MAX_UIO_MAPS(5) items |
@@ -45,32 +51,22 @@ enum hv_uio_map { | |||
45 | TXRX_RING_MAP = 0, | 51 | TXRX_RING_MAP = 0, |
46 | INT_PAGE_MAP, | 52 | INT_PAGE_MAP, |
47 | MON_PAGE_MAP, | 53 | MON_PAGE_MAP, |
54 | RECV_BUF_MAP, | ||
55 | SEND_BUF_MAP | ||
48 | }; | 56 | }; |
49 | 57 | ||
50 | #define HV_RING_SIZE 512 | ||
51 | |||
52 | struct hv_uio_private_data { | 58 | struct hv_uio_private_data { |
53 | struct uio_info info; | 59 | struct uio_info info; |
54 | struct hv_device *device; | 60 | struct hv_device *device; |
55 | }; | ||
56 | |||
57 | static int | ||
58 | hv_uio_mmap(struct uio_info *info, struct vm_area_struct *vma) | ||
59 | { | ||
60 | int mi; | ||
61 | 61 | ||
62 | if (vma->vm_pgoff >= MAX_UIO_MAPS) | 62 | void *recv_buf; |
63 | return -EINVAL; | 63 | u32 recv_gpadl; |
64 | char recv_name[32]; /* "recv_4294967295" */ | ||
64 | 65 | ||
65 | if (info->mem[vma->vm_pgoff].size == 0) | 66 | void *send_buf; |
66 | return -EINVAL; | 67 | u32 send_gpadl; |
67 | 68 | char send_name[32]; | |
68 | mi = (int)vma->vm_pgoff; | 69 | }; |
69 | |||
70 | return remap_pfn_range(vma, vma->vm_start, | ||
71 | info->mem[mi].addr >> PAGE_SHIFT, | ||
72 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
73 | } | ||
74 | 70 | ||
75 | /* | 71 | /* |
76 | * This is the irqcontrol callback to be registered to uio_info. | 72 | * This is the irqcontrol callback to be registered to uio_info. |
@@ -107,6 +103,36 @@ static void hv_uio_channel_cb(void *context) | |||
107 | uio_event_notify(&pdata->info); | 103 | uio_event_notify(&pdata->info); |
108 | } | 104 | } |
109 | 105 | ||
106 | /* | ||
107 | * Callback from vmbus_event when channel is rescinded. | ||
108 | */ | ||
109 | static void hv_uio_rescind(struct vmbus_channel *channel) | ||
110 | { | ||
111 | struct hv_device *hv_dev = channel->primary_channel->device_obj; | ||
112 | struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); | ||
113 | |||
114 | /* | ||
115 | * Turn off the interrupt file handle | ||
116 | * Next read for event will return -EIO | ||
117 | */ | ||
118 | pdata->info.irq = 0; | ||
119 | |||
120 | /* Wake up reader */ | ||
121 | uio_event_notify(&pdata->info); | ||
122 | } | ||
123 | |||
124 | static void | ||
125 | hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata) | ||
126 | { | ||
127 | if (pdata->send_gpadl) | ||
128 | vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl); | ||
129 | vfree(pdata->send_buf); | ||
130 | |||
131 | if (pdata->recv_gpadl) | ||
132 | vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl); | ||
133 | vfree(pdata->recv_buf); | ||
134 | } | ||
135 | |||
110 | static int | 136 | static int |
111 | hv_uio_probe(struct hv_device *dev, | 137 | hv_uio_probe(struct hv_device *dev, |
112 | const struct hv_vmbus_device_id *dev_id) | 138 | const struct hv_vmbus_device_id *dev_id) |
@@ -124,36 +150,82 @@ hv_uio_probe(struct hv_device *dev, | |||
124 | if (ret) | 150 | if (ret) |
125 | goto fail; | 151 | goto fail; |
126 | 152 | ||
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"); | ||
156 | ret = -ENOTSUPP; | ||
157 | goto fail_close; | ||
158 | } | ||
159 | |||
127 | dev->channel->inbound.ring_buffer->interrupt_mask = 1; | 160 | dev->channel->inbound.ring_buffer->interrupt_mask = 1; |
128 | set_channel_read_mode(dev->channel, HV_CALL_DIRECT); | 161 | set_channel_read_mode(dev->channel, HV_CALL_ISR); |
129 | 162 | ||
130 | /* Fill general uio info */ | 163 | /* Fill general uio info */ |
131 | pdata->info.name = "uio_hv_generic"; | 164 | pdata->info.name = "uio_hv_generic"; |
132 | pdata->info.version = DRIVER_VERSION; | 165 | pdata->info.version = DRIVER_VERSION; |
133 | pdata->info.irqcontrol = hv_uio_irqcontrol; | 166 | pdata->info.irqcontrol = hv_uio_irqcontrol; |
134 | pdata->info.mmap = hv_uio_mmap; | ||
135 | pdata->info.irq = UIO_IRQ_CUSTOM; | 167 | pdata->info.irq = UIO_IRQ_CUSTOM; |
136 | 168 | ||
137 | /* mem resources */ | 169 | /* mem resources */ |
138 | pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings"; | 170 | pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings"; |
139 | pdata->info.mem[TXRX_RING_MAP].addr | 171 | pdata->info.mem[TXRX_RING_MAP].addr |
140 | = virt_to_phys(dev->channel->ringbuffer_pages); | 172 | = (uintptr_t)dev->channel->ringbuffer_pages; |
141 | pdata->info.mem[TXRX_RING_MAP].size | 173 | pdata->info.mem[TXRX_RING_MAP].size |
142 | = dev->channel->ringbuffer_pagecount * PAGE_SIZE; | 174 | = dev->channel->ringbuffer_pagecount << PAGE_SHIFT; |
143 | pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL; | 175 | pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL; |
144 | 176 | ||
145 | pdata->info.mem[INT_PAGE_MAP].name = "int_page"; | 177 | pdata->info.mem[INT_PAGE_MAP].name = "int_page"; |
146 | pdata->info.mem[INT_PAGE_MAP].addr = | 178 | pdata->info.mem[INT_PAGE_MAP].addr |
147 | virt_to_phys(vmbus_connection.int_page); | 179 | = (uintptr_t)vmbus_connection.int_page; |
148 | pdata->info.mem[INT_PAGE_MAP].size = PAGE_SIZE; | 180 | pdata->info.mem[INT_PAGE_MAP].size = PAGE_SIZE; |
149 | pdata->info.mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL; | 181 | pdata->info.mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL; |
150 | 182 | ||
151 | pdata->info.mem[MON_PAGE_MAP].name = "monitor_pages"; | 183 | pdata->info.mem[MON_PAGE_MAP].name = "monitor_page"; |
152 | pdata->info.mem[MON_PAGE_MAP].addr = | 184 | pdata->info.mem[MON_PAGE_MAP].addr |
153 | virt_to_phys(vmbus_connection.monitor_pages[1]); | 185 | = (uintptr_t)vmbus_connection.monitor_pages[1]; |
154 | pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE; | 186 | pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE; |
155 | pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL; | 187 | pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL; |
156 | 188 | ||
189 | pdata->recv_buf = vzalloc(RECV_BUFFER_SIZE); | ||
190 | if (pdata->recv_buf == NULL) { | ||
191 | ret = -ENOMEM; | ||
192 | goto fail_close; | ||
193 | } | ||
194 | |||
195 | ret = vmbus_establish_gpadl(dev->channel, pdata->recv_buf, | ||
196 | RECV_BUFFER_SIZE, &pdata->recv_gpadl); | ||
197 | if (ret) | ||
198 | goto fail_close; | ||
199 | |||
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; | ||
208 | |||
209 | |||
210 | pdata->send_buf = vzalloc(SEND_BUFFER_SIZE); | ||
211 | if (pdata->send_buf == NULL) { | ||
212 | ret = -ENOMEM; | ||
213 | goto fail_close; | ||
214 | } | ||
215 | |||
216 | ret = vmbus_establish_gpadl(dev->channel, pdata->send_buf, | ||
217 | SEND_BUFFER_SIZE, &pdata->send_gpadl); | ||
218 | if (ret) | ||
219 | goto fail_close; | ||
220 | |||
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; | ||
228 | |||
157 | pdata->info.priv = pdata; | 229 | pdata->info.priv = pdata; |
158 | pdata->device = dev; | 230 | pdata->device = dev; |
159 | 231 | ||
@@ -163,11 +235,14 @@ hv_uio_probe(struct hv_device *dev, | |||
163 | goto fail_close; | 235 | goto fail_close; |
164 | } | 236 | } |
165 | 237 | ||
238 | vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind); | ||
239 | |||
166 | hv_set_drvdata(dev, pdata); | 240 | hv_set_drvdata(dev, pdata); |
167 | 241 | ||
168 | return 0; | 242 | return 0; |
169 | 243 | ||
170 | fail_close: | 244 | fail_close: |
245 | hv_uio_cleanup(dev, pdata); | ||
171 | vmbus_close(dev->channel); | 246 | vmbus_close(dev->channel); |
172 | fail: | 247 | fail: |
173 | kfree(pdata); | 248 | kfree(pdata); |
@@ -184,6 +259,7 @@ hv_uio_remove(struct hv_device *dev) | |||
184 | return 0; | 259 | return 0; |
185 | 260 | ||
186 | uio_unregister_device(&pdata->info); | 261 | uio_unregister_device(&pdata->info); |
262 | hv_uio_cleanup(dev, pdata); | ||
187 | hv_set_drvdata(dev, NULL); | 263 | hv_set_drvdata(dev, NULL); |
188 | vmbus_close(dev->channel); | 264 | vmbus_close(dev->channel); |
189 | kfree(pdata); | 265 | kfree(pdata); |