Hi, Pawel Laszczak writes: >>> +void cdns3_role_stop(struct cdns3 *cdns) >> >>not static? Why is it so that _start() is static but _stop() is not? >>Looks fishy > > This function is used in cdns3_role_stop in debugfs.c file so it can't > be static. it's still super fishy. Why don't you need _start() from debugfs.c? In any case, the role framework would remove the need for any of this, I suppose. >>> +static int cdns3_idle_role_start(struct cdns3 *cnds) >>> +{ /* Hold PHY in RESET */ >> >>huh? >> >>> + return 0; >>> +} >>> + >>> +static void cdns3_idle_role_stop(struct cdns3 *cnds) >>> +{ >>> + /* Program Lane swap and bring PHY out of RESET */ >> >>double huh? >> > > These functions were added for consistency with FSM described in controller specification. > Yes, I know that you don't like empty functions :), but it could be helpful in > understanding how this controller work. frankly, it really doesn't. An empty function doesn't really help IMHO. >>> +static const char *const cdns3_mode[] = { >>> + [USB_DR_MODE_UNKNOWN] = "unknown", >>> + [USB_DR_MODE_OTG] = "otg", >>> + [USB_DR_MODE_HOST] = "host", >>> + [USB_DR_MODE_PERIPHERAL] = "device", >>> +}; >> >>don't we have a generic version of this under usb/common ? >> > Yes, there is a similar array, but it is defined also as static > and there is no function for converting value to string. > There is only function for converting string to value. right. You can add the missing interface generically instead of duplicating the enumeration. > There is also: > [USB_DR_MODE_UNKNOWN] = "", > Instead of: > [USB_DR_MODE_UNKNOWN] = "unknown", > > So, for USB_DR_MODE_UNKNOWN user will not see anything information. But that's what "unknown" means :-) We don't know the information. >>> +static irqreturn_t cdns3_drd_irq(int irq, void *data) >>> +{ >>> + irqreturn_t ret = IRQ_NONE; >>> + struct cdns3 *cdns = data; >>> + u32 reg; >>> + >>> + if (cdns->dr_mode != USB_DR_MODE_OTG) >>> + return ret; >>> + >>> + reg = readl(&cdns->otg_regs->ivect); >>> + >>> + if (!reg) >>> + return ret; >>> + >>> + if (reg & OTGIEN_ID_CHANGE_INT) { >>> + dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n", >>> + cdns3_get_id(cdns)); >>> + >>> + ret = IRQ_HANDLED; >>> + } >>> + >>> + if (reg & (OTGIEN_VBUSVALID_RISE_INT | OTGIEN_VBUSVALID_FALL_INT)) { >>> + dev_dbg(cdns->dev, "OTG IRQ: new VBUS: %d\n", >>> + cdns3_get_vbus(cdns)); >>> + >>> + ret = IRQ_HANDLED; >>> + } >>> + >>> + if (ret == IRQ_HANDLED) >>> + queue_work(system_freezable_wq, &cdns->role_switch_wq); >>> + >>> + writel(~0, &cdns->otg_regs->ivect); >>> + return ret; >>> +} >> >>seems like you could use threaded irq to avoid this workqueue. > > > This function is also called in cdns3_mode_write (debugfs.c file), > therefor after changing it to threaded irq I will still need workqueue. Why? debugfs writes are not atomic. They run in process context, right? Just don't disable interrupts while running this and you should be fine. >>> + cdns->desired_dr_mode = cdns->dr_mode; >>> + cdns->current_dr_mode = USB_DR_MODE_UNKNOWN; >>> + >>> + ret = devm_request_threaded_irq(cdns->dev, cdns->otg_irq, >>> + cdns3_drd_irq, >>> + NULL, IRQF_SHARED, >> >>if you don't have a threaded handler, you should set IRQF_ONESHOT. I >>would prefer if you implement a threaded handler that doesn't require >>IRQF_ONESHOT, though. >> > > IRQF_ONESHOT can be used only in threaded handled. > " > * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished. > * Used by threaded interrupts which need to keep the > * irq line disabled until the threaded handler has been run. > " so? >>> + } else { >>> + struct usb_request *request; >>> + >>> + if (priv_dev->eps[index]->flags & EP_WEDGE) { >>> + cdns3_select_ep(priv_dev, 0x00); >>> + return 0; >>> + } >>> + >>> + cdns3_dbg(priv_ep->cdns3_dev, "Clear Stalled endpoint %s\n", >>> + priv_ep->name); >> >>why do you need your own wrapper around dev_dbg()? This looks quite unnecessary. > > It's generic function used for adding message to trace.log. It's not wrapper to dev_dbg > > void cdns3_dbg(struct cdns3_device *priv_dev, const char *fmt, ...) > { > struct va_format vaf; > va_list args; > > va_start(args, fmt); > vaf.fmt = fmt; > vaf.va = &args; > trace_cdns3_log(priv_dev, &vaf); > va_end(args); > } oh. Don't do it like that. Add a proper trace event that actually decodes the information you want. These random messages will give you trouble in the future. I had this sort of construct in dwc3 for a while and it became clear that it's a bad idea. It's best to have trace events that decode information coming from the HW. That way your trace logs have a "predictable" shape/format and you can easily find problem areas. -- balbi