usb: musb: Allow running without CONFIG_USB_PHY
authorPaul Cercueil <paul@crapouillou.net>
Wed, 26 Oct 2022 18:26:53 +0000 (19:26 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 9 Nov 2022 11:39:13 +0000 (12:39 +0100)
Modify the core so that musb->xceiv is never deferenced without being
checked first.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Link: https://lore.kernel.org/r/20221026182657.146630-4-paul@crapouillou.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_virthub.c

index 9bf0eba..648bb60 100644 (file)
@@ -2448,7 +2448,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        else
                musb->io.set_toggle = musb_default_set_toggle;
 
-       if (!musb->xceiv->io_ops) {
+       if (IS_ENABLED(CONFIG_USB_PHY) && musb->xceiv && !musb->xceiv->io_ops) {
                musb->xceiv->io_dev = musb->controller;
                musb->xceiv->io_priv = musb->mregs;
                musb->xceiv->io_ops = &musb_ulpi_access;
index a497c44..b7588d1 100644 (file)
@@ -339,6 +339,8 @@ struct musb {
        struct usb_phy          *xceiv;
        struct phy              *phy;
 
+       enum usb_otg_state      otg_state;
+
        int nIrq;
        unsigned                irq_wake:1;
 
@@ -595,12 +597,18 @@ static inline void musb_platform_clear_ep_rxintr(struct musb *musb, int epnum)
 static inline void musb_set_state(struct musb *musb,
                                  enum usb_otg_state otg_state)
 {
-       musb->xceiv->otg->state = otg_state;
+       if (musb->xceiv)
+               musb->xceiv->otg->state = otg_state;
+       else
+               musb->otg_state = otg_state;
 }
 
 static inline enum usb_otg_state musb_get_state(struct musb *musb)
 {
-       return musb->xceiv->otg->state;
+       if (musb->xceiv)
+               return musb->xceiv->otg->state;
+
+       return musb->otg_state;
 }
 
 static inline const char *musb_otg_state_string(struct musb *musb)
index 9f5c531..66c8b32 100644 (file)
@@ -1552,9 +1552,11 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
                                break;
                }
 
-               spin_unlock_irqrestore(&musb->lock, flags);
-               otg_start_srp(musb->xceiv->otg);
-               spin_lock_irqsave(&musb->lock, flags);
+               if (musb->xceiv) {
+                       spin_unlock_irqrestore(&musb->lock, flags);
+                       otg_start_srp(musb->xceiv->otg);
+                       spin_lock_irqsave(&musb->lock, flags);
+               }
 
                /* Block idling for at least 1s */
                musb_platform_try_idle(musb,
@@ -1628,7 +1630,7 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
        struct musb     *musb = gadget_to_musb(gadget);
 
-       if (!musb->xceiv->set_power)
+       if (!musb->xceiv || !musb->xceiv->set_power)
                return -EOPNOTSUPP;
        return usb_phy_set_power(musb->xceiv, mA);
 }
@@ -1834,7 +1836,6 @@ static int musb_gadget_start(struct usb_gadget *g,
                struct usb_gadget_driver *driver)
 {
        struct musb             *musb = gadget_to_musb(g);
-       struct usb_otg          *otg = musb->xceiv->otg;
        unsigned long           flags;
        int                     retval = 0;
 
@@ -1851,7 +1852,9 @@ static int musb_gadget_start(struct usb_gadget *g,
        spin_lock_irqsave(&musb->lock, flags);
        musb->is_active = 1;
 
-       otg_set_peripheral(otg, &musb->g);
+       if (musb->xceiv)
+               otg_set_peripheral(musb->xceiv->otg, &musb->g);
+
        musb_set_state(musb, OTG_STATE_B_IDLE);
        spin_unlock_irqrestore(&musb->lock, flags);
 
@@ -1861,7 +1864,7 @@ static int musb_gadget_start(struct usb_gadget *g,
         * handles power budgeting ... this way also
         * ensures HdrcStart is indirectly called.
         */
-       if (musb->xceiv->last_event == USB_EVENT_ID)
+       if (musb->xceiv && musb->xceiv->last_event == USB_EVENT_ID)
                musb_platform_set_vbus(musb, 1);
 
        pm_runtime_mark_last_busy(musb->controller);
@@ -1899,7 +1902,9 @@ static int musb_gadget_stop(struct usb_gadget *g)
 
        musb_set_state(musb, OTG_STATE_UNDEFINED);
        musb_stop(musb);
-       otg_set_peripheral(musb->xceiv->otg, NULL);
+
+       if (musb->xceiv)
+               otg_set_peripheral(musb->xceiv->otg, NULL);
 
        musb->is_active = 0;
        musb->gadget_driver = NULL;
index b7553da..8ad39ec 100644 (file)
@@ -2722,10 +2722,14 @@ int musb_host_setup(struct musb *musb, int power_budget)
                MUSB_HST_MODE(musb);
                musb_set_state(musb, OTG_STATE_A_IDLE);
        }
-       otg_set_host(musb->xceiv->otg, &hcd->self);
+
+       if (musb->xceiv) {
+               otg_set_host(musb->xceiv->otg, &hcd->self);
+               musb->xceiv->otg->host = &hcd->self;
+       }
+
        /* don't support otg protocols */
        hcd->self.otg_port = 0;
-       musb->xceiv->otg->host = &hcd->self;
        hcd->power_budget = 2 * (power_budget ? : 250);
        hcd->skip_phy_initialization = 1;
 
index 7eb929d..2b2164e 100644 (file)
@@ -50,7 +50,6 @@ void musb_host_finish_resume(struct work_struct *work)
 
 int musb_port_suspend(struct musb *musb, bool do_suspend)
 {
-       struct usb_otg  *otg = musb->xceiv->otg;
        u8              power;
        void __iomem    *mbase = musb->mregs;
 
@@ -88,7 +87,8 @@ int musb_port_suspend(struct musb *musb, bool do_suspend)
                switch (musb_get_state(musb)) {
                case OTG_STATE_A_HOST:
                        musb_set_state(musb, OTG_STATE_A_SUSPEND);
-                       musb->is_active = otg->host->b_hnp_enable;
+                       musb->is_active = musb->xceiv &&
+                               musb->xceiv->otg->host->b_hnp_enable;
                        if (musb->is_active)
                                mod_timer(&musb->otg_timer, jiffies
                                        + msecs_to_jiffies(
@@ -97,7 +97,8 @@ int musb_port_suspend(struct musb *musb, bool do_suspend)
                        break;
                case OTG_STATE_B_HOST:
                        musb_set_state(musb, OTG_STATE_B_WAIT_ACON);
-                       musb->is_active = otg->host->b_hnp_enable;
+                       musb->is_active = musb->xceiv &&
+                               musb->xceiv->otg->host->b_hnp_enable;
                        musb_platform_try_idle(musb, 0);
                        break;
                default:
@@ -196,8 +197,6 @@ void musb_port_reset(struct musb *musb, bool do_reset)
 
 void musb_root_disconnect(struct musb *musb)
 {
-       struct usb_otg  *otg = musb->xceiv->otg;
-
        musb->port1_status = USB_PORT_STAT_POWER
                        | (USB_PORT_STAT_C_CONNECTION << 16);
 
@@ -206,7 +205,7 @@ void musb_root_disconnect(struct musb *musb)
 
        switch (musb_get_state(musb)) {
        case OTG_STATE_A_SUSPEND:
-               if (otg->host->b_hnp_enable) {
+               if (musb->xceiv && musb->xceiv->otg->host->b_hnp_enable) {
                        musb_set_state(musb, OTG_STATE_A_PERIPHERAL);
                        musb->g.is_a_peripheral = 1;
                        break;