Пример #1
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 log_entry;
	unsigned int size = sizeof(log_entry);
	long status = 0xdeadbeef;
	int fatal;

	spin_lock(&log_lock);

	status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 
			   0x500, irq, 
			   RTAS_INTERNAL_ERROR, 
			   1, /* Time Critical */
			   __pa(&log_buf), size);

	log_entry = log_buf;

	spin_unlock(&log_lock);

	if ((status == 0) && (log_entry.severity >= SEVERITY_ERROR_SYNC)) 
		fatal = 1;
	else
		fatal = 0;

	/* format and print the extended information */
	log_error((char *)&log_entry, ERR_TYPE_RTAS_LOG, fatal); 

	if (fatal) {
		udbg_printf("HW Error <0x%lx 0x%lx>\n",
			    *((unsigned long *)&log_entry), status);
		printk(KERN_EMERG 
		       "Error: Fatal hardware error <0x%lx 0x%lx>\n",
		       *((unsigned long *)&log_entry), 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%lx>\n",
			    *((unsigned long *)&log_entry), status); 
		printk(KERN_WARNING 
		       "Warning: Recoverable hardware error <0x%lx 0x%lx>\n",
		       *((unsigned long *)&log_entry), status);
	}
	return IRQ_HANDLED;
}
Пример #2
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;
}
Пример #3
0
void udbg_init_scc(struct device_node *np)
{
	u32 *reg;
	unsigned long addr;
	int i, x;

	if (np == NULL)
		np = of_find_node_by_name(NULL, "escc");
	if (np == NULL || np->parent == NULL)
		return;

	udbg_printf("found SCC...\n");
	/* Get address within mac-io ASIC */ 
	reg = (u32 *)get_property(np, "reg", NULL);
	if (reg == NULL)
		return;
	addr = reg[0];
	udbg_printf("local addr: %lx\n", addr);
	/* Get address of mac-io PCI itself */
	reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL);
	if (reg == NULL)
		return;
	addr += reg[2];
	udbg_printf("final addr: %lx\n", addr);

	/* Setup for 57600 8N1 */
	addr += 0x20;
	sccc = (volatile u8 *) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
	sccc += addr & ~PAGE_MASK;
	sccd = sccc + 0x10;

	udbg_printf("ioremap result sccc: %p\n", sccc);
	mb();

	for (i = 20000; i != 0; --i)
		x = *sccc; eieio();
	*sccc = 9; eieio();		/* reset A or B side */
	*sccc = 0xc0; eieio();
	for (i = 0; i < sizeof(scc_inittab); ++i) {
		*sccc = scc_inittab[i];
		eieio();
	}

	ppc_md.udbg_putc = udbg_putc;
	ppc_md.udbg_getc = udbg_getc;
	ppc_md.udbg_getc_poll = udbg_getc_poll;

	udbg_puts("Hello World !\n");
}
Пример #4
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;
}
Пример #5
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)
{
	struct rtas_error_log log_entry;
	unsigned int size = sizeof(log_entry);
	long status = 0xdeadbeef;

	spin_lock(&log_lock);

	status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 
			   0x500, irq, 
			   RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, 
			   1,  /* Time Critical */
			   __pa(&log_buf), size);

	log_entry = log_buf;

	spin_unlock(&log_lock);

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

	/* format and print the extended information */
	log_error((char *)&log_entry, ERR_TYPE_RTAS_LOG, 0);
	
	return IRQ_HANDLED;
}
Пример #6
0
void early_printk(const char *fmt, ...)
{
	va_list args;

	va_start(args, fmt);
	udbg_printf (fmt, args);
	va_end(args);
}
Пример #7
0
__openfirmware
long
rtas_call(int token, int nargs, int nret,
	  unsigned long *outputs, ...)
{
	va_list list;
	int i;
	unsigned long s;
	struct rtas_args *rtas_args = &(get_paca()->xRtas);

	PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n");
	PPCDBG(PPCDBG_RTAS, "\ttoken    = 0x%x\n", token);
	PPCDBG(PPCDBG_RTAS, "\tnargs    = %d\n", nargs);
	PPCDBG(PPCDBG_RTAS, "\tnret     = %d\n", nret);
	PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs);
	if (token == RTAS_UNKNOWN_SERVICE)
		return -1;

	rtas_args->token = token;
	rtas_args->nargs = nargs;
	rtas_args->nret  = nret;
	rtas_args->rets  = (rtas_arg_t *)&(rtas_args->args[nargs]);
	va_start(list, outputs);
	for (i = 0; i < nargs; ++i) {
		rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
		PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
	}
	va_end(list);

	for (i = 0; i < nret; ++i)
	  rtas_args->rets[i] = 0;

#if 0   /* Gotta do something different here, use global lock for now... */
	spin_lock_irqsave(&rtas_args->lock, s);
#else
	spin_lock_irqsave(&rtas.lock, s);
#endif
	PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n",
		(void *)__pa((unsigned long)rtas_args));
	enter_rtas((void *)__pa((unsigned long)rtas_args));
	PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n");
#if 0   /* Gotta do something different here, use global lock for now... */
	spin_unlock_irqrestore(&rtas_args->lock, s);
#else
	spin_unlock_irqrestore(&rtas.lock, s);
#endif
	ifppcdebug(PPCDBG_RTAS) {
		for(i=0; i < nret ;i++)
			udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
	}

	if (nret > 1 && outputs != NULL)
		for (i = 0; i < nret-1; ++i)
			outputs[i] = rtas_args->rets[i+1];
	return (ulong)((nret > 0) ? rtas_args->rets[0] : 0);
}
Пример #8
0
static void pSeriesLP_qirr_info(int n_cpu , u8 value)
{
	unsigned long lpar_rc;

	lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu),value);
	if (lpar_rc != H_Success) {
    udbg_printf("pSeriesLP_qirr_info - plpar_ipi failed!!!!!!!! \n");
		panic(" bad return code qirr -ipi  - rc = %lx \n", lpar_rc); 
	}
}
Пример #9
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 void
ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
	struct rtas_error_log log_entry;
	unsigned int size = sizeof(log_entry);
	long status = 0xdeadbeef;

	status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 
			   0x500, irq, 
			   INTERNAL_ERROR, 
			   1, /* Time Critical */
			   __pa(&log_entry), size);

	if((status != 1) && 
	   (log_entry.severity >= SEVERITY_ERROR_SYNC)) {
		udbg_printf("HW Error <0x%lx 0x%lx>\n",
			    *((unsigned long *)&log_entry), status);
		printk(KERN_EMERG 
		       "Error: Fatal hardware error <0x%lx 0x%lx>\n",
		       *((unsigned long *)&log_entry), status);

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

		return;
	}
}
Пример #10
0
/*
 * early console initialization
 *
 * PowerPC kernels support an early printk console, also known as udbg.
 * This function must be called via the ppc_md.init_early function pointer.
 * At this point, the device tree has been unflattened, so we can obtain the
 * byte channel handle for stdout.
 *
 * We only support displaying of characters (putc).  We do not support
 * keyboard input.
 */
void __init udbg_init_ehv_bc(void)
{
	unsigned int rx_count, tx_count;
	unsigned int ret;

	/* Verify the byte channel handle */
	ret = ev_byte_channel_poll(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
				   &rx_count, &tx_count);
	if (ret)
		return;

	udbg_putc = ehv_bc_udbg_putc;
	register_early_udbg_console();

	udbg_printf("ehv-bc: early console using byte channel handle %u\n",
		    CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE);
}
Пример #11
0
/*
 * Handle power subsystem events (EPOW).
 *
 * Presently we just log the event has occured.  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 void
ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
	struct rtas_error_log log_entry;
	unsigned int size = sizeof(log_entry);
	long status = 0xdeadbeef;

	status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 
			   0x500, irq, 
			   EPOW_WARNING | POWERMGM_EVENTS, 
			   1,  /* Time Critical */
			   __pa(&log_entry), size);

	udbg_printf("EPOW <0x%lx 0x%lx>\n", 
		    *((unsigned long *)&log_entry), status); 
	printk(KERN_WARNING 
	       "EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status);
}
Пример #12
0
static void iommu_table_setparms(struct pci_controller *phb,
				 struct device_node *dn,
				 struct iommu_table *tbl)
{
	struct device_node *node;
	const unsigned long *basep;
	const u32 *sizep;

	node = phb->dn;

	basep = of_get_property(node, "linux,tce-base", NULL);
	sizep = of_get_property(node, "linux,tce-size", NULL);
	if (basep == NULL || sizep == NULL) {
		printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has "
				"missing tce entries !\n", dn->full_name);
		return;
	}

	tbl->it_base = (unsigned long)__va(*basep);

#ifndef CONFIG_CRASH_DUMP
	memset((void *)tbl->it_base, 0, *sizep);
#endif

	tbl->it_busno = phb->bus->number;

	/* Units of tce entries */
	tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT;

	/* Test if we are going over 2GB of DMA space */
	if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) {
		udbg_printf("PCI_DMA: Unexpected number of IOAs under this PHB.\n");
		panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n");
	}

	phb->dma_window_base_cur += phb->dma_window_size;

	/* Set the tce table size - measured in entries */
	tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT;

	tbl->it_index = 0;
	tbl->it_blocksize = 16;
	tbl->it_type = TCE_PCI;
}
/**********************************************************************************
 * Dump the iSeries Temp Device Node 
 *<4>buswalk [swapper : - DeviceNode: 0xC000000000634300
 *<4>00. Device Node   = 0xC000000000634300
 *<4>    - PciDev      = 0x0000000000000000
 *<4>    - tDevice     = 0x  17:01.00  0x1022 00
 *<4>  4. Device Node = 0xC000000000634480
 *<4>     - PciDev    = 0x0000000000000000
 *<4>     - Device    = 0x  18:38.16 Irq:0xA7 Vendor:0x1014  Flags:0x00
 *<4>     - Devfn     = 0xB0: 22.18
 **********************************************************************************/
void dumpDevice_Node(struct iSeries_Device_Node* DevNode)
{
	udbg_printf("Device Node      = 0x%p\n",DevNode);
	udbg_printf("     - PciDev    = 0x%p\n",DevNode->PciDev);
	udbg_printf("     - Device    = 0x%4X:%02X.%02X (0x%02X)\n",
		    ISERIES_BUS(DevNode),
		    ISERIES_SUBBUS(DevNode),
		    DevNode->AgentId,
		    DevNode->DevFn);
	udbg_printf("     - LSlot     = 0x%02X\n",DevNode->LogicalSlot);
	udbg_printf("     - TceTable  = 0x%p\n  ",DevNode->DevTceTable);

	udbg_printf("     - DSA       = 0x%04X\n",ISERIES_DSA(DevNode)>>32 );

	udbg_printf("                 = Irq:0x%02X Vendor:0x%04X  Flags:0x%02X\n",
		    DevNode->Irq,
		    DevNode->Vendor,
		    DevNode->Flags );
	udbg_printf("     - Location  = %s\n",DevNode->CardLocation);


}
Пример #14
0
void
xics_init_IRQ( void )
{
	int i;
	unsigned long intr_size = 0;
	struct device_node *np;
	uint *ireg, ilen, indx=0;

	ibm_get_xive = rtas_token("ibm,get-xive");
	ibm_set_xive = rtas_token("ibm,set-xive");
	ibm_int_off = rtas_token("ibm,int-off");

	np = find_type_devices("PowerPC-External-Interrupt-Presentation");
	if (!np) {
		printk(KERN_WARNING "Can't find Interrupt Presentation\n");
		udbg_printf("Can't find Interrupt Presentation\n");
		while (1);
	}
nextnode:
	ireg = (uint *)get_property(np, "ibm,interrupt-server-ranges", 0);
	if (ireg) {
		/*
		 * set node starting index for this node
		 */
		indx = *ireg;
	}

	ireg = (uint *)get_property(np, "reg", &ilen);
	if (!ireg) {
		printk(KERN_WARNING "Can't find Interrupt Reg Property\n");
		udbg_printf("Can't find Interrupt Reg Property\n");
		while (1);
	}
	
	while (ilen) {
		inodes[indx].addr = (unsigned long long)*ireg++ << 32;
		ilen -= sizeof(uint);
		inodes[indx].addr |= *ireg++;
		ilen -= sizeof(uint);
		inodes[indx].size = (unsigned long long)*ireg++ << 32;
		ilen -= sizeof(uint);
		inodes[indx].size |= *ireg++;
		ilen -= sizeof(uint);
		indx++;
		if (indx >= NR_CPUS) break;
	}

	np = np->next;
	if ((indx < NR_CPUS) && np) goto nextnode;

	/* Find the server numbers for the boot cpu. */
	for (np = find_type_devices("cpu"); np; np = np->next) {
		ireg = (uint *)get_property(np, "reg", &ilen);
		if (ireg && ireg[0] == hard_smp_processor_id()) {
			ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
			i = ilen / sizeof(int);
			if (ireg && i > 0) {
				default_server = ireg[0];
				default_distrib_server = ireg[i-1]; /* take last element */
			}
			break;
		}
	}

	intr_base = inodes[0].addr;
	intr_size = (ulong)inodes[0].size;

	np = find_type_devices("interrupt-controller");
	if (!np) {
		printk(KERN_WARNING "xics:  no ISA Interrupt Controller\n");
		xics_irq_8259_cascade = -1;
	} else {
		ireg = (uint *) get_property(np, "interrupts", 0);
		if (!ireg) {
			printk(KERN_WARNING "Can't find ISA Interrupts Property\n");
			udbg_printf("Can't find ISA Interrupts Property\n");
			while (1);
		}
		xics_irq_8259_cascade_real = *ireg;
		xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real);
	}

	if (naca->platform == PLATFORM_PSERIES) {
#ifdef CONFIG_SMP
		for (i = 0; i < naca->processorCount; ++i) {
			xics_info.per_cpu[i] =
			  __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, 
				  (ulong)inodes[get_hard_smp_processor_id(i)].size, _PAGE_NO_CACHE);
		}
#else
		xics_info.per_cpu[0] = __ioremap((ulong)intr_base, intr_size, _PAGE_NO_CACHE);
#endif /* CONFIG_SMP */
#ifdef CONFIG_PPC_PSERIES
	/* actually iSeries does not use any of xics...but it has link dependencies
	 * for now, except this new one...
	 */
	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
		ops = &pSeriesLP_ops;
#endif
	}

	xics_8259_pic.enable = i8259_pic.enable;
	xics_8259_pic.disable = i8259_pic.disable;
	for (i = 0; i < 16; ++i)
		irq_desc[i].handler = &xics_8259_pic;
	for (; i < NR_IRQS; ++i)
		irq_desc[i].handler = &xics_pic;

	ops->cppr_info(0, 0xff);
	iosync();
	if (xics_irq_8259_cascade != -1) {
		if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action,
				0, "8259 cascade", 0))
			printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n");
		i8259_init();
	}

#ifdef CONFIG_SMP
	real_irq_to_virt_map[XICS_IPI] = virt_irq_to_real_map[XICS_IPI] = XICS_IPI;
	request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0);
	irq_desc[XICS_IPI+XICS_IRQ_OFFSET].status |= IRQ_PER_CPU;
#endif
}
Пример #15
0
int rtas_call(int token, int nargs, int nret, int *outputs, ...)
{
	va_list list;
	int i, logit = 0;
	unsigned long s;
	struct rtas_args *rtas_args;
	char * buff_copy = NULL;
	int ret;

	PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n");
	PPCDBG(PPCDBG_RTAS, "\ttoken    = 0x%x\n", token);
	PPCDBG(PPCDBG_RTAS, "\tnargs    = %d\n", nargs);
	PPCDBG(PPCDBG_RTAS, "\tnret     = %d\n", nret);
	PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs);
	if (token == RTAS_UNKNOWN_SERVICE)
		return -1;

	/* Gotta do something different here, use global lock for now... */
	spin_lock_irqsave(&rtas.lock, s);
	rtas_args = &rtas.args;

	rtas_args->token = token;
	rtas_args->nargs = nargs;
	rtas_args->nret  = nret;
	rtas_args->rets  = (rtas_arg_t *)&(rtas_args->args[nargs]);
	va_start(list, outputs);
	for (i = 0; i < nargs; ++i) {
		rtas_args->args[i] = va_arg(list, rtas_arg_t);
		PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%x\n", i, rtas_args->args[i]);
	}
	va_end(list);

	for (i = 0; i < nret; ++i)
		rtas_args->rets[i] = 0;

	PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n",
		__pa(rtas_args));
	enter_rtas(__pa(rtas_args));
	PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n");

	/* A -1 return code indicates that the last command couldn't
	   be completed due to a hardware error. */
	if (rtas_args->rets[0] == -1)
		logit = (__fetch_rtas_last_error() == 0);

	ifppcdebug(PPCDBG_RTAS) {
		for(i=0; i < nret ;i++)
			udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
	}

	if (nret > 1 && outputs != NULL)
		for (i = 0; i < nret-1; ++i)
			outputs[i] = rtas_args->rets[i+1];
	ret = (nret > 0)? rtas_args->rets[0]: 0;

	/* Log the error in the unlikely case that there was one. */
	if (unlikely(logit)) {
		buff_copy = rtas_err_buf;
		if (mem_init_done) {
			buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC);
			if (buff_copy)
				memcpy(buff_copy, rtas_err_buf,
				       RTAS_ERROR_LOG_MAX);
		}
	}

	/* Gotta do something different here, use global lock for now... */
	spin_unlock_irqrestore(&rtas.lock, s);

	if (buff_copy) {
		log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0);
		if (mem_init_done)
			kfree(buff_copy);
	}
	return ret;
}
Пример #16
0
__openfirmware
long
rtas_call(int token, int nargs, int nret,
	  unsigned long *outputs, ...)
{
	va_list list;
	int i, logit = 0;
	unsigned long flags;
	struct rtas_args *rtas_args;
	char * buff_copy = NULL;
	unsigned long retval;

	PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n");
	PPCDBG(PPCDBG_RTAS, "\ttoken    = 0x%x\n", token);
	PPCDBG(PPCDBG_RTAS, "\tnargs    = %d\n", nargs);
	PPCDBG(PPCDBG_RTAS, "\tnret     = %d\n", nret);
	PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs);
	if (token == RTAS_UNKNOWN_SERVICE)
		return -1;

	spin_lock_irqsave(&rtas.lock, flags);
	rtas_args = &(get_paca()->xRtas);

	rtas_args->token = token;
	rtas_args->nargs = nargs;
	rtas_args->nret  = nret;
	rtas_args->rets  = (rtas_arg_t *)&(rtas_args->args[nargs]);
	va_start(list, outputs);
	for (i = 0; i < nargs; ++i) {
		rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
		PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
	}
	va_end(list);

	for (i = 0; i < nret; ++i)
	  rtas_args->rets[i] = 0;

	PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n",
		(void *)__pa((unsigned long)rtas_args));
	enter_rtas((void *)__pa((unsigned long)rtas_args));
	PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n");

	/* A -1 return code indicates that the last command couldn't
	 * be completed due to a hardware error. */
	if (rtas_args->rets[0] == -1)
		logit = (__fetch_rtas_last_error() == 0);

	ifppcdebug(PPCDBG_RTAS) {
		for(i=0; i < nret ;i++)
			udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
	}

	if (nret > 1 && outputs != NULL)
		for (i = 0; i < nret-1; ++i)
			outputs[i] = rtas_args->rets[i+1];
	retval = (ulong)((nret > 0) ? rtas_args->rets[0] : 0);

	/* Log the error in the unlikely case that there was one. */
	if (unlikely(logit)) {
		/* Can't call kmalloc if VM subsystem is not yet up. */
		if (slabpages>0) {
			buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC);
			if (buff_copy) {
				memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX);
			}
		}
	}

	spin_unlock_irqrestore(&rtas.lock, flags);

	if (buff_copy) {
		log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0);
		kfree(buff_copy);
	}
	return retval;
}