Commit 1e8bbe6c authored by Bjørn Mork's avatar Bjørn Mork Committed by David S. Miller

net: cdc_ncm, cdc_mbim: allow user to prefer NCM for backwards compatibility

commit bd329e12 ("net: cdc_ncm: do not bind to NCM compatible MBIM devices")
introduced a new policy, preferring MBIM for dual NCM/MBIM functions if
the cdc_mbim driver was enabled.  This caused a regression for users
wanting to use NCM.

Devices implementing NCM backwards compatibility according to section
3.2 of the MBIM v1.0 specification allow either NCM or MBIM on a single
USB function, using different altsettings.  The cdc_ncm and cdc_mbim
drivers will both probe such functions, and must agree on a common
policy for selecting either MBIM or NCM.  Until now, this policy has
been set at build time based on CONFIG_USB_NET_CDC_MBIM.

Use a module parameter to set the system policy at runtime, allowing the
user to prefer NCM on systems with the cdc_mbim driver.

Cc: Greg Suarez <gsuarez@smithmicro.com>
Cc: Alexey Orishko <alexey.orishko@stericsson.com>
Reported-by: default avatarGeir Haatveit <nospam@haatveit.nu>
Reported-by: default avatarTommi Kyntola <kynde@ts.ray.fi>
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=54791Signed-off-by: default avatarBjørn Mork <bjorn@mork.no>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a5b8db91
...@@ -68,18 +68,9 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -68,18 +68,9 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
struct cdc_ncm_ctx *ctx; struct cdc_ncm_ctx *ctx;
struct usb_driver *subdriver = ERR_PTR(-ENODEV); struct usb_driver *subdriver = ERR_PTR(-ENODEV);
int ret = -ENODEV; int ret = -ENODEV;
u8 data_altsetting = CDC_NCM_DATA_ALTSETTING_NCM; u8 data_altsetting = cdc_ncm_select_altsetting(dev, intf);
struct cdc_mbim_state *info = (void *)&dev->data; struct cdc_mbim_state *info = (void *)&dev->data;
/* see if interface supports MBIM alternate setting */
if (intf->num_altsetting == 2) {
if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
usb_set_interface(dev->udev,
intf->cur_altsetting->desc.bInterfaceNumber,
CDC_NCM_COMM_ALTSETTING_MBIM);
data_altsetting = CDC_NCM_DATA_ALTSETTING_MBIM;
}
/* Probably NCM, defer for cdc_ncm_bind */ /* Probably NCM, defer for cdc_ncm_bind */
if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
goto err; goto err;
......
...@@ -55,6 +55,14 @@ ...@@ -55,6 +55,14 @@
#define DRIVER_VERSION "14-Mar-2012" #define DRIVER_VERSION "14-Mar-2012"
#if IS_ENABLED(CONFIG_USB_NET_CDC_MBIM)
static bool prefer_mbim = true;
#else
static bool prefer_mbim;
#endif
module_param(prefer_mbim, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(prefer_mbim, "Prefer MBIM setting on dual NCM/MBIM functions");
static void cdc_ncm_txpath_bh(unsigned long param); static void cdc_ncm_txpath_bh(unsigned long param);
static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx); static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer); static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
...@@ -550,9 +558,12 @@ void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) ...@@ -550,9 +558,12 @@ void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
} }
EXPORT_SYMBOL_GPL(cdc_ncm_unbind); EXPORT_SYMBOL_GPL(cdc_ncm_unbind);
static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) /* Select the MBIM altsetting iff it is preferred and available,
* returning the number of the corresponding data interface altsetting
*/
u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf)
{ {
int ret; struct usb_host_interface *alt;
/* The MBIM spec defines a NCM compatible default altsetting, /* The MBIM spec defines a NCM compatible default altsetting,
* which we may have matched: * which we may have matched:
...@@ -568,23 +579,27 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -568,23 +579,27 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
* endpoint descriptors, shall be constructed according to * endpoint descriptors, shall be constructed according to
* the rules given in section 6 (USB Device Model) of this * the rules given in section 6 (USB Device Model) of this
* specification." * specification."
*
* Do not bind to such interfaces, allowing cdc_mbim to handle
* them
*/ */
#if IS_ENABLED(CONFIG_USB_NET_CDC_MBIM) if (prefer_mbim && intf->num_altsetting == 2) {
if ((intf->num_altsetting == 2) && alt = usb_altnum_to_altsetting(intf, CDC_NCM_COMM_ALTSETTING_MBIM);
!usb_set_interface(dev->udev, if (alt && cdc_ncm_comm_intf_is_mbim(alt) &&
intf->cur_altsetting->desc.bInterfaceNumber, !usb_set_interface(dev->udev,
CDC_NCM_COMM_ALTSETTING_MBIM)) { intf->cur_altsetting->desc.bInterfaceNumber,
if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) CDC_NCM_COMM_ALTSETTING_MBIM))
return -ENODEV; return CDC_NCM_DATA_ALTSETTING_MBIM;
else
usb_set_interface(dev->udev,
intf->cur_altsetting->desc.bInterfaceNumber,
CDC_NCM_COMM_ALTSETTING_NCM);
} }
#endif return CDC_NCM_DATA_ALTSETTING_NCM;
}
EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting);
static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;
/* MBIM backwards compatible function? */
cdc_ncm_select_altsetting(dev, intf);
if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
return -ENODEV;
/* NCM data altsetting is always 1 */ /* NCM data altsetting is always 1 */
ret = cdc_ncm_bind_common(dev, intf, 1); ret = cdc_ncm_bind_common(dev, intf, 1);
......
...@@ -127,6 +127,7 @@ struct cdc_ncm_ctx { ...@@ -127,6 +127,7 @@ struct cdc_ncm_ctx {
u16 connected; u16 connected;
}; };
extern u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf);
extern int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting); extern int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting);
extern void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf); extern void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
extern struct sk_buff *cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign); extern struct sk_buff *cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment