Esempio n. 1
0
/*
 * Handle power subsystem events (EPOW).
 *
 * Presently we just log the event has occurred.  This should be fixed
 * to examine the type of power failure and take appropriate action where
 * the time horizon permits something useful to be done.
 */
static irqreturn_t
ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
	int status = 0xdeadbeef;
	int state = 0;
	int critical;

	status = rtas_call(ras_get_sensor_state_token, 2, 2, &state,
			   EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX);

	if (state > 3)
		critical = 1;  /* Time Critical */
	else
		critical = 0;

	spin_lock(&ras_log_buf_lock);

	status = rtas_call(ras_check_exception_token, 6, 1, NULL,
			   RAS_VECTOR_OFFSET,
			   irq_map[irq].hwirq,
			   RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS,
			   critical, __pa(&ras_log_buf),
				rtas_get_error_log_max());

	udbg_printf("EPOW <0x%lx 0x%x 0x%x>\n",
		    *((unsigned long *)&ras_log_buf), status, state);
	printk(KERN_WARNING "EPOW <0x%lx 0x%x 0x%x>\n",
	       *((unsigned long *)&ras_log_buf), status, state);

	/* format and print the extended information */
	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);

	spin_unlock(&ras_log_buf_lock);
	return IRQ_HANDLED;
}
Esempio n. 2
0
/* Handle environmental and power warning (EPOW) interrupts. */
static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
{
	int status;
	int state;
	int critical;

	status = rtas_get_sensor_fast(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX,
				      &state);

	if (state > 3)
		critical = 1;		/* Time Critical */
	else
		critical = 0;

	spin_lock(&ras_log_buf_lock);

	status = rtas_call(ras_check_exception_token, 6, 1, NULL,
			   RTAS_VECTOR_EXTERNAL_INTERRUPT,
			   virq_to_hw(irq),
			   RTAS_EPOW_WARNING,
			   critical, __pa(&ras_log_buf),
				rtas_get_error_log_max());

	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);

	rtas_parse_epow_errlog((struct rtas_error_log *)ras_log_buf);

	spin_unlock(&ras_log_buf_lock);
	return IRQ_HANDLED;
}
Esempio n. 3
0
static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id)
{
	struct pseries_errorlog *pseries_log;
	struct pseries_hp_errorlog *hp_elog;

	spin_lock(&ras_log_buf_lock);

	rtas_call(ras_check_exception_token, 6, 1, NULL,
		  RTAS_VECTOR_EXTERNAL_INTERRUPT, virq_to_hw(irq),
		  RTAS_HOTPLUG_EVENTS, 0, __pa(&ras_log_buf),
		  rtas_get_error_log_max());

	pseries_log = get_pseries_errorlog((struct rtas_error_log *)ras_log_buf,
					   PSERIES_ELOG_SECT_ID_HOTPLUG);
	hp_elog = (struct pseries_hp_errorlog *)pseries_log->data;

	/*
	 * Since PCI hotplug is not currently supported on pseries, put PCI
	 * hotplug events on the ras_log_buf to be handled by rtas_errd.
	 */
	if (hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_MEM ||
	    hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU ||
	    hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_PMEM)
		queue_hotplug_event(hp_elog);
	else
		log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);

	spin_unlock(&ras_log_buf_lock);
	return IRQ_HANDLED;
}
Esempio n. 4
0
/** Return a copy of the detailed error text associated with the
 *  most recent failed call to rtas.  Because the error text
 *  might go stale if there are any other intervening rtas calls,
 *  this routine must be called atomically with whatever produced
 *  the error (i.e. with rtas.lock still held from the previous call).
 */
static int
__fetch_rtas_last_error(void)
{
	struct rtas_args err_args, save_args;
	u32 bufsz;

	bufsz = rtas_get_error_log_max();

	err_args.token = rtas_token("rtas-last-error");
	err_args.nargs = 2;
	err_args.nret = 1;

	err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf);
	err_args.args[1] = bufsz;
	err_args.args[2] = 0;

	save_args = rtas.args;
	rtas.args = err_args;

	enter_rtas(__pa(&rtas.args));

	err_args = rtas.args;
	rtas.args = save_args;

	return err_args.args[2];
}
Esempio n. 5
0
/*
 * Handle hardware error interrupts.
 *
 * RTAS check-exception is called to collect data on the exception.  If
 * the error is deemed recoverable, we log a warning and return.
 * For nonrecoverable errors, an error is logged and we stop all processing
 * as quickly as possible in order to prevent propagation of the failure.
 */
static irqreturn_t
ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
	struct rtas_error_log *rtas_elog;
	int status = 0xdeadbeef;
	int fatal;

	spin_lock(&ras_log_buf_lock);

	status = rtas_call(ras_check_exception_token, 6, 1, NULL,
			   RAS_VECTOR_OFFSET,
			   irq_map[irq].hwirq,
			   RTAS_INTERNAL_ERROR, 1 /*Time Critical */,
			   __pa(&ras_log_buf),
				rtas_get_error_log_max());

	rtas_elog = (struct rtas_error_log *)ras_log_buf;

	if ((status == 0) && (rtas_elog->severity >= RTAS_SEVERITY_ERROR_SYNC))
		fatal = 1;
	else
		fatal = 0;

	/* format and print the extended information */
	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal);

	if (fatal) {
		udbg_printf("Fatal HW Error <0x%lx 0x%x>\n",
			    *((unsigned long *)&ras_log_buf), status);
		printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%x>\n",
		       *((unsigned long *)&ras_log_buf), status);

#ifndef DEBUG
		/* Don't actually power off when debugging so we can test
		 * without actually failing while injecting errors.
		 * Error data will not be logged to syslog.
		 */
		ppc_md.power_off();
#endif
	} else {
		udbg_printf("Recoverable HW Error <0x%lx 0x%x>\n",
			    *((unsigned long *)&ras_log_buf), status);
		printk(KERN_WARNING
		       "Warning: Recoverable hardware error <0x%lx 0x%x>\n",
		       *((unsigned long *)&ras_log_buf), status);
	}

	spin_unlock(&ras_log_buf_lock);
	return IRQ_HANDLED;
}
Esempio n. 6
0
static int __init rtas_init(void)
{
	struct proc_dir_entry *entry;

	if (!machine_is(pseries) && !machine_is(chrp))
		return 0;

	/* No RTAS */
	event_scan = rtas_token("event-scan");
	if (event_scan == RTAS_UNKNOWN_SERVICE) {
		printk(KERN_INFO "rtasd: No event-scan on system\n");
		return -ENODEV;
	}

	rtas_event_scan_rate = rtas_token("rtas-event-scan-rate");
	if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) {
		printk(KERN_ERR "rtasd: no rtas-event-scan-rate on system\n");
		return -ENODEV;
	}

	if (!rtas_event_scan_rate) {
		/* Broken firmware: take a rate of zero to mean don't scan */
		printk(KERN_DEBUG "rtasd: scan rate is 0, not scanning\n");
		return 0;
	}

	/* Make room for the sequence number */
	rtas_error_log_max = rtas_get_error_log_max();
	rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int);

	rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER);
	if (!rtas_log_buf) {
		printk(KERN_ERR "rtasd: no memory\n");
		return -ENOMEM;
	}

	entry = proc_create("powerpc/rtas/error_log", S_IRUSR, NULL,
			    &proc_rtas_log_operations);
	if (!entry)
		printk(KERN_ERR "Failed to create error_log proc entry\n");

	start_event_scan();

	return 0;
}
Esempio n. 7
0
/** Return a copy of the detailed error text associated with the
 *  most recent failed call to rtas.  Because the error text
 *  might go stale if there are any other intervening rtas calls,
 *  this routine must be called atomically with whatever produced
 *  the error (i.e. with rtas.lock still held from the previous call).
 */
static char *__fetch_rtas_last_error(char *altbuf)
{
	struct rtas_args err_args, save_args;
	u32 bufsz;
	char *buf = NULL;

	if (rtas_last_error_token == -1)
		return NULL;

	bufsz = rtas_get_error_log_max();

	err_args.token = cpu_to_be32(rtas_last_error_token);
	err_args.nargs = cpu_to_be32(2);
	err_args.nret = cpu_to_be32(1);
	err_args.args[0] = cpu_to_be32(__pa(rtas_err_buf));
	err_args.args[1] = cpu_to_be32(bufsz);
	err_args.args[2] = 0;

	save_args = rtas.args;
	rtas.args = err_args;

	enter_rtas(__pa(&rtas.args));

	err_args = rtas.args;
	rtas.args = save_args;

	/* Log the error in the unlikely case that there was one. */
	if (unlikely(err_args.args[2] == 0)) {
		if (altbuf) {
			buf = altbuf;
		} else {
			buf = rtas_err_buf;
			if (mem_init_done)
				buf = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC);
		}
		if (buf)
			memcpy(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX);
	}

	return buf;
}
Esempio n. 8
0
static int __init rtas_init(void)
{
	struct proc_dir_entry *entry;

	if (!machine_is(pseries))
		return 0;

	/* No RTAS */
	event_scan = rtas_token("event-scan");
	if (event_scan == RTAS_UNKNOWN_SERVICE) {
		printk(KERN_DEBUG "rtasd: no event-scan on system\n");
		return -ENODEV;
	}

	rtas_event_scan_rate = rtas_token("rtas-event-scan-rate");
	if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) {
		printk(KERN_ERR "rtasd: no rtas-event-scan-rate on system\n");
		return -ENODEV;
	}

	/* Make room for the sequence number */
	rtas_error_log_max = rtas_get_error_log_max();
	rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int);

	rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER);
	if (!rtas_log_buf) {
		printk(KERN_ERR "rtasd: no memory\n");
		return -ENOMEM;
	}

	entry = create_proc_entry("ppc64/rtas/error_log", S_IRUSR, NULL);
	if (entry)
		entry->proc_fops = &proc_rtas_log_operations;
	else
		printk(KERN_ERR "Failed to create error_log proc entry\n");

	if (kernel_thread(rtasd, NULL, CLONE_FS) < 0)
		printk(KERN_ERR "Failed to start RTAS daemon\n");

	return 0;
}
Esempio n. 9
0
static int log_rtas_len(char * buf)
{
	int len;
	struct rtas_error_log *err;

	/* rtas fixed header */
	len = 8;
	err = (struct rtas_error_log *)buf;
	if (err->extended_log_length) {

		/* extended header */
		len += err->extended_log_length;
	}

	if (rtas_error_log_max == 0)
		rtas_error_log_max = rtas_get_error_log_max();

	if (len > rtas_error_log_max)
		len = rtas_error_log_max;

	return len;
}
Esempio n. 10
0
/*
 * Handle hardware error interrupts.
 *
 * RTAS check-exception is called to collect data on the exception.  If
 * the error is deemed recoverable, we log a warning and return.
 * For nonrecoverable errors, an error is logged and we stop all processing
 * as quickly as possible in order to prevent propagation of the failure.
 */
static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
{
	struct rtas_error_log *rtas_elog;
	int status;
	int fatal;

	spin_lock(&ras_log_buf_lock);

	status = rtas_call(ras_check_exception_token, 6, 1, NULL,
			   RTAS_VECTOR_EXTERNAL_INTERRUPT,
			   virq_to_hw(irq),
			   RTAS_INTERNAL_ERROR, 1 /* Time Critical */,
			   __pa(&ras_log_buf),
				rtas_get_error_log_max());

	rtas_elog = (struct rtas_error_log *)ras_log_buf;

	if (status == 0 &&
	    rtas_error_severity(rtas_elog) >= RTAS_SEVERITY_ERROR_SYNC)
		fatal = 1;
	else
		fatal = 0;

	/* format and print the extended information */
	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal);

	if (fatal) {
		pr_emerg("Fatal hardware error reported by firmware");
		pr_emerg("Check RTAS error log for details");
		pr_emerg("Immediate power off");
		emergency_sync();
		kernel_power_off();
	} else {
		pr_err("Recoverable hardware error reported by firmware");
	}

	spin_unlock(&ras_log_buf_lock);
	return IRQ_HANDLED;
}
Esempio n. 11
0
File: rtasd.c Progetto: xros/linux
static int __init rtas_event_scan_init(void)
{
	if (!machine_is(pseries) && !machine_is(chrp))
		return 0;

	/* No RTAS */
	event_scan = rtas_token("event-scan");
	if (event_scan == RTAS_UNKNOWN_SERVICE) {
		printk(KERN_INFO "rtasd: No event-scan on system\n");
		return -ENODEV;
	}

	rtas_event_scan_rate = rtas_token("rtas-event-scan-rate");
	if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) {
		printk(KERN_ERR "rtasd: no rtas-event-scan-rate on system\n");
		return -ENODEV;
	}

	if (!rtas_event_scan_rate) {
		/* Broken firmware: take a rate of zero to mean don't scan */
		printk(KERN_DEBUG "rtasd: scan rate is 0, not scanning\n");
		return 0;
	}

	/* Make room for the sequence number */
	rtas_error_log_max = rtas_get_error_log_max();
	rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int);

	rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER);
	if (!rtas_log_buf) {
		printk(KERN_ERR "rtasd: no memory\n");
		return -ENOMEM;
	}

	start_event_scan();

	return 0;
}
Esempio n. 12
0
static int get_eventscan_parms(void)
{
	struct device_node *node;
	const int *ip;

	node = of_find_node_by_path("/rtas");

	ip = get_property(node, "rtas-event-scan-rate", NULL);
	if (ip == NULL) {
		printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n");
		of_node_put(node);
		return -1;
	}
	rtas_event_scan_rate = *ip;
	DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate);

	/* Make room for the sequence number */
	rtas_error_log_max = rtas_get_error_log_max();
	rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int);

	of_node_put(node);

	return 0;
}