net: cdc_ncm, cdc_mbim: allow user to prefer NCM for backwards compatibility
commit bd329e1 ("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: Geir Haatveit <nospam@haatveit.nu> Reported-by: Tommi Kyntola <kynde@ts.ray.fi> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=54791 Signed-off-by: Bjørn Mork <bjorn@mork.no> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a5b8db9144
commit
1e8bbe6cd0
@ -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 @@
|
|||||||
|
|
||||||
#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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
* 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 {
|
|||||||
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user