RFC: aleksander/qmi-firmware-update branch

Bjørn Mork bjorn at mork.no
Wed Jan 4 14:56:22 UTC 2017


Bjørn Mork <bjorn at mork.no> writes:

> Aleksander Morgado <aleksander at aleksander.es> writes:
>
>> Hey,
>>
>> I took Bjørn's swi-update program and extended it into a
>> "qmi-firmware-update" which handles the whole firmware update process.
>>
>> https://cgit.freedesktop.org/libqmi/log/?h=aleksander/qmi-firmware-update
>>
>> Comments welcome!
>
> Nice!  Thanks.  Looking forward to playing with this.

So I finally did some experiments with this code.  First attempt was to
upgrade my EM7455 in MBIM mode from 02.23.00.00 to 02.23.00.00, using


root at miraculix:/tmp# qmi-firmware-update -v -w /dev/cdc-wdm0 -p --device-open-mbim \
  --update \
  ~bjorn/docs/hardware/sierra/em7455/firmware/SWI9X30C_02.23.00.00.cwe \
  ~bjorn/docs/hardware/sierra/em7455/firmware/SWI9X30C_02.23.00.00_Generic_002.018_000.nvu


This started out looking good, verifying the image and pri and
automaticall configuring the matching firmware preference. But it failed
to actually write the new image becasue it tries too hard to close the
QMI device cleanly:


[04 Jan 2017, 14:46:02] [Debug] [qfu-updater] setting operating mode 'reset'...
[04 Jan 2017, 14:46:02] [Debug] [/dev/cdc-wdm0] Sent message...
<<<<<< RAW:
<<<<<<   length = 17
<<<<<<   data   = 01:10:00:00:02:03:00:04:00:2E:00:04:00:01:01:00:04

[04 Jan 2017, 14:46:02] [Debug] [/dev/cdc-wdm0] Sent message (translated)...
<<<<<< QMUX:
<<<<<<   length  = 16
<<<<<<   flags   = 0x00
<<<<<<   service = "dms"
<<<<<<   client  = 3
<<<<<< QMI:
<<<<<<   flags       = "none"
<<<<<<   transaction = 4
<<<<<<   tlv_length  = 4
<<<<<<   message     = "Set Operating Mode" (0x002E)
<<<<<< TLV:
<<<<<<   type       = "Mode" (0x01)
<<<<<<   length     = 1
<<<<<<   value      = 04
<<<<<<   translated = reset

..

[04 Jan 2017, 14:46:02] [Debug] [/dev/cdc-wdm0] Received MBIM message
[04 Jan 2017, 14:46:02] [Debug] [/dev/cdc-wdm0] Received message...
>>>>>> RAW:
>>>>>>   length = 20
>>>>>>   data   = 01:13:00:80:02:03:02:04:00:2E:00:07:00:02:04:00:00:00:00:00

[04 Jan 2017, 14:46:02] [Debug] [/dev/cdc-wdm0] Received message (translated)...
>>>>>> QMUX:
>>>>>>   length  = 19
>>>>>>   flags   = 0x80
>>>>>>   service = "dms"
>>>>>>   client  = 3
>>>>>> QMI:
>>>>>>   flags       = "response"
>>>>>>   transaction = 4
>>>>>>   tlv_length  = 7
>>>>>>   message     = "Set Operating Mode" (0x002E)
>>>>>> TLV:
>>>>>>   type       = "Result" (0x02)
>>>>>>   length     = 4
>>>>>>   value      = 00:00:00:00
>>>>>>   translated = SUCCESS

[04 Jan 2017, 14:46:02] [Debug] [qfu-updater] operating mode set successfully...
[04 Jan 2017, 14:46:02] [Debug] [qfu-updater] releasing DMS QMI client...
[04 Jan 2017, 14:46:02] [Debug] [/dev/cdc-wdm0] Releasing 'dms' client with flags 'release-cid'...
[04 Jan 2017, 14:46:02] [Debug] [/dev/cdc-wdm0] Unregistered 'dms' client with ID '3'
[04 Jan 2017, 14:46:02] [Debug] [/dev/cdc-wdm0] Sent message...
<<<<<< RAW:
<<<<<<   length = 17
<<<<<<   data   = 01:10:00:00:00:00:00:02:23:00:05:00:01:02:00:02:03

[04 Jan 2017, 14:46:02] [Debug] [/dev/cdc-wdm0] Sent message (translated)...
<<<<<< QMUX:
<<<<<<   length  = 16
<<<<<<   flags   = 0x00
<<<<<<   service = "ctl"
<<<<<<   client  = 0
<<<<<< QMI:
<<<<<<   flags       = "none"
<<<<<<   transaction = 2
<<<<<<   tlv_length  = 5
<<<<<<   message     = "Release CID" (0x0023)
<<<<<< TLV:
<<<<<<   type       = "Release Info" (0x01)
<<<<<<   length     = 2
<<<<<<   value      = 02:03
<<<<<<   translated = [ service = 'dms' cid = '3' ]




This will of course never work... The modem was just reset. There is
nothing to talk to anymore. The utility should simply close the
/dev/cdc-wdm0 device unconditionally and move on.

Instead we end up with:


[04 Jan 2017, 14:46:12] [Debug] [qfu-updater] error (ignored): couldn't release DMS QMI client: MBIM error: Transaction timed out
[04 Jan 2017, 14:46:12] [Debug] [/dev/cdc-wdm0] Sent message...
<<<<<< RAW:
<<<<<<   length = 12
<<<<<<   data   = 02:00:00:00:0C:00:00:00:09:00:00:00

[04 Jan 2017, 14:46:12] [Debug] [/dev/cdc-wdm0] Sent message (translated)...
<<<<<< Header:
<<<<<<   length      = 12
<<<<<<   type        = close (0x00000002)
<<<<<<   transaction = 9

[04 Jan 2017, 14:46:22] [Debug] [qfu-updater] error (ignored): couldn't close QMI device: Transaction timed out
**
Qmi:ERROR:qmi-device.c:3262:finalize: assertion failed: (g_hash_table_size (self->priv->transactions) == 0)
Aborted



And I wonder if the error handling shouldn't be more focused on
rollback?  The modem will end up in a soft-failing state if anything
goes wrong between the "Set Firmware Preference" and the final boot into
the new image.

The above resulted in an updated firmware-preference:


root at miraculix:/tmp# qmicli -p --device-open-mbim  -d /dev/cdc-wdm0 --dms-get-firmware-preference
firmware preference successfully retrieved:
[image 0]
        Image type: 'modem'
        Unique ID:  '002.018_000'
        Build ID:   '02.23.00.00_GENERIC'
[image 1]
        Image type: 'pri'
        Unique ID:  '002.018_000'
        Build ID:   '02.23.00.00_GENERIC'


But no matching image:


root at miraculix:/tmp# qmicli -p --device-open-mbim  -d /dev/cdc-wdm0  --dms-list-stored-images
[/dev/cdc-wdm0] Device list of stored images retrieved:

        [0] Type:    'modem'
            Maximum: '4'

                [modem0]
                Unique ID:     '?_?'
                Build ID:      '02.20.03.00_?'
                Storage index: '1'
                Failure count: '0'

                [modem1]
                Unique ID:     '?_?'
                Build ID:      '02.08.02.00_?'
                Storage index: '2'
                Failure count: '0'

                [modem2]
                Unique ID:     '?_?'
                Build ID:      '02.14.03.00_?'
                Storage index: '3'
                Failure count: '0'

                [modem3]
                Unique ID:     '?_?'
                Build ID:      '02.18.02.00_?'
                Storage index: '4'
                Failure count: '0'

        [1] Type:    'pri'
            Maximum: '50'

                [pri0]
                Unique ID:     '002.017_000'
                Build ID:      '02.20.03.00_GENERIC'

                [pri1]
                Unique ID:     '002.006_000'
                Build ID:      '02.08.02.00_ORANGE-EU'



at!image?
TYPE SLOT STATUS LRU FAILURES UNIQUE_ID   BUILD_ID
FW   1    GOOD   22  0 0      ?_?         02.20.03.00_?
FW   2    GOOD   21  0 0      ?_?         02.08.02.00_?
FW   3    GOOD   18  0 0      ?_?         02.14.03.00_?
FW   4    GOOD   17  0 0      ?_?         02.18.02.00_?
Max FW images: 4
Active FW image is at slot 255

TYPE SLOT STATUS LRU FAILURES UNIQUE_ID   BUILD_ID
PRI  FF   GOOD   0   0 0      002.017_000 02.20.03.00_GENERIC
PRI  FF   GOOD   0   0 0      002.006_000 02.08.02.00_ORANGE-EU
Max PRI images: 50


OK
at!impref?
!IMPREF: 
 preferred fw version:    02.23.00.00
 preferred carrier name:  GENERIC
 preferred config name:   GENERIC_002.018_000
 current fw version:      02.20.03.00
 current carrier name:    GENERIC
 current config name:     GENERIC_002.017_000

 fw version mismatch
 config name mismatch

OK


So we have a mismatch and IMSWITCH is asserted:

at!pcinfo?
State: Low Power Mode
LPM voters - Temp:0, Volt:0, User:0, W_DISABLE:0, IMSWITCH:1, BIOS:1, LWM2M:0, OMADM:0, FOTA:0
LPM persistence - None

OK



No big deal, of course.  This can easily be fixed by either changing the
firmware preference or uploading the image, but it's not exactly user
friendly.



Also a bit confusing: "reset" will not work with with the MBIM device
path as selector:

root at miraculix:/tmp# qmi-firmware-update -v -w /dev/cdc-wdm0 -p --device-open-mbim  --reset 
error: device not specified



But resetting by USB device ID and then uploading in QDL mode work
flawlessly.  Although I didn't expect "reset" to use the AT command:

root at miraculix:/tmp# qmi-firmware-update -v -d 1199:9079 --reset
[04 Jan 2017, 15:12:58] [Debug] [vid 0x1199, pid 0x9079] sysfs path: /sys/devices/pci0000:00/0000:00:14.0/usb1/1-2
[04 Jan 2017, 15:12:58] [Debug] using tty device #0: /dev/ttyUSB2
[04 Jan 2017, 15:12:58] [Debug] using tty device #1: /dev/ttyUSB1
[04 Jan 2017, 15:12:58] [Debug] using tty device #2: /dev/ttyUSB0
[04 Jan 2017, 15:12:58] [Debug] [qfu-at-device,ttyUSB0] opening TTY
[04 Jan 2017, 15:12:58] [Debug] [qfu-at-device,ttyUSB0] setting up serial port...
[04 Jan 2017, 15:12:58] [Debug] [qfu-at-device,ttyUSB1] opening TTY
[04 Jan 2017, 15:12:58] [Debug] [qfu-at-device,ttyUSB1] setting up serial port...
[04 Jan 2017, 15:12:58] [Debug] [qfu-at-device,ttyUSB2] opening TTY
[04 Jan 2017, 15:12:58] [Debug] [qfu-at-device,ttyUSB2] setting up serial port...
[04 Jan 2017, 15:12:58] [Debug] [qfu-at-device,ttyUSB2] >> AT!BOOTHOLD
[04 Jan 2017, 15:12:58] [Debug] [qfu-at-device,ttyUSB2] << OK
reseter operation finished successfully



root at miraculix:/tmp# qmi-firmware-update -v -d 1199:9078  --update-qdl ~bjorn/docs/hardware/sierra/em7455/firmware/SWI9X30C_02.23.00.00.cwe  ~bjorn/docs/hardware/sierra/em7455/firmware/SWI9X30C_02.23.00.00_Generic_002.018_000.nvu
..
[04 Jan 2017, 15:14:21] [Debug] [qfu-updater] no more files to download
[04 Jan 2017, 15:14:21] [Debug] [qfu-updater] QDL reset
[04 Jan 2017, 15:14:21] [Debug] [qfu,qdl-message] sent reset-req:
[04 Jan 2017, 15:14:21] [Debug] [qfu-qdl-device] >> 2D [1, unframed]
[04 Jan 2017, 15:14:21] [Debug] [qfu-qdl-device] >> 7E:2D:9F:0A:7E [5]
rebooting in normal mode...
[04 Jan 2017, 15:14:21] [Debug] [qfu-updater] operation finished
firmware update operation finished successfully



Which updated the running image as expected:


at!impref?
!IMPREF: 
 preferred fw version:    02.23.00.00
 preferred carrier name:  GENERIC
 preferred config name:   GENERIC_002.018_000
 current fw version:      02.23.00.00
 current carrier name:    GENERIC
 current config name:     GENERIC_002.018_000

OK


But the bootloader didn't copy this image to any of the 4 firmware
backup partitions. The image was installed directly in the "modem"
partition, but does not appear in the list of available image versions:

at!image?
TYPE SLOT STATUS LRU FAILURES UNIQUE_ID   BUILD_ID
FW   1    GOOD   22  0 0      ?_?         02.20.03.00_?
FW   2    GOOD   21  0 0      ?_?         02.08.02.00_?
FW   3    GOOD   18  0 0      ?_?         02.14.03.00_?
FW   4    GOOD   17  0 0      ?_?         02.18.02.00_?
Max FW images: 4
Active FW image is at slot 255

TYPE SLOT STATUS LRU FAILURES UNIQUE_ID   BUILD_ID
PRI  FF   GOOD   0   0 0      002.018_000 02.23.00.00_GENERIC
PRI  FF   GOOD   0   0 0      002.006_000 02.08.02.00_ORANGE-EU
Max PRI images: 50


OK




I'm not 100% sure about this, but the experiments I've done so far seems
to indicate that this happens if we force the device into QDL mode
instead of letting the bootloader decide.  This should work as requested
if we avoid aborting after reset.  The bootloader will then enter QDL
mode as a result of "set firmware preference" + "reset", and the upload
is copied to one of the slots.

Which slot this is, is another question.  I thought the auto-selection
worked fine, but that was only when there were empty slots.  Now, when
all 4 slots were occupied, the bootloader actually decided to overwrite
the last used slot instead of the least used one:


at!image?
TYPE SLOT STATUS LRU FAILURES UNIQUE_ID   BUILD_ID
FW   1    GOOD   22  0 0      ?_?         02.23.00.00_?
FW   2    GOOD   21  0 0      ?_?         02.08.02.00_?
FW   3    GOOD   18  0 0      ?_?         02.14.03.00_?
FW   4    GOOD   17  0 0      ?_?         02.18.02.00_?
Max FW images: 4
Active FW image is at slot 1

TYPE SLOT STATUS LRU FAILURES UNIQUE_ID   BUILD_ID
PRI  FF   GOOD   0   0 0      002.018_000 02.23.00.00_GENERIC
PRI  FF   GOOD   0   0 0      002.006_000 02.08.02.00_ORANGE-EU
Max PRI images: 50



Not perfect.  Maybe we need to implement a slot selection algorithm as
well? There is an optional 1-byte TLV 0x10 to the "Set Firmware
Preference" requests, which can be used to select a specific slot.




Bjørn


More information about the libqmi-devel mailing list