Contents of /trunk/kernel-magellan/patches-4.13/0108-4.13.9-all-fixes.patch
Parent Directory | Revision Log
Revision 3012 -
(show annotations)
(download)
Wed Oct 25 09:41:48 2017 UTC (6 years, 11 months ago) by niro
File size: 28207 byte(s)
Wed Oct 25 09:41:48 2017 UTC (6 years, 11 months ago) by niro
File size: 28207 byte(s)
-linux-4.13.9
1 | diff --git a/Makefile b/Makefile |
2 | index 66ec023da822..aa0267950444 100644 |
3 | --- a/Makefile |
4 | +++ b/Makefile |
5 | @@ -1,6 +1,6 @@ |
6 | VERSION = 4 |
7 | PATCHLEVEL = 13 |
8 | -SUBLEVEL = 8 |
9 | +SUBLEVEL = 9 |
10 | EXTRAVERSION = |
11 | NAME = Fearless Coyote |
12 | |
13 | diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c |
14 | index 98b3dd8cf2bf..a7be1b4283a0 100644 |
15 | --- a/arch/x86/kernel/apic/apic.c |
16 | +++ b/arch/x86/kernel/apic/apic.c |
17 | @@ -599,9 +599,14 @@ static const struct x86_cpu_id deadline_match[] = { |
18 | |
19 | static void apic_check_deadline_errata(void) |
20 | { |
21 | - const struct x86_cpu_id *m = x86_match_cpu(deadline_match); |
22 | + const struct x86_cpu_id *m; |
23 | u32 rev; |
24 | |
25 | + if (!boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER) || |
26 | + boot_cpu_has(X86_FEATURE_HYPERVISOR)) |
27 | + return; |
28 | + |
29 | + m = x86_match_cpu(deadline_match); |
30 | if (!m) |
31 | return; |
32 | |
33 | diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig |
34 | index 3cd60f460b61..8b27211f6c50 100644 |
35 | --- a/drivers/hid/Kconfig |
36 | +++ b/drivers/hid/Kconfig |
37 | @@ -281,6 +281,7 @@ config HID_ELECOM |
38 | Support for ELECOM devices: |
39 | - BM084 Bluetooth Mouse |
40 | - DEFT Trackball (Wired and wireless) |
41 | + - HUGE Trackball (Wired and wireless) |
42 | |
43 | config HID_ELO |
44 | tristate "ELO USB 4000/4500 touchscreen" |
45 | diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c |
46 | index 9017dcc14502..efb3501b4123 100644 |
47 | --- a/drivers/hid/hid-core.c |
48 | +++ b/drivers/hid/hid-core.c |
49 | @@ -2031,6 +2031,8 @@ static const struct hid_device_id hid_have_special_driver[] = { |
50 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, |
51 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) }, |
52 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) }, |
53 | + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) }, |
54 | + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRELESS) }, |
55 | #endif |
56 | #if IS_ENABLED(CONFIG_HID_ELO) |
57 | { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) }, |
58 | diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c |
59 | index e2c7465df69f..54aeea57d209 100644 |
60 | --- a/drivers/hid/hid-elecom.c |
61 | +++ b/drivers/hid/hid-elecom.c |
62 | @@ -3,6 +3,7 @@ |
63 | * Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com> |
64 | * Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com> |
65 | * Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu> |
66 | + * Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org> |
67 | */ |
68 | |
69 | /* |
70 | @@ -32,9 +33,11 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
71 | break; |
72 | case USB_DEVICE_ID_ELECOM_DEFT_WIRED: |
73 | case USB_DEVICE_ID_ELECOM_DEFT_WIRELESS: |
74 | - /* The DEFT trackball has eight buttons, but its descriptor only |
75 | - * reports five, disabling the three Fn buttons on the top of |
76 | - * the mouse. |
77 | + case USB_DEVICE_ID_ELECOM_HUGE_WIRED: |
78 | + case USB_DEVICE_ID_ELECOM_HUGE_WIRELESS: |
79 | + /* The DEFT/HUGE trackball has eight buttons, but its descriptor |
80 | + * only reports five, disabling the three Fn buttons on the top |
81 | + * of the mouse. |
82 | * |
83 | * Apply the following diff to the descriptor: |
84 | * |
85 | @@ -62,7 +65,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
86 | * End Collection, End Collection, |
87 | */ |
88 | if (*rsize == 213 && rdesc[13] == 5 && rdesc[21] == 5) { |
89 | - hid_info(hdev, "Fixing up Elecom DEFT Fn buttons\n"); |
90 | + hid_info(hdev, "Fixing up Elecom DEFT/HUGE Fn buttons\n"); |
91 | rdesc[13] = 8; /* Button/Variable Report Count */ |
92 | rdesc[21] = 8; /* Button/Variable Usage Maximum */ |
93 | rdesc[29] = 0; /* Button/Constant Report Count */ |
94 | @@ -76,6 +79,8 @@ static const struct hid_device_id elecom_devices[] = { |
95 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, |
96 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) }, |
97 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) }, |
98 | + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) }, |
99 | + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRELESS) }, |
100 | { } |
101 | }; |
102 | MODULE_DEVICE_TABLE(hid, elecom_devices); |
103 | diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h |
104 | index c9ba4c6db74c..1333ac5c6597 100644 |
105 | --- a/drivers/hid/hid-ids.h |
106 | +++ b/drivers/hid/hid-ids.h |
107 | @@ -366,6 +366,8 @@ |
108 | #define USB_DEVICE_ID_ELECOM_BM084 0x0061 |
109 | #define USB_DEVICE_ID_ELECOM_DEFT_WIRED 0x00fe |
110 | #define USB_DEVICE_ID_ELECOM_DEFT_WIRELESS 0x00ff |
111 | +#define USB_DEVICE_ID_ELECOM_HUGE_WIRED 0x010c |
112 | +#define USB_DEVICE_ID_ELECOM_HUGE_WIRELESS 0x010d |
113 | |
114 | #define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34 |
115 | #define USB_DEVICE_ID_DREAM_CHEEKY_WN 0x0004 |
116 | diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c |
117 | index e57cc40cb768..be3fccab07fe 100644 |
118 | --- a/drivers/hv/channel.c |
119 | +++ b/drivers/hv/channel.c |
120 | @@ -177,6 +177,11 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, |
121 | &vmbus_connection.chn_msg_list); |
122 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
123 | |
124 | + if (newchannel->rescind) { |
125 | + err = -ENODEV; |
126 | + goto error_free_gpadl; |
127 | + } |
128 | + |
129 | ret = vmbus_post_msg(open_msg, |
130 | sizeof(struct vmbus_channel_open_channel), true); |
131 | |
132 | @@ -421,6 +426,11 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, |
133 | |
134 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
135 | |
136 | + if (channel->rescind) { |
137 | + ret = -ENODEV; |
138 | + goto cleanup; |
139 | + } |
140 | + |
141 | ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize - |
142 | sizeof(*msginfo), true); |
143 | if (ret != 0) |
144 | @@ -494,6 +504,10 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) |
145 | list_add_tail(&info->msglistentry, |
146 | &vmbus_connection.chn_msg_list); |
147 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
148 | + |
149 | + if (channel->rescind) |
150 | + goto post_msg_err; |
151 | + |
152 | ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_gpadl_teardown), |
153 | true); |
154 | |
155 | @@ -626,6 +640,7 @@ void vmbus_close(struct vmbus_channel *channel) |
156 | */ |
157 | return; |
158 | } |
159 | + mutex_lock(&vmbus_connection.channel_mutex); |
160 | /* |
161 | * Close all the sub-channels first and then close the |
162 | * primary channel. |
163 | @@ -634,16 +649,15 @@ void vmbus_close(struct vmbus_channel *channel) |
164 | cur_channel = list_entry(cur, struct vmbus_channel, sc_list); |
165 | vmbus_close_internal(cur_channel); |
166 | if (cur_channel->rescind) { |
167 | - mutex_lock(&vmbus_connection.channel_mutex); |
168 | - hv_process_channel_removal(cur_channel, |
169 | + hv_process_channel_removal( |
170 | cur_channel->offermsg.child_relid); |
171 | - mutex_unlock(&vmbus_connection.channel_mutex); |
172 | } |
173 | } |
174 | /* |
175 | * Now close the primary. |
176 | */ |
177 | vmbus_close_internal(channel); |
178 | + mutex_unlock(&vmbus_connection.channel_mutex); |
179 | } |
180 | EXPORT_SYMBOL_GPL(vmbus_close); |
181 | |
182 | diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c |
183 | index 037361158074..18c94ed02562 100644 |
184 | --- a/drivers/hv/channel_mgmt.c |
185 | +++ b/drivers/hv/channel_mgmt.c |
186 | @@ -159,7 +159,7 @@ static void vmbus_rescind_cleanup(struct vmbus_channel *channel) |
187 | |
188 | |
189 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
190 | - |
191 | + channel->rescind = true; |
192 | list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list, |
193 | msglistentry) { |
194 | |
195 | @@ -381,14 +381,21 @@ static void vmbus_release_relid(u32 relid) |
196 | true); |
197 | } |
198 | |
199 | -void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) |
200 | +void hv_process_channel_removal(u32 relid) |
201 | { |
202 | unsigned long flags; |
203 | - struct vmbus_channel *primary_channel; |
204 | + struct vmbus_channel *primary_channel, *channel; |
205 | |
206 | - BUG_ON(!channel->rescind); |
207 | BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex)); |
208 | |
209 | + /* |
210 | + * Make sure channel is valid as we may have raced. |
211 | + */ |
212 | + channel = relid2channel(relid); |
213 | + if (!channel) |
214 | + return; |
215 | + |
216 | + BUG_ON(!channel->rescind); |
217 | if (channel->target_cpu != get_cpu()) { |
218 | put_cpu(); |
219 | smp_call_function_single(channel->target_cpu, |
220 | @@ -451,6 +458,12 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) |
221 | /* Make sure this is a new offer */ |
222 | mutex_lock(&vmbus_connection.channel_mutex); |
223 | |
224 | + /* |
225 | + * Now that we have acquired the channel_mutex, |
226 | + * we can release the potentially racing rescind thread. |
227 | + */ |
228 | + atomic_dec(&vmbus_connection.offer_in_progress); |
229 | + |
230 | list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { |
231 | if (!uuid_le_cmp(channel->offermsg.offer.if_type, |
232 | newchannel->offermsg.offer.if_type) && |
233 | @@ -481,7 +494,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) |
234 | channel->num_sc++; |
235 | spin_unlock_irqrestore(&channel->lock, flags); |
236 | } else { |
237 | - atomic_dec(&vmbus_connection.offer_in_progress); |
238 | goto err_free_chan; |
239 | } |
240 | } |
241 | @@ -510,7 +522,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) |
242 | if (!fnew) { |
243 | if (channel->sc_creation_callback != NULL) |
244 | channel->sc_creation_callback(newchannel); |
245 | - atomic_dec(&vmbus_connection.offer_in_progress); |
246 | + newchannel->probe_done = true; |
247 | return; |
248 | } |
249 | |
250 | @@ -541,7 +553,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) |
251 | goto err_deq_chan; |
252 | } |
253 | |
254 | - atomic_dec(&vmbus_connection.offer_in_progress); |
255 | + newchannel->probe_done = true; |
256 | return; |
257 | |
258 | err_deq_chan: |
259 | @@ -839,7 +851,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) |
260 | { |
261 | struct vmbus_channel_rescind_offer *rescind; |
262 | struct vmbus_channel *channel; |
263 | - unsigned long flags; |
264 | struct device *dev; |
265 | |
266 | rescind = (struct vmbus_channel_rescind_offer *)hdr; |
267 | @@ -878,15 +889,25 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) |
268 | return; |
269 | } |
270 | |
271 | - spin_lock_irqsave(&channel->lock, flags); |
272 | - channel->rescind = true; |
273 | - spin_unlock_irqrestore(&channel->lock, flags); |
274 | + /* |
275 | + * Now wait for offer handling to complete. |
276 | + */ |
277 | + while (READ_ONCE(channel->probe_done) == false) { |
278 | + /* |
279 | + * We wait here until any channel offer is currently |
280 | + * being processed. |
281 | + */ |
282 | + msleep(1); |
283 | + } |
284 | |
285 | - vmbus_rescind_cleanup(channel); |
286 | + /* |
287 | + * At this point, the rescind handling can proceed safely. |
288 | + */ |
289 | |
290 | if (channel->device_obj) { |
291 | if (channel->chn_rescind_callback) { |
292 | channel->chn_rescind_callback(channel); |
293 | + vmbus_rescind_cleanup(channel); |
294 | return; |
295 | } |
296 | /* |
297 | @@ -895,6 +916,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) |
298 | */ |
299 | dev = get_device(&channel->device_obj->device); |
300 | if (dev) { |
301 | + vmbus_rescind_cleanup(channel); |
302 | vmbus_device_unregister(channel->device_obj); |
303 | put_device(dev); |
304 | } |
305 | @@ -907,16 +929,16 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) |
306 | * 1. Close all sub-channels first |
307 | * 2. Then close the primary channel. |
308 | */ |
309 | + mutex_lock(&vmbus_connection.channel_mutex); |
310 | + vmbus_rescind_cleanup(channel); |
311 | if (channel->state == CHANNEL_OPEN_STATE) { |
312 | /* |
313 | * The channel is currently not open; |
314 | * it is safe for us to cleanup the channel. |
315 | */ |
316 | - mutex_lock(&vmbus_connection.channel_mutex); |
317 | - hv_process_channel_removal(channel, |
318 | - channel->offermsg.child_relid); |
319 | - mutex_unlock(&vmbus_connection.channel_mutex); |
320 | + hv_process_channel_removal(rescind->child_relid); |
321 | } |
322 | + mutex_unlock(&vmbus_connection.channel_mutex); |
323 | } |
324 | } |
325 | |
326 | diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c |
327 | index 1f450c39a9b0..741daa6e2fc7 100644 |
328 | --- a/drivers/hv/ring_buffer.c |
329 | +++ b/drivers/hv/ring_buffer.c |
330 | @@ -29,6 +29,7 @@ |
331 | #include <linux/uio.h> |
332 | #include <linux/vmalloc.h> |
333 | #include <linux/slab.h> |
334 | +#include <linux/prefetch.h> |
335 | |
336 | #include "hyperv_vmbus.h" |
337 | |
338 | @@ -94,30 +95,6 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info, |
339 | ring_info->ring_buffer->write_index = next_write_location; |
340 | } |
341 | |
342 | -/* Get the next read location for the specified ring buffer. */ |
343 | -static inline u32 |
344 | -hv_get_next_read_location(const struct hv_ring_buffer_info *ring_info) |
345 | -{ |
346 | - return ring_info->ring_buffer->read_index; |
347 | -} |
348 | - |
349 | -/* |
350 | - * Get the next read location + offset for the specified ring buffer. |
351 | - * This allows the caller to skip. |
352 | - */ |
353 | -static inline u32 |
354 | -hv_get_next_readlocation_withoffset(const struct hv_ring_buffer_info *ring_info, |
355 | - u32 offset) |
356 | -{ |
357 | - u32 next = ring_info->ring_buffer->read_index; |
358 | - |
359 | - next += offset; |
360 | - if (next >= ring_info->ring_datasize) |
361 | - next -= ring_info->ring_datasize; |
362 | - |
363 | - return next; |
364 | -} |
365 | - |
366 | /* Set the next read location for the specified ring buffer. */ |
367 | static inline void |
368 | hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, |
369 | @@ -141,29 +118,6 @@ hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info) |
370 | return (u64)ring_info->ring_buffer->write_index << 32; |
371 | } |
372 | |
373 | -/* |
374 | - * Helper routine to copy to source from ring buffer. |
375 | - * Assume there is enough room. Handles wrap-around in src case only!! |
376 | - */ |
377 | -static u32 hv_copyfrom_ringbuffer( |
378 | - const struct hv_ring_buffer_info *ring_info, |
379 | - void *dest, |
380 | - u32 destlen, |
381 | - u32 start_read_offset) |
382 | -{ |
383 | - void *ring_buffer = hv_get_ring_buffer(ring_info); |
384 | - u32 ring_buffer_size = hv_get_ring_buffersize(ring_info); |
385 | - |
386 | - memcpy(dest, ring_buffer + start_read_offset, destlen); |
387 | - |
388 | - start_read_offset += destlen; |
389 | - if (start_read_offset >= ring_buffer_size) |
390 | - start_read_offset -= ring_buffer_size; |
391 | - |
392 | - return start_read_offset; |
393 | -} |
394 | - |
395 | - |
396 | /* |
397 | * Helper routine to copy from source to ring buffer. |
398 | * Assume there is enough room. Handles wrap-around in dest case only!! |
399 | @@ -334,33 +288,22 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, |
400 | return 0; |
401 | } |
402 | |
403 | -static inline void |
404 | -init_cached_read_index(struct hv_ring_buffer_info *rbi) |
405 | -{ |
406 | - rbi->cached_read_index = rbi->ring_buffer->read_index; |
407 | -} |
408 | - |
409 | int hv_ringbuffer_read(struct vmbus_channel *channel, |
410 | void *buffer, u32 buflen, u32 *buffer_actual_len, |
411 | u64 *requestid, bool raw) |
412 | { |
413 | - u32 bytes_avail_toread; |
414 | - u32 next_read_location; |
415 | - u64 prev_indices = 0; |
416 | - struct vmpacket_descriptor desc; |
417 | - u32 offset; |
418 | - u32 packetlen; |
419 | - struct hv_ring_buffer_info *inring_info = &channel->inbound; |
420 | - |
421 | - if (buflen <= 0) |
422 | + struct vmpacket_descriptor *desc; |
423 | + u32 packetlen, offset; |
424 | + |
425 | + if (unlikely(buflen == 0)) |
426 | return -EINVAL; |
427 | |
428 | *buffer_actual_len = 0; |
429 | *requestid = 0; |
430 | |
431 | - bytes_avail_toread = hv_get_bytes_to_read(inring_info); |
432 | /* Make sure there is something to read */ |
433 | - if (bytes_avail_toread < sizeof(desc)) { |
434 | + desc = hv_pkt_iter_first(channel); |
435 | + if (desc == NULL) { |
436 | /* |
437 | * No error is set when there is even no header, drivers are |
438 | * supposed to analyze buffer_actual_len. |
439 | @@ -368,48 +311,22 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, |
440 | return 0; |
441 | } |
442 | |
443 | - init_cached_read_index(inring_info); |
444 | - |
445 | - next_read_location = hv_get_next_read_location(inring_info); |
446 | - next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc, |
447 | - sizeof(desc), |
448 | - next_read_location); |
449 | - |
450 | - offset = raw ? 0 : (desc.offset8 << 3); |
451 | - packetlen = (desc.len8 << 3) - offset; |
452 | + offset = raw ? 0 : (desc->offset8 << 3); |
453 | + packetlen = (desc->len8 << 3) - offset; |
454 | *buffer_actual_len = packetlen; |
455 | - *requestid = desc.trans_id; |
456 | - |
457 | - if (bytes_avail_toread < packetlen + offset) |
458 | - return -EAGAIN; |
459 | + *requestid = desc->trans_id; |
460 | |
461 | - if (packetlen > buflen) |
462 | + if (unlikely(packetlen > buflen)) |
463 | return -ENOBUFS; |
464 | |
465 | - next_read_location = |
466 | - hv_get_next_readlocation_withoffset(inring_info, offset); |
467 | + /* since ring is double mapped, only one copy is necessary */ |
468 | + memcpy(buffer, (const char *)desc + offset, packetlen); |
469 | |
470 | - next_read_location = hv_copyfrom_ringbuffer(inring_info, |
471 | - buffer, |
472 | - packetlen, |
473 | - next_read_location); |
474 | + /* Advance ring index to next packet descriptor */ |
475 | + __hv_pkt_iter_next(channel, desc); |
476 | |
477 | - next_read_location = hv_copyfrom_ringbuffer(inring_info, |
478 | - &prev_indices, |
479 | - sizeof(u64), |
480 | - next_read_location); |
481 | - |
482 | - /* |
483 | - * Make sure all reads are done before we update the read index since |
484 | - * the writer may start writing to the read area once the read index |
485 | - * is updated. |
486 | - */ |
487 | - virt_mb(); |
488 | - |
489 | - /* Update the read index */ |
490 | - hv_set_next_read_location(inring_info, next_read_location); |
491 | - |
492 | - hv_signal_on_read(channel); |
493 | + /* Notify host of update */ |
494 | + hv_pkt_iter_close(channel); |
495 | |
496 | return 0; |
497 | } |
498 | @@ -441,9 +358,6 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel) |
499 | { |
500 | struct hv_ring_buffer_info *rbi = &channel->inbound; |
501 | |
502 | - /* set state for later hv_signal_on_read() */ |
503 | - init_cached_read_index(rbi); |
504 | - |
505 | if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor)) |
506 | return NULL; |
507 | |
508 | @@ -471,10 +385,7 @@ __hv_pkt_iter_next(struct vmbus_channel *channel, |
509 | rbi->priv_read_index -= dsize; |
510 | |
511 | /* more data? */ |
512 | - if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor)) |
513 | - return NULL; |
514 | - else |
515 | - return hv_get_ring_buffer(rbi) + rbi->priv_read_index; |
516 | + return hv_pkt_iter_first(channel); |
517 | } |
518 | EXPORT_SYMBOL_GPL(__hv_pkt_iter_next); |
519 | |
520 | @@ -484,6 +395,7 @@ EXPORT_SYMBOL_GPL(__hv_pkt_iter_next); |
521 | void hv_pkt_iter_close(struct vmbus_channel *channel) |
522 | { |
523 | struct hv_ring_buffer_info *rbi = &channel->inbound; |
524 | + u32 orig_write_sz = hv_get_bytes_to_write(rbi); |
525 | |
526 | /* |
527 | * Make sure all reads are done before we update the read index since |
528 | @@ -493,6 +405,40 @@ void hv_pkt_iter_close(struct vmbus_channel *channel) |
529 | virt_rmb(); |
530 | rbi->ring_buffer->read_index = rbi->priv_read_index; |
531 | |
532 | - hv_signal_on_read(channel); |
533 | + /* |
534 | + * Issue a full memory barrier before making the signaling decision. |
535 | + * Here is the reason for having this barrier: |
536 | + * If the reading of the pend_sz (in this function) |
537 | + * were to be reordered and read before we commit the new read |
538 | + * index (in the calling function) we could |
539 | + * have a problem. If the host were to set the pending_sz after we |
540 | + * have sampled pending_sz and go to sleep before we commit the |
541 | + * read index, we could miss sending the interrupt. Issue a full |
542 | + * memory barrier to address this. |
543 | + */ |
544 | + virt_mb(); |
545 | + |
546 | + /* If host has disabled notifications then skip */ |
547 | + if (rbi->ring_buffer->interrupt_mask) |
548 | + return; |
549 | + |
550 | + if (rbi->ring_buffer->feature_bits.feat_pending_send_sz) { |
551 | + u32 pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz); |
552 | + |
553 | + /* |
554 | + * If there was space before we began iteration, |
555 | + * then host was not blocked. Also handles case where |
556 | + * pending_sz is zero then host has nothing pending |
557 | + * and does not need to be signaled. |
558 | + */ |
559 | + if (orig_write_sz > pending_sz) |
560 | + return; |
561 | + |
562 | + /* If pending write will not fit, don't give false hope. */ |
563 | + if (hv_get_bytes_to_write(rbi) < pending_sz) |
564 | + return; |
565 | + } |
566 | + |
567 | + vmbus_setevent(channel); |
568 | } |
569 | EXPORT_SYMBOL_GPL(hv_pkt_iter_close); |
570 | diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c |
571 | index ed84e96715a0..5ad627044dd1 100644 |
572 | --- a/drivers/hv/vmbus_drv.c |
573 | +++ b/drivers/hv/vmbus_drv.c |
574 | @@ -768,8 +768,7 @@ static void vmbus_device_release(struct device *device) |
575 | struct vmbus_channel *channel = hv_dev->channel; |
576 | |
577 | mutex_lock(&vmbus_connection.channel_mutex); |
578 | - hv_process_channel_removal(channel, |
579 | - channel->offermsg.child_relid); |
580 | + hv_process_channel_removal(channel->offermsg.child_relid); |
581 | mutex_unlock(&vmbus_connection.channel_mutex); |
582 | kfree(hv_dev); |
583 | |
584 | @@ -940,6 +939,9 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu) |
585 | if (channel->offermsg.child_relid != relid) |
586 | continue; |
587 | |
588 | + if (channel->rescind) |
589 | + continue; |
590 | + |
591 | switch (channel->callback_mode) { |
592 | case HV_CALL_ISR: |
593 | vmbus_channel_isr(channel); |
594 | diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h |
595 | index b7d7bbec74e0..3647085dab0a 100644 |
596 | --- a/include/linux/hyperv.h |
597 | +++ b/include/linux/hyperv.h |
598 | @@ -127,7 +127,6 @@ struct hv_ring_buffer_info { |
599 | u32 ring_data_startoffset; |
600 | u32 priv_write_index; |
601 | u32 priv_read_index; |
602 | - u32 cached_read_index; |
603 | }; |
604 | |
605 | /* |
606 | @@ -180,19 +179,6 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi) |
607 | return write; |
608 | } |
609 | |
610 | -static inline u32 hv_get_cached_bytes_to_write( |
611 | - const struct hv_ring_buffer_info *rbi) |
612 | -{ |
613 | - u32 read_loc, write_loc, dsize, write; |
614 | - |
615 | - dsize = rbi->ring_datasize; |
616 | - read_loc = rbi->cached_read_index; |
617 | - write_loc = rbi->ring_buffer->write_index; |
618 | - |
619 | - write = write_loc >= read_loc ? dsize - (write_loc - read_loc) : |
620 | - read_loc - write_loc; |
621 | - return write; |
622 | -} |
623 | /* |
624 | * VMBUS version is 32 bit entity broken up into |
625 | * two 16 bit quantities: major_number. minor_number. |
626 | @@ -895,6 +881,8 @@ struct vmbus_channel { |
627 | */ |
628 | enum hv_numa_policy affinity_policy; |
629 | |
630 | + bool probe_done; |
631 | + |
632 | }; |
633 | |
634 | static inline bool is_hvsock_channel(const struct vmbus_channel *c) |
635 | @@ -1453,7 +1441,7 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, u8 *buf, |
636 | const int *srv_version, int srv_vercnt, |
637 | int *nego_fw_version, int *nego_srv_version); |
638 | |
639 | -void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); |
640 | +void hv_process_channel_removal(u32 relid); |
641 | |
642 | void vmbus_setevent(struct vmbus_channel *channel); |
643 | /* |
644 | @@ -1473,55 +1461,6 @@ hv_get_ring_buffer(const struct hv_ring_buffer_info *ring_info) |
645 | return ring_info->ring_buffer->buffer; |
646 | } |
647 | |
648 | -/* |
649 | - * To optimize the flow management on the send-side, |
650 | - * when the sender is blocked because of lack of |
651 | - * sufficient space in the ring buffer, potential the |
652 | - * consumer of the ring buffer can signal the producer. |
653 | - * This is controlled by the following parameters: |
654 | - * |
655 | - * 1. pending_send_sz: This is the size in bytes that the |
656 | - * producer is trying to send. |
657 | - * 2. The feature bit feat_pending_send_sz set to indicate if |
658 | - * the consumer of the ring will signal when the ring |
659 | - * state transitions from being full to a state where |
660 | - * there is room for the producer to send the pending packet. |
661 | - */ |
662 | - |
663 | -static inline void hv_signal_on_read(struct vmbus_channel *channel) |
664 | -{ |
665 | - u32 cur_write_sz, cached_write_sz; |
666 | - u32 pending_sz; |
667 | - struct hv_ring_buffer_info *rbi = &channel->inbound; |
668 | - |
669 | - /* |
670 | - * Issue a full memory barrier before making the signaling decision. |
671 | - * Here is the reason for having this barrier: |
672 | - * If the reading of the pend_sz (in this function) |
673 | - * were to be reordered and read before we commit the new read |
674 | - * index (in the calling function) we could |
675 | - * have a problem. If the host were to set the pending_sz after we |
676 | - * have sampled pending_sz and go to sleep before we commit the |
677 | - * read index, we could miss sending the interrupt. Issue a full |
678 | - * memory barrier to address this. |
679 | - */ |
680 | - virt_mb(); |
681 | - |
682 | - pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz); |
683 | - /* If the other end is not blocked on write don't bother. */ |
684 | - if (pending_sz == 0) |
685 | - return; |
686 | - |
687 | - cur_write_sz = hv_get_bytes_to_write(rbi); |
688 | - |
689 | - if (cur_write_sz < pending_sz) |
690 | - return; |
691 | - |
692 | - cached_write_sz = hv_get_cached_bytes_to_write(rbi); |
693 | - if (cached_write_sz < pending_sz) |
694 | - vmbus_setevent(channel); |
695 | -} |
696 | - |
697 | /* |
698 | * Mask off host interrupt callback notifications |
699 | */ |
700 | diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c |
701 | index 8ec6ba230bb9..6b9311631aa1 100644 |
702 | --- a/mm/page_vma_mapped.c |
703 | +++ b/mm/page_vma_mapped.c |
704 | @@ -6,17 +6,6 @@ |
705 | |
706 | #include "internal.h" |
707 | |
708 | -static inline bool check_pmd(struct page_vma_mapped_walk *pvmw) |
709 | -{ |
710 | - pmd_t pmde; |
711 | - /* |
712 | - * Make sure we don't re-load pmd between present and !trans_huge check. |
713 | - * We need a consistent view. |
714 | - */ |
715 | - pmde = READ_ONCE(*pvmw->pmd); |
716 | - return pmd_present(pmde) && !pmd_trans_huge(pmde); |
717 | -} |
718 | - |
719 | static inline bool not_found(struct page_vma_mapped_walk *pvmw) |
720 | { |
721 | page_vma_mapped_walk_done(pvmw); |
722 | @@ -106,6 +95,7 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw) |
723 | pgd_t *pgd; |
724 | p4d_t *p4d; |
725 | pud_t *pud; |
726 | + pmd_t pmde; |
727 | |
728 | /* The only possible pmd mapping has been handled on last iteration */ |
729 | if (pvmw->pmd && !pvmw->pte) |
730 | @@ -138,7 +128,13 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw) |
731 | if (!pud_present(*pud)) |
732 | return false; |
733 | pvmw->pmd = pmd_offset(pud, pvmw->address); |
734 | - if (pmd_trans_huge(*pvmw->pmd)) { |
735 | + /* |
736 | + * Make sure the pmd value isn't cached in a register by the |
737 | + * compiler and used as a stale value after we've observed a |
738 | + * subsequent update. |
739 | + */ |
740 | + pmde = READ_ONCE(*pvmw->pmd); |
741 | + if (pmd_trans_huge(pmde)) { |
742 | pvmw->ptl = pmd_lock(mm, pvmw->pmd); |
743 | if (!pmd_present(*pvmw->pmd)) |
744 | return not_found(pvmw); |
745 | @@ -153,9 +149,8 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw) |
746 | spin_unlock(pvmw->ptl); |
747 | pvmw->ptl = NULL; |
748 | } |
749 | - } else { |
750 | - if (!check_pmd(pvmw)) |
751 | - return false; |
752 | + } else if (!pmd_present(pmde)) { |
753 | + return false; |
754 | } |
755 | if (!map_pte(pvmw)) |
756 | goto next_pte; |
757 | diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c |
758 | index 01e779b91c8e..2e3ffc3bc483 100644 |
759 | --- a/tools/perf/util/parse-events.c |
760 | +++ b/tools/perf/util/parse-events.c |
761 | @@ -309,10 +309,11 @@ static char *get_config_name(struct list_head *head_terms) |
762 | static struct perf_evsel * |
763 | __add_event(struct list_head *list, int *idx, |
764 | struct perf_event_attr *attr, |
765 | - char *name, struct cpu_map *cpus, |
766 | + char *name, struct perf_pmu *pmu, |
767 | struct list_head *config_terms) |
768 | { |
769 | struct perf_evsel *evsel; |
770 | + struct cpu_map *cpus = pmu ? pmu->cpus : NULL; |
771 | |
772 | event_attr_init(attr); |
773 | |
774 | @@ -323,7 +324,7 @@ __add_event(struct list_head *list, int *idx, |
775 | (*idx)++; |
776 | evsel->cpus = cpu_map__get(cpus); |
777 | evsel->own_cpus = cpu_map__get(cpus); |
778 | - evsel->system_wide = !!cpus; |
779 | + evsel->system_wide = pmu ? pmu->is_uncore : false; |
780 | |
781 | if (name) |
782 | evsel->name = strdup(name); |
783 | @@ -1232,7 +1233,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data, |
784 | |
785 | if (!head_config) { |
786 | attr.type = pmu->type; |
787 | - evsel = __add_event(list, &data->idx, &attr, NULL, pmu->cpus, NULL); |
788 | + evsel = __add_event(list, &data->idx, &attr, NULL, pmu, NULL); |
789 | return evsel ? 0 : -ENOMEM; |
790 | } |
791 | |
792 | @@ -1253,7 +1254,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data, |
793 | return -EINVAL; |
794 | |
795 | evsel = __add_event(list, &data->idx, &attr, |
796 | - get_config_name(head_config), pmu->cpus, |
797 | + get_config_name(head_config), pmu, |
798 | &config_terms); |
799 | if (evsel) { |
800 | evsel->unit = info.unit; |
801 | diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c |
802 | index ac16a9db1fb5..1c4d7b4e4fb5 100644 |
803 | --- a/tools/perf/util/pmu.c |
804 | +++ b/tools/perf/util/pmu.c |
805 | @@ -470,17 +470,36 @@ static void pmu_read_sysfs(void) |
806 | closedir(dir); |
807 | } |
808 | |
809 | +static struct cpu_map *__pmu_cpumask(const char *path) |
810 | +{ |
811 | + FILE *file; |
812 | + struct cpu_map *cpus; |
813 | + |
814 | + file = fopen(path, "r"); |
815 | + if (!file) |
816 | + return NULL; |
817 | + |
818 | + cpus = cpu_map__read(file); |
819 | + fclose(file); |
820 | + return cpus; |
821 | +} |
822 | + |
823 | +/* |
824 | + * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) |
825 | + * may have a "cpus" file. |
826 | + */ |
827 | +#define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" |
828 | +#define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" |
829 | + |
830 | static struct cpu_map *pmu_cpumask(const char *name) |
831 | { |
832 | - struct stat st; |
833 | char path[PATH_MAX]; |
834 | - FILE *file; |
835 | struct cpu_map *cpus; |
836 | const char *sysfs = sysfs__mountpoint(); |
837 | const char *templates[] = { |
838 | - "%s/bus/event_source/devices/%s/cpumask", |
839 | - "%s/bus/event_source/devices/%s/cpus", |
840 | - NULL |
841 | + CPUS_TEMPLATE_UNCORE, |
842 | + CPUS_TEMPLATE_CPU, |
843 | + NULL |
844 | }; |
845 | const char **template; |
846 | |
847 | @@ -489,20 +508,25 @@ static struct cpu_map *pmu_cpumask(const char *name) |
848 | |
849 | for (template = templates; *template; template++) { |
850 | snprintf(path, PATH_MAX, *template, sysfs, name); |
851 | - if (stat(path, &st) == 0) |
852 | - break; |
853 | + cpus = __pmu_cpumask(path); |
854 | + if (cpus) |
855 | + return cpus; |
856 | } |
857 | |
858 | - if (!*template) |
859 | - return NULL; |
860 | + return NULL; |
861 | +} |
862 | |
863 | - file = fopen(path, "r"); |
864 | - if (!file) |
865 | - return NULL; |
866 | +static bool pmu_is_uncore(const char *name) |
867 | +{ |
868 | + char path[PATH_MAX]; |
869 | + struct cpu_map *cpus; |
870 | + const char *sysfs = sysfs__mountpoint(); |
871 | |
872 | - cpus = cpu_map__read(file); |
873 | - fclose(file); |
874 | - return cpus; |
875 | + snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); |
876 | + cpus = __pmu_cpumask(path); |
877 | + cpu_map__put(cpus); |
878 | + |
879 | + return !!cpus; |
880 | } |
881 | |
882 | /* |
883 | @@ -617,6 +641,8 @@ static struct perf_pmu *pmu_lookup(const char *name) |
884 | |
885 | pmu->cpus = pmu_cpumask(name); |
886 | |
887 | + pmu->is_uncore = pmu_is_uncore(name); |
888 | + |
889 | INIT_LIST_HEAD(&pmu->format); |
890 | INIT_LIST_HEAD(&pmu->aliases); |
891 | list_splice(&format, &pmu->format); |
892 | diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h |
893 | index 389e9729331f..fe0de0502ce2 100644 |
894 | --- a/tools/perf/util/pmu.h |
895 | +++ b/tools/perf/util/pmu.h |
896 | @@ -22,6 +22,7 @@ struct perf_pmu { |
897 | char *name; |
898 | __u32 type; |
899 | bool selectable; |
900 | + bool is_uncore; |
901 | struct perf_event_attr *default_config; |
902 | struct cpu_map *cpus; |
903 | struct list_head format; /* HEAD struct perf_pmu_format -> list */ |