xref: /openbmc/linux/arch/powerpc/kernel/rtas_flash.c (revision f4fcbbe9a7fdf11305fea657202b954bdc2228ec)
1*f4fcbbe9SPaul Mackerras /*
2*f4fcbbe9SPaul Mackerras  *  c 2001 PPC 64 Team, IBM Corp
3*f4fcbbe9SPaul Mackerras  *
4*f4fcbbe9SPaul Mackerras  *      This program is free software; you can redistribute it and/or
5*f4fcbbe9SPaul Mackerras  *      modify it under the terms of the GNU General Public License
6*f4fcbbe9SPaul Mackerras  *      as published by the Free Software Foundation; either version
7*f4fcbbe9SPaul Mackerras  *      2 of the License, or (at your option) any later version.
8*f4fcbbe9SPaul Mackerras  *
9*f4fcbbe9SPaul Mackerras  * /proc/ppc64/rtas/firmware_flash interface
10*f4fcbbe9SPaul Mackerras  *
11*f4fcbbe9SPaul Mackerras  * This file implements a firmware_flash interface to pump a firmware
12*f4fcbbe9SPaul Mackerras  * image into the kernel.  At reboot time rtas_restart() will see the
13*f4fcbbe9SPaul Mackerras  * firmware image and flash it as it reboots (see rtas.c).
14*f4fcbbe9SPaul Mackerras  */
15*f4fcbbe9SPaul Mackerras 
16*f4fcbbe9SPaul Mackerras #include <linux/module.h>
17*f4fcbbe9SPaul Mackerras #include <linux/init.h>
18*f4fcbbe9SPaul Mackerras #include <linux/proc_fs.h>
19*f4fcbbe9SPaul Mackerras #include <asm/delay.h>
20*f4fcbbe9SPaul Mackerras #include <asm/uaccess.h>
21*f4fcbbe9SPaul Mackerras #include <asm/rtas.h>
22*f4fcbbe9SPaul Mackerras #include <asm/abs_addr.h>
23*f4fcbbe9SPaul Mackerras 
24*f4fcbbe9SPaul Mackerras #define MODULE_VERS "1.0"
25*f4fcbbe9SPaul Mackerras #define MODULE_NAME "rtas_flash"
26*f4fcbbe9SPaul Mackerras 
27*f4fcbbe9SPaul Mackerras #define FIRMWARE_FLASH_NAME "firmware_flash"
28*f4fcbbe9SPaul Mackerras #define FIRMWARE_UPDATE_NAME "firmware_update"
29*f4fcbbe9SPaul Mackerras #define MANAGE_FLASH_NAME "manage_flash"
30*f4fcbbe9SPaul Mackerras #define VALIDATE_FLASH_NAME "validate_flash"
31*f4fcbbe9SPaul Mackerras 
32*f4fcbbe9SPaul Mackerras /* General RTAS Status Codes */
33*f4fcbbe9SPaul Mackerras #define RTAS_RC_SUCCESS  0
34*f4fcbbe9SPaul Mackerras #define RTAS_RC_HW_ERR	-1
35*f4fcbbe9SPaul Mackerras #define RTAS_RC_BUSY	-2
36*f4fcbbe9SPaul Mackerras 
37*f4fcbbe9SPaul Mackerras /* Flash image status values */
38*f4fcbbe9SPaul Mackerras #define FLASH_AUTH           -9002 /* RTAS Not Service Authority Partition */
39*f4fcbbe9SPaul Mackerras #define FLASH_NO_OP          -1099 /* No operation initiated by user */
40*f4fcbbe9SPaul Mackerras #define FLASH_IMG_SHORT	     -1005 /* Flash image shorter than expected */
41*f4fcbbe9SPaul Mackerras #define FLASH_IMG_BAD_LEN    -1004 /* Bad length value in flash list block */
42*f4fcbbe9SPaul Mackerras #define FLASH_IMG_NULL_DATA  -1003 /* Bad data value in flash list block */
43*f4fcbbe9SPaul Mackerras #define FLASH_IMG_READY      0     /* Firmware img ready for flash on reboot */
44*f4fcbbe9SPaul Mackerras 
45*f4fcbbe9SPaul Mackerras /* Manage image status values */
46*f4fcbbe9SPaul Mackerras #define MANAGE_AUTH          -9002 /* RTAS Not Service Authority Partition */
47*f4fcbbe9SPaul Mackerras #define MANAGE_ACTIVE_ERR    -9001 /* RTAS Cannot Overwrite Active Img */
48*f4fcbbe9SPaul Mackerras #define MANAGE_NO_OP         -1099 /* No operation initiated by user */
49*f4fcbbe9SPaul Mackerras #define MANAGE_PARAM_ERR     -3    /* RTAS Parameter Error */
50*f4fcbbe9SPaul Mackerras #define MANAGE_HW_ERR        -1    /* RTAS Hardware Error */
51*f4fcbbe9SPaul Mackerras 
52*f4fcbbe9SPaul Mackerras /* Validate image status values */
53*f4fcbbe9SPaul Mackerras #define VALIDATE_AUTH          -9002 /* RTAS Not Service Authority Partition */
54*f4fcbbe9SPaul Mackerras #define VALIDATE_NO_OP         -1099 /* No operation initiated by the user */
55*f4fcbbe9SPaul Mackerras #define VALIDATE_INCOMPLETE    -1002 /* User copied < VALIDATE_BUF_SIZE */
56*f4fcbbe9SPaul Mackerras #define VALIDATE_READY	       -1001 /* Firmware image ready for validation */
57*f4fcbbe9SPaul Mackerras #define VALIDATE_PARAM_ERR     -3    /* RTAS Parameter Error */
58*f4fcbbe9SPaul Mackerras #define VALIDATE_HW_ERR        -1    /* RTAS Hardware Error */
59*f4fcbbe9SPaul Mackerras #define VALIDATE_TMP_UPDATE    0     /* Validate Return Status */
60*f4fcbbe9SPaul Mackerras #define VALIDATE_FLASH_AUTH    1     /* Validate Return Status */
61*f4fcbbe9SPaul Mackerras #define VALIDATE_INVALID_IMG   2     /* Validate Return Status */
62*f4fcbbe9SPaul Mackerras #define VALIDATE_CUR_UNKNOWN   3     /* Validate Return Status */
63*f4fcbbe9SPaul Mackerras #define VALIDATE_TMP_COMMIT_DL 4     /* Validate Return Status */
64*f4fcbbe9SPaul Mackerras #define VALIDATE_TMP_COMMIT    5     /* Validate Return Status */
65*f4fcbbe9SPaul Mackerras #define VALIDATE_TMP_UPDATE_DL 6     /* Validate Return Status */
66*f4fcbbe9SPaul Mackerras 
67*f4fcbbe9SPaul Mackerras /* ibm,manage-flash-image operation tokens */
68*f4fcbbe9SPaul Mackerras #define RTAS_REJECT_TMP_IMG   0
69*f4fcbbe9SPaul Mackerras #define RTAS_COMMIT_TMP_IMG   1
70*f4fcbbe9SPaul Mackerras 
71*f4fcbbe9SPaul Mackerras /* Array sizes */
72*f4fcbbe9SPaul Mackerras #define VALIDATE_BUF_SIZE 4096
73*f4fcbbe9SPaul Mackerras #define RTAS_MSG_MAXLEN   64
74*f4fcbbe9SPaul Mackerras 
75*f4fcbbe9SPaul Mackerras struct flash_block {
76*f4fcbbe9SPaul Mackerras 	char *data;
77*f4fcbbe9SPaul Mackerras 	unsigned long length;
78*f4fcbbe9SPaul Mackerras };
79*f4fcbbe9SPaul Mackerras 
80*f4fcbbe9SPaul Mackerras /* This struct is very similar but not identical to
81*f4fcbbe9SPaul Mackerras  * that needed by the rtas flash update.
82*f4fcbbe9SPaul Mackerras  * All we need to do for rtas is rewrite num_blocks
83*f4fcbbe9SPaul Mackerras  * into a version/length and translate the pointers
84*f4fcbbe9SPaul Mackerras  * to absolute.
85*f4fcbbe9SPaul Mackerras  */
86*f4fcbbe9SPaul Mackerras #define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block))
87*f4fcbbe9SPaul Mackerras struct flash_block_list {
88*f4fcbbe9SPaul Mackerras 	unsigned long num_blocks;
89*f4fcbbe9SPaul Mackerras 	struct flash_block_list *next;
90*f4fcbbe9SPaul Mackerras 	struct flash_block blocks[FLASH_BLOCKS_PER_NODE];
91*f4fcbbe9SPaul Mackerras };
92*f4fcbbe9SPaul Mackerras struct flash_block_list_header { /* just the header of flash_block_list */
93*f4fcbbe9SPaul Mackerras 	unsigned long num_blocks;
94*f4fcbbe9SPaul Mackerras 	struct flash_block_list *next;
95*f4fcbbe9SPaul Mackerras };
96*f4fcbbe9SPaul Mackerras 
97*f4fcbbe9SPaul Mackerras static struct flash_block_list_header rtas_firmware_flash_list = {0, NULL};
98*f4fcbbe9SPaul Mackerras 
99*f4fcbbe9SPaul Mackerras #define FLASH_BLOCK_LIST_VERSION (1UL)
100*f4fcbbe9SPaul Mackerras 
101*f4fcbbe9SPaul Mackerras /* Local copy of the flash block list.
102*f4fcbbe9SPaul Mackerras  * We only allow one open of the flash proc file and create this
103*f4fcbbe9SPaul Mackerras  * list as we go.  This list will be put in the
104*f4fcbbe9SPaul Mackerras  * rtas_firmware_flash_list var once it is fully read.
105*f4fcbbe9SPaul Mackerras  *
106*f4fcbbe9SPaul Mackerras  * For convenience as we build the list we use virtual addrs,
107*f4fcbbe9SPaul Mackerras  * we do not fill in the version number, and the length field
108*f4fcbbe9SPaul Mackerras  * is treated as the number of entries currently in the block
109*f4fcbbe9SPaul Mackerras  * (i.e. not a byte count).  This is all fixed on release.
110*f4fcbbe9SPaul Mackerras  */
111*f4fcbbe9SPaul Mackerras 
112*f4fcbbe9SPaul Mackerras /* Status int must be first member of struct */
113*f4fcbbe9SPaul Mackerras struct rtas_update_flash_t
114*f4fcbbe9SPaul Mackerras {
115*f4fcbbe9SPaul Mackerras 	int status;			/* Flash update status */
116*f4fcbbe9SPaul Mackerras 	struct flash_block_list *flist; /* Local copy of flash block list */
117*f4fcbbe9SPaul Mackerras };
118*f4fcbbe9SPaul Mackerras 
119*f4fcbbe9SPaul Mackerras /* Status int must be first member of struct */
120*f4fcbbe9SPaul Mackerras struct rtas_manage_flash_t
121*f4fcbbe9SPaul Mackerras {
122*f4fcbbe9SPaul Mackerras 	int status;			/* Returned status */
123*f4fcbbe9SPaul Mackerras 	unsigned int op;		/* Reject or commit image */
124*f4fcbbe9SPaul Mackerras };
125*f4fcbbe9SPaul Mackerras 
126*f4fcbbe9SPaul Mackerras /* Status int must be first member of struct */
127*f4fcbbe9SPaul Mackerras struct rtas_validate_flash_t
128*f4fcbbe9SPaul Mackerras {
129*f4fcbbe9SPaul Mackerras 	int status;		 	/* Returned status */
130*f4fcbbe9SPaul Mackerras 	char buf[VALIDATE_BUF_SIZE]; 	/* Candidate image buffer */
131*f4fcbbe9SPaul Mackerras 	unsigned int buf_size;		/* Size of image buf */
132*f4fcbbe9SPaul Mackerras 	unsigned int update_results;	/* Update results token */
133*f4fcbbe9SPaul Mackerras };
134*f4fcbbe9SPaul Mackerras 
135*f4fcbbe9SPaul Mackerras static DEFINE_SPINLOCK(flash_file_open_lock);
136*f4fcbbe9SPaul Mackerras static struct proc_dir_entry *firmware_flash_pde;
137*f4fcbbe9SPaul Mackerras static struct proc_dir_entry *firmware_update_pde;
138*f4fcbbe9SPaul Mackerras static struct proc_dir_entry *validate_pde;
139*f4fcbbe9SPaul Mackerras static struct proc_dir_entry *manage_pde;
140*f4fcbbe9SPaul Mackerras 
141*f4fcbbe9SPaul Mackerras /* Do simple sanity checks on the flash image. */
142*f4fcbbe9SPaul Mackerras static int flash_list_valid(struct flash_block_list *flist)
143*f4fcbbe9SPaul Mackerras {
144*f4fcbbe9SPaul Mackerras 	struct flash_block_list *f;
145*f4fcbbe9SPaul Mackerras 	int i;
146*f4fcbbe9SPaul Mackerras 	unsigned long block_size, image_size;
147*f4fcbbe9SPaul Mackerras 
148*f4fcbbe9SPaul Mackerras 	/* Paranoid self test here.  We also collect the image size. */
149*f4fcbbe9SPaul Mackerras 	image_size = 0;
150*f4fcbbe9SPaul Mackerras 	for (f = flist; f; f = f->next) {
151*f4fcbbe9SPaul Mackerras 		for (i = 0; i < f->num_blocks; i++) {
152*f4fcbbe9SPaul Mackerras 			if (f->blocks[i].data == NULL) {
153*f4fcbbe9SPaul Mackerras 				return FLASH_IMG_NULL_DATA;
154*f4fcbbe9SPaul Mackerras 			}
155*f4fcbbe9SPaul Mackerras 			block_size = f->blocks[i].length;
156*f4fcbbe9SPaul Mackerras 			if (block_size <= 0 || block_size > PAGE_SIZE) {
157*f4fcbbe9SPaul Mackerras 				return FLASH_IMG_BAD_LEN;
158*f4fcbbe9SPaul Mackerras 			}
159*f4fcbbe9SPaul Mackerras 			image_size += block_size;
160*f4fcbbe9SPaul Mackerras 		}
161*f4fcbbe9SPaul Mackerras 	}
162*f4fcbbe9SPaul Mackerras 
163*f4fcbbe9SPaul Mackerras 	if (image_size < (256 << 10)) {
164*f4fcbbe9SPaul Mackerras 		if (image_size < 2)
165*f4fcbbe9SPaul Mackerras 			return FLASH_NO_OP;
166*f4fcbbe9SPaul Mackerras 	}
167*f4fcbbe9SPaul Mackerras 
168*f4fcbbe9SPaul Mackerras 	printk(KERN_INFO "FLASH: flash image with %ld bytes stored for hardware flash on reboot\n", image_size);
169*f4fcbbe9SPaul Mackerras 
170*f4fcbbe9SPaul Mackerras 	return FLASH_IMG_READY;
171*f4fcbbe9SPaul Mackerras }
172*f4fcbbe9SPaul Mackerras 
173*f4fcbbe9SPaul Mackerras static void free_flash_list(struct flash_block_list *f)
174*f4fcbbe9SPaul Mackerras {
175*f4fcbbe9SPaul Mackerras 	struct flash_block_list *next;
176*f4fcbbe9SPaul Mackerras 	int i;
177*f4fcbbe9SPaul Mackerras 
178*f4fcbbe9SPaul Mackerras 	while (f) {
179*f4fcbbe9SPaul Mackerras 		for (i = 0; i < f->num_blocks; i++)
180*f4fcbbe9SPaul Mackerras 			free_page((unsigned long)(f->blocks[i].data));
181*f4fcbbe9SPaul Mackerras 		next = f->next;
182*f4fcbbe9SPaul Mackerras 		free_page((unsigned long)f);
183*f4fcbbe9SPaul Mackerras 		f = next;
184*f4fcbbe9SPaul Mackerras 	}
185*f4fcbbe9SPaul Mackerras }
186*f4fcbbe9SPaul Mackerras 
187*f4fcbbe9SPaul Mackerras static int rtas_flash_release(struct inode *inode, struct file *file)
188*f4fcbbe9SPaul Mackerras {
189*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
190*f4fcbbe9SPaul Mackerras 	struct rtas_update_flash_t *uf;
191*f4fcbbe9SPaul Mackerras 
192*f4fcbbe9SPaul Mackerras 	uf = (struct rtas_update_flash_t *) dp->data;
193*f4fcbbe9SPaul Mackerras 	if (uf->flist) {
194*f4fcbbe9SPaul Mackerras 		/* File was opened in write mode for a new flash attempt */
195*f4fcbbe9SPaul Mackerras 		/* Clear saved list */
196*f4fcbbe9SPaul Mackerras 		if (rtas_firmware_flash_list.next) {
197*f4fcbbe9SPaul Mackerras 			free_flash_list(rtas_firmware_flash_list.next);
198*f4fcbbe9SPaul Mackerras 			rtas_firmware_flash_list.next = NULL;
199*f4fcbbe9SPaul Mackerras 		}
200*f4fcbbe9SPaul Mackerras 
201*f4fcbbe9SPaul Mackerras 		if (uf->status != FLASH_AUTH)
202*f4fcbbe9SPaul Mackerras 			uf->status = flash_list_valid(uf->flist);
203*f4fcbbe9SPaul Mackerras 
204*f4fcbbe9SPaul Mackerras 		if (uf->status == FLASH_IMG_READY)
205*f4fcbbe9SPaul Mackerras 			rtas_firmware_flash_list.next = uf->flist;
206*f4fcbbe9SPaul Mackerras 		else
207*f4fcbbe9SPaul Mackerras 			free_flash_list(uf->flist);
208*f4fcbbe9SPaul Mackerras 
209*f4fcbbe9SPaul Mackerras 		uf->flist = NULL;
210*f4fcbbe9SPaul Mackerras 	}
211*f4fcbbe9SPaul Mackerras 
212*f4fcbbe9SPaul Mackerras 	atomic_dec(&dp->count);
213*f4fcbbe9SPaul Mackerras 	return 0;
214*f4fcbbe9SPaul Mackerras }
215*f4fcbbe9SPaul Mackerras 
216*f4fcbbe9SPaul Mackerras static void get_flash_status_msg(int status, char *buf)
217*f4fcbbe9SPaul Mackerras {
218*f4fcbbe9SPaul Mackerras 	char *msg;
219*f4fcbbe9SPaul Mackerras 
220*f4fcbbe9SPaul Mackerras 	switch (status) {
221*f4fcbbe9SPaul Mackerras 	case FLASH_AUTH:
222*f4fcbbe9SPaul Mackerras 		msg = "error: this partition does not have service authority\n";
223*f4fcbbe9SPaul Mackerras 		break;
224*f4fcbbe9SPaul Mackerras 	case FLASH_NO_OP:
225*f4fcbbe9SPaul Mackerras 		msg = "info: no firmware image for flash\n";
226*f4fcbbe9SPaul Mackerras 		break;
227*f4fcbbe9SPaul Mackerras 	case FLASH_IMG_SHORT:
228*f4fcbbe9SPaul Mackerras 		msg = "error: flash image short\n";
229*f4fcbbe9SPaul Mackerras 		break;
230*f4fcbbe9SPaul Mackerras 	case FLASH_IMG_BAD_LEN:
231*f4fcbbe9SPaul Mackerras 		msg = "error: internal error bad length\n";
232*f4fcbbe9SPaul Mackerras 		break;
233*f4fcbbe9SPaul Mackerras 	case FLASH_IMG_NULL_DATA:
234*f4fcbbe9SPaul Mackerras 		msg = "error: internal error null data\n";
235*f4fcbbe9SPaul Mackerras 		break;
236*f4fcbbe9SPaul Mackerras 	case FLASH_IMG_READY:
237*f4fcbbe9SPaul Mackerras 		msg = "ready: firmware image ready for flash on reboot\n";
238*f4fcbbe9SPaul Mackerras 		break;
239*f4fcbbe9SPaul Mackerras 	default:
240*f4fcbbe9SPaul Mackerras 		sprintf(buf, "error: unexpected status value %d\n", status);
241*f4fcbbe9SPaul Mackerras 		return;
242*f4fcbbe9SPaul Mackerras 	}
243*f4fcbbe9SPaul Mackerras 
244*f4fcbbe9SPaul Mackerras 	strcpy(buf, msg);
245*f4fcbbe9SPaul Mackerras }
246*f4fcbbe9SPaul Mackerras 
247*f4fcbbe9SPaul Mackerras /* Reading the proc file will show status (not the firmware contents) */
248*f4fcbbe9SPaul Mackerras static ssize_t rtas_flash_read(struct file *file, char __user *buf,
249*f4fcbbe9SPaul Mackerras 			       size_t count, loff_t *ppos)
250*f4fcbbe9SPaul Mackerras {
251*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
252*f4fcbbe9SPaul Mackerras 	struct rtas_update_flash_t *uf;
253*f4fcbbe9SPaul Mackerras 	char msg[RTAS_MSG_MAXLEN];
254*f4fcbbe9SPaul Mackerras 	int msglen;
255*f4fcbbe9SPaul Mackerras 
256*f4fcbbe9SPaul Mackerras 	uf = (struct rtas_update_flash_t *) dp->data;
257*f4fcbbe9SPaul Mackerras 
258*f4fcbbe9SPaul Mackerras 	if (!strcmp(dp->name, FIRMWARE_FLASH_NAME)) {
259*f4fcbbe9SPaul Mackerras 		get_flash_status_msg(uf->status, msg);
260*f4fcbbe9SPaul Mackerras 	} else {	   /* FIRMWARE_UPDATE_NAME */
261*f4fcbbe9SPaul Mackerras 		sprintf(msg, "%d\n", uf->status);
262*f4fcbbe9SPaul Mackerras 	}
263*f4fcbbe9SPaul Mackerras 	msglen = strlen(msg);
264*f4fcbbe9SPaul Mackerras 	if (msglen > count)
265*f4fcbbe9SPaul Mackerras 		msglen = count;
266*f4fcbbe9SPaul Mackerras 
267*f4fcbbe9SPaul Mackerras 	if (ppos && *ppos != 0)
268*f4fcbbe9SPaul Mackerras 		return 0;	/* be cheap */
269*f4fcbbe9SPaul Mackerras 
270*f4fcbbe9SPaul Mackerras 	if (!access_ok(VERIFY_WRITE, buf, msglen))
271*f4fcbbe9SPaul Mackerras 		return -EINVAL;
272*f4fcbbe9SPaul Mackerras 
273*f4fcbbe9SPaul Mackerras 	if (copy_to_user(buf, msg, msglen))
274*f4fcbbe9SPaul Mackerras 		return -EFAULT;
275*f4fcbbe9SPaul Mackerras 
276*f4fcbbe9SPaul Mackerras 	if (ppos)
277*f4fcbbe9SPaul Mackerras 		*ppos = msglen;
278*f4fcbbe9SPaul Mackerras 	return msglen;
279*f4fcbbe9SPaul Mackerras }
280*f4fcbbe9SPaul Mackerras 
281*f4fcbbe9SPaul Mackerras /* We could be much more efficient here.  But to keep this function
282*f4fcbbe9SPaul Mackerras  * simple we allocate a page to the block list no matter how small the
283*f4fcbbe9SPaul Mackerras  * count is.  If the system is low on memory it will be just as well
284*f4fcbbe9SPaul Mackerras  * that we fail....
285*f4fcbbe9SPaul Mackerras  */
286*f4fcbbe9SPaul Mackerras static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
287*f4fcbbe9SPaul Mackerras 				size_t count, loff_t *off)
288*f4fcbbe9SPaul Mackerras {
289*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
290*f4fcbbe9SPaul Mackerras 	struct rtas_update_flash_t *uf;
291*f4fcbbe9SPaul Mackerras 	char *p;
292*f4fcbbe9SPaul Mackerras 	int next_free;
293*f4fcbbe9SPaul Mackerras 	struct flash_block_list *fl;
294*f4fcbbe9SPaul Mackerras 
295*f4fcbbe9SPaul Mackerras 	uf = (struct rtas_update_flash_t *) dp->data;
296*f4fcbbe9SPaul Mackerras 
297*f4fcbbe9SPaul Mackerras 	if (uf->status == FLASH_AUTH || count == 0)
298*f4fcbbe9SPaul Mackerras 		return count;	/* discard data */
299*f4fcbbe9SPaul Mackerras 
300*f4fcbbe9SPaul Mackerras 	/* In the case that the image is not ready for flashing, the memory
301*f4fcbbe9SPaul Mackerras 	 * allocated for the block list will be freed upon the release of the
302*f4fcbbe9SPaul Mackerras 	 * proc file
303*f4fcbbe9SPaul Mackerras 	 */
304*f4fcbbe9SPaul Mackerras 	if (uf->flist == NULL) {
305*f4fcbbe9SPaul Mackerras 		uf->flist = (struct flash_block_list *) get_zeroed_page(GFP_KERNEL);
306*f4fcbbe9SPaul Mackerras 		if (!uf->flist)
307*f4fcbbe9SPaul Mackerras 			return -ENOMEM;
308*f4fcbbe9SPaul Mackerras 	}
309*f4fcbbe9SPaul Mackerras 
310*f4fcbbe9SPaul Mackerras 	fl = uf->flist;
311*f4fcbbe9SPaul Mackerras 	while (fl->next)
312*f4fcbbe9SPaul Mackerras 		fl = fl->next; /* seek to last block_list for append */
313*f4fcbbe9SPaul Mackerras 	next_free = fl->num_blocks;
314*f4fcbbe9SPaul Mackerras 	if (next_free == FLASH_BLOCKS_PER_NODE) {
315*f4fcbbe9SPaul Mackerras 		/* Need to allocate another block_list */
316*f4fcbbe9SPaul Mackerras 		fl->next = (struct flash_block_list *)get_zeroed_page(GFP_KERNEL);
317*f4fcbbe9SPaul Mackerras 		if (!fl->next)
318*f4fcbbe9SPaul Mackerras 			return -ENOMEM;
319*f4fcbbe9SPaul Mackerras 		fl = fl->next;
320*f4fcbbe9SPaul Mackerras 		next_free = 0;
321*f4fcbbe9SPaul Mackerras 	}
322*f4fcbbe9SPaul Mackerras 
323*f4fcbbe9SPaul Mackerras 	if (count > PAGE_SIZE)
324*f4fcbbe9SPaul Mackerras 		count = PAGE_SIZE;
325*f4fcbbe9SPaul Mackerras 	p = (char *)get_zeroed_page(GFP_KERNEL);
326*f4fcbbe9SPaul Mackerras 	if (!p)
327*f4fcbbe9SPaul Mackerras 		return -ENOMEM;
328*f4fcbbe9SPaul Mackerras 
329*f4fcbbe9SPaul Mackerras 	if(copy_from_user(p, buffer, count)) {
330*f4fcbbe9SPaul Mackerras 		free_page((unsigned long)p);
331*f4fcbbe9SPaul Mackerras 		return -EFAULT;
332*f4fcbbe9SPaul Mackerras 	}
333*f4fcbbe9SPaul Mackerras 	fl->blocks[next_free].data = p;
334*f4fcbbe9SPaul Mackerras 	fl->blocks[next_free].length = count;
335*f4fcbbe9SPaul Mackerras 	fl->num_blocks++;
336*f4fcbbe9SPaul Mackerras 
337*f4fcbbe9SPaul Mackerras 	return count;
338*f4fcbbe9SPaul Mackerras }
339*f4fcbbe9SPaul Mackerras 
340*f4fcbbe9SPaul Mackerras static int rtas_excl_open(struct inode *inode, struct file *file)
341*f4fcbbe9SPaul Mackerras {
342*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(inode);
343*f4fcbbe9SPaul Mackerras 
344*f4fcbbe9SPaul Mackerras 	/* Enforce exclusive open with use count of PDE */
345*f4fcbbe9SPaul Mackerras 	spin_lock(&flash_file_open_lock);
346*f4fcbbe9SPaul Mackerras 	if (atomic_read(&dp->count) > 1) {
347*f4fcbbe9SPaul Mackerras 		spin_unlock(&flash_file_open_lock);
348*f4fcbbe9SPaul Mackerras 		return -EBUSY;
349*f4fcbbe9SPaul Mackerras 	}
350*f4fcbbe9SPaul Mackerras 
351*f4fcbbe9SPaul Mackerras 	atomic_inc(&dp->count);
352*f4fcbbe9SPaul Mackerras 	spin_unlock(&flash_file_open_lock);
353*f4fcbbe9SPaul Mackerras 
354*f4fcbbe9SPaul Mackerras 	return 0;
355*f4fcbbe9SPaul Mackerras }
356*f4fcbbe9SPaul Mackerras 
357*f4fcbbe9SPaul Mackerras static int rtas_excl_release(struct inode *inode, struct file *file)
358*f4fcbbe9SPaul Mackerras {
359*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(inode);
360*f4fcbbe9SPaul Mackerras 
361*f4fcbbe9SPaul Mackerras 	atomic_dec(&dp->count);
362*f4fcbbe9SPaul Mackerras 
363*f4fcbbe9SPaul Mackerras 	return 0;
364*f4fcbbe9SPaul Mackerras }
365*f4fcbbe9SPaul Mackerras 
366*f4fcbbe9SPaul Mackerras static void manage_flash(struct rtas_manage_flash_t *args_buf)
367*f4fcbbe9SPaul Mackerras {
368*f4fcbbe9SPaul Mackerras 	unsigned int wait_time;
369*f4fcbbe9SPaul Mackerras 	s32 rc;
370*f4fcbbe9SPaul Mackerras 
371*f4fcbbe9SPaul Mackerras 	while (1) {
372*f4fcbbe9SPaul Mackerras 		rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1,
373*f4fcbbe9SPaul Mackerras 			       1, NULL, args_buf->op);
374*f4fcbbe9SPaul Mackerras 		if (rc == RTAS_RC_BUSY)
375*f4fcbbe9SPaul Mackerras 			udelay(1);
376*f4fcbbe9SPaul Mackerras 		else if (rtas_is_extended_busy(rc)) {
377*f4fcbbe9SPaul Mackerras 			wait_time = rtas_extended_busy_delay_time(rc);
378*f4fcbbe9SPaul Mackerras 			udelay(wait_time * 1000);
379*f4fcbbe9SPaul Mackerras 		} else
380*f4fcbbe9SPaul Mackerras 			break;
381*f4fcbbe9SPaul Mackerras 	}
382*f4fcbbe9SPaul Mackerras 
383*f4fcbbe9SPaul Mackerras 	args_buf->status = rc;
384*f4fcbbe9SPaul Mackerras }
385*f4fcbbe9SPaul Mackerras 
386*f4fcbbe9SPaul Mackerras static ssize_t manage_flash_read(struct file *file, char __user *buf,
387*f4fcbbe9SPaul Mackerras 			       size_t count, loff_t *ppos)
388*f4fcbbe9SPaul Mackerras {
389*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
390*f4fcbbe9SPaul Mackerras 	struct rtas_manage_flash_t *args_buf;
391*f4fcbbe9SPaul Mackerras 	char msg[RTAS_MSG_MAXLEN];
392*f4fcbbe9SPaul Mackerras 	int msglen;
393*f4fcbbe9SPaul Mackerras 
394*f4fcbbe9SPaul Mackerras 	args_buf = (struct rtas_manage_flash_t *) dp->data;
395*f4fcbbe9SPaul Mackerras 	if (args_buf == NULL)
396*f4fcbbe9SPaul Mackerras 		return 0;
397*f4fcbbe9SPaul Mackerras 
398*f4fcbbe9SPaul Mackerras 	msglen = sprintf(msg, "%d\n", args_buf->status);
399*f4fcbbe9SPaul Mackerras 	if (msglen > count)
400*f4fcbbe9SPaul Mackerras 		msglen = count;
401*f4fcbbe9SPaul Mackerras 
402*f4fcbbe9SPaul Mackerras 	if (ppos && *ppos != 0)
403*f4fcbbe9SPaul Mackerras 		return 0;	/* be cheap */
404*f4fcbbe9SPaul Mackerras 
405*f4fcbbe9SPaul Mackerras 	if (!access_ok(VERIFY_WRITE, buf, msglen))
406*f4fcbbe9SPaul Mackerras 		return -EINVAL;
407*f4fcbbe9SPaul Mackerras 
408*f4fcbbe9SPaul Mackerras 	if (copy_to_user(buf, msg, msglen))
409*f4fcbbe9SPaul Mackerras 		return -EFAULT;
410*f4fcbbe9SPaul Mackerras 
411*f4fcbbe9SPaul Mackerras 	if (ppos)
412*f4fcbbe9SPaul Mackerras 		*ppos = msglen;
413*f4fcbbe9SPaul Mackerras 	return msglen;
414*f4fcbbe9SPaul Mackerras }
415*f4fcbbe9SPaul Mackerras 
416*f4fcbbe9SPaul Mackerras static ssize_t manage_flash_write(struct file *file, const char __user *buf,
417*f4fcbbe9SPaul Mackerras 				size_t count, loff_t *off)
418*f4fcbbe9SPaul Mackerras {
419*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
420*f4fcbbe9SPaul Mackerras 	struct rtas_manage_flash_t *args_buf;
421*f4fcbbe9SPaul Mackerras 	const char reject_str[] = "0";
422*f4fcbbe9SPaul Mackerras 	const char commit_str[] = "1";
423*f4fcbbe9SPaul Mackerras 	char stkbuf[10];
424*f4fcbbe9SPaul Mackerras 	int op;
425*f4fcbbe9SPaul Mackerras 
426*f4fcbbe9SPaul Mackerras 	args_buf = (struct rtas_manage_flash_t *) dp->data;
427*f4fcbbe9SPaul Mackerras 	if ((args_buf->status == MANAGE_AUTH) || (count == 0))
428*f4fcbbe9SPaul Mackerras 		return count;
429*f4fcbbe9SPaul Mackerras 
430*f4fcbbe9SPaul Mackerras 	op = -1;
431*f4fcbbe9SPaul Mackerras 	if (buf) {
432*f4fcbbe9SPaul Mackerras 		if (count > 9) count = 9;
433*f4fcbbe9SPaul Mackerras 		if (copy_from_user (stkbuf, buf, count)) {
434*f4fcbbe9SPaul Mackerras 			return -EFAULT;
435*f4fcbbe9SPaul Mackerras 		}
436*f4fcbbe9SPaul Mackerras 		if (strncmp(stkbuf, reject_str, strlen(reject_str)) == 0)
437*f4fcbbe9SPaul Mackerras 			op = RTAS_REJECT_TMP_IMG;
438*f4fcbbe9SPaul Mackerras 		else if (strncmp(stkbuf, commit_str, strlen(commit_str)) == 0)
439*f4fcbbe9SPaul Mackerras 			op = RTAS_COMMIT_TMP_IMG;
440*f4fcbbe9SPaul Mackerras 	}
441*f4fcbbe9SPaul Mackerras 
442*f4fcbbe9SPaul Mackerras 	if (op == -1)   /* buf is empty, or contains invalid string */
443*f4fcbbe9SPaul Mackerras 		return -EINVAL;
444*f4fcbbe9SPaul Mackerras 
445*f4fcbbe9SPaul Mackerras 	args_buf->op = op;
446*f4fcbbe9SPaul Mackerras 	manage_flash(args_buf);
447*f4fcbbe9SPaul Mackerras 
448*f4fcbbe9SPaul Mackerras 	return count;
449*f4fcbbe9SPaul Mackerras }
450*f4fcbbe9SPaul Mackerras 
451*f4fcbbe9SPaul Mackerras static void validate_flash(struct rtas_validate_flash_t *args_buf)
452*f4fcbbe9SPaul Mackerras {
453*f4fcbbe9SPaul Mackerras 	int token = rtas_token("ibm,validate-flash-image");
454*f4fcbbe9SPaul Mackerras 	unsigned int wait_time;
455*f4fcbbe9SPaul Mackerras 	int update_results;
456*f4fcbbe9SPaul Mackerras 	s32 rc;
457*f4fcbbe9SPaul Mackerras 
458*f4fcbbe9SPaul Mackerras 	rc = 0;
459*f4fcbbe9SPaul Mackerras 	while(1) {
460*f4fcbbe9SPaul Mackerras 		spin_lock(&rtas_data_buf_lock);
461*f4fcbbe9SPaul Mackerras 		memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE);
462*f4fcbbe9SPaul Mackerras 		rc = rtas_call(token, 2, 2, &update_results,
463*f4fcbbe9SPaul Mackerras 			       (u32) __pa(rtas_data_buf), args_buf->buf_size);
464*f4fcbbe9SPaul Mackerras 		memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE);
465*f4fcbbe9SPaul Mackerras 		spin_unlock(&rtas_data_buf_lock);
466*f4fcbbe9SPaul Mackerras 
467*f4fcbbe9SPaul Mackerras 		if (rc == RTAS_RC_BUSY)
468*f4fcbbe9SPaul Mackerras 			udelay(1);
469*f4fcbbe9SPaul Mackerras 		else if (rtas_is_extended_busy(rc)) {
470*f4fcbbe9SPaul Mackerras 			wait_time = rtas_extended_busy_delay_time(rc);
471*f4fcbbe9SPaul Mackerras 			udelay(wait_time * 1000);
472*f4fcbbe9SPaul Mackerras 		} else
473*f4fcbbe9SPaul Mackerras 			break;
474*f4fcbbe9SPaul Mackerras 	}
475*f4fcbbe9SPaul Mackerras 
476*f4fcbbe9SPaul Mackerras 	args_buf->status = rc;
477*f4fcbbe9SPaul Mackerras 	args_buf->update_results = update_results;
478*f4fcbbe9SPaul Mackerras }
479*f4fcbbe9SPaul Mackerras 
480*f4fcbbe9SPaul Mackerras static int get_validate_flash_msg(struct rtas_validate_flash_t *args_buf,
481*f4fcbbe9SPaul Mackerras 		                   char *msg)
482*f4fcbbe9SPaul Mackerras {
483*f4fcbbe9SPaul Mackerras 	int n;
484*f4fcbbe9SPaul Mackerras 
485*f4fcbbe9SPaul Mackerras 	if (args_buf->status >= VALIDATE_TMP_UPDATE) {
486*f4fcbbe9SPaul Mackerras 		n = sprintf(msg, "%d\n", args_buf->update_results);
487*f4fcbbe9SPaul Mackerras 		if ((args_buf->update_results >= VALIDATE_CUR_UNKNOWN) ||
488*f4fcbbe9SPaul Mackerras 		    (args_buf->update_results == VALIDATE_TMP_UPDATE))
489*f4fcbbe9SPaul Mackerras 			n += sprintf(msg + n, "%s\n", args_buf->buf);
490*f4fcbbe9SPaul Mackerras 	} else {
491*f4fcbbe9SPaul Mackerras 		n = sprintf(msg, "%d\n", args_buf->status);
492*f4fcbbe9SPaul Mackerras 	}
493*f4fcbbe9SPaul Mackerras 	return n;
494*f4fcbbe9SPaul Mackerras }
495*f4fcbbe9SPaul Mackerras 
496*f4fcbbe9SPaul Mackerras static ssize_t validate_flash_read(struct file *file, char __user *buf,
497*f4fcbbe9SPaul Mackerras 			       size_t count, loff_t *ppos)
498*f4fcbbe9SPaul Mackerras {
499*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
500*f4fcbbe9SPaul Mackerras 	struct rtas_validate_flash_t *args_buf;
501*f4fcbbe9SPaul Mackerras 	char msg[RTAS_MSG_MAXLEN];
502*f4fcbbe9SPaul Mackerras 	int msglen;
503*f4fcbbe9SPaul Mackerras 
504*f4fcbbe9SPaul Mackerras 	args_buf = (struct rtas_validate_flash_t *) dp->data;
505*f4fcbbe9SPaul Mackerras 
506*f4fcbbe9SPaul Mackerras 	if (ppos && *ppos != 0)
507*f4fcbbe9SPaul Mackerras 		return 0;	/* be cheap */
508*f4fcbbe9SPaul Mackerras 
509*f4fcbbe9SPaul Mackerras 	msglen = get_validate_flash_msg(args_buf, msg);
510*f4fcbbe9SPaul Mackerras 	if (msglen > count)
511*f4fcbbe9SPaul Mackerras 		msglen = count;
512*f4fcbbe9SPaul Mackerras 
513*f4fcbbe9SPaul Mackerras 	if (!access_ok(VERIFY_WRITE, buf, msglen))
514*f4fcbbe9SPaul Mackerras 		return -EINVAL;
515*f4fcbbe9SPaul Mackerras 
516*f4fcbbe9SPaul Mackerras 	if (copy_to_user(buf, msg, msglen))
517*f4fcbbe9SPaul Mackerras 		return -EFAULT;
518*f4fcbbe9SPaul Mackerras 
519*f4fcbbe9SPaul Mackerras 	if (ppos)
520*f4fcbbe9SPaul Mackerras 		*ppos = msglen;
521*f4fcbbe9SPaul Mackerras 	return msglen;
522*f4fcbbe9SPaul Mackerras }
523*f4fcbbe9SPaul Mackerras 
524*f4fcbbe9SPaul Mackerras static ssize_t validate_flash_write(struct file *file, const char __user *buf,
525*f4fcbbe9SPaul Mackerras 				    size_t count, loff_t *off)
526*f4fcbbe9SPaul Mackerras {
527*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
528*f4fcbbe9SPaul Mackerras 	struct rtas_validate_flash_t *args_buf;
529*f4fcbbe9SPaul Mackerras 	int rc;
530*f4fcbbe9SPaul Mackerras 
531*f4fcbbe9SPaul Mackerras 	args_buf = (struct rtas_validate_flash_t *) dp->data;
532*f4fcbbe9SPaul Mackerras 
533*f4fcbbe9SPaul Mackerras 	if (dp->data == NULL) {
534*f4fcbbe9SPaul Mackerras 		dp->data = kmalloc(sizeof(struct rtas_validate_flash_t),
535*f4fcbbe9SPaul Mackerras 				GFP_KERNEL);
536*f4fcbbe9SPaul Mackerras 		if (dp->data == NULL)
537*f4fcbbe9SPaul Mackerras 			return -ENOMEM;
538*f4fcbbe9SPaul Mackerras 	}
539*f4fcbbe9SPaul Mackerras 
540*f4fcbbe9SPaul Mackerras 	/* We are only interested in the first 4K of the
541*f4fcbbe9SPaul Mackerras 	 * candidate image */
542*f4fcbbe9SPaul Mackerras 	if ((*off >= VALIDATE_BUF_SIZE) ||
543*f4fcbbe9SPaul Mackerras 		(args_buf->status == VALIDATE_AUTH)) {
544*f4fcbbe9SPaul Mackerras 		*off += count;
545*f4fcbbe9SPaul Mackerras 		return count;
546*f4fcbbe9SPaul Mackerras 	}
547*f4fcbbe9SPaul Mackerras 
548*f4fcbbe9SPaul Mackerras 	if (*off + count >= VALIDATE_BUF_SIZE)  {
549*f4fcbbe9SPaul Mackerras 		count = VALIDATE_BUF_SIZE - *off;
550*f4fcbbe9SPaul Mackerras 		args_buf->status = VALIDATE_READY;
551*f4fcbbe9SPaul Mackerras 	} else {
552*f4fcbbe9SPaul Mackerras 		args_buf->status = VALIDATE_INCOMPLETE;
553*f4fcbbe9SPaul Mackerras 	}
554*f4fcbbe9SPaul Mackerras 
555*f4fcbbe9SPaul Mackerras 	if (!access_ok(VERIFY_READ, buf, count)) {
556*f4fcbbe9SPaul Mackerras 		rc = -EFAULT;
557*f4fcbbe9SPaul Mackerras 		goto done;
558*f4fcbbe9SPaul Mackerras 	}
559*f4fcbbe9SPaul Mackerras 	if (copy_from_user(args_buf->buf + *off, buf, count)) {
560*f4fcbbe9SPaul Mackerras 		rc = -EFAULT;
561*f4fcbbe9SPaul Mackerras 		goto done;
562*f4fcbbe9SPaul Mackerras 	}
563*f4fcbbe9SPaul Mackerras 
564*f4fcbbe9SPaul Mackerras 	*off += count;
565*f4fcbbe9SPaul Mackerras 	rc = count;
566*f4fcbbe9SPaul Mackerras done:
567*f4fcbbe9SPaul Mackerras 	if (rc < 0) {
568*f4fcbbe9SPaul Mackerras 		kfree(dp->data);
569*f4fcbbe9SPaul Mackerras 		dp->data = NULL;
570*f4fcbbe9SPaul Mackerras 	}
571*f4fcbbe9SPaul Mackerras 	return rc;
572*f4fcbbe9SPaul Mackerras }
573*f4fcbbe9SPaul Mackerras 
574*f4fcbbe9SPaul Mackerras static int validate_flash_release(struct inode *inode, struct file *file)
575*f4fcbbe9SPaul Mackerras {
576*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
577*f4fcbbe9SPaul Mackerras 	struct rtas_validate_flash_t *args_buf;
578*f4fcbbe9SPaul Mackerras 
579*f4fcbbe9SPaul Mackerras 	args_buf = (struct rtas_validate_flash_t *) dp->data;
580*f4fcbbe9SPaul Mackerras 
581*f4fcbbe9SPaul Mackerras 	if (args_buf->status == VALIDATE_READY) {
582*f4fcbbe9SPaul Mackerras 		args_buf->buf_size = VALIDATE_BUF_SIZE;
583*f4fcbbe9SPaul Mackerras 		validate_flash(args_buf);
584*f4fcbbe9SPaul Mackerras 	}
585*f4fcbbe9SPaul Mackerras 
586*f4fcbbe9SPaul Mackerras 	/* The matching atomic_inc was in rtas_excl_open() */
587*f4fcbbe9SPaul Mackerras 	atomic_dec(&dp->count);
588*f4fcbbe9SPaul Mackerras 
589*f4fcbbe9SPaul Mackerras 	return 0;
590*f4fcbbe9SPaul Mackerras }
591*f4fcbbe9SPaul Mackerras 
592*f4fcbbe9SPaul Mackerras static void rtas_flash_firmware(int reboot_type)
593*f4fcbbe9SPaul Mackerras {
594*f4fcbbe9SPaul Mackerras 	unsigned long image_size;
595*f4fcbbe9SPaul Mackerras 	struct flash_block_list *f, *next, *flist;
596*f4fcbbe9SPaul Mackerras 	unsigned long rtas_block_list;
597*f4fcbbe9SPaul Mackerras 	int i, status, update_token;
598*f4fcbbe9SPaul Mackerras 
599*f4fcbbe9SPaul Mackerras 	if (rtas_firmware_flash_list.next == NULL)
600*f4fcbbe9SPaul Mackerras 		return;		/* nothing to do */
601*f4fcbbe9SPaul Mackerras 
602*f4fcbbe9SPaul Mackerras 	if (reboot_type != SYS_RESTART) {
603*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n");
604*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n");
605*f4fcbbe9SPaul Mackerras 		return;
606*f4fcbbe9SPaul Mackerras 	}
607*f4fcbbe9SPaul Mackerras 
608*f4fcbbe9SPaul Mackerras 	update_token = rtas_token("ibm,update-flash-64-and-reboot");
609*f4fcbbe9SPaul Mackerras 	if (update_token == RTAS_UNKNOWN_SERVICE) {
610*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot "
611*f4fcbbe9SPaul Mackerras 		       "is not available -- not a service partition?\n");
612*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: firmware will not be flashed\n");
613*f4fcbbe9SPaul Mackerras 		return;
614*f4fcbbe9SPaul Mackerras 	}
615*f4fcbbe9SPaul Mackerras 
616*f4fcbbe9SPaul Mackerras 	/* NOTE: the "first" block list is a global var with no data
617*f4fcbbe9SPaul Mackerras 	 * blocks in the kernel data segment.  We do this because
618*f4fcbbe9SPaul Mackerras 	 * we want to ensure this block_list addr is under 4GB.
619*f4fcbbe9SPaul Mackerras 	 */
620*f4fcbbe9SPaul Mackerras 	rtas_firmware_flash_list.num_blocks = 0;
621*f4fcbbe9SPaul Mackerras 	flist = (struct flash_block_list *)&rtas_firmware_flash_list;
622*f4fcbbe9SPaul Mackerras 	rtas_block_list = virt_to_abs(flist);
623*f4fcbbe9SPaul Mackerras 	if (rtas_block_list >= 4UL*1024*1024*1024) {
624*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n");
625*f4fcbbe9SPaul Mackerras 		return;
626*f4fcbbe9SPaul Mackerras 	}
627*f4fcbbe9SPaul Mackerras 
628*f4fcbbe9SPaul Mackerras 	printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n");
629*f4fcbbe9SPaul Mackerras 	/* Update the block_list in place. */
630*f4fcbbe9SPaul Mackerras 	image_size = 0;
631*f4fcbbe9SPaul Mackerras 	for (f = flist; f; f = next) {
632*f4fcbbe9SPaul Mackerras 		/* Translate data addrs to absolute */
633*f4fcbbe9SPaul Mackerras 		for (i = 0; i < f->num_blocks; i++) {
634*f4fcbbe9SPaul Mackerras 			f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data);
635*f4fcbbe9SPaul Mackerras 			image_size += f->blocks[i].length;
636*f4fcbbe9SPaul Mackerras 		}
637*f4fcbbe9SPaul Mackerras 		next = f->next;
638*f4fcbbe9SPaul Mackerras 		/* Don't translate NULL pointer for last entry */
639*f4fcbbe9SPaul Mackerras 		if (f->next)
640*f4fcbbe9SPaul Mackerras 			f->next = (struct flash_block_list *)virt_to_abs(f->next);
641*f4fcbbe9SPaul Mackerras 		else
642*f4fcbbe9SPaul Mackerras 			f->next = NULL;
643*f4fcbbe9SPaul Mackerras 		/* make num_blocks into the version/length field */
644*f4fcbbe9SPaul Mackerras 		f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16);
645*f4fcbbe9SPaul Mackerras 	}
646*f4fcbbe9SPaul Mackerras 
647*f4fcbbe9SPaul Mackerras 	printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size);
648*f4fcbbe9SPaul Mackerras 	printk(KERN_ALERT "FLASH: performing flash and reboot\n");
649*f4fcbbe9SPaul Mackerras 	rtas_progress("Flashing        \n", 0x0);
650*f4fcbbe9SPaul Mackerras 	rtas_progress("Please Wait...  ", 0x0);
651*f4fcbbe9SPaul Mackerras 	printk(KERN_ALERT "FLASH: this will take several minutes.  Do not power off!\n");
652*f4fcbbe9SPaul Mackerras 	status = rtas_call(update_token, 1, 1, NULL, rtas_block_list);
653*f4fcbbe9SPaul Mackerras 	switch (status) {	/* should only get "bad" status */
654*f4fcbbe9SPaul Mackerras 	    case 0:
655*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: success\n");
656*f4fcbbe9SPaul Mackerras 		break;
657*f4fcbbe9SPaul Mackerras 	    case -1:
658*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: hardware error.  Firmware may not be not flashed\n");
659*f4fcbbe9SPaul Mackerras 		break;
660*f4fcbbe9SPaul Mackerras 	    case -3:
661*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform.  Firmware not flashed\n");
662*f4fcbbe9SPaul Mackerras 		break;
663*f4fcbbe9SPaul Mackerras 	    case -4:
664*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: flash failed when partially complete.  System may not reboot\n");
665*f4fcbbe9SPaul Mackerras 		break;
666*f4fcbbe9SPaul Mackerras 	    default:
667*f4fcbbe9SPaul Mackerras 		printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status);
668*f4fcbbe9SPaul Mackerras 		break;
669*f4fcbbe9SPaul Mackerras 	}
670*f4fcbbe9SPaul Mackerras }
671*f4fcbbe9SPaul Mackerras 
672*f4fcbbe9SPaul Mackerras static void remove_flash_pde(struct proc_dir_entry *dp)
673*f4fcbbe9SPaul Mackerras {
674*f4fcbbe9SPaul Mackerras 	if (dp) {
675*f4fcbbe9SPaul Mackerras 		if (dp->data != NULL)
676*f4fcbbe9SPaul Mackerras 			kfree(dp->data);
677*f4fcbbe9SPaul Mackerras 		dp->owner = NULL;
678*f4fcbbe9SPaul Mackerras 		remove_proc_entry(dp->name, dp->parent);
679*f4fcbbe9SPaul Mackerras 	}
680*f4fcbbe9SPaul Mackerras }
681*f4fcbbe9SPaul Mackerras 
682*f4fcbbe9SPaul Mackerras static int initialize_flash_pde_data(const char *rtas_call_name,
683*f4fcbbe9SPaul Mackerras 				     size_t buf_size,
684*f4fcbbe9SPaul Mackerras 				     struct proc_dir_entry *dp)
685*f4fcbbe9SPaul Mackerras {
686*f4fcbbe9SPaul Mackerras 	int *status;
687*f4fcbbe9SPaul Mackerras 	int token;
688*f4fcbbe9SPaul Mackerras 
689*f4fcbbe9SPaul Mackerras 	dp->data = kmalloc(buf_size, GFP_KERNEL);
690*f4fcbbe9SPaul Mackerras 	if (dp->data == NULL) {
691*f4fcbbe9SPaul Mackerras 		remove_flash_pde(dp);
692*f4fcbbe9SPaul Mackerras 		return -ENOMEM;
693*f4fcbbe9SPaul Mackerras 	}
694*f4fcbbe9SPaul Mackerras 
695*f4fcbbe9SPaul Mackerras 	memset(dp->data, 0, buf_size);
696*f4fcbbe9SPaul Mackerras 
697*f4fcbbe9SPaul Mackerras 	/*
698*f4fcbbe9SPaul Mackerras 	 * This code assumes that the status int is the first member of the
699*f4fcbbe9SPaul Mackerras 	 * struct
700*f4fcbbe9SPaul Mackerras 	 */
701*f4fcbbe9SPaul Mackerras 	status = (int *) dp->data;
702*f4fcbbe9SPaul Mackerras 	token = rtas_token(rtas_call_name);
703*f4fcbbe9SPaul Mackerras 	if (token == RTAS_UNKNOWN_SERVICE)
704*f4fcbbe9SPaul Mackerras 		*status = FLASH_AUTH;
705*f4fcbbe9SPaul Mackerras 	else
706*f4fcbbe9SPaul Mackerras 		*status = FLASH_NO_OP;
707*f4fcbbe9SPaul Mackerras 
708*f4fcbbe9SPaul Mackerras 	return 0;
709*f4fcbbe9SPaul Mackerras }
710*f4fcbbe9SPaul Mackerras 
711*f4fcbbe9SPaul Mackerras static struct proc_dir_entry *create_flash_pde(const char *filename,
712*f4fcbbe9SPaul Mackerras 					       struct file_operations *fops)
713*f4fcbbe9SPaul Mackerras {
714*f4fcbbe9SPaul Mackerras 	struct proc_dir_entry *ent = NULL;
715*f4fcbbe9SPaul Mackerras 
716*f4fcbbe9SPaul Mackerras 	ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, NULL);
717*f4fcbbe9SPaul Mackerras 	if (ent != NULL) {
718*f4fcbbe9SPaul Mackerras 		ent->nlink = 1;
719*f4fcbbe9SPaul Mackerras 		ent->proc_fops = fops;
720*f4fcbbe9SPaul Mackerras 		ent->owner = THIS_MODULE;
721*f4fcbbe9SPaul Mackerras 	}
722*f4fcbbe9SPaul Mackerras 
723*f4fcbbe9SPaul Mackerras 	return ent;
724*f4fcbbe9SPaul Mackerras }
725*f4fcbbe9SPaul Mackerras 
726*f4fcbbe9SPaul Mackerras static struct file_operations rtas_flash_operations = {
727*f4fcbbe9SPaul Mackerras 	.read		= rtas_flash_read,
728*f4fcbbe9SPaul Mackerras 	.write		= rtas_flash_write,
729*f4fcbbe9SPaul Mackerras 	.open		= rtas_excl_open,
730*f4fcbbe9SPaul Mackerras 	.release	= rtas_flash_release,
731*f4fcbbe9SPaul Mackerras };
732*f4fcbbe9SPaul Mackerras 
733*f4fcbbe9SPaul Mackerras static struct file_operations manage_flash_operations = {
734*f4fcbbe9SPaul Mackerras 	.read		= manage_flash_read,
735*f4fcbbe9SPaul Mackerras 	.write		= manage_flash_write,
736*f4fcbbe9SPaul Mackerras 	.open		= rtas_excl_open,
737*f4fcbbe9SPaul Mackerras 	.release	= rtas_excl_release,
738*f4fcbbe9SPaul Mackerras };
739*f4fcbbe9SPaul Mackerras 
740*f4fcbbe9SPaul Mackerras static struct file_operations validate_flash_operations = {
741*f4fcbbe9SPaul Mackerras 	.read		= validate_flash_read,
742*f4fcbbe9SPaul Mackerras 	.write		= validate_flash_write,
743*f4fcbbe9SPaul Mackerras 	.open		= rtas_excl_open,
744*f4fcbbe9SPaul Mackerras 	.release	= validate_flash_release,
745*f4fcbbe9SPaul Mackerras };
746*f4fcbbe9SPaul Mackerras 
747*f4fcbbe9SPaul Mackerras int __init rtas_flash_init(void)
748*f4fcbbe9SPaul Mackerras {
749*f4fcbbe9SPaul Mackerras 	int rc;
750*f4fcbbe9SPaul Mackerras 
751*f4fcbbe9SPaul Mackerras 	if (rtas_token("ibm,update-flash-64-and-reboot") ==
752*f4fcbbe9SPaul Mackerras 		       RTAS_UNKNOWN_SERVICE) {
753*f4fcbbe9SPaul Mackerras 		printk(KERN_ERR "rtas_flash: no firmware flash support\n");
754*f4fcbbe9SPaul Mackerras 		return 1;
755*f4fcbbe9SPaul Mackerras 	}
756*f4fcbbe9SPaul Mackerras 
757*f4fcbbe9SPaul Mackerras 	firmware_flash_pde = create_flash_pde("ppc64/rtas/"
758*f4fcbbe9SPaul Mackerras 					      FIRMWARE_FLASH_NAME,
759*f4fcbbe9SPaul Mackerras 					      &rtas_flash_operations);
760*f4fcbbe9SPaul Mackerras 	if (firmware_flash_pde == NULL) {
761*f4fcbbe9SPaul Mackerras 		rc = -ENOMEM;
762*f4fcbbe9SPaul Mackerras 		goto cleanup;
763*f4fcbbe9SPaul Mackerras 	}
764*f4fcbbe9SPaul Mackerras 
765*f4fcbbe9SPaul Mackerras 	rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot",
766*f4fcbbe9SPaul Mackerras 			 	       sizeof(struct rtas_update_flash_t),
767*f4fcbbe9SPaul Mackerras 				       firmware_flash_pde);
768*f4fcbbe9SPaul Mackerras 	if (rc != 0)
769*f4fcbbe9SPaul Mackerras 		goto cleanup;
770*f4fcbbe9SPaul Mackerras 
771*f4fcbbe9SPaul Mackerras 	firmware_update_pde = create_flash_pde("ppc64/rtas/"
772*f4fcbbe9SPaul Mackerras 					       FIRMWARE_UPDATE_NAME,
773*f4fcbbe9SPaul Mackerras 					       &rtas_flash_operations);
774*f4fcbbe9SPaul Mackerras 	if (firmware_update_pde == NULL) {
775*f4fcbbe9SPaul Mackerras 		rc = -ENOMEM;
776*f4fcbbe9SPaul Mackerras 		goto cleanup;
777*f4fcbbe9SPaul Mackerras 	}
778*f4fcbbe9SPaul Mackerras 
779*f4fcbbe9SPaul Mackerras 	rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot",
780*f4fcbbe9SPaul Mackerras 			 	       sizeof(struct rtas_update_flash_t),
781*f4fcbbe9SPaul Mackerras 				       firmware_update_pde);
782*f4fcbbe9SPaul Mackerras 	if (rc != 0)
783*f4fcbbe9SPaul Mackerras 		goto cleanup;
784*f4fcbbe9SPaul Mackerras 
785*f4fcbbe9SPaul Mackerras 	validate_pde = create_flash_pde("ppc64/rtas/" VALIDATE_FLASH_NAME,
786*f4fcbbe9SPaul Mackerras 			      		&validate_flash_operations);
787*f4fcbbe9SPaul Mackerras 	if (validate_pde == NULL) {
788*f4fcbbe9SPaul Mackerras 		rc = -ENOMEM;
789*f4fcbbe9SPaul Mackerras 		goto cleanup;
790*f4fcbbe9SPaul Mackerras 	}
791*f4fcbbe9SPaul Mackerras 
792*f4fcbbe9SPaul Mackerras 	rc = initialize_flash_pde_data("ibm,validate-flash-image",
793*f4fcbbe9SPaul Mackerras 		                       sizeof(struct rtas_validate_flash_t),
794*f4fcbbe9SPaul Mackerras 				       validate_pde);
795*f4fcbbe9SPaul Mackerras 	if (rc != 0)
796*f4fcbbe9SPaul Mackerras 		goto cleanup;
797*f4fcbbe9SPaul Mackerras 
798*f4fcbbe9SPaul Mackerras 	manage_pde = create_flash_pde("ppc64/rtas/" MANAGE_FLASH_NAME,
799*f4fcbbe9SPaul Mackerras 				      &manage_flash_operations);
800*f4fcbbe9SPaul Mackerras 	if (manage_pde == NULL) {
801*f4fcbbe9SPaul Mackerras 		rc = -ENOMEM;
802*f4fcbbe9SPaul Mackerras 		goto cleanup;
803*f4fcbbe9SPaul Mackerras 	}
804*f4fcbbe9SPaul Mackerras 
805*f4fcbbe9SPaul Mackerras 	rc = initialize_flash_pde_data("ibm,manage-flash-image",
806*f4fcbbe9SPaul Mackerras 			               sizeof(struct rtas_manage_flash_t),
807*f4fcbbe9SPaul Mackerras 				       manage_pde);
808*f4fcbbe9SPaul Mackerras 	if (rc != 0)
809*f4fcbbe9SPaul Mackerras 		goto cleanup;
810*f4fcbbe9SPaul Mackerras 
811*f4fcbbe9SPaul Mackerras 	rtas_flash_term_hook = rtas_flash_firmware;
812*f4fcbbe9SPaul Mackerras 	return 0;
813*f4fcbbe9SPaul Mackerras 
814*f4fcbbe9SPaul Mackerras cleanup:
815*f4fcbbe9SPaul Mackerras 	remove_flash_pde(firmware_flash_pde);
816*f4fcbbe9SPaul Mackerras 	remove_flash_pde(firmware_update_pde);
817*f4fcbbe9SPaul Mackerras 	remove_flash_pde(validate_pde);
818*f4fcbbe9SPaul Mackerras 	remove_flash_pde(manage_pde);
819*f4fcbbe9SPaul Mackerras 
820*f4fcbbe9SPaul Mackerras 	return rc;
821*f4fcbbe9SPaul Mackerras }
822*f4fcbbe9SPaul Mackerras 
823*f4fcbbe9SPaul Mackerras void __exit rtas_flash_cleanup(void)
824*f4fcbbe9SPaul Mackerras {
825*f4fcbbe9SPaul Mackerras 	rtas_flash_term_hook = NULL;
826*f4fcbbe9SPaul Mackerras 	remove_flash_pde(firmware_flash_pde);
827*f4fcbbe9SPaul Mackerras 	remove_flash_pde(firmware_update_pde);
828*f4fcbbe9SPaul Mackerras 	remove_flash_pde(validate_pde);
829*f4fcbbe9SPaul Mackerras 	remove_flash_pde(manage_pde);
830*f4fcbbe9SPaul Mackerras }
831*f4fcbbe9SPaul Mackerras 
832*f4fcbbe9SPaul Mackerras module_init(rtas_flash_init);
833*f4fcbbe9SPaul Mackerras module_exit(rtas_flash_cleanup);
834*f4fcbbe9SPaul Mackerras MODULE_LICENSE("GPL");
835