⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtas_flash.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  c 2001 PPC 64 Team, IBM Corp * *      This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. * * /proc/ppc64/rtas/firmware_flash interface * * This file implements a firmware_flash interface to pump a firmware * image into the kernel.  At reboot time rtas_restart() will see the * firmware image and flash it as it reboots (see rtas.c). */#include <linux/module.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <asm/delay.h>#include <asm/uaccess.h>#include <asm/rtas.h>#include <asm/abs_addr.h>#define MODULE_VERS "1.0"#define MODULE_NAME "rtas_flash"#define FIRMWARE_FLASH_NAME "firmware_flash"   #define FIRMWARE_UPDATE_NAME "firmware_update"#define MANAGE_FLASH_NAME "manage_flash"#define VALIDATE_FLASH_NAME "validate_flash"/* General RTAS Status Codes */#define RTAS_RC_SUCCESS  0#define RTAS_RC_HW_ERR	-1#define RTAS_RC_BUSY	-2/* Flash image status values */#define FLASH_AUTH           -9002 /* RTAS Not Service Authority Partition */#define FLASH_NO_OP          -1099 /* No operation initiated by user */	#define FLASH_IMG_SHORT	     -1005 /* Flash image shorter than expected */#define FLASH_IMG_BAD_LEN    -1004 /* Bad length value in flash list block */#define FLASH_IMG_NULL_DATA  -1003 /* Bad data value in flash list block */#define FLASH_IMG_READY      0     /* Firmware img ready for flash on reboot *//* Manage image status values */#define MANAGE_AUTH          -9002 /* RTAS Not Service Authority Partition */#define MANAGE_ACTIVE_ERR    -9001 /* RTAS Cannot Overwrite Active Img */#define MANAGE_NO_OP         -1099 /* No operation initiated by user */#define MANAGE_PARAM_ERR     -3    /* RTAS Parameter Error */#define MANAGE_HW_ERR        -1    /* RTAS Hardware Error *//* Validate image status values */#define VALIDATE_AUTH          -9002 /* RTAS Not Service Authority Partition */#define VALIDATE_NO_OP         -1099 /* No operation initiated by the user */#define VALIDATE_INCOMPLETE    -1002 /* User copied < VALIDATE_BUF_SIZE */#define VALIDATE_READY	       -1001 /* Firmware image ready for validation */#define VALIDATE_PARAM_ERR     -3    /* RTAS Parameter Error */#define VALIDATE_HW_ERR        -1    /* RTAS Hardware Error */#define VALIDATE_TMP_UPDATE    0     /* Validate Return Status */#define VALIDATE_FLASH_AUTH    1     /* Validate Return Status */#define VALIDATE_INVALID_IMG   2     /* Validate Return Status */#define VALIDATE_CUR_UNKNOWN   3     /* Validate Return Status */#define VALIDATE_TMP_COMMIT_DL 4     /* Validate Return Status */#define VALIDATE_TMP_COMMIT    5     /* Validate Return Status */#define VALIDATE_TMP_UPDATE_DL 6     /* Validate Return Status *//* ibm,manage-flash-image operation tokens */#define RTAS_REJECT_TMP_IMG   0#define RTAS_COMMIT_TMP_IMG   1/* Array sizes */#define VALIDATE_BUF_SIZE 4096    #define RTAS_MSG_MAXLEN   64struct flash_block {	char *data;	unsigned long length;};/* This struct is very similar but not identical to * that needed by the rtas flash update. * All we need to do for rtas is rewrite num_blocks * into a version/length and translate the pointers * to absolute. */#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block))struct flash_block_list {	unsigned long num_blocks;	struct flash_block_list *next;	struct flash_block blocks[FLASH_BLOCKS_PER_NODE];};struct flash_block_list_header { /* just the header of flash_block_list */	unsigned long num_blocks;	struct flash_block_list *next;};static struct flash_block_list_header rtas_firmware_flash_list = {0, NULL};#define FLASH_BLOCK_LIST_VERSION (1UL)/* Local copy of the flash block list. * We only allow one open of the flash proc file and create this * list as we go.  This list will be put in the * rtas_firmware_flash_list var once it is fully read. * * For convenience as we build the list we use virtual addrs, * we do not fill in the version number, and the length field * is treated as the number of entries currently in the block * (i.e. not a byte count).  This is all fixed on release. *//* Status int must be first member of struct */struct rtas_update_flash_t{	int status;			/* Flash update status */	struct flash_block_list *flist; /* Local copy of flash block list */};/* Status int must be first member of struct */struct rtas_manage_flash_t{	int status;			/* Returned status */	unsigned int op;		/* Reject or commit image */};/* Status int must be first member of struct */struct rtas_validate_flash_t{	int status;		 	/* Returned status */		char buf[VALIDATE_BUF_SIZE]; 	/* Candidate image buffer */	unsigned int buf_size;		/* Size of image buf */	unsigned int update_results;	/* Update results token */};static DEFINE_SPINLOCK(flash_file_open_lock);static struct proc_dir_entry *firmware_flash_pde;static struct proc_dir_entry *firmware_update_pde;static struct proc_dir_entry *validate_pde;static struct proc_dir_entry *manage_pde;/* Do simple sanity checks on the flash image. */static int flash_list_valid(struct flash_block_list *flist){	struct flash_block_list *f;	int i;	unsigned long block_size, image_size;	/* Paranoid self test here.  We also collect the image size. */	image_size = 0;	for (f = flist; f; f = f->next) {		for (i = 0; i < f->num_blocks; i++) {			if (f->blocks[i].data == NULL) {				return FLASH_IMG_NULL_DATA;			}			block_size = f->blocks[i].length;			if (block_size <= 0 || block_size > PAGE_SIZE) {				return FLASH_IMG_BAD_LEN;			}			image_size += block_size;		}	}	if (image_size < (256 << 10)) {		if (image_size < 2) 			return FLASH_NO_OP;	}	printk(KERN_INFO "FLASH: flash image with %ld bytes stored for hardware flash on reboot\n", image_size);	return FLASH_IMG_READY;}static void free_flash_list(struct flash_block_list *f){	struct flash_block_list *next;	int i;	while (f) {		for (i = 0; i < f->num_blocks; i++)			free_page((unsigned long)(f->blocks[i].data));		next = f->next;		free_page((unsigned long)f);		f = next;	}}static int rtas_flash_release(struct inode *inode, struct file *file){	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);	struct rtas_update_flash_t *uf;		uf = (struct rtas_update_flash_t *) dp->data;	if (uf->flist) {    		/* File was opened in write mode for a new flash attempt */		/* Clear saved list */		if (rtas_firmware_flash_list.next) {			free_flash_list(rtas_firmware_flash_list.next);			rtas_firmware_flash_list.next = NULL;		}		if (uf->status != FLASH_AUTH)  			uf->status = flash_list_valid(uf->flist);		if (uf->status == FLASH_IMG_READY) 			rtas_firmware_flash_list.next = uf->flist;		else			free_flash_list(uf->flist);		uf->flist = NULL;	}	atomic_dec(&dp->count);	return 0;}static void get_flash_status_msg(int status, char *buf){	char *msg;	switch (status) {	case FLASH_AUTH:		msg = "error: this partition does not have service authority\n";		break;	case FLASH_NO_OP:		msg = "info: no firmware image for flash\n";		break;	case FLASH_IMG_SHORT:		msg = "error: flash image short\n";		break;	case FLASH_IMG_BAD_LEN:		msg = "error: internal error bad length\n";		break;	case FLASH_IMG_NULL_DATA:		msg = "error: internal error null data\n";		break;	case FLASH_IMG_READY:		msg = "ready: firmware image ready for flash on reboot\n";		break;	default:		sprintf(buf, "error: unexpected status value %d\n", status);		return;	}	strcpy(buf, msg);	}/* Reading the proc file will show status (not the firmware contents) */static ssize_t rtas_flash_read(struct file *file, char __user *buf,			       size_t count, loff_t *ppos){	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);	struct rtas_update_flash_t *uf;	char msg[RTAS_MSG_MAXLEN];	int msglen;	uf = (struct rtas_update_flash_t *) dp->data;	if (!strcmp(dp->name, FIRMWARE_FLASH_NAME)) {		get_flash_status_msg(uf->status, msg);	} else {	   /* FIRMWARE_UPDATE_NAME */		sprintf(msg, "%d\n", uf->status);	}	msglen = strlen(msg);	if (msglen > count)		msglen = count;	if (ppos && *ppos != 0)		return 0;	/* be cheap */	if (!access_ok(VERIFY_WRITE, buf, msglen))		return -EINVAL;	if (copy_to_user(buf, msg, msglen))		return -EFAULT;	if (ppos)		*ppos = msglen;	return msglen;}/* We could be much more efficient here.  But to keep this function * simple we allocate a page to the block list no matter how small the * count is.  If the system is low on memory it will be just as well * that we fail.... */static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,				size_t count, loff_t *off){	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);	struct rtas_update_flash_t *uf;	char *p;	int next_free;	struct flash_block_list *fl;	uf = (struct rtas_update_flash_t *) dp->data;	if (uf->status == FLASH_AUTH || count == 0)		return count;	/* discard data */	/* In the case that the image is not ready for flashing, the memory	 * allocated for the block list will be freed upon the release of the 	 * proc file	 */	if (uf->flist == NULL) {		uf->flist = (struct flash_block_list *) get_zeroed_page(GFP_KERNEL);		if (!uf->flist)			return -ENOMEM;	}	fl = uf->flist;	while (fl->next)		fl = fl->next; /* seek to last block_list for append */	next_free = fl->num_blocks;	if (next_free == FLASH_BLOCKS_PER_NODE) {		/* Need to allocate another block_list */		fl->next = (struct flash_block_list *)get_zeroed_page(GFP_KERNEL);		if (!fl->next)			return -ENOMEM;		fl = fl->next;		next_free = 0;	}	if (count > PAGE_SIZE)		count = PAGE_SIZE;	p = (char *)get_zeroed_page(GFP_KERNEL);	if (!p)		return -ENOMEM;		if(copy_from_user(p, buffer, count)) {		free_page((unsigned long)p);		return -EFAULT;	}	fl->blocks[next_free].data = p;	fl->blocks[next_free].length = count;	fl->num_blocks++;	return count;}static int rtas_excl_open(struct inode *inode, struct file *file){	struct proc_dir_entry *dp = PDE(inode);	/* Enforce exclusive open with use count of PDE */	spin_lock(&flash_file_open_lock);	if (atomic_read(&dp->count) > 1) {		spin_unlock(&flash_file_open_lock);		return -EBUSY;	}	atomic_inc(&dp->count);	spin_unlock(&flash_file_open_lock);		return 0;}static int rtas_excl_release(struct inode *inode, struct file *file){	struct proc_dir_entry *dp = PDE(inode);	atomic_dec(&dp->count);	return 0;}static void manage_flash(struct rtas_manage_flash_t *args_buf){	unsigned int wait_time;	s32 rc;	while (1) {		rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 			       1, NULL, args_buf->op);		if (rc == RTAS_RC_BUSY)			udelay(1);		else if (rtas_is_extended_busy(rc)) {			wait_time = rtas_extended_busy_delay_time(rc);			udelay(wait_time * 1000);		} else			break;	}	args_buf->status = rc;}static ssize_t manage_flash_read(struct file *file, char __user *buf,			       size_t count, loff_t *ppos){	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);	struct rtas_manage_flash_t *args_buf;	char msg[RTAS_MSG_MAXLEN];	int msglen;	args_buf = (struct rtas_manage_flash_t *) dp->data;	if (args_buf == NULL)		return 0;	msglen = sprintf(msg, "%d\n", args_buf->status);	if (msglen > count)		msglen = count;	if (ppos && *ppos != 0)		return 0;	/* be cheap */	if (!access_ok(VERIFY_WRITE, buf, msglen))		return -EINVAL;	if (copy_to_user(buf, msg, msglen))		return -EFAULT;	if (ppos)		*ppos = msglen;	return msglen;}static ssize_t manage_flash_write(struct file *file, const char __user *buf,				size_t count, loff_t *off){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -