[PATCH] usb: dwc2: detect power supplies to reduce spam
By statically hardcoding at compile time the number of supplies ("#define DWC2_NUM_SUPPLIES ARRAY_SIZE(dwc2_hsotg_supply_names)"), the driver assumed that every controller uses supplies and issued a warning if none were detected via the device tree [1], even though the vast majority of devices (with 1 exception from Samsung) don't need nor use them. So to return to normality and stop warning everyone unconditionally, detect if there are any supplies and no-op just like the dummy regulator which got loudly auto-asigned does. This issue has been previously discussed based on an alternative fix at [2] a year back but nothing came out of it then. [1] dwc2 3f98.usb: 3f98.usb supply vusb_d not found, using dummy regulator dwc2 3f98.usb: 3f98.usb supply vusb_a not found, using dummy regulator [2] https://www.spinics.net/lists/linux-usb/msg153010.html Signed-off-by: Ioan-Adrian Ratiu --- drivers/usb/dwc2/core.h | 5 +++-- drivers/usb/dwc2/platform.c | 46 +++-- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index cd77af3b1565..c50b9fc4a162 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -128,7 +128,7 @@ static const char * const dwc2_hsotg_supply_names[] = { "vusb_a", /* analog USB supply, 1.1V */ }; -#define DWC2_NUM_SUPPLIES ARRAY_SIZE(dwc2_hsotg_supply_names) +#define DWC2_MAX_SUPPLIES ARRAY_SIZE(dwc2_hsotg_supply_names) /* * EP0_MPS_LIMIT @@ -921,7 +921,8 @@ struct dwc2_hsotg { struct phy *phy; struct usb_phy *uphy; struct dwc2_hsotg_plat *plat; - struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; + struct regulator_bulk_data supplies[DWC2_MAX_SUPPLIES]; + u8 num_supplies; u32 phyif; spinlock_t lock; diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 4703478f702f..3acf658af4e9 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -126,10 +126,12 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) struct platform_device *pdev = to_platform_device(hsotg->dev); int ret; - ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), - hsotg->supplies); - if (ret) - return ret; + if (hsotg->num_supplies) { + ret = regulator_bulk_enable(hsotg->num_supplies, + hsotg->supplies); + if (ret) + return ret; + } if (hsotg->clk) { ret = clk_prepare_enable(hsotg->clk); @@ -186,8 +188,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) if (hsotg->clk) clk_disable_unprepare(hsotg->clk); - ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), -hsotg->supplies); + if (hsotg->num_supplies) + ret = regulator_bulk_disable(hsotg->num_supplies, +hsotg->supplies); return ret; } @@ -210,6 +213,7 @@ int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) { + struct regulator *reg; int i, ret; hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2"); @@ -290,16 +294,30 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "cannot get otg clock\n"); } - /* Regulators */ - for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) - hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i]; + /* Regulators, vast majority of dwc2 devices don't use them at all */ + for (i = 0; i < DWC2_MAX_SUPPLIES; i++) { + reg = regulator_get_optional(hsotg->dev, +dwc2_hsotg_supply_names[i]); + + /* All or nothing (bulk): regs either are or aren't present */ + if (IS_ERR(reg)) { + while (--i >= 0) { + regulator_put(hsotg->supplies[i].consumer); + hsotg->supplies[i].consumer = NULL; + hsotg->supplies[i].supply = NULL; + --hsotg->num_supplies; + } + break; + } - ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies), - hsotg->supplies); - if (ret) { - dev_err(hsotg->dev, "failed to request supplies: %d\n", ret); - return ret; + hsotg->supplies[i].consumer =
Re: [PATCH v2] hid: usbhid: hid-core: fix recursive deadlock
On Fri, 20 Nov 2015 22:19:02 +0200 Ioan-Adrian Ratiu wrote: > The critical section protected by usbhid->lock in hid_ctrl() is too > big and because of this it causes a recursive deadlock. "Too big" means > the case statement and the call to hid_input_report() do not need to be > protected by the spinlock (no URB operations are done inside them). > > The deadlock happens because in certain rare cases drivers try to grab > the lock while handling the ctrl irq which grabs the lock before them > as described above. For example newer wacom tablets like 056a:033c try > to reschedule proximity reads from wacom_intuos_schedule_prox_event() > calling hid_hw_request() -> usbhid_request() -> usbhid_submit_report() > which tries to grab the usbhid lock already held by hid_ctrl(). > > There are two ways to get out of this deadlock: > 1. Make the drivers work "around" the ctrl critical region, in the > wacom case for ex. by delaying the scheduling of the proximity read > request itself to a workqueue. > 2. Shrink the critical region so the usbhid lock protects only the > instructions which modify usbhid state, calling hid_input_report() > with the spinlock unlocked, allowing the device driver to grab the > lock first, finish and then grab the lock afterwards in hid_ctrl(). > > This patch implements the 2nd solution. > > Signed-off-by: Ioan-Adrian Ratiu > --- > drivers/hid/usbhid/hid-core.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c > index 36712e9..5dd426f 100644 > --- a/drivers/hid/usbhid/hid-core.c > +++ b/drivers/hid/usbhid/hid-core.c > @@ -477,8 +477,6 @@ static void hid_ctrl(struct urb *urb) > struct usbhid_device *usbhid = hid->driver_data; > int unplug = 0, status = urb->status; > > - spin_lock(&usbhid->lock); > - > switch (status) { > case 0: /* success */ > if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) > @@ -498,6 +496,8 @@ static void hid_ctrl(struct urb *urb) > hid_warn(urb->dev, "ctrl urb status %d received\n", status); > } > > + spin_lock(&usbhid->lock); > + > if (unplug) { > usbhid->ctrltail = usbhid->ctrlhead; > } else { Hello again Can this please be merged in the 4.4? There are quite a few people who have their tablets deadlock and don't know how to patch their kernels so are stuck waiting for a new release. The severity of this issue is much bigger than I initially thought. Since I've posted on the wacom mailing list that I have a fix for this deadlock I've recived lots of email from people complaining of the same problem on a wide range of tablets. Some of those people know how to patch a kernel, some found this patch on the mailing list and tested it and confirmed that it works on the wacom mailing list (you can verify the deadlock + fix on that mailing list). Thank you, Adrian -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2] hid: usbhid: hid-core: fix recursive deadlock
The critical section protected by usbhid->lock in hid_ctrl() is too big and because of this it causes a recursive deadlock. "Too big" means the case statement and the call to hid_input_report() do not need to be protected by the spinlock (no URB operations are done inside them). The deadlock happens because in certain rare cases drivers try to grab the lock while handling the ctrl irq which grabs the lock before them as described above. For example newer wacom tablets like 056a:033c try to reschedule proximity reads from wacom_intuos_schedule_prox_event() calling hid_hw_request() -> usbhid_request() -> usbhid_submit_report() which tries to grab the usbhid lock already held by hid_ctrl(). There are two ways to get out of this deadlock: 1. Make the drivers work "around" the ctrl critical region, in the wacom case for ex. by delaying the scheduling of the proximity read request itself to a workqueue. 2. Shrink the critical region so the usbhid lock protects only the instructions which modify usbhid state, calling hid_input_report() with the spinlock unlocked, allowing the device driver to grab the lock first, finish and then grab the lock afterwards in hid_ctrl(). This patch implements the 2nd solution. Signed-off-by: Ioan-Adrian Ratiu --- drivers/hid/usbhid/hid-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 36712e9..5dd426f 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -477,8 +477,6 @@ static void hid_ctrl(struct urb *urb) struct usbhid_device *usbhid = hid->driver_data; int unplug = 0, status = urb->status; - spin_lock(&usbhid->lock); - switch (status) { case 0: /* success */ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) @@ -498,6 +496,8 @@ static void hid_ctrl(struct urb *urb) hid_warn(urb->dev, "ctrl urb status %d received\n", status); } + spin_lock(&usbhid->lock); + if (unplug) { usbhid->ctrltail = usbhid->ctrlhead; } else { -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] hid: usbhid: hid-core: fix recursive deadlock
On Thu, 19 Nov 2015 22:34:18 +0100 (CET) Jiri Kosina wrote: > Could you please reformulate the changelog in this respect and resubmit? Yes, of course, I tried to reformulate the problem and solution as clear and succint as I could in v2, which I'll send shortly. Thank you very much for your patience and feedback. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] hid: usbhid: hid-core: fix recursive deadlock
On Thu, 19 Nov 2015 10:10:19 +0100 (CET) Jiri Kosina wrote: > On Thu, 19 Nov 2015, Ioan-Adrian Ratiu wrote: > > > First part of lockdep report: > > http://imgur.com/clLsCWe > > > > Second part: > > http://imgur.com/Wa2PzRl > > > > Here are some printk's of mine while reproducing + debugging the issue: > > http://imgur.com/SETOHT7 > > So the real problem is that Intuos driver is calling hid_hw_request() > (which tries to grab the lock in usbhid_submit_report()) while handling > the CTRL IRQ (lock gets acquired there). > > So the proper way to fix seems to be delaying the scheduling of the > proximity read event in wacom_intuos_inout() to workqueue. > > > I'll continue to research this more in depth, but progress is slow > > because I don't have much time, I'm doing this in my spare time because > > it's my girlfriend's tablet. > > Oh, now I understand the level of severity of this bug! :-) > > Thanks, > Yes, exactly, you are beginning to understand! :) When I've put my 2 variants above to solve this deadlock, by "removing the call from wacom" at 1) I was trying to say exactly this, removing it from the irq to a workqueue. But please understand further my reasoning for submitting this patch. Consider if this is a bug in the wacom driver or in the usbhid core? IMO this is a usbhid bug: the critical region in hid_ctrl() is too big, there is no reason for the call to hid_input_report() to be protected by usbhid->lock. The correct way to fix this deadlock is to fix the critical section in usbhid, not remove the call from the wacom irq. If wacom wants to reschedule in the irq, it should not deadlock on usbhid. "Fixing" the wacom call would just work around the critical region bug inside usbhid. I hope I've made myself clear this time; I really needed to explain this patch better :( sorry. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] hid: usbhid: hid-core: fix recursive deadlock
On Wed, 18 Nov 2015 17:58:56 -0600 Josh Cartwright wrote: > On Wed, Nov 18, 2015 at 11:05:44PM +0200, Ioan-Adrian Ratiu wrote: > > On Wed, 18 Nov 2015 21:37:42 +0100 (CET) > > Jiri Kosina wrote: > > > > > On Wed, 18 Nov 2015, Ioan-Adrian Ratiu wrote: > > > > > > > The critical section protected by usbhid->lock in hid_ctrl() is too > > > > big and in rare cases causes a recursive deadlock because of its call > > > > to hid_input_report(). > > > > > > > > This deadlock reproduces on newer wacom tablets like 056a:033c because > > > > the wacom driver in its irq handler ends up calling hid_hw_request() > > > > from wacom_intuos_schedule_prox_event() in wacom_wac.c. What this means > > > > is that it submits a report to reschedule a proximity read through a > > > > sync ctrl call which grabs the lock in hid_ctrl(struct urb *urb) > > > > before calling hid_input_report(). When the irq kicks in on the same > > > > cpu, it also tries to grab the lock resulting in a recursive deadlock. > > > > > > > > The proper fix is to shrink the critical section in hid_ctrl() to > > > > protect only the instructions which modify usbhid, thus move the lock > > > > after the hid_input_report() call and the deadlock dissapears. > > > > > > I think the proper fix actually is to spin_lock_irqsave() in hid_ctrl(), > > > isn't it? > > > > > > > That was my first attempt, yes, but the deadlock still happens with > > interrupts disabled. It is very weird, I know. > > I think your best course of action is to figure out why this is the > case, instead of continuing with trying to solve the symptoms. Do you > have actual callstacks showing the cases where you hit? That might be > useful to share (your lockdep picture cuts out the callstacks). > > Also, have you tried without the PREEMPT_RT patch in the picture at all? > > Josh Yes, of course I tried it without PREEMPT_RT_FULL :) This happens on vanilla mainline kernels (only after 4.4-rc1 which introduced support for this kind of tablets). I also backported all the wacom patches to 4.1 non-RT and the same deadlock happens. I've sent another email with some lockdep traces and printk's on a running vanilla linux-next, maybe it didn't get through, here are the links again: First part of lockdep report: http://imgur.com/clLsCWe Second part: http://imgur.com/Wa2PzRl Here are some printk's of mine while reproducing + debugging the issue: http://imgur.com/SETOHT7 I'll continue to research this more in depth, but progress is slow because I don't have much time, I'm doing this in my spare time because it's my girlfriend's tablet. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] hid: usbhid: hid-core: fix recursive deadlock
On Wed, 18 Nov 2015 21:37:42 +0100 (CET) Jiri Kosina wrote: > On Wed, 18 Nov 2015, Ioan-Adrian Ratiu wrote: > > > The critical section protected by usbhid->lock in hid_ctrl() is too > > big and in rare cases causes a recursive deadlock because of its call > > to hid_input_report(). > > > > This deadlock reproduces on newer wacom tablets like 056a:033c because > > the wacom driver in its irq handler ends up calling hid_hw_request() > > from wacom_intuos_schedule_prox_event() in wacom_wac.c. What this means > > is that it submits a report to reschedule a proximity read through a > > sync ctrl call which grabs the lock in hid_ctrl(struct urb *urb) > > before calling hid_input_report(). When the irq kicks in on the same > > cpu, it also tries to grab the lock resulting in a recursive deadlock. > > > > The proper fix is to shrink the critical section in hid_ctrl() to > > protect only the instructions which modify usbhid, thus move the lock > > after the hid_input_report() call and the deadlock dissapears. > > I think the proper fix actually is to spin_lock_irqsave() in hid_ctrl(), > isn't it? > That was my first attempt, yes, but the deadlock still happens with interrupts disabled. It is very weird, I know. I tried many configurations, like disabling PREEMPT_RT and other stuff which might affect the call stack in this case, but the only two methods which actually avoid the deadlock are: 1. don't call wacom_intuos_schedule_prox_event() / hid_hw_request() from the wacom driver 2. shrink the critical region to not cover hid_input_report() inside hid_ctrl() I am very open to any ideas on how to better fix this, just to be able to use a mainline kernel with my device without out of tree patching :) -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] hid: usbhid: hid-core: fix recursive deadlock
Here are some images with more information on this deadlock, might be helpful. First part of lockdep report: http://imgur.com/clLsCWe Second part: http://imgur.com/Wa2PzRl Here are some printk's of mine while reproducing + debugging the issue: http://imgur.com/SETOHT7 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] hid: usbhid: hid-core: fix recursive deadlock
The critical section protected by usbhid->lock in hid_ctrl() is too big and in rare cases causes a recursive deadlock because of its call to hid_input_report(). This deadlock reproduces on newer wacom tablets like 056a:033c because the wacom driver in its irq handler ends up calling hid_hw_request() from wacom_intuos_schedule_prox_event() in wacom_wac.c. What this means is that it submits a report to reschedule a proximity read through a sync ctrl call which grabs the lock in hid_ctrl(struct urb *urb) before calling hid_input_report(). When the irq kicks in on the same cpu, it also tries to grab the lock resulting in a recursive deadlock. The proper fix is to shrink the critical section in hid_ctrl() to protect only the instructions which modify usbhid, thus move the lock after the hid_input_report() call and the deadlock dissapears. Signed-off-by: Ioan-Adrian Ratiu --- drivers/hid/usbhid/hid-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 36712e9..5dd426f 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -477,8 +477,6 @@ static void hid_ctrl(struct urb *urb) struct usbhid_device *usbhid = hid->driver_data; int unplug = 0, status = urb->status; - spin_lock(&usbhid->lock); - switch (status) { case 0: /* success */ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) @@ -498,6 +496,8 @@ static void hid_ctrl(struct urb *urb) hid_warn(urb->dev, "ctrl urb status %d received\n", status); } + spin_lock(&usbhid->lock); + if (unplug) { usbhid->ctrltail = usbhid->ctrlhead; } else { -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html