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