150bd6153SVasant Hegde /* 250bd6153SVasant Hegde * PowerNV OPAL Firmware Update Interface 350bd6153SVasant Hegde * 450bd6153SVasant Hegde * Copyright 2013 IBM Corp. 550bd6153SVasant Hegde * 650bd6153SVasant Hegde * This program is free software; you can redistribute it and/or 750bd6153SVasant Hegde * modify it under the terms of the GNU General Public License 850bd6153SVasant Hegde * as published by the Free Software Foundation; either version 950bd6153SVasant Hegde * 2 of the License, or (at your option) any later version. 1050bd6153SVasant Hegde */ 1150bd6153SVasant Hegde 1250bd6153SVasant Hegde #define DEBUG 1350bd6153SVasant Hegde 1450bd6153SVasant Hegde #include <linux/kernel.h> 1550bd6153SVasant Hegde #include <linux/reboot.h> 1650bd6153SVasant Hegde #include <linux/init.h> 1750bd6153SVasant Hegde #include <linux/kobject.h> 1850bd6153SVasant Hegde #include <linux/sysfs.h> 1950bd6153SVasant Hegde #include <linux/slab.h> 2050bd6153SVasant Hegde #include <linux/mm.h> 2150bd6153SVasant Hegde #include <linux/vmalloc.h> 2250bd6153SVasant Hegde #include <linux/pagemap.h> 2350bd6153SVasant Hegde 2450bd6153SVasant Hegde #include <asm/opal.h> 2550bd6153SVasant Hegde 2650bd6153SVasant Hegde /* FLASH status codes */ 2750bd6153SVasant Hegde #define FLASH_NO_OP -1099 /* No operation initiated by user */ 2850bd6153SVasant Hegde #define FLASH_NO_AUTH -9002 /* Not a service authority partition */ 2950bd6153SVasant Hegde 3050bd6153SVasant Hegde /* Validate image status values */ 3150bd6153SVasant Hegde #define VALIDATE_IMG_READY -1001 /* Image ready for validation */ 3250bd6153SVasant Hegde #define VALIDATE_IMG_INCOMPLETE -1002 /* User copied < VALIDATE_BUF_SIZE */ 3350bd6153SVasant Hegde 3450bd6153SVasant Hegde /* Manage image status values */ 3550bd6153SVasant Hegde #define MANAGE_ACTIVE_ERR -9001 /* Cannot overwrite active img */ 3650bd6153SVasant Hegde 3750bd6153SVasant Hegde /* Flash image status values */ 3850bd6153SVasant Hegde #define FLASH_IMG_READY 0 /* Img ready for flash on reboot */ 3950bd6153SVasant Hegde #define FLASH_INVALID_IMG -1003 /* Flash image shorter than expected */ 4050bd6153SVasant Hegde #define FLASH_IMG_NULL_DATA -1004 /* Bad data in sg list entry */ 4150bd6153SVasant Hegde #define FLASH_IMG_BAD_LEN -1005 /* Bad length in sg list entry */ 4250bd6153SVasant Hegde 4350bd6153SVasant Hegde /* Manage operation tokens */ 4450bd6153SVasant Hegde #define FLASH_REJECT_TMP_SIDE 0 /* Reject temporary fw image */ 4550bd6153SVasant Hegde #define FLASH_COMMIT_TMP_SIDE 1 /* Commit temporary fw image */ 4650bd6153SVasant Hegde 4750bd6153SVasant Hegde /* Update tokens */ 4850bd6153SVasant Hegde #define FLASH_UPDATE_CANCEL 0 /* Cancel update request */ 4950bd6153SVasant Hegde #define FLASH_UPDATE_INIT 1 /* Initiate update */ 5050bd6153SVasant Hegde 5150bd6153SVasant Hegde /* Validate image update result tokens */ 5250bd6153SVasant Hegde #define VALIDATE_TMP_UPDATE 0 /* T side will be updated */ 5350bd6153SVasant Hegde #define VALIDATE_FLASH_AUTH 1 /* Partition does not have authority */ 5450bd6153SVasant Hegde #define VALIDATE_INVALID_IMG 2 /* Candidate image is not valid */ 5550bd6153SVasant Hegde #define VALIDATE_CUR_UNKNOWN 3 /* Current fixpack level is unknown */ 5650bd6153SVasant Hegde /* 5750bd6153SVasant Hegde * Current T side will be committed to P side before being replace with new 5850bd6153SVasant Hegde * image, and the new image is downlevel from current image 5950bd6153SVasant Hegde */ 6050bd6153SVasant Hegde #define VALIDATE_TMP_COMMIT_DL 4 6150bd6153SVasant Hegde /* 6250bd6153SVasant Hegde * Current T side will be committed to P side before being replaced with new 6350bd6153SVasant Hegde * image 6450bd6153SVasant Hegde */ 6550bd6153SVasant Hegde #define VALIDATE_TMP_COMMIT 5 6650bd6153SVasant Hegde /* 6750bd6153SVasant Hegde * T side will be updated with a downlevel image 6850bd6153SVasant Hegde */ 6950bd6153SVasant Hegde #define VALIDATE_TMP_UPDATE_DL 6 7050bd6153SVasant Hegde /* 7150bd6153SVasant Hegde * The candidate image's release date is later than the system's firmware 7250bd6153SVasant Hegde * service entitlement date - service warranty period has expired 7350bd6153SVasant Hegde */ 7450bd6153SVasant Hegde #define VALIDATE_OUT_OF_WRNTY 7 7550bd6153SVasant Hegde 7650bd6153SVasant Hegde /* Validate buffer size */ 7750bd6153SVasant Hegde #define VALIDATE_BUF_SIZE 4096 7850bd6153SVasant Hegde 79bf16a4c2SVasant Hegde /* XXX: Assume candidate image size is <= 1GB */ 80bf16a4c2SVasant Hegde #define MAX_IMAGE_SIZE 0x40000000 8150bd6153SVasant Hegde 8250bd6153SVasant Hegde /* Image status */ 8350bd6153SVasant Hegde enum { 8450bd6153SVasant Hegde IMAGE_INVALID, 8550bd6153SVasant Hegde IMAGE_LOADING, 8650bd6153SVasant Hegde IMAGE_READY, 8750bd6153SVasant Hegde }; 8850bd6153SVasant Hegde 8950bd6153SVasant Hegde /* Candidate image data */ 9050bd6153SVasant Hegde struct image_data_t { 9150bd6153SVasant Hegde int status; 9250bd6153SVasant Hegde void *data; 9350bd6153SVasant Hegde uint32_t size; 9450bd6153SVasant Hegde }; 9550bd6153SVasant Hegde 9650bd6153SVasant Hegde /* Candidate image header */ 9750bd6153SVasant Hegde struct image_header_t { 9850bd6153SVasant Hegde uint16_t magic; 9950bd6153SVasant Hegde uint16_t version; 10050bd6153SVasant Hegde uint32_t size; 10150bd6153SVasant Hegde }; 10250bd6153SVasant Hegde 10350bd6153SVasant Hegde struct validate_flash_t { 10450bd6153SVasant Hegde int status; /* Return status */ 1058faaaeadSMasanari Iida void *buf; /* Candidate image buffer */ 10650bd6153SVasant Hegde uint32_t buf_size; /* Image size */ 10750bd6153SVasant Hegde uint32_t result; /* Update results token */ 10850bd6153SVasant Hegde }; 10950bd6153SVasant Hegde 11050bd6153SVasant Hegde struct manage_flash_t { 11150bd6153SVasant Hegde int status; /* Return status */ 11250bd6153SVasant Hegde }; 11350bd6153SVasant Hegde 11450bd6153SVasant Hegde struct update_flash_t { 11550bd6153SVasant Hegde int status; /* Return status */ 11650bd6153SVasant Hegde }; 11750bd6153SVasant Hegde 11850bd6153SVasant Hegde static struct image_header_t image_header; 11950bd6153SVasant Hegde static struct image_data_t image_data; 12050bd6153SVasant Hegde static struct validate_flash_t validate_flash_data; 12150bd6153SVasant Hegde static struct manage_flash_t manage_flash_data; 12250bd6153SVasant Hegde static struct update_flash_t update_flash_data; 12350bd6153SVasant Hegde 12450bd6153SVasant Hegde static DEFINE_MUTEX(image_data_mutex); 12550bd6153SVasant Hegde 12650bd6153SVasant Hegde /* 12750bd6153SVasant Hegde * Validate candidate image 12850bd6153SVasant Hegde */ 12950bd6153SVasant Hegde static inline void opal_flash_validate(void) 13050bd6153SVasant Hegde { 131cc146d1dSAnton Blanchard long ret; 132cc146d1dSAnton Blanchard void *buf = validate_flash_data.buf; 133cc146d1dSAnton Blanchard __be32 size, result; 13450bd6153SVasant Hegde 135cc146d1dSAnton Blanchard ret = opal_validate_flash(__pa(buf), &size, &result); 136cc146d1dSAnton Blanchard 137cc146d1dSAnton Blanchard validate_flash_data.status = ret; 138cc146d1dSAnton Blanchard validate_flash_data.buf_size = be32_to_cpu(size); 139cc146d1dSAnton Blanchard validate_flash_data.result = be32_to_cpu(result); 14050bd6153SVasant Hegde } 14150bd6153SVasant Hegde 14250bd6153SVasant Hegde /* 14350bd6153SVasant Hegde * Validate output format: 14450bd6153SVasant Hegde * validate result token 14550bd6153SVasant Hegde * current image version details 14650bd6153SVasant Hegde * new image version details 14750bd6153SVasant Hegde */ 14850bd6153SVasant Hegde static ssize_t validate_show(struct kobject *kobj, 14950bd6153SVasant Hegde struct kobj_attribute *attr, char *buf) 15050bd6153SVasant Hegde { 15150bd6153SVasant Hegde struct validate_flash_t *args_buf = &validate_flash_data; 15250bd6153SVasant Hegde int len; 15350bd6153SVasant Hegde 15450bd6153SVasant Hegde /* Candidate image is not validated */ 15550bd6153SVasant Hegde if (args_buf->status < VALIDATE_TMP_UPDATE) { 15650bd6153SVasant Hegde len = sprintf(buf, "%d\n", args_buf->status); 15750bd6153SVasant Hegde goto out; 15850bd6153SVasant Hegde } 15950bd6153SVasant Hegde 16050bd6153SVasant Hegde /* Result token */ 16150bd6153SVasant Hegde len = sprintf(buf, "%d\n", args_buf->result); 16250bd6153SVasant Hegde 16350bd6153SVasant Hegde /* Current and candidate image version details */ 16450bd6153SVasant Hegde if ((args_buf->result != VALIDATE_TMP_UPDATE) && 16550bd6153SVasant Hegde (args_buf->result < VALIDATE_CUR_UNKNOWN)) 16650bd6153SVasant Hegde goto out; 16750bd6153SVasant Hegde 16850bd6153SVasant Hegde if (args_buf->buf_size > (VALIDATE_BUF_SIZE - len)) { 16950bd6153SVasant Hegde memcpy(buf + len, args_buf->buf, VALIDATE_BUF_SIZE - len); 17050bd6153SVasant Hegde len = VALIDATE_BUF_SIZE; 17150bd6153SVasant Hegde } else { 17250bd6153SVasant Hegde memcpy(buf + len, args_buf->buf, args_buf->buf_size); 17350bd6153SVasant Hegde len += args_buf->buf_size; 17450bd6153SVasant Hegde } 17550bd6153SVasant Hegde out: 17650bd6153SVasant Hegde /* Set status to default */ 17750bd6153SVasant Hegde args_buf->status = FLASH_NO_OP; 17850bd6153SVasant Hegde return len; 17950bd6153SVasant Hegde } 18050bd6153SVasant Hegde 18150bd6153SVasant Hegde /* 18250bd6153SVasant Hegde * Validate candidate firmware image 18350bd6153SVasant Hegde * 18450bd6153SVasant Hegde * Note: 18550bd6153SVasant Hegde * We are only interested in first 4K bytes of the 18650bd6153SVasant Hegde * candidate image. 18750bd6153SVasant Hegde */ 18850bd6153SVasant Hegde static ssize_t validate_store(struct kobject *kobj, 18950bd6153SVasant Hegde struct kobj_attribute *attr, 19050bd6153SVasant Hegde const char *buf, size_t count) 19150bd6153SVasant Hegde { 19250bd6153SVasant Hegde struct validate_flash_t *args_buf = &validate_flash_data; 19350bd6153SVasant Hegde 19450bd6153SVasant Hegde if (buf[0] != '1') 19550bd6153SVasant Hegde return -EINVAL; 19650bd6153SVasant Hegde 19750bd6153SVasant Hegde mutex_lock(&image_data_mutex); 19850bd6153SVasant Hegde 19950bd6153SVasant Hegde if (image_data.status != IMAGE_READY || 20050bd6153SVasant Hegde image_data.size < VALIDATE_BUF_SIZE) { 20150bd6153SVasant Hegde args_buf->result = VALIDATE_INVALID_IMG; 20250bd6153SVasant Hegde args_buf->status = VALIDATE_IMG_INCOMPLETE; 20350bd6153SVasant Hegde goto out; 20450bd6153SVasant Hegde } 20550bd6153SVasant Hegde 20650bd6153SVasant Hegde /* Copy first 4k bytes of candidate image */ 20750bd6153SVasant Hegde memcpy(args_buf->buf, image_data.data, VALIDATE_BUF_SIZE); 20850bd6153SVasant Hegde 20950bd6153SVasant Hegde args_buf->status = VALIDATE_IMG_READY; 21050bd6153SVasant Hegde args_buf->buf_size = VALIDATE_BUF_SIZE; 21150bd6153SVasant Hegde 21250bd6153SVasant Hegde /* Validate candidate image */ 21350bd6153SVasant Hegde opal_flash_validate(); 21450bd6153SVasant Hegde 21550bd6153SVasant Hegde out: 21650bd6153SVasant Hegde mutex_unlock(&image_data_mutex); 21750bd6153SVasant Hegde return count; 21850bd6153SVasant Hegde } 21950bd6153SVasant Hegde 22050bd6153SVasant Hegde /* 22150bd6153SVasant Hegde * Manage flash routine 22250bd6153SVasant Hegde */ 22350bd6153SVasant Hegde static inline void opal_flash_manage(uint8_t op) 22450bd6153SVasant Hegde { 22550bd6153SVasant Hegde struct manage_flash_t *const args_buf = &manage_flash_data; 22650bd6153SVasant Hegde 22750bd6153SVasant Hegde args_buf->status = opal_manage_flash(op); 22850bd6153SVasant Hegde } 22950bd6153SVasant Hegde 23050bd6153SVasant Hegde /* 23150bd6153SVasant Hegde * Show manage flash status 23250bd6153SVasant Hegde */ 23350bd6153SVasant Hegde static ssize_t manage_show(struct kobject *kobj, 23450bd6153SVasant Hegde struct kobj_attribute *attr, char *buf) 23550bd6153SVasant Hegde { 23650bd6153SVasant Hegde struct manage_flash_t *const args_buf = &manage_flash_data; 23750bd6153SVasant Hegde int rc; 23850bd6153SVasant Hegde 23950bd6153SVasant Hegde rc = sprintf(buf, "%d\n", args_buf->status); 24050bd6153SVasant Hegde /* Set status to default*/ 24150bd6153SVasant Hegde args_buf->status = FLASH_NO_OP; 24250bd6153SVasant Hegde return rc; 24350bd6153SVasant Hegde } 24450bd6153SVasant Hegde 24550bd6153SVasant Hegde /* 24650bd6153SVasant Hegde * Manage operations: 24750bd6153SVasant Hegde * 0 - Reject 24850bd6153SVasant Hegde * 1 - Commit 24950bd6153SVasant Hegde */ 25050bd6153SVasant Hegde static ssize_t manage_store(struct kobject *kobj, 25150bd6153SVasant Hegde struct kobj_attribute *attr, 25250bd6153SVasant Hegde const char *buf, size_t count) 25350bd6153SVasant Hegde { 25450bd6153SVasant Hegde uint8_t op; 25550bd6153SVasant Hegde switch (buf[0]) { 25650bd6153SVasant Hegde case '0': 25750bd6153SVasant Hegde op = FLASH_REJECT_TMP_SIDE; 25850bd6153SVasant Hegde break; 25950bd6153SVasant Hegde case '1': 26050bd6153SVasant Hegde op = FLASH_COMMIT_TMP_SIDE; 26150bd6153SVasant Hegde break; 26250bd6153SVasant Hegde default: 26350bd6153SVasant Hegde return -EINVAL; 26450bd6153SVasant Hegde } 26550bd6153SVasant Hegde 26650bd6153SVasant Hegde /* commit/reject temporary image */ 26750bd6153SVasant Hegde opal_flash_manage(op); 26850bd6153SVasant Hegde return count; 26950bd6153SVasant Hegde } 27050bd6153SVasant Hegde 27150bd6153SVasant Hegde /* 27250bd6153SVasant Hegde * OPAL update flash 27350bd6153SVasant Hegde */ 27450bd6153SVasant Hegde static int opal_flash_update(int op) 27550bd6153SVasant Hegde { 2763441f04bSAnton Blanchard struct opal_sg_list *list; 27750bd6153SVasant Hegde unsigned long addr; 27850bd6153SVasant Hegde int64_t rc = OPAL_PARAMETER; 27950bd6153SVasant Hegde 28050bd6153SVasant Hegde if (op == FLASH_UPDATE_CANCEL) { 28150bd6153SVasant Hegde pr_alert("FLASH: Image update cancelled\n"); 28250bd6153SVasant Hegde addr = '\0'; 28350bd6153SVasant Hegde goto flash; 28450bd6153SVasant Hegde } 28550bd6153SVasant Hegde 2863441f04bSAnton Blanchard list = opal_vmalloc_to_sg_list(image_data.data, image_data.size); 28750bd6153SVasant Hegde if (!list) 28850bd6153SVasant Hegde goto invalid_img; 28950bd6153SVasant Hegde 29050bd6153SVasant Hegde /* First entry address */ 29150bd6153SVasant Hegde addr = __pa(list); 29250bd6153SVasant Hegde 29350bd6153SVasant Hegde pr_alert("FLASH: Image is %u bytes\n", image_data.size); 29450bd6153SVasant Hegde pr_alert("FLASH: Image update requested\n"); 29550bd6153SVasant Hegde pr_alert("FLASH: Image will be updated during system reboot\n"); 29650bd6153SVasant Hegde pr_alert("FLASH: This will take several minutes. Do not power off!\n"); 29750bd6153SVasant Hegde 29850bd6153SVasant Hegde flash: 29950bd6153SVasant Hegde rc = opal_update_flash(addr); 30050bd6153SVasant Hegde 30150bd6153SVasant Hegde invalid_img: 30250bd6153SVasant Hegde return rc; 30350bd6153SVasant Hegde } 30450bd6153SVasant Hegde 30550bd6153SVasant Hegde /* 30650bd6153SVasant Hegde * Show candidate image status 30750bd6153SVasant Hegde */ 30850bd6153SVasant Hegde static ssize_t update_show(struct kobject *kobj, 30950bd6153SVasant Hegde struct kobj_attribute *attr, char *buf) 31050bd6153SVasant Hegde { 31150bd6153SVasant Hegde struct update_flash_t *const args_buf = &update_flash_data; 31250bd6153SVasant Hegde return sprintf(buf, "%d\n", args_buf->status); 31350bd6153SVasant Hegde } 31450bd6153SVasant Hegde 31550bd6153SVasant Hegde /* 31650bd6153SVasant Hegde * Set update image flag 31750bd6153SVasant Hegde * 1 - Flash new image 31850bd6153SVasant Hegde * 0 - Cancel flash request 31950bd6153SVasant Hegde */ 32050bd6153SVasant Hegde static ssize_t update_store(struct kobject *kobj, 32150bd6153SVasant Hegde struct kobj_attribute *attr, 32250bd6153SVasant Hegde const char *buf, size_t count) 32350bd6153SVasant Hegde { 32450bd6153SVasant Hegde struct update_flash_t *const args_buf = &update_flash_data; 32550bd6153SVasant Hegde int rc = count; 32650bd6153SVasant Hegde 32750bd6153SVasant Hegde mutex_lock(&image_data_mutex); 32850bd6153SVasant Hegde 32950bd6153SVasant Hegde switch (buf[0]) { 33050bd6153SVasant Hegde case '0': 33150bd6153SVasant Hegde if (args_buf->status == FLASH_IMG_READY) 33250bd6153SVasant Hegde opal_flash_update(FLASH_UPDATE_CANCEL); 33350bd6153SVasant Hegde args_buf->status = FLASH_NO_OP; 33450bd6153SVasant Hegde break; 33550bd6153SVasant Hegde case '1': 33650bd6153SVasant Hegde /* Image is loaded? */ 33750bd6153SVasant Hegde if (image_data.status == IMAGE_READY) 33850bd6153SVasant Hegde args_buf->status = 33950bd6153SVasant Hegde opal_flash_update(FLASH_UPDATE_INIT); 34050bd6153SVasant Hegde else 34150bd6153SVasant Hegde args_buf->status = FLASH_INVALID_IMG; 34250bd6153SVasant Hegde break; 34350bd6153SVasant Hegde default: 34450bd6153SVasant Hegde rc = -EINVAL; 34550bd6153SVasant Hegde } 34650bd6153SVasant Hegde 34750bd6153SVasant Hegde mutex_unlock(&image_data_mutex); 34850bd6153SVasant Hegde return rc; 34950bd6153SVasant Hegde } 35050bd6153SVasant Hegde 35150bd6153SVasant Hegde /* 35250bd6153SVasant Hegde * Free image buffer 35350bd6153SVasant Hegde */ 35450bd6153SVasant Hegde static void free_image_buf(void) 35550bd6153SVasant Hegde { 35650bd6153SVasant Hegde void *addr; 35750bd6153SVasant Hegde int size; 35850bd6153SVasant Hegde 35950bd6153SVasant Hegde addr = image_data.data; 36050bd6153SVasant Hegde size = PAGE_ALIGN(image_data.size); 36150bd6153SVasant Hegde while (size > 0) { 36250bd6153SVasant Hegde ClearPageReserved(vmalloc_to_page(addr)); 36350bd6153SVasant Hegde addr += PAGE_SIZE; 36450bd6153SVasant Hegde size -= PAGE_SIZE; 36550bd6153SVasant Hegde } 36650bd6153SVasant Hegde vfree(image_data.data); 36750bd6153SVasant Hegde image_data.data = NULL; 36850bd6153SVasant Hegde image_data.status = IMAGE_INVALID; 36950bd6153SVasant Hegde } 37050bd6153SVasant Hegde 37150bd6153SVasant Hegde /* 37250bd6153SVasant Hegde * Allocate image buffer. 37350bd6153SVasant Hegde */ 37450bd6153SVasant Hegde static int alloc_image_buf(char *buffer, size_t count) 37550bd6153SVasant Hegde { 37650bd6153SVasant Hegde void *addr; 37750bd6153SVasant Hegde int size; 37850bd6153SVasant Hegde 37950bd6153SVasant Hegde if (count < sizeof(struct image_header_t)) { 38050bd6153SVasant Hegde pr_warn("FLASH: Invalid candidate image\n"); 38150bd6153SVasant Hegde return -EINVAL; 38250bd6153SVasant Hegde } 38350bd6153SVasant Hegde 38450bd6153SVasant Hegde memcpy(&image_header, (void *)buffer, sizeof(struct image_header_t)); 38550bd6153SVasant Hegde image_data.size = be32_to_cpu(image_header.size); 3868faaaeadSMasanari Iida pr_debug("FLASH: Candidate image size = %u\n", image_data.size); 38750bd6153SVasant Hegde 38850bd6153SVasant Hegde if (image_data.size > MAX_IMAGE_SIZE) { 38950bd6153SVasant Hegde pr_warn("FLASH: Too large image\n"); 39050bd6153SVasant Hegde return -EINVAL; 39150bd6153SVasant Hegde } 39250bd6153SVasant Hegde if (image_data.size < VALIDATE_BUF_SIZE) { 39350bd6153SVasant Hegde pr_warn("FLASH: Image is shorter than expected\n"); 39450bd6153SVasant Hegde return -EINVAL; 39550bd6153SVasant Hegde } 39650bd6153SVasant Hegde 39750bd6153SVasant Hegde image_data.data = vzalloc(PAGE_ALIGN(image_data.size)); 39850bd6153SVasant Hegde if (!image_data.data) { 39950bd6153SVasant Hegde pr_err("%s : Failed to allocate memory\n", __func__); 40050bd6153SVasant Hegde return -ENOMEM; 40150bd6153SVasant Hegde } 40250bd6153SVasant Hegde 40350bd6153SVasant Hegde /* Pin memory */ 40450bd6153SVasant Hegde addr = image_data.data; 40550bd6153SVasant Hegde size = PAGE_ALIGN(image_data.size); 40650bd6153SVasant Hegde while (size > 0) { 40750bd6153SVasant Hegde SetPageReserved(vmalloc_to_page(addr)); 40850bd6153SVasant Hegde addr += PAGE_SIZE; 40950bd6153SVasant Hegde size -= PAGE_SIZE; 41050bd6153SVasant Hegde } 41150bd6153SVasant Hegde 41250bd6153SVasant Hegde image_data.status = IMAGE_LOADING; 41350bd6153SVasant Hegde return 0; 41450bd6153SVasant Hegde } 41550bd6153SVasant Hegde 41650bd6153SVasant Hegde /* 41750bd6153SVasant Hegde * Copy candidate image 41850bd6153SVasant Hegde * 41950bd6153SVasant Hegde * Parse candidate image header to get total image size 42050bd6153SVasant Hegde * and pre-allocate required memory. 42150bd6153SVasant Hegde */ 42250bd6153SVasant Hegde static ssize_t image_data_write(struct file *filp, struct kobject *kobj, 42350bd6153SVasant Hegde struct bin_attribute *bin_attr, 42450bd6153SVasant Hegde char *buffer, loff_t pos, size_t count) 42550bd6153SVasant Hegde { 42650bd6153SVasant Hegde int rc; 42750bd6153SVasant Hegde 42850bd6153SVasant Hegde mutex_lock(&image_data_mutex); 42950bd6153SVasant Hegde 43050bd6153SVasant Hegde /* New image ? */ 43150bd6153SVasant Hegde if (pos == 0) { 43250bd6153SVasant Hegde /* Free memory, if already allocated */ 43350bd6153SVasant Hegde if (image_data.data) 43450bd6153SVasant Hegde free_image_buf(); 43550bd6153SVasant Hegde 43650bd6153SVasant Hegde /* Cancel outstanding image update request */ 43750bd6153SVasant Hegde if (update_flash_data.status == FLASH_IMG_READY) 43850bd6153SVasant Hegde opal_flash_update(FLASH_UPDATE_CANCEL); 43950bd6153SVasant Hegde 44050bd6153SVasant Hegde /* Allocate memory */ 44150bd6153SVasant Hegde rc = alloc_image_buf(buffer, count); 44250bd6153SVasant Hegde if (rc) 44350bd6153SVasant Hegde goto out; 44450bd6153SVasant Hegde } 44550bd6153SVasant Hegde 44650bd6153SVasant Hegde if (image_data.status != IMAGE_LOADING) { 44750bd6153SVasant Hegde rc = -ENOMEM; 44850bd6153SVasant Hegde goto out; 44950bd6153SVasant Hegde } 45050bd6153SVasant Hegde 45150bd6153SVasant Hegde if ((pos + count) > image_data.size) { 45250bd6153SVasant Hegde rc = -EINVAL; 45350bd6153SVasant Hegde goto out; 45450bd6153SVasant Hegde } 45550bd6153SVasant Hegde 45650bd6153SVasant Hegde memcpy(image_data.data + pos, (void *)buffer, count); 45750bd6153SVasant Hegde rc = count; 45850bd6153SVasant Hegde 45950bd6153SVasant Hegde /* Set image status */ 46050bd6153SVasant Hegde if ((pos + count) == image_data.size) { 46150bd6153SVasant Hegde pr_debug("FLASH: Candidate image loaded....\n"); 46250bd6153SVasant Hegde image_data.status = IMAGE_READY; 46350bd6153SVasant Hegde } 46450bd6153SVasant Hegde 46550bd6153SVasant Hegde out: 46650bd6153SVasant Hegde mutex_unlock(&image_data_mutex); 46750bd6153SVasant Hegde return rc; 46850bd6153SVasant Hegde } 46950bd6153SVasant Hegde 47050bd6153SVasant Hegde /* 47150bd6153SVasant Hegde * sysfs interface : 47250bd6153SVasant Hegde * OPAL uses below sysfs files for code update. 47350bd6153SVasant Hegde * We create these files under /sys/firmware/opal. 47450bd6153SVasant Hegde * 47550bd6153SVasant Hegde * image : Interface to load candidate firmware image 47650bd6153SVasant Hegde * validate_flash : Validate firmware image 47750bd6153SVasant Hegde * manage_flash : Commit/Reject firmware image 47850bd6153SVasant Hegde * update_flash : Flash new firmware image 47950bd6153SVasant Hegde * 48050bd6153SVasant Hegde */ 48150bd6153SVasant Hegde static struct bin_attribute image_data_attr = { 48250bd6153SVasant Hegde .attr = {.name = "image", .mode = 0200}, 48350bd6153SVasant Hegde .size = MAX_IMAGE_SIZE, /* Limit image size */ 48450bd6153SVasant Hegde .write = image_data_write, 48550bd6153SVasant Hegde }; 48650bd6153SVasant Hegde 48750bd6153SVasant Hegde static struct kobj_attribute validate_attribute = 48850bd6153SVasant Hegde __ATTR(validate_flash, 0600, validate_show, validate_store); 48950bd6153SVasant Hegde 49050bd6153SVasant Hegde static struct kobj_attribute manage_attribute = 49150bd6153SVasant Hegde __ATTR(manage_flash, 0600, manage_show, manage_store); 49250bd6153SVasant Hegde 49350bd6153SVasant Hegde static struct kobj_attribute update_attribute = 49450bd6153SVasant Hegde __ATTR(update_flash, 0600, update_show, update_store); 49550bd6153SVasant Hegde 49650bd6153SVasant Hegde static struct attribute *image_op_attrs[] = { 49750bd6153SVasant Hegde &validate_attribute.attr, 49850bd6153SVasant Hegde &manage_attribute.attr, 49950bd6153SVasant Hegde &update_attribute.attr, 50050bd6153SVasant Hegde NULL /* need to NULL terminate the list of attributes */ 50150bd6153SVasant Hegde }; 50250bd6153SVasant Hegde 50350bd6153SVasant Hegde static struct attribute_group image_op_attr_group = { 50450bd6153SVasant Hegde .attrs = image_op_attrs, 50550bd6153SVasant Hegde }; 50650bd6153SVasant Hegde 50750bd6153SVasant Hegde void __init opal_flash_init(void) 50850bd6153SVasant Hegde { 50950bd6153SVasant Hegde int ret; 51050bd6153SVasant Hegde 51150bd6153SVasant Hegde /* Allocate validate image buffer */ 51250bd6153SVasant Hegde validate_flash_data.buf = kzalloc(VALIDATE_BUF_SIZE, GFP_KERNEL); 51350bd6153SVasant Hegde if (!validate_flash_data.buf) { 51450bd6153SVasant Hegde pr_err("%s : Failed to allocate memory\n", __func__); 51550bd6153SVasant Hegde return; 51650bd6153SVasant Hegde } 51750bd6153SVasant Hegde 51850bd6153SVasant Hegde /* Make sure /sys/firmware/opal directory is created */ 51950bd6153SVasant Hegde if (!opal_kobj) { 52050bd6153SVasant Hegde pr_warn("FLASH: opal kobject is not available\n"); 52150bd6153SVasant Hegde goto nokobj; 52250bd6153SVasant Hegde } 52350bd6153SVasant Hegde 52450bd6153SVasant Hegde /* Create the sysfs files */ 52550bd6153SVasant Hegde ret = sysfs_create_group(opal_kobj, &image_op_attr_group); 52650bd6153SVasant Hegde if (ret) { 52750bd6153SVasant Hegde pr_warn("FLASH: Failed to create sysfs files\n"); 52850bd6153SVasant Hegde goto nokobj; 52950bd6153SVasant Hegde } 53050bd6153SVasant Hegde 53150bd6153SVasant Hegde ret = sysfs_create_bin_file(opal_kobj, &image_data_attr); 53250bd6153SVasant Hegde if (ret) { 53350bd6153SVasant Hegde pr_warn("FLASH: Failed to create sysfs files\n"); 53450bd6153SVasant Hegde goto nosysfs_file; 53550bd6153SVasant Hegde } 53650bd6153SVasant Hegde 53750bd6153SVasant Hegde /* Set default status */ 53850bd6153SVasant Hegde validate_flash_data.status = FLASH_NO_OP; 53950bd6153SVasant Hegde manage_flash_data.status = FLASH_NO_OP; 54050bd6153SVasant Hegde update_flash_data.status = FLASH_NO_OP; 54150bd6153SVasant Hegde image_data.status = IMAGE_INVALID; 54250bd6153SVasant Hegde return; 54350bd6153SVasant Hegde 54450bd6153SVasant Hegde nosysfs_file: 54550bd6153SVasant Hegde sysfs_remove_group(opal_kobj, &image_op_attr_group); 54650bd6153SVasant Hegde 54750bd6153SVasant Hegde nokobj: 54850bd6153SVasant Hegde kfree(validate_flash_data.buf); 54950bd6153SVasant Hegde return; 55050bd6153SVasant Hegde } 551