From: "Peter E. Berger" <pberger@xxxxxxxxxxx> The io_ti driver fails to download firmware to Edgeport devices such as the EP/416, even when the on-disk firmware image (/lib/firmware/edgeport/down3.bin) is more current than the version on the EP/416. The current download code is broken in a few ways. Notably it mis-uses global variables OperationalMajorVersion and OperationalMinorVersion (reading their values before they've been properly initialized and subsequently initializing them multiple times without synchronization) and using an insufficient timeout in ti_vsend_sync() when doing UMPC_COPY_DNLD_TO_I2C operations. With this patch, firmware downloads work as expected: if the on disk firmware version is newer than that on the device, it will be downloaded. Signed-off-by: Peter E. Berger <pberger@xxxxxxxxxxx> --- drivers/usb/serial/io_ti.c | 72 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index c882716..23ed61f 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -188,10 +188,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static unsigned char OperationalMajorVersion; -static unsigned char OperationalMinorVersion; -static unsigned short OperationalBuildNumber; - static int closing_wait = EDGE_CLOSING_WAIT; static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ @@ -213,6 +209,25 @@ static int edge_remove_sysfs_attrs(struct usb_serial_port *port); /* Newer Edgeport firmware disconnects ports after periods of inactivity */ #define EP_HEARTBEAT_SECS 15 +int wrap_request_firmware(const struct firmware **fw, struct device *dev, + __u8 *MajorVersion, __u8 *MinorVersion, __u16 *BuildNumber) +{ + const char *fw_name = "edgeport/down3.bin"; + int err; + + err = request_firmware(fw, fw_name, dev); + if (err) { + dev_dbg(dev, "%s - Failed to load image \"%s\" err %d\n", + __func__, fw_name, err); + } else { + /* Save Download Version Number */ + *MajorVersion = (*fw)->data[0]; + *MinorVersion = (*fw)->data[1]; + *BuildNumber = le16_to_cpup((__le16 *)&(*fw)->data[2]); + } + return err; +} + static int ti_vread_sync(struct usb_device *dev, __u8 request, __u16 value, __u16 index, u8 *data, int size) { @@ -235,10 +250,13 @@ static int ti_vsend_sync(struct usb_device *dev, __u8 request, __u16 value, __u16 index, u8 *data, int size) { int status; + int timeout = 1000; /* Timeout in msecs */ + if (request == UMPC_COPY_DNLD_TO_I2C) /* Downloads take longer */ + timeout = 10000; status = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), - value, index, data, size, 1000); + value, index, data, size, timeout); if (status < 0) return status; if (status != size) { @@ -762,7 +780,9 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) struct ti_i2c_image_header *img_header; struct ti_i2c_firmware_rec *firmware_rec; const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; + __u8 OperationalMajorVersion = 0; + __u8 OperationalMinorVersion = 0; + __u16 OperationalBuildNumber = 0; /* In order to update the I2C firmware we must change the type 2 record * to type 0xF2. This will force the UMP to come up in Boot Mode. @@ -785,19 +805,14 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) // Set entire image of 0xffs memset(buffer, 0xff, buffer_size); - err = request_firmware(&fw, fw_name, dev); + err = wrap_request_firmware(&fw, dev, &OperationalMajorVersion, + &OperationalMinorVersion, &OperationalBuildNumber); + if (err) { - dev_err(dev, "Failed to load image \"%s\" err %d\n", - fw_name, err); kfree(buffer); return err; } - /* Save Download Version Number */ - OperationalMajorVersion = fw->data[0]; - OperationalMinorVersion = fw->data[1]; - OperationalBuildNumber = fw->data[2] | (fw->data[3] << 8); - /* Copy version number into firmware record */ firmware_rec = (struct ti_i2c_firmware_rec *)buffer; @@ -943,6 +958,10 @@ static int download_fw(struct edgeport_serial *serial) struct usb_interface_descriptor *interface; int download_cur_ver; int download_new_ver; + const struct firmware *fw = NULL; + __u8 OperationalMajorVersion = 0; + __u8 OperationalMinorVersion = 0; + __u16 OperationalBuildNumber = 0; /* This routine is entered by both the BOOT mode and the Download mode * We can determine which code is running by the reading the config @@ -1046,6 +1065,19 @@ static int download_fw(struct edgeport_serial *serial) return status; } + /* Get version numbers for on-disk fw */ + if (wrap_request_firmware(&fw, dev, + &OperationalMajorVersion, + &OperationalMinorVersion, + &OperationalBuildNumber)) { + dev_dbg(dev, "%s - FW version query failed. Setting version to 0.", + __func__); + OperationalMajorVersion = 0; + OperationalMinorVersion = 0; + OperationalBuildNumber = 0; + } + release_firmware(fw); + /* Check version number of download with current version in I2c */ download_cur_ver = (firmware_version->Ver_Major << 8) + @@ -1283,7 +1315,6 @@ static int download_fw(struct edgeport_serial *serial) int buffer_size; int err; const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; /* Validate Hardware version number * Read Manufacturing Descriptor from TI Based Edgeport @@ -1332,10 +1363,11 @@ static int download_fw(struct edgeport_serial *serial) /* Initialize the buffer to 0xff (pad the buffer) */ memset(buffer, 0xff, buffer_size); - err = request_firmware(&fw, fw_name, dev); + err = wrap_request_firmware(&fw, dev, &OperationalMajorVersion, + &OperationalMinorVersion, + &OperationalBuildNumber); + if (err) { - dev_err(dev, "Failed to load image \"%s\" err %d\n", - fw_name, err); kfree(buffer); return err; } @@ -1355,7 +1387,9 @@ static int download_fw(struct edgeport_serial *serial) header->CheckSum = cs; /* Download the operational code */ - dev_dbg(dev, "%s - Downloading operational code image (TI UMP)\n", __func__); + dev_dbg(dev, "%s - Downloading operational code image version %d.%d (TI UMP)\n", + __func__, OperationalMajorVersion, + OperationalMinorVersion); status = download_code(serial, buffer, buffer_size); kfree(buffer); -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html