Input: synaptics-rmi4 - add sysfs attribute update_fw_status

The attribute returns the percentage complete. If the firmware update fails, it
reports a negative error code.

Signed-off-by: Nick Dyer <nick@shmanahar.org>
Tested-by: Chris Healy <cphealy@gmail.com>
Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
Nick Dyer 2017-01-31 15:25:56 -08:00 committed by Dmitry Torokhov
parent ed77bdf4e4
commit 5a89916df2
3 changed files with 80 additions and 27 deletions

View File

@ -157,6 +157,9 @@ static int rmi_f34_write_blocks(struct f34_data *f34, const void *data,
i + 1, block_count); i + 1, block_count);
data += f34->v5.block_size; data += f34->v5.block_size;
f34->update_progress += f34->v5.block_size;
f34->update_status = (f34->update_progress * 100) /
f34->update_size;
} }
return 0; return 0;
@ -174,7 +177,7 @@ static int rmi_f34_write_config(struct f34_data *f34, const void *data)
F34_WRITE_CONFIG_BLOCK); F34_WRITE_CONFIG_BLOCK);
} }
int rmi_f34_enable_flash(struct f34_data *f34) static int rmi_f34_enable_flash(struct f34_data *f34)
{ {
return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG, return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG,
F34_ENABLE_WAIT_MS, true); F34_ENABLE_WAIT_MS, true);
@ -184,9 +187,14 @@ static int rmi_f34_flash_firmware(struct f34_data *f34,
const struct rmi_f34_firmware *syn_fw) const struct rmi_f34_firmware *syn_fw)
{ {
struct rmi_function *fn = f34->fn; struct rmi_function *fn = f34->fn;
u32 image_size = le32_to_cpu(syn_fw->image_size);
u32 config_size = le32_to_cpu(syn_fw->config_size);
int ret; int ret;
if (syn_fw->image_size) { f34->update_progress = 0;
f34->update_size = image_size + config_size;
if (image_size) {
dev_info(&fn->dev, "Erasing firmware...\n"); dev_info(&fn->dev, "Erasing firmware...\n");
ret = rmi_f34_command(f34, F34_ERASE_ALL, ret = rmi_f34_command(f34, F34_ERASE_ALL,
F34_ERASE_WAIT_MS, true); F34_ERASE_WAIT_MS, true);
@ -194,18 +202,18 @@ static int rmi_f34_flash_firmware(struct f34_data *f34,
return ret; return ret;
dev_info(&fn->dev, "Writing firmware (%d bytes)...\n", dev_info(&fn->dev, "Writing firmware (%d bytes)...\n",
syn_fw->image_size); image_size);
ret = rmi_f34_write_firmware(f34, syn_fw->data); ret = rmi_f34_write_firmware(f34, syn_fw->data);
if (ret) if (ret)
return ret; return ret;
} }
if (syn_fw->config_size) { if (config_size) {
/* /*
* We only need to erase config if we haven't updated * We only need to erase config if we haven't updated
* firmware. * firmware.
*/ */
if (!syn_fw->image_size) { if (!image_size) {
dev_info(&fn->dev, "Erasing config...\n"); dev_info(&fn->dev, "Erasing config...\n");
ret = rmi_f34_command(f34, F34_ERASE_CONFIG, ret = rmi_f34_command(f34, F34_ERASE_CONFIG,
F34_ERASE_WAIT_MS, true); F34_ERASE_WAIT_MS, true);
@ -214,9 +222,8 @@ static int rmi_f34_flash_firmware(struct f34_data *f34,
} }
dev_info(&fn->dev, "Writing config (%d bytes)...\n", dev_info(&fn->dev, "Writing config (%d bytes)...\n",
syn_fw->config_size); config_size);
ret = rmi_f34_write_config(f34, ret = rmi_f34_write_config(f34, &syn_fw->data[image_size]);
&syn_fw->data[syn_fw->image_size]);
if (ret) if (ret)
return ret; return ret;
} }
@ -224,21 +231,23 @@ static int rmi_f34_flash_firmware(struct f34_data *f34,
return 0; return 0;
} }
int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw) static int rmi_f34_update_firmware(struct f34_data *f34,
const struct firmware *fw)
{ {
const struct rmi_f34_firmware *syn_fw; const struct rmi_f34_firmware *syn_fw =
(const struct rmi_f34_firmware *)fw->data;
u32 image_size = le32_to_cpu(syn_fw->image_size);
u32 config_size = le32_to_cpu(syn_fw->config_size);
int ret; int ret;
syn_fw = (const struct rmi_f34_firmware *)fw->data;
BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) != BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) !=
F34_FW_IMAGE_OFFSET); F34_FW_IMAGE_OFFSET);
rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
"FW size:%d, checksum:%08x, image_size:%d, config_size:%d\n", "FW size:%zd, checksum:%08x, image_size:%d, config_size:%d\n",
(int)fw->size, fw->size,
le32_to_cpu(syn_fw->checksum), le32_to_cpu(syn_fw->checksum),
le32_to_cpu(syn_fw->image_size), image_size, config_size);
le32_to_cpu(syn_fw->config_size));
rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
"FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n", "FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n",
@ -246,27 +255,25 @@ int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw)
(int)sizeof(syn_fw->product_id), syn_fw->product_id, (int)sizeof(syn_fw->product_id), syn_fw->product_id,
syn_fw->product_info[0], syn_fw->product_info[1]); syn_fw->product_info[0], syn_fw->product_info[1]);
if (syn_fw->image_size && if (image_size && image_size != f34->v5.fw_blocks * f34->v5.block_size) {
syn_fw->image_size != f34->v5.fw_blocks * f34->v5.block_size) {
dev_err(&f34->fn->dev, dev_err(&f34->fn->dev,
"Bad firmware image: fw size %d, expected %d\n", "Bad firmware image: fw size %d, expected %d\n",
syn_fw->image_size, image_size, f34->v5.fw_blocks * f34->v5.block_size);
f34->v5.fw_blocks * f34->v5.block_size);
ret = -EILSEQ; ret = -EILSEQ;
goto out; goto out;
} }
if (syn_fw->config_size && if (config_size &&
syn_fw->config_size != f34->v5.config_blocks * f34->v5.block_size) { config_size != f34->v5.config_blocks * f34->v5.block_size) {
dev_err(&f34->fn->dev, dev_err(&f34->fn->dev,
"Bad firmware image: config size %d, expected %d\n", "Bad firmware image: config size %d, expected %d\n",
syn_fw->config_size, config_size,
f34->v5.config_blocks * f34->v5.block_size); f34->v5.config_blocks * f34->v5.block_size);
ret = -EILSEQ; ret = -EILSEQ;
goto out; goto out;
} }
if (syn_fw->image_size && !syn_fw->config_size) { if (image_size && !config_size) {
dev_err(&f34->fn->dev, "Bad firmware image: no config data\n"); dev_err(&f34->fn->dev, "Bad firmware image: no config data\n");
ret = -EILSEQ; ret = -EILSEQ;
goto out; goto out;
@ -283,6 +290,17 @@ int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw)
return ret; return ret;
} }
static int rmi_f34_status(struct rmi_function *fn)
{
struct f34_data *f34 = dev_get_drvdata(&fn->dev);
/*
* The status is the percentage complete, or once complete,
* zero for success or a negative return code.
*/
return f34->update_status;
}
static int rmi_firmware_update(struct rmi_driver_data *data, static int rmi_firmware_update(struct rmi_driver_data *data,
const struct firmware *fw) const struct firmware *fw)
{ {
@ -346,7 +364,13 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
else else
ret = rmi_f34_update_firmware(f34, fw); ret = rmi_f34_update_firmware(f34, fw);
dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret); if (ret) {
f34->update_status = ret;
dev_err(&f34->fn->dev,
"Firmware update failed, status: %d\n", ret);
} else {
dev_info(&f34->fn->dev, "Firmware update complete\n");
}
rmi_disable_irq(rmi_dev, false); rmi_disable_irq(rmi_dev, false);
@ -377,9 +401,6 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
return ret; return ret;
} }
static int rmi_firmware_update(struct rmi_driver_data *data,
const struct firmware *fw);
static ssize_t rmi_driver_update_fw_store(struct device *dev, static ssize_t rmi_driver_update_fw_store(struct device *dev,
struct device_attribute *dattr, struct device_attribute *dattr,
const char *buf, size_t count) const char *buf, size_t count)
@ -414,8 +435,25 @@ static ssize_t rmi_driver_update_fw_store(struct device *dev,
static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store); static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store);
static ssize_t rmi_driver_update_fw_status_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
{
struct rmi_driver_data *data = dev_get_drvdata(dev);
int update_status = 0;
if (data->f34_container)
update_status = rmi_f34_status(data->f34_container);
return scnprintf(buf, PAGE_SIZE, "%d\n", update_status);
}
static DEVICE_ATTR(update_fw_status, 0444,
rmi_driver_update_fw_status_show, NULL);
static struct attribute *rmi_firmware_attrs[] = { static struct attribute *rmi_firmware_attrs[] = {
&dev_attr_update_fw.attr, &dev_attr_update_fw.attr,
&dev_attr_update_fw_status.attr,
NULL NULL
}; };

View File

@ -301,6 +301,10 @@ struct f34_data {
unsigned char bootloader_id[5]; unsigned char bootloader_id[5];
unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1]; unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1];
int update_status;
int update_progress;
int update_size;
union { union {
struct f34v5_data v5; struct f34v5_data v5;
struct f34v7_data v7; struct f34v7_data v7;

View File

@ -588,6 +588,7 @@ static int rmi_f34v7_check_ui_firmware_size(struct f34_data *f34)
u16 block_count; u16 block_count;
block_count = f34->v7.img.ui_firmware.size / f34->v7.block_size; block_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
f34->update_size += block_count;
if (block_count != f34->v7.blkcount.ui_firmware) { if (block_count != f34->v7.blkcount.ui_firmware) {
dev_err(&f34->fn->dev, dev_err(&f34->fn->dev,
@ -604,6 +605,7 @@ static int rmi_f34v7_check_ui_config_size(struct f34_data *f34)
u16 block_count; u16 block_count;
block_count = f34->v7.img.ui_config.size / f34->v7.block_size; block_count = f34->v7.img.ui_config.size / f34->v7.block_size;
f34->update_size += block_count;
if (block_count != f34->v7.blkcount.ui_config) { if (block_count != f34->v7.blkcount.ui_config) {
dev_err(&f34->fn->dev, "UI config size mismatch\n"); dev_err(&f34->fn->dev, "UI config size mismatch\n");
@ -618,6 +620,7 @@ static int rmi_f34v7_check_dp_config_size(struct f34_data *f34)
u16 block_count; u16 block_count;
block_count = f34->v7.img.dp_config.size / f34->v7.block_size; block_count = f34->v7.img.dp_config.size / f34->v7.block_size;
f34->update_size += block_count;
if (block_count != f34->v7.blkcount.dp_config) { if (block_count != f34->v7.blkcount.dp_config) {
dev_err(&f34->fn->dev, "Display config size mismatch\n"); dev_err(&f34->fn->dev, "Display config size mismatch\n");
@ -632,6 +635,8 @@ static int rmi_f34v7_check_guest_code_size(struct f34_data *f34)
u16 block_count; u16 block_count;
block_count = f34->v7.img.guest_code.size / f34->v7.block_size; block_count = f34->v7.img.guest_code.size / f34->v7.block_size;
f34->update_size += block_count;
if (block_count != f34->v7.blkcount.guest_code) { if (block_count != f34->v7.blkcount.guest_code) {
dev_err(&f34->fn->dev, "Guest code size mismatch\n"); dev_err(&f34->fn->dev, "Guest code size mismatch\n");
return -EINVAL; return -EINVAL;
@ -645,6 +650,7 @@ static int rmi_f34v7_check_bl_config_size(struct f34_data *f34)
u16 block_count; u16 block_count;
block_count = f34->v7.img.bl_config.size / f34->v7.block_size; block_count = f34->v7.img.bl_config.size / f34->v7.block_size;
f34->update_size += block_count;
if (block_count != f34->v7.blkcount.bl_config) { if (block_count != f34->v7.blkcount.bl_config) {
dev_err(&f34->fn->dev, "Bootloader config size mismatch\n"); dev_err(&f34->fn->dev, "Bootloader config size mismatch\n");
@ -881,6 +887,9 @@ static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34,
block_ptr += (transfer * f34->v7.block_size); block_ptr += (transfer * f34->v7.block_size);
remaining -= transfer; remaining -= transfer;
f34->update_progress += transfer;
f34->update_status = (f34->update_progress * 100) /
f34->update_size;
} while (remaining); } while (remaining);
return 0; return 0;
@ -1191,6 +1200,8 @@ int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw)
rmi_f34v7_read_queries_bl_version(f34); rmi_f34v7_read_queries_bl_version(f34);
f34->v7.image = fw->data; f34->v7.image = fw->data;
f34->update_progress = 0;
f34->update_size = 0;
ret = rmi_f34v7_parse_image_info(f34); ret = rmi_f34v7_parse_image_info(f34);
if (ret < 0) if (ret < 0)