forked from openwrt/openwrt
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into fix-814-v6.6-0012-nvmem-sec
- Loading branch information
Showing
49 changed files
with
4,080 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
229 changes: 229 additions & 0 deletions
229
.../generic/backport-5.15/795-v6.3-01-r8152-add-USB-device-driver-for-config-selection.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
From ec51fbd1b8a2bca2948dede99c14ec63dc57ff6b Mon Sep 17 00:00:00 2001 | ||
From: Bjørn Mork <bjorn@mork.no> | ||
Date: Fri, 6 Jan 2023 17:07:38 +0100 | ||
Subject: [PATCH] r8152: add USB device driver for config selection | ||
MIME-Version: 1.0 | ||
Content-Type: text/plain; charset=UTF-8 | ||
Content-Transfer-Encoding: 8bit | ||
|
||
Subclassing the generic USB device driver to override the | ||
default configuration selection regardless of matching interface | ||
drivers. | ||
|
||
The r815x family devices expose a vendor specific function which | ||
the r8152 interface driver wants to handle. This is the preferred | ||
device mode. Additionally one or more USB class functions are | ||
usually supported for hosts lacking a vendor specific driver. The | ||
choice is USB configuration based, with one alternate function per | ||
configuration. | ||
|
||
Example device with both NCM and ECM alternate cfgs: | ||
|
||
T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 4 Spd=5000 MxCh= 0 | ||
D: Ver= 3.20 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 9 #Cfgs= 3 | ||
P: Vendor=0bda ProdID=8156 Rev=31.00 | ||
S: Manufacturer=Realtek | ||
S: Product=USB 10/100/1G/2.5G LAN | ||
S: SerialNumber=001000001 | ||
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=256mA | ||
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=00 Driver=r8152 | ||
E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms | ||
E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms | ||
E: Ad=83(I) Atr=03(Int.) MxPS= 2 Ivl=128ms | ||
C: #Ifs= 2 Cfg#= 2 Atr=a0 MxPwr=256mA | ||
I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0d Prot=00 Driver= | ||
E: Ad=83(I) Atr=03(Int.) MxPS= 16 Ivl=128ms | ||
I: If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=01 Driver= | ||
I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=01 Driver= | ||
E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms | ||
E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms | ||
C: #Ifs= 2 Cfg#= 3 Atr=a0 MxPwr=256mA | ||
I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=06 Prot=00 Driver= | ||
E: Ad=83(I) Atr=03(Int.) MxPS= 16 Ivl=128ms | ||
I: If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=00 Driver= | ||
I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver= | ||
E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms | ||
E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms | ||
|
||
A problem with this is that Linux will prefer class functions over | ||
vendor specific functions. Using the above example, Linux defaults | ||
to cfg #2, running the device in a sub-optimal NCM mode. | ||
|
||
Previously we've attempted to work around the problem by | ||
blacklisting the devices in the ECM class driver "cdc_ether", and | ||
matching on the ECM class function in the vendor specific interface | ||
driver. The latter has been used to switch back to the vendor | ||
specific configuration when the driver is probed for a class | ||
function. | ||
|
||
This workaround has several issues; | ||
- class driver blacklists is additional maintanence cruft in an | ||
unrelated driver | ||
- class driver blacklists prevents users from optionally running | ||
the devices in class mode | ||
- each device needs double match entries in the vendor driver | ||
- the initial probing as a class function slows down device | ||
discovery | ||
|
||
Now these issues have become even worse with the introduction of | ||
firmware supporting both NCM and ECM, where NCM ends up as the | ||
default mode in Linux. To use the same workaround, we now have | ||
to blacklist the devices in to two different class drivers and | ||
add yet another match entry to the vendor specific driver. | ||
|
||
This patch implements an alternative workaround strategy - | ||
independent of the interface drivers. It avoids adding a | ||
blacklist to the cdc_ncm driver and will let us remove the | ||
existing blacklist from the cdc_ether driver. | ||
|
||
As an additional bonus, removing the blacklists allow users to | ||
select one of the other device modes if wanted. | ||
|
||
Signed-off-by: Bjørn Mork <bjorn@mork.no> | ||
Signed-off-by: David S. Miller <davem@davemloft.net> | ||
--- | ||
drivers/net/usb/r8152.c | 113 ++++++++++++++++++++++++++++------------ | ||
1 file changed, 81 insertions(+), 32 deletions(-) | ||
|
||
--- a/drivers/net/usb/r8152.c | ||
+++ b/drivers/net/usb/r8152.c | ||
@@ -9625,6 +9625,9 @@ static int rtl8152_probe(struct usb_inte | ||
if (version == RTL_VER_UNKNOWN) | ||
return -ENODEV; | ||
|
||
+ if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) | ||
+ return -ENODEV; | ||
+ | ||
if (!rtl_vendor_mode(intf)) | ||
return -ENODEV; | ||
|
||
@@ -9834,43 +9837,35 @@ static void rtl8152_disconnect(struct us | ||
} | ||
} | ||
|
||
-#define REALTEK_USB_DEVICE(vend, prod) { \ | ||
- USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC), \ | ||
-}, \ | ||
-{ \ | ||
- USB_DEVICE_AND_INTERFACE_INFO(vend, prod, USB_CLASS_COMM, \ | ||
- USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), \ | ||
-} | ||
|
||
/* table of devices that work with this driver */ | ||
static const struct usb_device_id rtl8152_table[] = { | ||
/* Realtek */ | ||
- REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8050), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8053), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8155), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8156), | ||
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x8050) }, | ||
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x8053) }, | ||
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x8152) }, | ||
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x8153) }, | ||
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x8155) }, | ||
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x8156) }, | ||
|
||
/* Microsoft */ | ||
- REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0c5e), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3054), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3062), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3069), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3082), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x720c), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7214), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x721e), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0xa387), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff), | ||
- REALTEK_USB_DEVICE(VENDOR_ID_TPLINK, 0x0601), | ||
+ { USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab) }, | ||
+ { USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6) }, | ||
+ { USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927) }, | ||
+ { USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x304f) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x3054) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x3062) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x3069) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x3082) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x7205) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x720c) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x7214) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x721e) }, | ||
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0xa387) }, | ||
+ { USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041) }, | ||
+ { USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff) }, | ||
+ { USB_DEVICE(VENDOR_ID_TPLINK, 0x0601) }, | ||
{} | ||
}; | ||
|
||
@@ -9890,7 +9885,61 @@ static struct usb_driver rtl8152_driver | ||
.disable_hub_initiated_lpm = 1, | ||
}; | ||
|
||
-module_usb_driver(rtl8152_driver); | ||
+static int rtl8152_cfgselector_probe(struct usb_device *udev) | ||
+{ | ||
+ struct usb_host_config *c; | ||
+ int i, num_configs; | ||
+ | ||
+ /* The vendor mode is not always config #1, so to find it out. */ | ||
+ c = udev->config; | ||
+ num_configs = udev->descriptor.bNumConfigurations; | ||
+ for (i = 0; i < num_configs; (i++, c++)) { | ||
+ struct usb_interface_descriptor *desc = NULL; | ||
+ | ||
+ if (!c->desc.bNumInterfaces) | ||
+ continue; | ||
+ desc = &c->intf_cache[0]->altsetting->desc; | ||
+ if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC) | ||
+ break; | ||
+ } | ||
+ | ||
+ if (i == num_configs) | ||
+ return -ENODEV; | ||
+ | ||
+ if (usb_set_configuration(udev, c->desc.bConfigurationValue)) { | ||
+ dev_err(&udev->dev, "Failed to set configuration %d\n", | ||
+ c->desc.bConfigurationValue); | ||
+ return -ENODEV; | ||
+ } | ||
+ | ||
+ return 0; | ||
+} | ||
+ | ||
+static struct usb_device_driver rtl8152_cfgselector_driver = { | ||
+ .name = MODULENAME "-cfgselector", | ||
+ .probe = rtl8152_cfgselector_probe, | ||
+ .id_table = rtl8152_table, | ||
+ .generic_subclass = 1, | ||
+}; | ||
+ | ||
+static int __init rtl8152_driver_init(void) | ||
+{ | ||
+ int ret; | ||
+ | ||
+ ret = usb_register_device_driver(&rtl8152_cfgselector_driver, THIS_MODULE); | ||
+ if (ret) | ||
+ return ret; | ||
+ return usb_register(&rtl8152_driver); | ||
+} | ||
+ | ||
+static void __exit rtl8152_driver_exit(void) | ||
+{ | ||
+ usb_deregister(&rtl8152_driver); | ||
+ usb_deregister_device_driver(&rtl8152_cfgselector_driver); | ||
+} | ||
+ | ||
+module_init(rtl8152_driver_init); | ||
+module_exit(rtl8152_driver_exit); | ||
|
||
MODULE_AUTHOR(DRIVER_AUTHOR); | ||
MODULE_DESCRIPTION(DRIVER_DESC); |
Oops, something went wrong.