Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: hid-sensor-hub: Allow parallel synchronous reads

Current implementation only allows one outstanding synchronous read.
This is a performance hit when user mode is requesting raw reads
of sensor attributes on multiple sensors together.
This change changes the mutex lock to per hid sensor hub device instead
of global lock. Although request to hid sensor hub is serialized, there
can be multiple outstanding read requests pending for responses via
hid reports.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Srinivas Pandruvada and committed by
Jiri Kosina
e651a1da 870fd0f5

+65 -49
+41 -49
drivers/hid/hid-sensor-hub.c
··· 29 29 #define HID_SENSOR_HUB_ENUM_QUIRK 0x01 30 30 31 31 /** 32 - * struct sensor_hub_pending - Synchronous read pending information 33 - * @status: Pending status true/false. 34 - * @ready: Completion synchronization data. 35 - * @usage_id: Usage id for physical device, E.g. Gyro usage id. 36 - * @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro. 37 - * @raw_size: Response size for a read request. 38 - * @raw_data: Place holder for received response. 39 - */ 40 - struct sensor_hub_pending { 41 - bool status; 42 - struct completion ready; 43 - u32 usage_id; 44 - u32 attr_usage_id; 45 - int raw_size; 46 - u8 *raw_data; 47 - }; 48 - 49 - /** 50 32 * struct sensor_hub_data - Hold a instance data for a HID hub device 51 33 * @hsdev: Stored hid instance for current hub device. 52 34 * @mutex: Mutex to serialize synchronous request. 53 35 * @lock: Spin lock to protect pending request structure. 54 - * @pending: Holds information of pending sync read request. 55 36 * @dyn_callback_list: Holds callback function 56 37 * @dyn_callback_lock: spin lock to protect callback list 57 38 * @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance. ··· 42 61 struct sensor_hub_data { 43 62 struct mutex mutex; 44 63 spinlock_t lock; 45 - struct sensor_hub_pending pending; 46 64 struct list_head dyn_callback_list; 47 65 spinlock_t dyn_callback_lock; 48 66 struct mfd_cell *hid_sensor_hub_client_devs; ··· 244 264 struct hid_report *report; 245 265 int ret_val = 0; 246 266 247 - mutex_lock(&data->mutex); 248 - memset(&data->pending, 0, sizeof(data->pending)); 249 - init_completion(&data->pending.ready); 250 - data->pending.usage_id = usage_id; 251 - data->pending.attr_usage_id = attr_usage_id; 252 - data->pending.raw_size = 0; 267 + mutex_lock(&hsdev->mutex); 268 + memset(&hsdev->pending, 0, sizeof(hsdev->pending)); 269 + init_completion(&hsdev->pending.ready); 270 + hsdev->pending.usage_id = usage_id; 271 + hsdev->pending.attr_usage_id = attr_usage_id; 272 + hsdev->pending.raw_size = 0; 253 273 254 274 spin_lock_irqsave(&data->lock, flags); 255 - data->pending.status = true; 275 + hsdev->pending.status = true; 256 276 spin_unlock_irqrestore(&data->lock, flags); 257 277 report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT); 258 278 if (!report) 259 279 goto err_free; 260 280 281 + mutex_lock(&data->mutex); 261 282 hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); 262 - wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5); 263 - switch (data->pending.raw_size) { 283 + mutex_unlock(&data->mutex); 284 + wait_for_completion_interruptible_timeout(&hsdev->pending.ready, HZ*5); 285 + switch (hsdev->pending.raw_size) { 264 286 case 1: 265 - ret_val = *(u8 *)data->pending.raw_data; 287 + ret_val = *(u8 *)hsdev->pending.raw_data; 266 288 break; 267 289 case 2: 268 - ret_val = *(u16 *)data->pending.raw_data; 290 + ret_val = *(u16 *)hsdev->pending.raw_data; 269 291 break; 270 292 case 4: 271 - ret_val = *(u32 *)data->pending.raw_data; 293 + ret_val = *(u32 *)hsdev->pending.raw_data; 272 294 break; 273 295 default: 274 296 ret_val = 0; 275 297 } 276 - kfree(data->pending.raw_data); 298 + kfree(hsdev->pending.raw_data); 277 299 278 300 err_free: 279 - data->pending.status = false; 280 - mutex_unlock(&data->mutex); 301 + hsdev->pending.status = false; 302 + mutex_unlock(&hsdev->mutex); 281 303 282 304 return ret_val; 283 305 } ··· 435 453 report->field[i]->report_count)/8); 436 454 sz = (report->field[i]->report_size * 437 455 report->field[i]->report_count)/8; 438 - if (pdata->pending.status && pdata->pending.attr_usage_id == 439 - report->field[i]->usage->hid) { 440 - hid_dbg(hdev, "data was pending ...\n"); 441 - pdata->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); 442 - if (pdata->pending.raw_data) 443 - pdata->pending.raw_size = sz; 444 - else 445 - pdata->pending.raw_size = 0; 446 - complete(&pdata->pending.ready); 447 - } 448 456 collection = &hdev->collection[ 449 457 report->field[i]->usage->collection_index]; 450 458 hid_dbg(hdev, "collection->usage %x\n", ··· 444 472 report->field[i]->physical, 445 473 report->field[i]->usage[0].collection_index, 446 474 &hsdev, &priv); 447 - 448 - if (callback && callback->capture_sample) { 475 + if (!callback) { 476 + ptr += sz; 477 + continue; 478 + } 479 + if (hsdev->pending.status && hsdev->pending.attr_usage_id == 480 + report->field[i]->usage->hid) { 481 + hid_dbg(hdev, "data was pending ...\n"); 482 + hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); 483 + if (hsdev->pending.raw_data) 484 + hsdev->pending.raw_size = sz; 485 + else 486 + hsdev->pending.raw_size = 0; 487 + complete(&hsdev->pending.ready); 488 + } 489 + if (callback->capture_sample) { 449 490 if (report->field[i]->logical) 450 491 callback->capture_sample(hsdev, 451 492 report->field[i]->logical, sz, ptr, ··· 613 628 hsdev->hdev = hdev; 614 629 hsdev->vendor_id = hdev->vendor; 615 630 hsdev->product_id = hdev->product; 631 + hsdev->usage = collection->usage; 632 + mutex_init(&hsdev->mutex); 616 633 hsdev->start_collection_index = i; 617 634 if (last_hsdev) 618 635 last_hsdev->end_collection_index = i; ··· 661 674 { 662 675 struct sensor_hub_data *data = hid_get_drvdata(hdev); 663 676 unsigned long flags; 677 + int i; 664 678 665 679 hid_dbg(hdev, " hardware removed\n"); 666 680 hid_hw_close(hdev); 667 681 hid_hw_stop(hdev); 668 682 spin_lock_irqsave(&data->lock, flags); 669 - if (data->pending.status) 670 - complete(&data->pending.ready); 683 + for (i = 0; i < data->hid_sensor_client_cnt; ++i) { 684 + struct hid_sensor_hub_device *hsdev = 685 + data->hid_sensor_hub_client_devs[i].platform_data; 686 + if (hsdev->pending.status) 687 + complete(&hsdev->pending.ready); 688 + } 671 689 spin_unlock_irqrestore(&data->lock, flags); 672 690 mfd_remove_devices(&hdev->dev); 673 691 hid_set_drvdata(hdev, NULL);
+24
include/linux/hid-sensor-hub.h
··· 47 47 }; 48 48 49 49 /** 50 + * struct sensor_hub_pending - Synchronous read pending information 51 + * @status: Pending status true/false. 52 + * @ready: Completion synchronization data. 53 + * @usage_id: Usage id for physical device, E.g. Gyro usage id. 54 + * @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro. 55 + * @raw_size: Response size for a read request. 56 + * @raw_data: Place holder for received response. 57 + */ 58 + struct sensor_hub_pending { 59 + bool status; 60 + struct completion ready; 61 + u32 usage_id; 62 + u32 attr_usage_id; 63 + int raw_size; 64 + u8 *raw_data; 65 + }; 66 + 67 + /** 50 68 * struct hid_sensor_hub_device - Stores the hub instance data 51 69 * @hdev: Stores the hid instance. 52 70 * @vendor_id: Vendor id of hub device. 53 71 * @product_id: Product id of hub device. 72 + * @usage: Usage id for this hub device instance. 54 73 * @start_collection_index: Starting index for a phy type collection 55 74 * @end_collection_index: Last index for a phy type collection 75 + * @mutex: synchronizing mutex. 76 + * @pending: Holds information of pending sync read request. 56 77 */ 57 78 struct hid_sensor_hub_device { 58 79 struct hid_device *hdev; 59 80 u32 vendor_id; 60 81 u32 product_id; 82 + u32 usage; 61 83 int start_collection_index; 62 84 int end_collection_index; 85 + struct mutex mutex; 86 + struct sensor_hub_pending pending; 63 87 }; 64 88 65 89 /**