Commit 57bd45fd authored by Anton Blanchard's avatar Anton Blanchard

ppc64: EEH updates and FWNMI handler from Todd Inglett

parent b8dd4c32
...@@ -24,7 +24,6 @@ if [ "$CONFIG_SMP" = "y" ]; then ...@@ -24,7 +24,6 @@ if [ "$CONFIG_SMP" = "y" ]; then
bool ' Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS bool ' Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
if [ "$CONFIG_PPC_PSERIES" = "y" ]; then if [ "$CONFIG_PPC_PSERIES" = "y" ]; then
bool ' Hardware multithreading' CONFIG_HMT bool ' Hardware multithreading' CONFIG_HMT
bool ' PCI Enhanced Error Handling' CONFIG_PPC_EEH
fi fi
fi fi
define_bool CONFIG_PREEMPT n define_bool CONFIG_PREEMPT n
......
...@@ -30,13 +30,12 @@ obj-y := ppc_ksyms.o setup.o entry.o traps.o irq.o idle.o \ ...@@ -30,13 +30,12 @@ obj-y := ppc_ksyms.o setup.o entry.o traps.o irq.o idle.o \
rtc.o init_task.o pSeries_htab.o rtc.o init_task.o pSeries_htab.o
obj-$(CONFIG_PCI) += pci.o pci_dn.o pci_dma.o obj-$(CONFIG_PCI) += pci.o pci_dn.o pci_dma.o
obj-$(CONFIG_PPC_EEH) += eeh.o
ifeq ($(CONFIG_PPC_ISERIES),y) ifeq ($(CONFIG_PPC_ISERIES),y)
obj-$(CONFIG_PCI) += iSeries_pci.o iSeries_pci_reset.o iSeries_IoMmTable.o iSeries_irq.o iSeries_VpdInfo.o XmPciLpEvent.o obj-$(CONFIG_PCI) += iSeries_pci.o iSeries_pci_reset.o iSeries_IoMmTable.o iSeries_irq.o iSeries_VpdInfo.o XmPciLpEvent.o
endif endif
ifeq ($(CONFIG_PPC_PSERIES),y) ifeq ($(CONFIG_PPC_PSERIES),y)
obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o eeh.o
obj-y += rtasd.o nvram.o obj-y += rtasd.o nvram.o
endif endif
......
...@@ -90,6 +90,9 @@ extern void iSeries_pcibios_fixup(void); ...@@ -90,6 +90,9 @@ extern void iSeries_pcibios_fixup(void);
extern void pSeries_get_rtc_time(struct rtc_time *rtc_time); extern void pSeries_get_rtc_time(struct rtc_time *rtc_time);
extern int pSeries_set_rtc_time(struct rtc_time *rtc_time); extern int pSeries_set_rtc_time(struct rtc_time *rtc_time);
void pSeries_calibrate_decr(void); void pSeries_calibrate_decr(void);
static void fwnmi_init(void);
extern void SystemReset_FWNMI(void), MachineCheck_FWNMI(void); /* from head.S */
int fwnmi_active; /* TRUE if an FWNMI handler is present */
kdev_t boot_dev; kdev_t boot_dev;
unsigned long virtPython0Facilities = 0; // python0 facility area (memory mapped io) (64-bit format) VIRTUAL address. unsigned long virtPython0Facilities = 0; // python0 facility area (memory mapped io) (64-bit format) VIRTUAL address.
...@@ -152,6 +155,8 @@ chrp_setup_arch(void) ...@@ -152,6 +155,8 @@ chrp_setup_arch(void)
printk("Boot arguments: %s\n", cmd_line); printk("Boot arguments: %s\n", cmd_line);
fwnmi_init();
/* Find and initialize PCI host bridges */ /* Find and initialize PCI host bridges */
/* iSeries needs to be done much later. */ /* iSeries needs to be done much later. */
#ifndef CONFIG_PPC_ISERIES #ifndef CONFIG_PPC_ISERIES
...@@ -189,6 +194,23 @@ chrp_init2(void) ...@@ -189,6 +194,23 @@ chrp_init2(void)
ppc_md.progress(UTS_RELEASE, 0x7777); ppc_md.progress(UTS_RELEASE, 0x7777);
} }
/* Initialize firmware assisted non-maskable interrupts if
* the firmware supports this feature.
*
*/
static void __init fwnmi_init(void)
{
long ret;
int ibm_nmi_register = rtas_token("ibm,nmi-register");
if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE)
return;
ret = rtas_call(ibm_nmi_register, 2, 1, NULL,
__pa((unsigned long)SystemReset_FWNMI),
__pa((unsigned long)MachineCheck_FWNMI));
if (ret == 0)
fwnmi_active = 1;
}
/* Early initialization. Relocation is on but do not reference unbolted pages */ /* Early initialization. Relocation is on but do not reference unbolted pages */
void __init pSeries_init_early(void) void __init pSeries_init_early(void)
......
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#define BUID_LO(buid) ((buid) & 0xffffffff) #define BUID_LO(buid) ((buid) & 0xffffffff)
#define CONFIG_ADDR(busno, devfn) (((((busno) & 0xff) << 8) | ((devfn) & 0xf8)) << 8) #define CONFIG_ADDR(busno, devfn) (((((busno) & 0xff) << 8) | ((devfn) & 0xf8)) << 8)
unsigned long eeh_total_mmio_reads;
unsigned long eeh_total_mmio_ffs; unsigned long eeh_total_mmio_ffs;
unsigned long eeh_false_positives; unsigned long eeh_false_positives;
/* RTAS tokens */ /* RTAS tokens */
...@@ -44,11 +43,11 @@ static int ibm_set_eeh_option; ...@@ -44,11 +43,11 @@ static int ibm_set_eeh_option;
static int ibm_set_slot_reset; static int ibm_set_slot_reset;
static int ibm_read_slot_reset_state; static int ibm_read_slot_reset_state;
static int eeh_implemented; int eeh_implemented;
#define EEH_MAX_OPTS 4096 #define EEH_MAX_OPTS 4096
static char *eeh_opts; static char *eeh_opts;
static int eeh_opts_last; static int eeh_opts_last;
static int eeh_check_opts_config(struct pci_dev *dev); static int eeh_check_opts_config(struct pci_dev *dev, int default_state);
unsigned long eeh_token(unsigned long phb, unsigned long bus, unsigned long devfn, unsigned long offset) unsigned long eeh_token(unsigned long phb, unsigned long bus, unsigned long devfn, unsigned long offset)
...@@ -86,33 +85,58 @@ unsigned long eeh_check_failure(void *token, unsigned long val) ...@@ -86,33 +85,58 @@ unsigned long eeh_check_failure(void *token, unsigned long val)
panic("EEH: checking token %p phb index of %ld is greater than max of %d\n", token, phbidx, global_phb_number-1); panic("EEH: checking token %p phb index of %ld is greater than max of %d\n", token, phbidx, global_phb_number-1);
} }
phb = phbtab[phbidx]; phb = phbtab[phbidx];
eeh_false_positives++;
ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
config_addr, BUID_HI(phb->buid), BUID_LO(phb->buid)); config_addr, BUID_HI(phb->buid), BUID_LO(phb->buid));
if (ret == 0 && rets[1] == 1 && rets[2] != 0) { if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
struct pci_dev *dev; struct pci_dev *dev;
int bus = ((unsigned long)token >> 40) & 0xffff; /* include PHB# in bus */ int bus = ((unsigned long)token >> 40) & 0xffff; /* include PHB# in bus */
int devfn = (config_addr >> 8) & 0xff; int devfn = (config_addr >> 8) & 0xff;
dev = pci_find_slot(bus, devfn); dev = pci_find_slot(bus, devfn);
if (dev) if (dev) {
udbg_printf("EEH: MMIO failure (%ld) on device:\n %s %s\n",
rets[0], dev->slot_name, dev->name);
printk("EEH: MMIO failure (%ld) on device:\n %s %s\n",
rets[0], dev->slot_name, dev->name);
PPCDBG_ENTER_DEBUGGER();
panic("EEH: MMIO failure (%ld) on device:\n %s %s\n", panic("EEH: MMIO failure (%ld) on device:\n %s %s\n",
rets[2], dev->slot_name, dev->name); rets[0], dev->slot_name, dev->name);
else } else {
panic("EEH: MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[2], phb->buid, config_addr); udbg_printf("EEH: MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
printk("EEH: MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
PPCDBG_ENTER_DEBUGGER();
panic("EEH: MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
}
} }
eeh_false_positives++;
return val; /* good case */ return val; /* good case */
} }
void eeh_init(void) { void eeh_init(void) {
extern char cmd_line[]; /* Very early cmd line parse. Cheap, but works. */
char *eeh_force_off = strstr(cmd_line, "eeh-force-off");
char *eeh_force_on = strstr(cmd_line, "eeh-force-on");
ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
if (ibm_set_eeh_option != RTAS_UNKNOWN_SERVICE) { if (ibm_set_eeh_option != RTAS_UNKNOWN_SERVICE && _machine == _MACH_pSeriesLP)
printk("PCI Enhanced I/O Error Handling Enabled\n");
eeh_implemented = 1; eeh_implemented = 1;
if (eeh_force_off > eeh_force_on) {
/* User is forcing EEH off. Be noisy if it is implemented. */
if (eeh_implemented)
printk("EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
eeh_implemented = 0;
return;
} }
if (eeh_force_on > eeh_force_off)
eeh_implemented = 1; /* User is forcing it on. */
if (eeh_implemented)
printk("EEH: PCI Enhanced I/O Error Handling Enabled\n");
} }
...@@ -124,27 +148,35 @@ int is_eeh_configured(struct pci_dev *dev) ...@@ -124,27 +148,35 @@ int is_eeh_configured(struct pci_dev *dev)
struct device_node *dn = pci_device_to_OF_node(dev); struct device_node *dn = pci_device_to_OF_node(dev);
struct pci_controller *phb = PCI_GET_PHB_PTR(dev); struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
unsigned long ret, rets[2]; unsigned long ret, rets[2];
int eeh_capable;
int default_state = 1; /* default enable EEH if we can. */
if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented) if (dn == NULL || phb == NULL || !eeh_implemented)
return 0; return 0;
/* Hack: turn off eeh for display class devices. /* Hack: turn off eeh for display class devices by default.
* This fixes matrox accel framebuffer. * This fixes matrox accel framebuffer.
*/ */
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
return 0; default_state = 0;
if (!eeh_check_opts_config(dev)) /* Ignore known PHBs and EADs bridges */
if (dev->vendor == PCI_VENDOR_ID_IBM &&
(dev->device == 0x0102 || dev->device == 0x008b))
default_state = 0;
if (!eeh_check_opts_config(dev, default_state)) {
if (default_state)
printk("EEH: %s %s user requested to run without EEH.\n", dev->slot_name, dev->name);
return 0; return 0;
}
ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
CONFIG_ADDR(dn->busno, dn->devfn), CONFIG_ADDR(dn->busno, dn->devfn),
BUID_HI(phb->buid), BUID_LO(phb->buid)); BUID_HI(phb->buid), BUID_LO(phb->buid));
if (ret == 0 && rets[1] == 1) { eeh_capable = (ret == 0 && rets[1] == 1);
printk("EEH: %s %s is EEH capable.\n", dev->slot_name, dev->name); printk("EEH: %s %s is%s EEH capable.\n", dev->slot_name, dev->name, eeh_capable ? "" : " not");
return 1; return eeh_capable;
}
return 0;
} }
int eeh_set_option(struct pci_dev *dev, int option) int eeh_set_option(struct pci_dev *dev, int option)
...@@ -166,41 +198,41 @@ static int eeh_proc_falsepositive_read(char *page, char **start, off_t off, ...@@ -166,41 +198,41 @@ static int eeh_proc_falsepositive_read(char *page, char **start, off_t off,
{ {
int len; int len;
len = sprintf(page, "eeh_false_positives=%ld\n" len = sprintf(page, "eeh_false_positives=%ld\n"
"eeh_total_mmio_ffs=%ld\n" "eeh_total_mmio_ffs=%ld\n",
"eeh_total_mmio_reads=%ld\n", eeh_false_positives, eeh_total_mmio_ffs);
eeh_false_positives, eeh_total_mmio_ffs, eeh_total_mmio_reads);
return len; return len;
} }
/* Implementation of /proc/ppc64/eeh /* Implementation of /proc/ppc64/eeh
* For now it is one file showing false positives. * For now it is one file showing false positives.
*/ */
void eeh_init_proc(struct proc_dir_entry *top) static int __init eeh_init_proc(void)
{ {
struct proc_dir_entry *ent = create_proc_entry("eeh", S_IRUGO, top); struct proc_dir_entry *ent = create_proc_entry("ppc64/eeh", S_IRUGO, 0);
if (ent) { if (ent) {
ent->nlink = 1; ent->nlink = 1;
ent->data = NULL; ent->data = NULL;
ent->read_proc = (void *)eeh_proc_falsepositive_read; ent->read_proc = (void *)eeh_proc_falsepositive_read;
} }
return 0;
} }
/* /*
* Test if "dev" should be configured on or off. * Test if "dev" should be configured on or off.
* This processes the options literally from right to left. * This processes the options literally from left to right.
* This lets the user specify stupid combinations of options, * This lets the user specify stupid combinations of options,
* but at least the result should be very predictable. * but at least the result should be very predictable.
*/ */
static int eeh_check_opts_config(struct pci_dev *dev) static int eeh_check_opts_config(struct pci_dev *dev, int default_state)
{ {
struct device_node *dn = pci_device_to_OF_node(dev); struct device_node *dn = pci_device_to_OF_node(dev);
struct pci_controller *phb = PCI_GET_PHB_PTR(dev); struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
char devname[32], classname[32], phbname[32]; char devname[32], classname[32], phbname[32];
char *strs[8], *s; char *strs[8], *s;
int nstrs, i; int nstrs, i;
int ret = 0; int ret = default_state;
if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented) if (dn == NULL || phb == NULL)
return 0; return 0;
/* Build list of strings to match */ /* Build list of strings to match */
nstrs = 0; nstrs = 0;
...@@ -221,7 +253,7 @@ static int eeh_check_opts_config(struct pci_dev *dev) ...@@ -221,7 +253,7 @@ static int eeh_check_opts_config(struct pci_dev *dev)
for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last)); s += strlen(s)+1) { for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last)); s += strlen(s)+1) {
for (i = 0; i < nstrs; i++) { for (i = 0; i < nstrs; i++) {
if (strcasecmp(strs[i], s+1) == 0) { if (strcasecmp(strs[i], s+1) == 0) {
ret = (strs[0] == '+') ? 1 : 0; ret = (strs[i][0] == '+') ? 1 : 0;
} }
} }
} }
...@@ -234,7 +266,7 @@ static int eeh_check_opts_config(struct pci_dev *dev) ...@@ -234,7 +266,7 @@ static int eeh_check_opts_config(struct pci_dev *dev)
* eeh-off=loc1,loc2,loc3... * eeh-off=loc1,loc2,loc3...
* *
* and this option can be repeated so * and this option can be repeated so
* eeh-off=loc1,loc2 eeh=loc3 * eeh-off=loc1,loc2 eeh-off=loc3
* is the same as eeh-off=loc1,loc2,loc3 * is the same as eeh-off=loc1,loc2,loc3
* *
* loc is an IBM location code that can be found in a manual or * loc is an IBM location code that can be found in a manual or
...@@ -285,7 +317,6 @@ static int __init eeh_parm(char *str, int state) ...@@ -285,7 +317,6 @@ static int __init eeh_parm(char *str, int state)
curend = cur + strlen(cur); curend = cur + strlen(cur);
if (*cur) { if (*cur) {
int curlen = curend-cur; int curlen = curend-cur;
char *sym = eeh_opts+eeh_opts_last;
if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) { if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) {
printk("EEH: sorry...too many eeh cmd line options\n"); printk("EEH: sorry...too many eeh cmd line options\n");
return 1; return 1;
...@@ -308,6 +339,6 @@ static int __init eehon_parm(char *str) ...@@ -308,6 +339,6 @@ static int __init eehon_parm(char *str)
return eeh_parm(str, 1); return eeh_parm(str, 1);
} }
__initcall(eeh_init_proc);
__setup("eeh-off", eehoff_parm); __setup("eeh-off", eehoff_parm);
__setup("eeh-on", eehon_parm); __setup("eeh-on", eehon_parm);
/* /*
* arch/ppc/kernel/entry.S * arch/ppc64/kernel/entry.S
* *
* PowerPC version * PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
......
...@@ -490,6 +490,24 @@ maskable_exception_exit: ...@@ -490,6 +490,24 @@ maskable_exception_exit:
mfspr r20,SPRG2 mfspr r20,SPRG2
rfid rfid
/*
* Data area reserved for FWNMI option.
*/
.= 0x7000
.globl fwnmi_data_area
fwnmi_data_area:
/*
* Vectors for the FWNMI option. Share common code.
*/
. = 0x8000
.globl SystemReset_FWNMI
SystemReset_FWNMI:
//EXCEPTION_PROLOG_PSERIES(0x100, SystemReset_common)
.globl MachineCheck_FWNMI
MachineCheck_FWNMI:
//EXCEPTION_PROLOG_PSERIES(0x200, MachineCheck_common)
/*** Common interrupt handlers ***/ /*** Common interrupt handlers ***/
STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException ) STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
...@@ -1285,7 +1303,7 @@ _STATIC(__after_prom_start) ...@@ -1285,7 +1303,7 @@ _STATIC(__after_prom_start)
/* this includes the code being */ /* this includes the code being */
/* executed here. */ /* executed here. */
li r0,4f@l /* Jump to the copy of this code */ LOADADDR(r0, 4f) /* Jump to the copy of this code */
mtctr r0 /* that we just made */ mtctr r0 /* that we just made */
bctr bctr
......
...@@ -41,9 +41,7 @@ ...@@ -41,9 +41,7 @@
#include <asm/ppcdebug.h> #include <asm/ppcdebug.h>
#include <asm/naca.h> #include <asm/naca.h>
#include <asm/pci_dma.h> #include <asm/pci_dma.h>
#ifdef CONFIG_PPC_EEH
#include <asm/eeh.h> #include <asm/eeh.h>
#endif
#include "xics.h" #include "xics.h"
#include "open_pic.h" #include "open_pic.h"
...@@ -256,9 +254,8 @@ find_and_init_phbs(void) ...@@ -256,9 +254,8 @@ find_and_init_phbs(void)
write_pci_config = rtas_token("write-pci-config"); write_pci_config = rtas_token("write-pci-config");
ibm_read_pci_config = rtas_token("ibm,read-pci-config"); ibm_read_pci_config = rtas_token("ibm,read-pci-config");
ibm_write_pci_config = rtas_token("ibm,write-pci-config"); ibm_write_pci_config = rtas_token("ibm,write-pci-config");
#ifdef CONFIG_PPC_EEH
eeh_init(); eeh_init();
#endif
if (naca->interrupt_controller == IC_OPEN_PIC) { if (naca->interrupt_controller == IC_OPEN_PIC) {
opprop = (unsigned int *)get_property(find_path_device("/"), opprop = (unsigned int *)get_property(find_path_device("/"),
...@@ -358,24 +355,24 @@ find_and_init_phbs(void) ...@@ -358,24 +355,24 @@ find_and_init_phbs(void)
res = &phb->io_resource; res = &phb->io_resource;
res->name = Pci_Node->full_name; res->name = Pci_Node->full_name;
res->flags = IORESOURCE_IO; res->flags = IORESOURCE_IO;
#ifdef CONFIG_PPC_EEH if (is_eeh_implemented()) {
if (!isa_io_base && has_isa) { if (!isa_io_base && has_isa) {
/* map a page for ISA ports. Not EEH protected. */ /* map a page for ISA ports. Not EEH protected. */
isa_io_base = (unsigned long)__ioremap(phb->io_base_phys, PAGE_SIZE, _PAGE_NO_CACHE); isa_io_base = (unsigned long)__ioremap(phb->io_base_phys, PAGE_SIZE, _PAGE_NO_CACHE);
} }
res->start = phb->io_base_virt = eeh_token(index, 0, 0, 0); res->start = phb->io_base_virt = eeh_token(index, 0, 0, 0);
res->end = eeh_token(index, 0xff, 0xff, 0xffffffff); res->end = eeh_token(index, 0xff, 0xff, 0xffffffff);
#else } else {
phb->io_base_virt = ioremap(phb->io_base_phys, range.size); phb->io_base_virt = ioremap(phb->io_base_phys, range.size);
if (!pci_io_base) { if (!pci_io_base) {
pci_io_base = (unsigned long)phb->io_base_virt; pci_io_base = (unsigned long)phb->io_base_virt;
if (has_isa) if (has_isa)
isa_io_base = pci_io_base; isa_io_base = pci_io_base;
}
res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
res->start += (unsigned long)phb->io_base_virt;
res->end = res->start + range.size - 1;
} }
res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
res->start += (unsigned long)phb->io_base_virt;
res->end = res->start + range.size - 1;
#endif
res->parent = NULL; res->parent = NULL;
res->sibling = NULL; res->sibling = NULL;
res->child = NULL; res->child = NULL;
...@@ -399,13 +396,13 @@ find_and_init_phbs(void) ...@@ -399,13 +396,13 @@ find_and_init_phbs(void)
++memno; ++memno;
res->name = Pci_Node->full_name; res->name = Pci_Node->full_name;
res->flags = IORESOURCE_MEM; res->flags = IORESOURCE_MEM;
#ifdef CONFIG_PPC_EEH if (is_eeh_implemented()) {
res->start = eeh_token(index, 0, 0, 0); res->start = eeh_token(index, 0, 0, 0);
res->end = eeh_token(index, 0xff, 0xff, 0xffffffff); res->end = eeh_token(index, 0xff, 0xff, 0xffffffff);
#else } else {
res->start = range.parent_addr; res->start = range.parent_addr;
res->end = range.parent_addr + range.size - 1; res->end = range.parent_addr + range.size - 1;
#endif }
res->parent = NULL; res->parent = NULL;
res->sibling = NULL; res->sibling = NULL;
res->child = NULL; res->child = NULL;
...@@ -566,14 +563,11 @@ alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ...@@ -566,14 +563,11 @@ alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words)
phb->ops = &rtas_pci_ops; phb->ops = &rtas_pci_ops;
buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len); buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len);
if (buid_vals == NULL || len < 2 * sizeof(int)) {
if (buid_vals == NULL) {
phb->buid = 0; phb->buid = 0;
} else { }
/* Big bus system. These systems start new bus numbers under else {
* each phb. Until pci domains are standard, we depend on a
* patch which makes bus numbers ints and we shift the phb
* number into the upper bits.
*/
struct pci_bus check; struct pci_bus check;
if (sizeof(check.number) == 1 || sizeof(check.primary) == 1 || if (sizeof(check.number) == 1 || sizeof(check.primary) == 1 ||
sizeof(check.secondary) == 1 || sizeof(check.subordinate) == 1) { sizeof(check.secondary) == 1 || sizeof(check.subordinate) == 1) {
...@@ -583,9 +577,14 @@ alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ...@@ -583,9 +577,14 @@ alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words)
panic("pSeries_pci: this system has large bus numbers and the kernel was not\n" panic("pSeries_pci: this system has large bus numbers and the kernel was not\n"
"built with the patch that fixes include/linux/pci.h struct pci_bus so\n" "built with the patch that fixes include/linux/pci.h struct pci_bus so\n"
"number, primary, secondary and subordinate are ints.\n"); "number, primary, secondary and subordinate are ints.\n");
} }
phb->buid = (((unsigned long)buid_vals[0]) << 32UL) |
(((unsigned long)buid_vals[1]) & 0xffffffff); if (len < 2 * sizeof(int))
phb->buid = (unsigned long)buid_vals[0]; // Support for new OF that only has 1 integer for buid.
else
phb->buid = (((unsigned long)buid_vals[0]) << 32UL) |
(((unsigned long)buid_vals[1]) & 0xffffffff);
phb->first_busno += (phb->global_number << 8); phb->first_busno += (phb->global_number << 8);
phb->last_busno += (phb->global_number << 8); phb->last_busno += (phb->global_number << 8);
} }
...@@ -601,7 +600,6 @@ fixup_resources(struct pci_dev *dev) ...@@ -601,7 +600,6 @@ fixup_resources(struct pci_dev *dev)
{ {
int i; int i;
struct pci_controller *phb = PCI_GET_PHB_PTR(dev); struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
#ifdef CONFIG_PPC_EEH
struct device_node *dn; struct device_node *dn;
unsigned long eeh_disable_bit; unsigned long eeh_disable_bit;
...@@ -620,19 +618,19 @@ fixup_resources(struct pci_dev *dev) ...@@ -620,19 +618,19 @@ fixup_resources(struct pci_dev *dev)
} }
} }
if (is_eeh_configured(dev)) { if (is_eeh_implemented()) {
eeh_disable_bit = 0; if (is_eeh_configured(dev)) {
printk("PCI: eeh configured for %s %s\n", dev->slot_name, dev->name); eeh_disable_bit = 0;
if (eeh_set_option(dev, EEH_ENABLE) != 0) { if (eeh_set_option(dev, EEH_ENABLE) != 0) {
printk("PCI: failed to enable eeh for %s %s\n", dev->slot_name, dev->name); printk("PCI: failed to enable EEH for %s %s\n", dev->slot_name, dev->name);
eeh_disable_bit = EEH_TOKEN_DISABLED;
}
} else {
/* Assume device is by default EEH_DISABLE'd */
printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name);
eeh_disable_bit = EEH_TOKEN_DISABLED; eeh_disable_bit = EEH_TOKEN_DISABLED;
} }
} else {
/* Assume device is by default EEH_DISABLE'd */
printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name);
eeh_disable_bit = EEH_TOKEN_DISABLED;
} }
#endif
PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n"); PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n");
PPCDBG(PPCDBG_PHBINIT, "\tphb = 0x%016LX\n", phb); PPCDBG(PPCDBG_PHBINIT, "\tphb = 0x%016LX\n", phb);
...@@ -657,19 +655,19 @@ fixup_resources(struct pci_dev *dev) ...@@ -657,19 +655,19 @@ fixup_resources(struct pci_dev *dev)
} }
if (dev->resource[i].flags & IORESOURCE_IO) { if (dev->resource[i].flags & IORESOURCE_IO) {
#ifdef CONFIG_PPC_EEH if (is_eeh_implemented()) {
unsigned int busno = dev->bus ? dev->bus->number : 0; unsigned int busno = dev->bus ? dev->bus->number : 0;
unsigned long size = dev->resource[i].end - dev->resource[i].start; unsigned long size = dev->resource[i].end - dev->resource[i].start;
unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE); unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE);
if (!addr) if (!addr)
panic("fixup_resources: ioremap failed!\n"); panic("fixup_resources: ioremap failed!\n");
dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit; dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
dev->resource[i].end = dev->resource[i].start + size; dev->resource[i].end = dev->resource[i].start + size;
#else } else {
unsigned long offset = (unsigned long)phb->io_base_virt; unsigned long offset = (unsigned long)phb->io_base_virt;
dev->resource[i].start += offset; dev->resource[i].start += offset;
dev->resource[i].end += offset; dev->resource[i].end += offset;
#endif }
PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n", PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n",
dev->resource[i].start, dev->resource[i].end); dev->resource[i].start, dev->resource[i].end);
} else if (dev->resource[i].flags & IORESOURCE_MEM) { } else if (dev->resource[i].flags & IORESOURCE_MEM) {
...@@ -677,18 +675,18 @@ fixup_resources(struct pci_dev *dev) ...@@ -677,18 +675,18 @@ fixup_resources(struct pci_dev *dev)
/* Bogus. Probably an unused bridge. */ /* Bogus. Probably an unused bridge. */
dev->resource[i].end = 0; dev->resource[i].end = 0;
} else { } else {
#ifdef CONFIG_PPC_EEH if (is_eeh_implemented()) {
unsigned int busno = dev->bus ? dev->bus->number : 0; unsigned int busno = dev->bus ? dev->bus->number : 0;
unsigned long size = dev->resource[i].end - dev->resource[i].start; unsigned long size = dev->resource[i].end - dev->resource[i].start;
unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE); unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE);
if (!addr) if (!addr)
panic("fixup_resources: ioremap failed!\n"); panic("fixup_resources: ioremap failed!\n");
dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit; dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
dev->resource[i].end = dev->resource[i].start + size; dev->resource[i].end = dev->resource[i].start + size;
#else } else {
dev->resource[i].start += phb->pci_mem_offset; dev->resource[i].start += phb->pci_mem_offset;
dev->resource[i].end += phb->pci_mem_offset; dev->resource[i].end += phb->pci_mem_offset;
#endif }
} }
PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n", PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n",
dev->resource[i].start, dev->resource[i].end); dev->resource[i].start, dev->resource[i].end);
......
...@@ -33,9 +33,7 @@ ...@@ -33,9 +33,7 @@
#include <asm/naca.h> #include <asm/naca.h>
#include <asm/pci_dma.h> #include <asm/pci_dma.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#ifdef CONFIG_PPC_EEH
#include <asm/eeh.h> #include <asm/eeh.h>
#endif
#include "pci.h" #include "pci.h"
...@@ -61,8 +59,7 @@ void fixup_resources(struct pci_dev* dev); ...@@ -61,8 +59,7 @@ void fixup_resources(struct pci_dev* dev);
void iSeries_pcibios_init(void); void iSeries_pcibios_init(void);
void pSeries_pcibios_init(void); void pSeries_pcibios_init(void);
int pci_assign_all_busses = 0; int pci_assign_all_busses = 0;
struct pci_controller* hose_head; struct pci_controller* hose_head;
struct pci_controller** hose_tail = &hose_head; struct pci_controller** hose_tail = &hose_head;
...@@ -514,7 +511,6 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) ...@@ -514,7 +511,6 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
{ {
struct pci_controller *phb = PCI_GET_PHB_PTR(bus); struct pci_controller *phb = PCI_GET_PHB_PTR(bus);
struct resource *res; struct resource *res;
unsigned long io_offset;
int i; int i;
#ifndef CONFIG_PPC_ISERIES #ifndef CONFIG_PPC_ISERIES
...@@ -546,23 +542,23 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) ...@@ -546,23 +542,23 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
/* Transparent resource -- don't try to "fix" it. */ /* Transparent resource -- don't try to "fix" it. */
continue; continue;
} }
#ifdef CONFIG_PPC_EEH if (is_eeh_implemented()) {
if (res->flags & (IORESOURCE_IO|IORESOURCE_MEM)) { if (res->flags & (IORESOURCE_IO|IORESOURCE_MEM)) {
res->start = eeh_token(phb->global_number, bus->number, 0, 0); res->start = eeh_token(phb->global_number, bus->number, 0, 0);
res->end = eeh_token(phb->global_number, bus->number, 0xff, 0xffffffff); res->end = eeh_token(phb->global_number, bus->number, 0xff, 0xffffffff);
} }
#else } else {
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
res->start += (unsigned long)phb->io_base_virt; res->start += (unsigned long)phb->io_base_virt;
res->end += (unsigned long)phb->io_base_virt; res->end += (unsigned long)phb->io_base_virt;
} else if (phb->pci_mem_offset } else if (phb->pci_mem_offset
&& (res->flags & IORESOURCE_MEM)) { && (res->flags & IORESOURCE_MEM)) {
if (res->start < phb->pci_mem_offset) { if (res->start < phb->pci_mem_offset) {
res->start += phb->pci_mem_offset; res->start += phb->pci_mem_offset;
res->end += phb->pci_mem_offset; res->end += phb->pci_mem_offset;
}
} }
} }
#endif
} }
} }
#endif #endif
......
/* /*
* arch/ppc/kernel/ppc_asm.h * arch/ppc64/kernel/ppc_asm.h
* *
* Definitions used by various bits of low-level assembly code on PowerPC. * Definitions used by various bits of low-level assembly code on PowerPC.
* *
......
...@@ -191,13 +191,11 @@ EXPORT_SYMBOL(iSeries_memcpy_fromio); ...@@ -191,13 +191,11 @@ EXPORT_SYMBOL(iSeries_memcpy_fromio);
EXPORT_SYMBOL(iSeries_Read_Word); EXPORT_SYMBOL(iSeries_Read_Word);
EXPORT_SYMBOL(iSeries_Read_Byte); EXPORT_SYMBOL(iSeries_Read_Byte);
EXPORT_SYMBOL(iSeries_Write_Byte); EXPORT_SYMBOL(iSeries_Write_Byte);
#endif /* CONFIG_PPC_ISERIES */ #endif /* CONFIG_PPC_ISERIES */
#ifdef CONFIG_PPC_EEH #ifndef CONFIG_PPC_ISERIES
EXPORT_SYMBOL(eeh_check_failure); EXPORT_SYMBOL(eeh_check_failure);
EXPORT_SYMBOL(eeh_total_mmio_ffs); EXPORT_SYMBOL(eeh_total_mmio_ffs);
EXPORT_SYMBOL(eeh_total_mmio_reads); #endif /* CONFIG_PPC_ISERIES */
#endif /* CONFIG_PPC_EEH */
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
EXPORT_SYMBOL(iSeries_veth_dev); EXPORT_SYMBOL(iSeries_veth_dev);
...@@ -241,10 +239,6 @@ EXPORT_SYMBOL(machine_is_compatible); ...@@ -241,10 +239,6 @@ EXPORT_SYMBOL(machine_is_compatible);
EXPORT_SYMBOL(find_all_nodes); EXPORT_SYMBOL(find_all_nodes);
EXPORT_SYMBOL(get_property); EXPORT_SYMBOL(get_property);
#ifdef CONFIG_NVRAM
EXPORT_SYMBOL(nvram_read_byte);
EXPORT_SYMBOL(nvram_write_byte);
#endif /* CONFIG_NVRAM */
EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_NOVERS(__ashrdi3);
EXPORT_SYMBOL_NOVERS(__ashldi3); EXPORT_SYMBOL_NOVERS(__ashldi3);
......
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
extern int fix_alignment(struct pt_regs *); extern int fix_alignment(struct pt_regs *);
extern void bad_page_fault(struct pt_regs *, unsigned long); extern void bad_page_fault(struct pt_regs *, unsigned long);
/* This is true if we are using the firmware NMI handler (typically LPAR) */
extern int fwnmi_active;
#ifdef CONFIG_XMON #ifdef CONFIG_XMON
extern void xmon(struct pt_regs *regs); extern void xmon(struct pt_regs *regs);
extern int xmon_bpt(struct pt_regs *regs); extern int xmon_bpt(struct pt_regs *regs);
...@@ -91,13 +94,55 @@ _exception(int signr, struct pt_regs *regs) ...@@ -91,13 +94,55 @@ _exception(int signr, struct pt_regs *regs)
force_sig(signr, current); force_sig(signr, current);
} }
/* Get the error information for errors coming through the
* FWNMI vectors. The pt_regs' r3 will be updated to reflect
* the actual r3 if possible, and a ptr to the error log entry
* will be returned if found.
*/
static struct rtas_error_log *FWNMI_get_errinfo(struct pt_regs *regs)
{
unsigned long errdata = regs->gpr[3];
struct rtas_error_log *errhdr = NULL;
unsigned long *savep;
if ((errdata >= 0x7000 && errdata < 0x7fff0) ||
(errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) {
savep = __va(errdata);
regs->gpr[3] = savep[0]; /* restore original r3 */
errhdr = (struct rtas_error_log *)(savep + 1);
} else {
printk("FWNMI: corrupt r3\n");
}
return errhdr;
}
/* Call this when done with the data returned by FWNMI_get_errinfo.
* It will release the saved data area for other CPUs in the
* partition to receive FWNMI errors.
*/
static void FWNMI_release_errinfo(void)
{
unsigned long ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
if (ret != 0)
printk("FWNMI: nmi-interlock failed: %ld\n", ret);
}
void void
SystemResetException(struct pt_regs *regs) SystemResetException(struct pt_regs *regs)
{ {
udbg_printf("System Reset in kernel mode.\n"); char *msg = "System Reset in kernel mode.\n";
printk("System Reset in kernel mode.\n"); udbg_printf(msg); printk(msg);
if (fwnmi_active) {
unsigned long *r3 = __va(regs->gpr[3]); /* for FWNMI debug */
struct rtas_error_log *errlog;
msg = "FWNMI is active with save area at %016lx\n";
udbg_printf(msg, r3); printk(msg, r3);
errlog = FWNMI_get_errinfo(regs);
}
#if defined(CONFIG_XMON) #if defined(CONFIG_XMON)
xmon(regs); xmon(regs);
udbg_printf("leaving xmon...\n");
#else #else
for(;;); for(;;);
#endif #endif
...@@ -106,6 +151,13 @@ SystemResetException(struct pt_regs *regs) ...@@ -106,6 +151,13 @@ SystemResetException(struct pt_regs *regs)
void void
MachineCheckException(struct pt_regs *regs) MachineCheckException(struct pt_regs *regs)
{ {
if (fwnmi_active) {
struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
if (errhdr) {
/* ToDo: attempt to recover from some errors here */
}
FWNMI_release_errinfo();
}
if ( !user_mode(regs) ) if ( !user_mode(regs) )
{ {
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
......
...@@ -155,13 +155,11 @@ ioremap(unsigned long addr, unsigned long size) ...@@ -155,13 +155,11 @@ ioremap(unsigned long addr, unsigned long size)
#ifdef CONFIG_PPC_ISERIES #ifdef CONFIG_PPC_ISERIES
return (void*)addr; return (void*)addr;
#else #else
#ifdef CONFIG_PPC_EEH
if(mem_init_done && (addr >> 60UL)) { if(mem_init_done && (addr >> 60UL)) {
if (IS_EEH_TOKEN_DISABLED(addr)) if (IS_EEH_TOKEN_DISABLED(addr))
return IO_TOKEN_TO_ADDR(addr); return IO_TOKEN_TO_ADDR(addr);
return (void*)addr; /* already mapped address or EEH token. */ return (void*)addr; /* already mapped address or EEH token. */
} }
#endif
return __ioremap(addr, size, _PAGE_NO_CACHE); return __ioremap(addr, size, _PAGE_NO_CACHE);
#endif #endif
} }
......
...@@ -37,11 +37,13 @@ struct pci_dev; ...@@ -37,11 +37,13 @@ struct pci_dev;
#define EEH_STATE_OVERRIDE 1 /* IOA does not require eeh traps */ #define EEH_STATE_OVERRIDE 1 /* IOA does not require eeh traps */
#define EEH_STATE_FAILURE 16 /* */ #define EEH_STATE_FAILURE 16 /* */
/* This is for profiling only and should be removed */ /* This is for profiling only */
extern unsigned long eeh_total_mmio_reads;
extern unsigned long eeh_total_mmio_ffs; extern unsigned long eeh_total_mmio_ffs;
extern int eeh_implemented;
void eeh_init(void); void eeh_init(void);
static inline int is_eeh_implemented(void) { return eeh_implemented; }
int eeh_get_state(unsigned long ea); int eeh_get_state(unsigned long ea);
unsigned long eeh_check_failure(void *token, unsigned long val); unsigned long eeh_check_failure(void *token, unsigned long val);
...@@ -83,7 +85,7 @@ extern void *memset(void *,int, unsigned long); ...@@ -83,7 +85,7 @@ extern void *memset(void *,int, unsigned long);
*/ */
/* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && ~(val) == 0 && !IS_EEH_TOKEN_DISABLED(addr)) */ /* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && ~(val) == 0 && !IS_EEH_TOKEN_DISABLED(addr)) */
/* This version is rearranged to collect some profiling data */ /* This version is rearranged to collect some profiling data */
#define EEH_POSSIBLE_ERROR(addr, vaddr, val) (++eeh_total_mmio_reads, (~(val) == 0 && (++eeh_total_mmio_ffs, (vaddr) != (addr) && !IS_EEH_TOKEN_DISABLED(addr)))) #define EEH_POSSIBLE_ERROR(addr, vaddr, val) (~(val) == 0 && (++eeh_total_mmio_ffs, (vaddr) != (addr) && !IS_EEH_TOKEN_DISABLED(addr)))
/* /*
* MMIO read/write operations with EEH support. * MMIO read/write operations with EEH support.
......
...@@ -51,7 +51,6 @@ extern int have_print; ...@@ -51,7 +51,6 @@ extern int have_print;
#define outl(data,addr) writel(data,((unsigned long)(addr))) #define outl(data,addr) writel(data,((unsigned long)(addr)))
#else #else
#define IS_MAPPED_VADDR(port) ((unsigned long)(port) >> 60UL) #define IS_MAPPED_VADDR(port) ((unsigned long)(port) >> 60UL)
#ifdef CONFIG_PPC_EEH
#define readb(addr) eeh_readb((void*)(addr)) #define readb(addr) eeh_readb((void*)(addr))
#define readw(addr) eeh_readw((void*)(addr)) #define readw(addr) eeh_readw((void*)(addr))
#define readl(addr) eeh_readl((void*)(addr)) #define readl(addr) eeh_readl((void*)(addr))
...@@ -61,17 +60,6 @@ extern int have_print; ...@@ -61,17 +60,6 @@ extern int have_print;
#define memset_io(a,b,c) eeh_memset((void *)(a),(b),(c)) #define memset_io(a,b,c) eeh_memset((void *)(a),(b),(c))
#define memcpy_fromio(a,b,c) eeh_memcpy_fromio((a),(void *)(b),(c)) #define memcpy_fromio(a,b,c) eeh_memcpy_fromio((a),(void *)(b),(c))
#define memcpy_toio(a,b,c) eeh_memcpy_toio((void *)(a),(b),(c)) #define memcpy_toio(a,b,c) eeh_memcpy_toio((void *)(a),(b),(c))
#else
#define readb(addr) in_8((volatile u8 *)(addr))
#define writeb(b,addr) out_8((volatile u8 *)(addr), (b))
#define readw(addr) in_le16((volatile u16 *)(addr))
#define readl(addr) in_le32((volatile u32 *)(addr))
#define writew(b,addr) out_le16((volatile u16 *)(addr),(b))
#define writel(b,addr) out_le32((volatile u32 *)(addr),(b))
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
#endif
#define inb(port) _inb((unsigned long)port) #define inb(port) _inb((unsigned long)port)
#define outb(val, port) _outb(val, (unsigned long)port) #define outb(val, port) _outb(val, (unsigned long)port)
#define inw(port) _inw((unsigned long)port) #define inw(port) _inw((unsigned long)port)
...@@ -259,11 +247,9 @@ extern inline void out_be32(volatile unsigned *addr, int val) ...@@ -259,11 +247,9 @@ extern inline void out_be32(volatile unsigned *addr, int val)
__asm__ __volatile__("stw%U0%X0 %1,%0" : "=m" (*addr) : "r" (val)); __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
} }
#ifdef CONFIG_PPC_EEH #ifndef CONFIG_PPC_ISERIES
#include <asm/eeh.h> #include <asm/eeh.h>
#endif
#ifndef CONFIG_PPC_ISERIES
static inline u8 _inb(unsigned long port) { static inline u8 _inb(unsigned long port) {
if (IS_MAPPED_VADDR(port)) if (IS_MAPPED_VADDR(port))
return readb((void *)port); return readb((void *)port);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment