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