RFC: aleksander/qmi-firmware-update branch
Aleksander Morgado
aleksander at aleksander.es
Thu Jan 5 16:46:06 UTC 2017
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
>
Ouch, the transactions assertion; I need to look at that issue one of
these days again.
Anyway, in the tests I did I was able to release the clients cleanly
before the reset operation was actually done by the device; i.e. after
setting "reset" operating mode I could still do the CTL transactions
to release the CIDs. I'll try to avoid this race condition and just
ignore the CID releases, as you said it doesn't make much sense since
the device is going to get power cycled.
>
>
> 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.
>
>
Hum... what would be the rollback approach in this case? recover the
original firmware preference settings and fallback to them if any
error happens?
>
> 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
>
--reset requires an AT port as it does AT!BOOTHOLD; this is probably a
missing if() somewhere.
Anyway, maybe it's worth completely removing the cdc-wdm based device
selection? What do you think? It was the first one I had, but using
the other methods seems easier in most cases (e.g. I just do "-d 1199"
most of the times I play with the tool).
>
>
> 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:
>
It was the "suggested" way to reset the devices that don't support the
set firwmware preference command, at least that is what I could find.
> 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.
>
In the tests I've done with the MC7455, I believe the image was in
fact copied to one of the slots; but this was directly using the
automatic method which does "set firmware preference" as you said. Is
this something that we should take care of somehow? Ideally we could
detect this situation and warn it, but I'm not sure it's worth the
effort, don't know. No one should need the "manual" QDL download mode
if the automatic way works as it should, right?
> 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.
>
I think we should add the slot selection option as an optional
argument. E.g., if the user doesn't care what gets overwritten, she
can still ignore the slot id.
--
Aleksander
https://aleksander.es
More information about the libqmi-devel
mailing list