xref: /linux/arch/powerpc/platforms/powernv/opal-flash.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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