Message ID | alpine.LNX.2.00.1308091310490.13089@pobox.suse.cz |
---|---|
State | Accepted |
Headers | show |
Am 09.08.2013 13:12, schrieb Jiri Kosina: > On Fri, 9 Aug 2013, Alexander Holler wrote: > > >> ================================= >> [ INFO: inconsistent lock state ] >> 3.10.5-dockstar-00038-g03242d1-dirty #408 Not tainted >> --------------------------------- >> inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage. >> swapper/0 [HC1[1]:SC0[0]:HE0:SE1] takes: >> (&(&sd->dyn_callback_lock)->rlock){?.+...}, at: [<c02af9f8>] >> sensor_hub_raw_event+0x10c/0x204 >> {HARDIRQ-ON-W} state was registered at: > > I think you need the patch below. Please let me know if it fixes it. Thanks a lot. That actually fixed the bug I never have seen before and the patch might be a candidate for the stable series (even if almost no one would see the problem because there don't seem to be many hid-sensor-hub users and the bug seems only to be visible with some debug options enabled). Btw, I've lied and that bug happened with the enforced error path as well as during normal operation. It seems I have enabled some debug option in the kernel, I never had enabled before. Unfortunaly that doesn't answer Andrew Mortons questions. I've now also verified if hid-sensor-hub receives an event with sensor_hub_raw_event() in the error-path (hid_device_io_stop() called and probe() failed), and this still *does* happen. That event (input report) doesn't come through hid-sensor-hub to my driver, but I think this is because of my call to sensor_hub_remove_callback() which is in the error path too. So I actually wonder why the input report still is reported from the hid-subsystem to hid-sensor-hub, even after I've called hid_device_io_stop() and probe() failed. Maybe everything is still ok and I just got confused with the somehow complicate interactions between the usb- and hid-subsystem, hid-sensor-hub (which uses MFD) and rtc-hid-sensor-time. I will also have a look if I find the seem to be missing down(), maybe that will offer some explanations to what goes on. Unfortunately I still don't know the complete path of events, I've stopped reading the source after you've told me about the patch from Andrew de los Reyes, beeing happy to have found a nice and proper solution (instead of the delayed rtc-device registering I did before). ;) Regards, Alexander Holler
Am 09.08.2013 18:21, schrieb Alexander Holler: > I've now also verified if hid-sensor-hub receives an event with > sensor_hub_raw_event() in the error-path (hid_device_io_stop() called > and probe() failed), and this still *does* happen. That event (input > report) doesn't come through hid-sensor-hub to my driver, but I think > this is because of my call to sensor_hub_remove_callback() which is in > the error path too. > So I actually wonder why the input report still is reported from the > hid-subsystem to hid-sensor-hub, even after I've called > hid_device_io_stop() and probe() failed. > Maybe everything is still ok and I just got confused with the somehow > complicate interactions between the usb- and hid-subsystem, > hid-sensor-hub (which uses MFD) and rtc-hid-sensor-time. Adding some more stuff to the confusion: Currently I think it is correct that hid-sensor-hub still receives the event, even after rtc-hid-sensor-time called hid_device_io_stop() and probe() failed. The reason the same reason, why hid-sensor-hub uses mfd, the actual hardware device might be shared by different drivers (therfor -hub). Regards, Alexander Holler
Hi Alexander On Fri, Aug 9, 2013 at 6:33 PM, Alexander Holler <holler@ahsoftware.de> wrote: > Am 09.08.2013 18:21, schrieb Alexander Holler: > >> I've now also verified if hid-sensor-hub receives an event with >> sensor_hub_raw_event() in the error-path (hid_device_io_stop() called >> and probe() failed), and this still *does* happen. That event (input >> report) doesn't come through hid-sensor-hub to my driver, but I think >> this is because of my call to sensor_hub_remove_callback() which is in >> the error path too. >> So I actually wonder why the input report still is reported from the >> hid-subsystem to hid-sensor-hub, even after I've called >> hid_device_io_stop() and probe() failed. >> Maybe everything is still ok and I just got confused with the somehow >> complicate interactions between the usb- and hid-subsystem, >> hid-sensor-hub (which uses MFD) and rtc-hid-sensor-time. > > > Adding some more stuff to the confusion: Currently I think it is correct > that hid-sensor-hub still receives the event, even after rtc-hid-sensor-time > called hid_device_io_stop() and probe() failed. The reason the same reason, > why hid-sensor-hub uses mfd, the actual hardware device might be shared by > different drivers (therfor -hub). I don't have time right know to debug this, but I thought I'd just clarify how the HID I/O lock works: HID core uses a semaphore to protect driver probe and removal. That is, the semaphore is locked during the ->probe() and ->remove() callbacks. The input event handler (in atomic context!) tries to lock this, too. If it fails due to ->probe or ->remove currently running, it simply drops the input events (which is fine for reasons that don't matter here). If it can lock it, it simply calls the ->raw_event() or whatever callbacks of the driver (probably via hid-input). If no driver is currently bound to a device, all input events are always dropped. If a driver now needs to perform I/O during ->probe or ->remove, they must explicitly notify HID core about this. We cannot allow it automatically as drivers must have a chance to setup some context before the first events are passed in. We start I/O via hid_device_io_start(). This simply releases the ->probe() semaphore and makes sure HID core knows about this. Once you call it, your drivers input callbacks will be used by HID core so you can perform I/O. Once you call hid_device_io_stop() the semaphore is locked again and no more I/O is possible. Same applies to the ->remove() callback, although it's not used by any driver, yet. The reason is that ->remove() is almost always called if the transport layer is already closed so any I/O will return -EIO. We make sure we don't do any double down() or up() by tracking it via a boolean. The memory barriers there aren't really obvious but it should be correct. I hope that explains how all this works. I can look over your patch on Sunday if still necessary. Cheers David
Am 09.08.2013 19:02, schrieb David Herrmann: > I hope that explains how all this works. I can look over your patch on > Sunday if still necessary. Thanks a lot for the explanation. Actually I don't have a problem but Andrew Morton asked me some questions I can't answer without looking in someone else source. ;) Fortunately that forced me to enable some debug options which have shown a bug Jiri fixed right after I've reported it. So if your explanation answered Andrew Morton questions, I'm fine, because my driver still works as I think it should. ;) Thanks again, Alexander Holler
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index ca749810..b334e50 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -147,23 +147,24 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, { struct hid_sensor_hub_callbacks_list *callback; struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); + unsigned long flags; - spin_lock(&pdata->dyn_callback_lock); + spin_lock_irqsave(&pdata->dyn_callback_lock, flags); list_for_each_entry(callback, &pdata->dyn_callback_list, list) if (callback->usage_id == usage_id) { - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return -EINVAL; } callback = kzalloc(sizeof(*callback), GFP_ATOMIC); if (!callback) { - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return -ENOMEM; } callback->usage_callback = usage_callback; callback->usage_id = usage_id; callback->priv = NULL; list_add_tail(&callback->list, &pdata->dyn_callback_list); - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return 0; } @@ -174,15 +175,16 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, { struct hid_sensor_hub_callbacks_list *callback; struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); + unsigned long flags; - spin_lock(&pdata->dyn_callback_lock); + spin_lock_irqsave(&pdata->dyn_callback_lock, flags); list_for_each_entry(callback, &pdata->dyn_callback_list, list) if (callback->usage_id == usage_id) { list_del(&callback->list); kfree(callback); break; } - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return 0; } @@ -359,15 +361,16 @@ static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message) { struct sensor_hub_data *pdata = hid_get_drvdata(hdev); struct hid_sensor_hub_callbacks_list *callback; + unsigned long flags; hid_dbg(hdev, " sensor_hub_suspend\n"); - spin_lock(&pdata->dyn_callback_lock); + spin_lock_irqsave(&pdata->dyn_callback_lock, flags); list_for_each_entry(callback, &pdata->dyn_callback_list, list) { if (callback->usage_callback->suspend) callback->usage_callback->suspend( pdata->hsdev, callback->priv); } - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return 0; } @@ -376,15 +379,16 @@ static int sensor_hub_resume(struct hid_device *hdev) { struct sensor_hub_data *pdata = hid_get_drvdata(hdev); struct hid_sensor_hub_callbacks_list *callback; + unsigned long flags; hid_dbg(hdev, " sensor_hub_resume\n"); - spin_lock(&pdata->dyn_callback_lock); + spin_lock_irqsave(&pdata->dyn_callback_lock, flags); list_for_each_entry(callback, &pdata->dyn_callback_list, list) { if (callback->usage_callback->resume) callback->usage_callback->resume( pdata->hsdev, callback->priv); } - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return 0; }