Thales IoT Developer Community
MV31 USB variant RMNET **** and the Linux setup process
Tutorial, April 19, 2021 - 9:13pm, 12895 views
RMNET/QMI is a demanding feature to many customers, that's why it was added to MV31 USB variant in firmware version F0.0.0.5.7. This article describes the process about how to enable it, and the bring-up process when MV31 is running in RMNET **** under Linux.
Preparation on MV31
- Update the MV31 USB variant module to firmware version equals or greater than F0.0.0.5.7.
- Switch the MV31 USB Configuration via an AT command.
Switch the MV31 USB **** to RMNET
The F0.0.0.5.7 firmware added a new AT command AT+USBSWITCH to change the personality of module, please use Teraterm or any terminal emulator program on Windows 10 to apply this command to MV31:
AT+USBSWITCH=00B7
MV31 will switch to RMNET/QMI **** permanently; you can apply the same command with the parameter 00B3 to switch it back to the MBIM ****.
Preparation on Linux
Let's assume the user will use a Debian-based Linux system on a PC or any single board computer (SBC), in this case any PC/SBC running a recent version of Ubuntu/Debian or Raspberry Pi OS will work if applying below commands.
Stop the ****mManager
Before testing MV31, please remember to stop ****mManager via:
$ sudo systemctl stop ****mManager
If you want to disable it permanently, you can run this additional command:
$ sudo systemctl disable ****mManager
In this way you won't have to bother stopping it.
Install Additional Packages
The default Ubuntu/Debian installation doesn't provide some required tools, so please run this command to fill-in the gap:
$ sudo apt update && sudo apt install -y libqmi-utils udhcpc
You can download and run mv31_apt script to automate this task.
You'll need configure/change two kernel drivers to manage the MV31 in RMNET ****; they are the qmi_wwan for qmi/rmnet and option for ATC/GNSS/Diag ports.
Configure the Built-in Driver
The official kernel built by Ubuntu/Debian or Raspbian already contains the two drivers, so the simplest way is just loading them and apply some configuration.
A temporary setup can be done like this:
$ sudo modprobe qmi_wwan $ sudo modprobe option
and configure them via adding the VID PID information into the drivers' new_id field so that they can recognize the MV31:
$ echo '1e2d 00b7' | sudo tee /sys/bus/usb/drivers/qmi_wwan/new_id
$ echo '1e2d 00b7' | sudo tee /sys/bus/usb-serial/drivers/option1/new_id
The benefit of this approach is that it's easy to accomplish, and if your goal was testing RMNET feature, it works well; however the drawback is the qmi_wwan driver can wrongly take over ATC/GNSS ports and mis-configure them as another WAN ports like below:
So with this approach you won't have ATC/GNSS port to access.
A much elaborated way is changing the respective kernel source to include the PID and USB interface information to avoid any possible mis-configuration like the aforementioned one.
Modify the Driver
For option driver, depending on module firmware version and Linux kernel version, the way to modify the option driver (kernel/drivers/usb/serial/option.c,) could be different. That is because a new macro RSVD was introduced to Linux in v4.16.8, before this particular version, to ask option driver to bypass certain USB interfaces, one has to define a struct option_blacklist_info object to reserve given interface(s).
So for Linux kernel greater or equal to this version, the patch looks like below (lines to add beginning with '+'):
#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085
+ #define CINTERION_PRODUCT_BARRACUDA_MBIM 0x00B3 + #define CINTERION_PRODUCT_BARRACUDA_RMNET 0x00B7 ... { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), .driver_info = RSVD(4) },
/* For MV31 with FW < 5.0, add the line below */ + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_BARRACUDA_MBIM), .driver_info = RSVD(2) | RSVD(1) | RSVD(3) },
/* For MV31 with FW >= 5.0, add the line below */ + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_BARRACUDA_MBIM), .driver_info = RSVD(0) | RSVD(1) | RSVD(3) },
/* For MV31 with FW >= 5.7, add the line below as well */ + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_BARRACUDA_RMNET), .driver_info = RSVD(0) },
If the Linux kernel version was before 4.16.8, below lines should work:
#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085
+ #define CINTERION_PRODUCT_BARRACUDA_MBIM 0x00B3 + #define CINTERION_PRODUCT_BARRACUDA_RMNET 0x00B7 ... /* For MV31 with FW < 5.0 , add the lines below */ +static const struct option_blacklist_info cinterion_mv31_mbim_blacklist123 = { + .reserved = BIT(2) | BIT(1) | BIT(3), +}; ... { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), .driver_info = (kernel_ulong_t)&net_intf4_blacklist },/* For MV31 with FW < 5.0 */ + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_BARRACUDA), .driver_info = (kernel_ulong_t)&cinterion_mv31_mbim_blacklist123 },
/* For MV31 with FW >= 5.0, add the lines below */
+static const struct option_blacklist_info cinterion_mv31_mbim_blacklist013 = { + .reserved = BIT(0) | BIT(1) | BIT(3),
+};
/* For MV31 with FW >= 5.7, add the lines below */
+static const struct option_blacklist_info cinterion_mv31_mbim_blacklist0 = { + .reserved = BIT(0),
+};
... { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, /* For MV31 with FW < 5.0, add below line */ + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_BARRACUDA_MBIM), .driver_info = (kernel_ulong_t)&cinterion_mv31_mbim_blacklist123 }, /* Otherwise, for MV31 with FW >= 5.0, add below line */ + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_BARRACUDA_MBIM), .driver_info = (kernel_ulong_t)&cinterion_mv31_mbim_blacklist013 }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_BARRACUDA_RMNET), .driver_info = (kernel_ulong_t)&cinterion_mv31_mbim_blacklist0 },
After properly patched the source recompile the driver and deploy, then plug in the MV31.
For qmi_wwan driver, please download the corresponding Linux source for the Linux distribution you are running, edit the drivers/net/usb/qmi_wwan.c file under that Linux source tree, add the line labeled with + sign:
...
{QMI_FIXED_INTF(0x1e2d, 0x0083, 4)}, /* Cinterion PHxx,PXxx (1 RmNet + USB Audio)*/
{QMI_QUIRK_SET_DTR(0x1e2d, 0x00b0, 4)}, /* Cinterion CLS8 */
+{QMI_FIXED_INTF(0x1e2d, 0x00b7, 0)}, /* Cinterion MV31 USB variant */
...
them compile and install the modified module.
After that the new driver should be able to correctly identify the MV31 wwan0 and 3 option-based ttyUSBx port like below:
The AT command port will be mapped on /dev/ttyUSB0.
Plug-In MV31 to the Linux Device
After walk through the driver configuration steps, now you can plug-in the MV31 USB module; checking the Linux kernel message, you should find message output like below:
The PID has changed to 00b7, although in the Product Description the MV31 still wrongly call itself as Cinterion PID 0x00B3 USB Mobile Broadband.
If checking the NICs available on the system, you should find a wwan0 port show up:
Bring up the wwan0
Once the rmnet driver is up and running, we'll use qmicli as the primary tool to bring-up the wwan0. To learn which QMI command is provided by this tool, please visit https://www.freedesktop.org/software/libqmi/man/latest/qmicli.1.html for detail. Below is an example of useful commands for common usage scenario.
To make sure the module is ready, one can test it with the following command:
$ sudo qmicli -d /dev/cdc-wdm0 -p --dms-get-operating-****
This should return online like below
[/dev/cdc-wdm0] Operating **** retrieved: ****: 'online' HW restricted: 'no'
if not please try
$ sudo qmicli -d /dev/cdc-wdm0 -p --dms-get-operating-****='online'
If a SIM pin is required for the SIM card, use command bellow:
$ sudo qmicli --device=/dev/cdc-wdm0 -p --dms-uim-verify-pin=PIN,1234
The name of the related network interface to QMI control channel can be acquired with the command:
$ sudo qmicli -d /dev/cdc-wdm0 -p --get-wwan-iface wwan0
Now configure the network interface to run via the raw-ip protocol:
$ sudo ip link set wwan0 down $ echo 'Y' | sudo tee /sys/class/net/wwan0/qmi/raw_ip $ sudo ip link set wwan0 up
Once the wwan0 is up, connect the mobile network by changing the apn='YOUR_APN',username='YOUR_USERNAME',password='YOUR_PASSWORD' part of the line according to the information of your SIM & operator:
$ sudo qmicli -p -d /dev/cdc-wdm0 -p --wds-start-network="apn='YOUR_APN',username='YOUR_USERNAME',password='YOUR_PASSWORD',ip-type=4" --client-no-release-cid
When using a AT&T SIM card the output would like this:
$ sudo qmicli -d /dev/cdc-wdm0 -p --wds-start-network="ip-type=4,apn=broadband" --client-no-release-cid
[/dev/cdc-wdm0] Network started
Packet data handle: '938601328'
[/dev/cdc-wdm0] Client ID not released:
Service: 'wds'
CID: '19'
Both the network handle 938601328 and CID 19 are important because they'll be needed for --wds-stop-network command so please take note here.
Once the network was started, you can send a DHCP request on the network interface. Please note that not all DHCP clients in Linux can support Raw-IP format, udhcpc however support this for IPv4 over Raw-IP. Please apply this command to request DHCP configuration on wwan0:
$ sudo udhcpc -q -f -i wwan0 udhcpc: started, v1.30.1 udhcpc: sending discover udhcpc: sending select for 10.221.72.243 udhcpc: lease of 10.221.72.243 obtained, lease time 7200
Up until now the wwan0 has been up and running, you may check it's assignment via
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether f0:1f:af:32:95:a1 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.132/24 brd 192.168.0.255 scope global dynamic noprefixroute eno1
valid_lft 81682sec preferred_lft 81682sec
inet6 fe80::5011:eb4e:ab0a:a4fb/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether ac:b5:7d:34:32:2e brd ff:ff:ff:ff:ff:ff
inet 192.168.0.130/24 brd 192.168.0.255 scope global dynamic noprefixroute wlp2s0
valid_lft 81678sec preferred_lft 81678sec
inet6 fe80::54f:a4c1:c634:1a69/64 scope link noprefixroute
valid_lft forever preferred_lft forever
7: wwan0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
link/none
inet 10.221.72.243/29 scope global wwan0
valid_lft forever preferred_lft forever
inet6 fe80::d818:dcfa:e1b9:e612/64 scope link stable-privacy
valid_lft forever preferred_lft forever
8: wwan1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 1e:be:e4:44:73:12 brd ff:ff:ff:ff:ff:ff
9: wwan2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 1e:be:e4:44:73:12 brd ff:ff:ff:ff:ff:ff
To bring-down wwan0, you'll need to providing the network handle and CID returned at connection activation:
$ sudo qmicli --device=/dev/cdc-wdm0 -p --wds-stop-network=NETWORK_HANDLE --client-cid=CID
As aforementioned case, we can run below command the stop the rmnet:
$ sudo qmicli --device=/dev/cdc-wdm0 -p --wds-stop-network=938601328 --client-cid=19
Don't forget to remove the IP associated with wwan0:
$ sudo ip addr del 10.221.72.243/29 dev wwan0
I prepared a bash script: mv31_qmi_test.zip for anyone who is interested to quickly test run these commands, a sample output log from that script is copied below for reference:
libqmi version used: qmicli 1.24.8 Copyright (C) 2012-2019 Aleksander Morgado License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. sudo qmicli -d /dev/cdc-wdm0 -p --dms-get-software-version [/dev/cdc-wdm0] Software version: T99W175.F0.0.0.5.7 Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --get-wwan-iface wwan0 Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --dms-get-operating-**** [/dev/cdc-wdm0] Operating **** retrieved: ****: 'online' HW restricted: 'no' Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --dms-get-ids [/dev/cdc-wdm0] Device IDs retrieved: ESN: '0' IMEI: '351859110037672' MEID: 'unknown' IMEI SV: '4' Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --dms-get-****l [/dev/cdc-wdm0] Device ****l retrieved: ****l: 'Thales Snapdragon X55' Press ENTER to continue... sudo qmicli --device=/dev/cdc-wdm0 -p --dms-get-manufacturer [/dev/cdc-wdm0] Device manufacturer retrieved: Manufacturer: 'Thales' Press ENTER to continue... sudo qmicli --device=/dev/cdc-wdm0 -p --dms-get-revision [/dev/cdc-wdm0] Device revision retrieved: Revision: '㥔圹㜱⸵う〮〮㔮㜮䄮⹔〰㜰‶ㄠ†佛瑣㈠″〲〲ㄠ㨴〰〺崰' Press ENTER to continue... sudo qmicli --device=/dev/cdc-wdm0 -p --uim-get-card-status [/dev/cdc-wdm0] Successfully got card status Provisioning applications: Primary GW: slot '1', application '1' Primary 1X: session doesn't exist Secondary GW: session doesn't exist Secondary 1X: session doesn't exist Slot [1]: Card state: 'present' UPIN state: 'not-initialized' UPIN retries: '0' UPUK retries: '0' Application [1]: Application type: 'usim (2)' Application state: 'ready' Application ID: A0:00:00:00:87:10:02:FF:FF:FF:FF:89:03:02:00:00 Personalization state: 'ready' UPIN replaces PIN1: 'no' PIN1 state: 'disabled' PIN1 retries: '3' PUK1 retries: '10' PIN2 state: 'enabled-not-verified' PIN2 retries: '3' PUK2 retries: '10' Application [2]: Application type: 'isim (5)' Application state: 'detected' Application ID: A0:00:00:00:87:10:04:FF:FF:FF:FF:89:03:02:00:00 Personalization state: 'unknown' UPIN replaces PIN1: 'no' PIN1 state: 'disabled' PIN1 retries: '3' PUK1 retries: '10' PIN2 state: 'not-initialized' PIN2 retries: '0' PUK2 retries: '0' Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --nas-get-serving-system [/dev/cdc-wdm0] Successfully got serving system: Registration state: 'registered' CS: 'attached' PS: 'attached' Selected network: '3gpp' Radio interfaces: '1' [0]: 'lte' Roaming status: 'off' Data service capabilities: '1' [0]: 'lte' Current PLMN: MCC: '310' MNC: '410' Description: 'AT&T' Roaming indicators: '1' [0]: 'off' (lte) 3GPP time zone offset: '-480' minutes 3GPP daylight saving time adjustment: '0' hours 3GPP cell ID: '107898902' Detailed status: Status: 'available' Capability: 'cs-ps' HDR Status: 'none' HDR Hybrid: 'no' Forbidden: 'no' LTE tracking area code: '37143' Full operator code info: MCC: '310' MNC: '410' MNC with PCS digit: 'yes' Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --nas-get-signal-info [/dev/cdc-wdm0] Successfully got signal info LTE: RSSI: '-54 dBm' RSRQ: '-18 dB' RSRP: '-92 dBm' SNR: '10.0 dB' Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --nas-get-system-info [/dev/cdc-wdm0] Successfully got system info: WCDMA service: Status: 'none' True Status: 'none' Preferred data path: 'no' LTE service: Status: 'available' True Status: 'available' Preferred data path: 'no' Domain: 'cs-ps' Service capability: 'cs-ps' Roaming status: 'off' Forbidden: 'no' Cell ID: '107898902' MCC: '310' MNC: '410' Tracking Area Code: '37143' Voice support: 'no' IMS voice support: 'yes' eMBMS coverage info support: 'no' eMBMS coverage info trace ID: '65535' Cell access: 'all-calls' Registration restriction: 'unrestricted' Registration domain: 'not-applicable' SIM reject info: 'available' Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --get-expected-data-format 802-3 Press ENTER to continue... sudo ip link set wwan0 down Press ENTER to continue... echo 'Y' | sudo tee /sys/class/net/wwan0/qmi/raw_ip Y Press ENTER to continue... sudo ip link set wwan0 up Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --wds-start-network="ip-type=4,apn=broadband" --client-no-release-cid [/dev/cdc-wdm0] Network started Packet data handle: '4010122464' [/dev/cdc-wdm0] Client ID not released: Service: 'wds' CID: '19' Press ENTER to continue... sudo qmicli -d /dev/cdc-wdm0 -p --wds-get-current-settings [/dev/cdc-wdm0] Current settings retrieved: IP Family: IPv4 IPv4 address: 10.104.71.12 IPv4 subnet mask: 255.255.255.248 IPv4 gateway address: 10.104.71.13 IPv4 primary DNS: 172.26.38.1 MTU: 1430 Domains: none Press ENTER to continue... sudo udhcpc -q -f -i wwan0 udhcpc: started, v1.30.1 udhcpc: sending discover udhcpc: sending select for 10.104.71.12 udhcpc: lease of 10.104.71.12 obtained, lease time 7200 Press ENTER to continue... Current Linux IP configuration: 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether f0:1f:af:32:95:a1 brd ff:ff:ff:ff:ff:ff inet 192.168.0.132/24 brd 192.168.0.255 scope global dynamic noprefixroute eno1 valid_lft 73025sec preferred_lft 73025sec inet6 fe80::5011:eb4e:ab0a:a4fb/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether ac:b5:7d:34:32:2e brd ff:ff:ff:ff:ff:ff inet 192.168.0.130/24 brd 192.168.0.255 scope global dynamic noprefixroute wlp2s0 valid_lft 73021sec preferred_lft 73021sec inet6 fe80::54f:a4c1:c634:1a69/64 scope link noprefixroute valid_lft forever preferred_lft forever 4: wwan0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000 link/none inet 10.104.71.12/29 scope global wwan0 valid_lft forever preferred_lft forever inet6 fe80::7fa6:c522:4ac7:9038/64 scope link stable-privacy valid_lft forever preferred_lft forever default via 10.104.71.13 dev wwan0 default via 192.168.0.1 dev eno1 proto dhcp metric 100 default via 192.168.0.1 dev wlp2s0 proto dhcp metric 600 10.104.71.8/29 dev wwan0 proto kernel scope link src 10.104.71.12 169.254.0.0/16 dev wlp2s0 scope link metric 1000 192.168.0.0/24 dev eno1 proto kernel scope link src 192.168.0.132 metric 100 192.168.0.0/24 dev wlp2s0 proto kernel scope link src 192.168.0.130 metric 600 Press ENTER to continue... Ping test via wwan0: PING 8.8.8.8 (8.8.8.8) from 10.104.71.12 wwan0: 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=114 time=75.0 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=114 time=70.9 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=114 time=67.0 ms 64 bytes from 8.8.8.8: icmp_seq=4 ttl=114 time=61.0 ms ...
References:
You can refer to below sites for qmicli related information:
https://www.freedesktop.org/software/libqmi/man/latest/qmicli.1.html
Is there a plan to describe the setup process for PCIe (MHI) variant of the MV31-W modem?
Where we can find a support for that version?
PCIe variant requires deeper knowledge for kernel integration, better use a dedicate CSP to drive HQ support.
Best Regards,
Antony Shen
Is there any difference in driver modification for USB and PCIe version of MV31 module?
PCIe version require MHA driver to work with the MV31, please contact TS for detail.
Best Regards,
Antony Shen