Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

watchdog: ziirave_wdt: Add support to upload the firmware.

This patch adds and entry to the sysfs to start firmware upload process
on the specified device with the requested firmware.

The uploading of the firmware needs only to happen once per firmware
upgrade, as the firmware is stored in persistent storage. If the
firmware upload or the firmware verification fails then we print and
error message and exit.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

authored by

Enric Balletbo i Serra and committed by
Wim Van Sebroeck
217209db 9d6b4efc

+404 -5
+404 -5
drivers/watchdog/ziirave_wdt.c
··· 18 18 * GNU General Public License for more details. 19 19 */ 20 20 21 + #include <linux/delay.h> 21 22 #include <linux/i2c.h> 23 + #include <linux/ihex.h> 24 + #include <linux/firmware.h> 22 25 #include <linux/kernel.h> 23 26 #include <linux/module.h> 24 27 #include <linux/slab.h> ··· 39 36 #define ZIIRAVE_STATE_OFF 0x1 40 37 #define ZIIRAVE_STATE_ON 0x2 41 38 39 + #define ZIIRAVE_FW_NAME "ziirave_wdt.fw" 40 + 42 41 static char *ziirave_reasons[] = {"power cycle", "hw watchdog", NULL, NULL, 43 42 "host request", NULL, "illegal configuration", 44 43 "illegal instruction", "illegal trap", ··· 55 50 #define ZIIRAVE_WDT_PING 0x9 56 51 #define ZIIRAVE_WDT_RESET_DURATION 0xa 57 52 53 + #define ZIIRAVE_FIRM_PKT_TOTAL_SIZE 20 54 + #define ZIIRAVE_FIRM_PKT_DATA_SIZE 16 55 + #define ZIIRAVE_FIRM_FLASH_MEMORY_START 0x1600 56 + #define ZIIRAVE_FIRM_FLASH_MEMORY_END 0x2bbf 57 + 58 + /* Received and ready for next Download packet. */ 59 + #define ZIIRAVE_FIRM_DOWNLOAD_ACK 1 60 + /* Currently writing to flash. Retry Download status in a moment! */ 61 + #define ZIIRAVE_FIRM_DOWNLOAD_BUSY 2 62 + 63 + /* Wait for ACK timeout in ms */ 64 + #define ZIIRAVE_FIRM_WAIT_FOR_ACK_TIMEOUT 50 65 + 66 + /* Firmware commands */ 67 + #define ZIIRAVE_CMD_DOWNLOAD_START 0x10 68 + #define ZIIRAVE_CMD_DOWNLOAD_END 0x11 69 + #define ZIIRAVE_CMD_DOWNLOAD_SET_READ_ADDR 0x12 70 + #define ZIIRAVE_CMD_DOWNLOAD_READ_BYTE 0x13 71 + #define ZIIRAVE_CMD_RESET_PROCESSOR 0x0b 72 + #define ZIIRAVE_CMD_JUMP_TO_BOOTLOADER 0x0c 73 + #define ZIIRAVE_CMD_DOWNLOAD_PACKET 0x0e 74 + 58 75 struct ziirave_wdt_rev { 59 76 unsigned char major; 60 77 unsigned char minor; 61 78 }; 62 79 63 80 struct ziirave_wdt_data { 81 + struct mutex sysfs_mutex; 64 82 struct watchdog_device wdd; 65 83 struct ziirave_wdt_rev bootloader_rev; 66 84 struct ziirave_wdt_rev firmware_rev; ··· 174 146 return ret; 175 147 } 176 148 149 + static int ziirave_firm_wait_for_ack(struct watchdog_device *wdd) 150 + { 151 + struct i2c_client *client = to_i2c_client(wdd->parent); 152 + int ret; 153 + unsigned long timeout; 154 + 155 + timeout = jiffies + msecs_to_jiffies(ZIIRAVE_FIRM_WAIT_FOR_ACK_TIMEOUT); 156 + do { 157 + if (time_after(jiffies, timeout)) 158 + return -ETIMEDOUT; 159 + 160 + usleep_range(5000, 10000); 161 + 162 + ret = i2c_smbus_read_byte(client); 163 + if (ret < 0) { 164 + dev_err(&client->dev, "Failed to read byte\n"); 165 + return ret; 166 + } 167 + } while (ret == ZIIRAVE_FIRM_DOWNLOAD_BUSY); 168 + 169 + return ret == ZIIRAVE_FIRM_DOWNLOAD_ACK ? 0 : -EIO; 170 + } 171 + 172 + static int ziirave_firm_set_read_addr(struct watchdog_device *wdd, u16 addr) 173 + { 174 + struct i2c_client *client = to_i2c_client(wdd->parent); 175 + u8 address[2]; 176 + 177 + address[0] = addr & 0xff; 178 + address[1] = (addr >> 8) & 0xff; 179 + 180 + return i2c_smbus_write_block_data(client, 181 + ZIIRAVE_CMD_DOWNLOAD_SET_READ_ADDR, 182 + ARRAY_SIZE(address), address); 183 + } 184 + 185 + static int ziirave_firm_write_block_data(struct watchdog_device *wdd, 186 + u8 command, u8 length, const u8 *data, 187 + bool wait_for_ack) 188 + { 189 + struct i2c_client *client = to_i2c_client(wdd->parent); 190 + int ret; 191 + 192 + ret = i2c_smbus_write_block_data(client, command, length, data); 193 + if (ret) { 194 + dev_err(&client->dev, 195 + "Failed to send command 0x%02x: %d\n", command, ret); 196 + return ret; 197 + } 198 + 199 + if (wait_for_ack) 200 + ret = ziirave_firm_wait_for_ack(wdd); 201 + 202 + return ret; 203 + } 204 + 205 + static int ziirave_firm_write_byte(struct watchdog_device *wdd, u8 command, 206 + u8 byte, bool wait_for_ack) 207 + { 208 + return ziirave_firm_write_block_data(wdd, command, 1, &byte, 209 + wait_for_ack); 210 + } 211 + 212 + /* 213 + * ziirave_firm_write_pkt() - Build and write a firmware packet 214 + * 215 + * A packet to send to the firmware is composed by following bytes: 216 + * Length | Addr0 | Addr1 | Data0 .. Data15 | Checksum | 217 + * Where, 218 + * Length: A data byte containing the length of the data. 219 + * Addr0: Low byte of the address. 220 + * Addr1: High byte of the address. 221 + * Data0 .. Data15: Array of 16 bytes of data. 222 + * Checksum: Checksum byte to verify data integrity. 223 + */ 224 + static int ziirave_firm_write_pkt(struct watchdog_device *wdd, 225 + const struct ihex_binrec *rec) 226 + { 227 + struct i2c_client *client = to_i2c_client(wdd->parent); 228 + u8 i, checksum = 0, packet[ZIIRAVE_FIRM_PKT_TOTAL_SIZE]; 229 + int ret; 230 + u16 addr; 231 + 232 + memset(packet, 0, ARRAY_SIZE(packet)); 233 + 234 + /* Packet length */ 235 + packet[0] = (u8)be16_to_cpu(rec->len); 236 + /* Packet address */ 237 + addr = (be32_to_cpu(rec->addr) & 0xffff) >> 1; 238 + packet[1] = addr & 0xff; 239 + packet[2] = (addr & 0xff00) >> 8; 240 + 241 + /* Packet data */ 242 + if (be16_to_cpu(rec->len) > ZIIRAVE_FIRM_PKT_DATA_SIZE) 243 + return -EMSGSIZE; 244 + memcpy(packet + 3, rec->data, be16_to_cpu(rec->len)); 245 + 246 + /* Packet checksum */ 247 + for (i = 0; i < ZIIRAVE_FIRM_PKT_TOTAL_SIZE - 1; i++) 248 + checksum += packet[i]; 249 + packet[ZIIRAVE_FIRM_PKT_TOTAL_SIZE - 1] = checksum; 250 + 251 + ret = ziirave_firm_write_block_data(wdd, ZIIRAVE_CMD_DOWNLOAD_PACKET, 252 + ARRAY_SIZE(packet), packet, true); 253 + if (ret) 254 + dev_err(&client->dev, 255 + "Failed to write firmware packet at address 0x%04x: %d\n", 256 + addr, ret); 257 + 258 + return ret; 259 + } 260 + 261 + static int ziirave_firm_verify(struct watchdog_device *wdd, 262 + const struct firmware *fw) 263 + { 264 + struct i2c_client *client = to_i2c_client(wdd->parent); 265 + const struct ihex_binrec *rec; 266 + int i, ret; 267 + u8 data[ZIIRAVE_FIRM_PKT_DATA_SIZE]; 268 + u16 addr; 269 + 270 + for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { 271 + /* Zero length marks end of records */ 272 + if (!be16_to_cpu(rec->len)) 273 + break; 274 + 275 + addr = (be32_to_cpu(rec->addr) & 0xffff) >> 1; 276 + if (addr < ZIIRAVE_FIRM_FLASH_MEMORY_START || 277 + addr > ZIIRAVE_FIRM_FLASH_MEMORY_END) 278 + continue; 279 + 280 + ret = ziirave_firm_set_read_addr(wdd, addr); 281 + if (ret) { 282 + dev_err(&client->dev, 283 + "Failed to send SET_READ_ADDR command: %d\n", 284 + ret); 285 + return ret; 286 + } 287 + 288 + for (i = 0; i < ARRAY_SIZE(data); i++) { 289 + ret = i2c_smbus_read_byte_data(client, 290 + ZIIRAVE_CMD_DOWNLOAD_READ_BYTE); 291 + if (ret < 0) { 292 + dev_err(&client->dev, 293 + "Failed to READ DATA: %d\n", ret); 294 + return ret; 295 + } 296 + data[i] = ret; 297 + } 298 + 299 + if (memcmp(data, rec->data, be16_to_cpu(rec->len))) { 300 + dev_err(&client->dev, 301 + "Firmware mismatch at address 0x%04x\n", addr); 302 + return -EINVAL; 303 + } 304 + } 305 + 306 + return 0; 307 + } 308 + 309 + static int ziirave_firm_upload(struct watchdog_device *wdd, 310 + const struct firmware *fw) 311 + { 312 + struct i2c_client *client = to_i2c_client(wdd->parent); 313 + int ret, words_till_page_break; 314 + const struct ihex_binrec *rec; 315 + struct ihex_binrec *rec_new; 316 + 317 + ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_JUMP_TO_BOOTLOADER, 1, 318 + false); 319 + if (ret) 320 + return ret; 321 + 322 + msleep(500); 323 + 324 + ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_DOWNLOAD_START, 1, true); 325 + if (ret) 326 + return ret; 327 + 328 + msleep(500); 329 + 330 + for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { 331 + /* Zero length marks end of records */ 332 + if (!be16_to_cpu(rec->len)) 333 + break; 334 + 335 + /* Check max data size */ 336 + if (be16_to_cpu(rec->len) > ZIIRAVE_FIRM_PKT_DATA_SIZE) { 337 + dev_err(&client->dev, "Firmware packet too long (%d)\n", 338 + be16_to_cpu(rec->len)); 339 + return -EMSGSIZE; 340 + } 341 + 342 + /* Calculate words till page break */ 343 + words_till_page_break = (64 - ((be32_to_cpu(rec->addr) >> 1) & 344 + 0x3f)); 345 + if ((be16_to_cpu(rec->len) >> 1) > words_till_page_break) { 346 + /* 347 + * Data in passes page boundary, so we need to split in 348 + * two blocks of data. Create a packet with the first 349 + * block of data. 350 + */ 351 + rec_new = kzalloc(sizeof(struct ihex_binrec) + 352 + (words_till_page_break << 1), 353 + GFP_KERNEL); 354 + if (!rec_new) 355 + return -ENOMEM; 356 + 357 + rec_new->len = cpu_to_be16(words_till_page_break << 1); 358 + rec_new->addr = rec->addr; 359 + memcpy(rec_new->data, rec->data, 360 + be16_to_cpu(rec_new->len)); 361 + 362 + ret = ziirave_firm_write_pkt(wdd, rec_new); 363 + kfree(rec_new); 364 + if (ret) 365 + return ret; 366 + 367 + /* Create a packet with the second block of data */ 368 + rec_new = kzalloc(sizeof(struct ihex_binrec) + 369 + be16_to_cpu(rec->len) - 370 + (words_till_page_break << 1), 371 + GFP_KERNEL); 372 + if (!rec_new) 373 + return -ENOMEM; 374 + 375 + /* Remaining bytes */ 376 + rec_new->len = rec->len - 377 + cpu_to_be16(words_till_page_break << 1); 378 + 379 + rec_new->addr = cpu_to_be32(be32_to_cpu(rec->addr) + 380 + (words_till_page_break << 1)); 381 + 382 + memcpy(rec_new->data, 383 + rec->data + (words_till_page_break << 1), 384 + be16_to_cpu(rec_new->len)); 385 + 386 + ret = ziirave_firm_write_pkt(wdd, rec_new); 387 + kfree(rec_new); 388 + if (ret) 389 + return ret; 390 + } else { 391 + ret = ziirave_firm_write_pkt(wdd, rec); 392 + if (ret) 393 + return ret; 394 + } 395 + } 396 + 397 + /* For end of download, the length field will be set to 0 */ 398 + rec_new = kzalloc(sizeof(struct ihex_binrec) + 1, GFP_KERNEL); 399 + if (!rec_new) 400 + return -ENOMEM; 401 + 402 + ret = ziirave_firm_write_pkt(wdd, rec_new); 403 + kfree(rec_new); 404 + if (ret) { 405 + dev_err(&client->dev, "Failed to send EMPTY packet: %d\n", ret); 406 + return ret; 407 + } 408 + 409 + /* This sleep seems to be required */ 410 + msleep(20); 411 + 412 + /* Start firmware verification */ 413 + ret = ziirave_firm_verify(wdd, fw); 414 + if (ret) { 415 + dev_err(&client->dev, 416 + "Failed to verify firmware: %d\n", ret); 417 + return ret; 418 + } 419 + 420 + /* End download operation */ 421 + ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_DOWNLOAD_END, 1, false); 422 + if (ret) 423 + return ret; 424 + 425 + /* Reset the processor */ 426 + ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_RESET_PROCESSOR, 1, 427 + false); 428 + if (ret) 429 + return ret; 430 + 431 + msleep(500); 432 + 433 + return 0; 434 + } 435 + 177 436 static const struct watchdog_info ziirave_wdt_info = { 178 437 .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, 179 438 .identity = "Zodiac RAVE Watchdog", ··· 481 166 { 482 167 struct i2c_client *client = to_i2c_client(dev->parent); 483 168 struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); 169 + int ret; 484 170 485 - return sprintf(buf, "02.%02u.%02u", w_priv->firmware_rev.major, 486 - w_priv->firmware_rev.minor); 171 + ret = mutex_lock_interruptible(&w_priv->sysfs_mutex); 172 + if (ret) 173 + return ret; 174 + 175 + ret = sprintf(buf, "02.%02u.%02u", w_priv->firmware_rev.major, 176 + w_priv->firmware_rev.minor); 177 + 178 + mutex_unlock(&w_priv->sysfs_mutex); 179 + 180 + return ret; 487 181 } 488 182 489 183 static DEVICE_ATTR(firmware_version, S_IRUGO, ziirave_wdt_sysfs_show_firm, ··· 504 180 { 505 181 struct i2c_client *client = to_i2c_client(dev->parent); 506 182 struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); 183 + int ret; 507 184 508 - return sprintf(buf, "01.%02u.%02u", w_priv->bootloader_rev.major, 509 - w_priv->bootloader_rev.minor); 185 + ret = mutex_lock_interruptible(&w_priv->sysfs_mutex); 186 + if (ret) 187 + return ret; 188 + 189 + ret = sprintf(buf, "01.%02u.%02u", w_priv->bootloader_rev.major, 190 + w_priv->bootloader_rev.minor); 191 + 192 + mutex_unlock(&w_priv->sysfs_mutex); 193 + 194 + return ret; 510 195 } 511 196 512 197 static DEVICE_ATTR(bootloader_version, S_IRUGO, ziirave_wdt_sysfs_show_boot, ··· 527 194 { 528 195 struct i2c_client *client = to_i2c_client(dev->parent); 529 196 struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); 197 + int ret; 530 198 531 - return sprintf(buf, "%s", ziirave_reasons[w_priv->reset_reason]); 199 + ret = mutex_lock_interruptible(&w_priv->sysfs_mutex); 200 + if (ret) 201 + return ret; 202 + 203 + ret = sprintf(buf, "%s", ziirave_reasons[w_priv->reset_reason]); 204 + 205 + mutex_unlock(&w_priv->sysfs_mutex); 206 + 207 + return ret; 532 208 } 533 209 534 210 static DEVICE_ATTR(reset_reason, S_IRUGO, ziirave_wdt_sysfs_show_reason, 535 211 NULL); 536 212 213 + static ssize_t ziirave_wdt_sysfs_store_firm(struct device *dev, 214 + struct device_attribute *attr, 215 + const char *buf, size_t count) 216 + { 217 + struct i2c_client *client = to_i2c_client(dev->parent); 218 + struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); 219 + const struct firmware *fw; 220 + int err; 221 + 222 + err = request_ihex_firmware(&fw, ZIIRAVE_FW_NAME, dev); 223 + if (err) { 224 + dev_err(&client->dev, "Failed to request ihex firmware\n"); 225 + return err; 226 + } 227 + 228 + err = mutex_lock_interruptible(&w_priv->sysfs_mutex); 229 + if (err) 230 + goto release_firmware; 231 + 232 + err = ziirave_firm_upload(&w_priv->wdd, fw); 233 + if (err) { 234 + dev_err(&client->dev, "The firmware update failed: %d\n", err); 235 + goto unlock_mutex; 236 + } 237 + 238 + /* Update firmware version */ 239 + err = ziirave_wdt_revision(client, &w_priv->firmware_rev, 240 + ZIIRAVE_WDT_FIRM_VER_MAJOR); 241 + if (err) { 242 + dev_err(&client->dev, "Failed to read firmware version: %d\n", 243 + err); 244 + goto unlock_mutex; 245 + } 246 + 247 + dev_info(&client->dev, "Firmware updated to version 02.%02u.%02u\n", 248 + w_priv->firmware_rev.major, w_priv->firmware_rev.minor); 249 + 250 + /* Restore the watchdog timeout */ 251 + err = ziirave_wdt_set_timeout(&w_priv->wdd, w_priv->wdd.timeout); 252 + if (err) 253 + dev_err(&client->dev, "Failed to set timeout: %d\n", err); 254 + 255 + unlock_mutex: 256 + mutex_unlock(&w_priv->sysfs_mutex); 257 + 258 + release_firmware: 259 + release_firmware(fw); 260 + 261 + return err ? err : count; 262 + } 263 + 264 + static DEVICE_ATTR(update_firmware, S_IWUSR, NULL, 265 + ziirave_wdt_sysfs_store_firm); 266 + 537 267 static struct attribute *ziirave_wdt_attrs[] = { 538 268 &dev_attr_firmware_version.attr, 539 269 &dev_attr_bootloader_version.attr, 540 270 &dev_attr_reset_reason.attr, 271 + &dev_attr_update_firmware.attr, 541 272 NULL 542 273 }; 543 274 ATTRIBUTE_GROUPS(ziirave_wdt); ··· 648 251 w_priv = devm_kzalloc(&client->dev, sizeof(*w_priv), GFP_KERNEL); 649 252 if (!w_priv) 650 253 return -ENOMEM; 254 + 255 + mutex_init(&w_priv->sysfs_mutex); 651 256 652 257 w_priv->wdd.info = &ziirave_wdt_info; 653 258 w_priv->wdd.ops = &ziirave_wdt_ops;