diff options
Diffstat (limited to 'arch/powerpc/kernel/rtasd.c')
| -rw-r--r-- | arch/powerpc/kernel/rtasd.c | 71 | 
1 files changed, 63 insertions, 8 deletions
diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index 0438f819fe6..e736387fee6 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -27,8 +27,9 @@  #include <asm/rtas.h>  #include <asm/prom.h>  #include <asm/nvram.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include <asm/machdep.h> +#include <asm/topology.h>  static DEFINE_SPINLOCK(rtasd_log_lock); @@ -87,6 +88,8 @@ static char *rtas_event_type(int type)  			return "Resource Deallocation Event";  		case RTAS_TYPE_DUMP:  			return "Dump Notification Event"; +		case RTAS_TYPE_PRRN: +			return "Platform Resource Reassignment Event";  	}  	return rtas_type[0]; @@ -147,8 +150,8 @@ static void printk_log_rtas(char *buf, int len)  		struct rtas_error_log *errlog = (struct rtas_error_log *)buf;  		printk(RTAS_DEBUG "event: %d, Type: %s, Severity: %d\n", -		       error_log_cnt, rtas_event_type(errlog->type), -		       errlog->severity); +		       error_log_cnt, rtas_event_type(rtas_error_type(errlog)), +		       rtas_error_severity(errlog));  	}  } @@ -156,14 +159,16 @@ static int log_rtas_len(char * buf)  {  	int len;  	struct rtas_error_log *err; +	uint32_t extended_log_length;  	/* rtas fixed header */  	len = 8;  	err = (struct rtas_error_log *)buf; -	if (err->extended_log_length) { +	extended_log_length = rtas_error_extended_log_length(err); +	if (rtas_error_extended(err) && extended_log_length) {  		/* extended header */ -		len += err->extended_log_length; +		len += extended_log_length;  	}  	if (rtas_error_log_max == 0) @@ -265,9 +270,49 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal)  		spin_unlock_irqrestore(&rtasd_log_lock, s);  		return;  	} +} + +#ifdef CONFIG_PPC_PSERIES +static s32 prrn_update_scope; + +static void prrn_work_fn(struct work_struct *work) +{ +	/* +	 * For PRRN, we must pass the negative of the scope value in +	 * the RTAS event. +	 */ +	pseries_devicetree_update(-prrn_update_scope); +} + +static DECLARE_WORK(prrn_work, prrn_work_fn); + +void prrn_schedule_update(u32 scope) +{ +	flush_work(&prrn_work); +	prrn_update_scope = scope; +	schedule_work(&prrn_work); +} + +static void handle_rtas_event(const struct rtas_error_log *log) +{ +	if (rtas_error_type(log) != RTAS_TYPE_PRRN || !prrn_is_enabled()) +		return; + +	/* For PRRN Events the extended log length is used to denote +	 * the scope for calling rtas update-nodes. +	 */ +	prrn_schedule_update(rtas_error_extended_log_length(log)); +} + +#else +static void handle_rtas_event(const struct rtas_error_log *log) +{ +	return;  } +#endif +  static int rtas_log_open(struct inode * inode, struct file * file)  {  	return 0; @@ -388,8 +433,10 @@ static void do_event_scan(void)  			break;  		} -		if (error == 0) +		if (error == 0) {  			pSeries_log_error(logdata, ERR_TYPE_RTAS_LOG, 0); +			handle_rtas_event((struct rtas_error_log *)logdata); +		}  	} while(error == 0);  } @@ -412,7 +459,8 @@ static void rtas_event_scan(struct work_struct *w)  	get_online_cpus(); -	cpu = cpumask_next(smp_processor_id(), cpu_online_mask); +	/* raw_ OK because just using CPU as starting point. */ +	cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask);          if (cpu >= nr_cpu_ids) {  		cpu = cpumask_first(cpu_online_mask); @@ -464,13 +512,20 @@ static void start_event_scan(void)  	pr_debug("rtasd: will sleep for %d milliseconds\n",  		 (30000 / rtas_event_scan_rate)); -	/* Retreive errors from nvram if any */ +	/* Retrieve errors from nvram if any */  	retreive_nvram_error_log();  	schedule_delayed_work_on(cpumask_first(cpu_online_mask),  				 &event_scan_work, event_scan_delay);  } +/* Cancel the rtas event scan work */ +void rtas_cancel_event_scan(void) +{ +	cancel_delayed_work_sync(&event_scan_work); +} +EXPORT_SYMBOL_GPL(rtas_cancel_event_scan); +  static int __init rtas_init(void)  {  	struct proc_dir_entry *entry;  | 
