summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig1
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c67
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c2
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c80
-rw-r--r--arch/powerpc/platforms/pseries/ras.c3
5 files changed, 102 insertions, 51 deletions
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 1bd3399146ed..62b4f8025de0 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -19,7 +19,6 @@ config PPC_PSERIES
select ZLIB_DEFLATE
select PPC_DOORBELL
select HAVE_CONTEXT_TRACKING
- select HOTPLUG if SMP
select HOTPLUG_CPU if SMP
default y
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index b456b157d33d..7fbc25b1813f 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -133,6 +133,48 @@ static int pseries_eeh_init(void)
return 0;
}
+static int pseries_eeh_cap_start(struct device_node *dn)
+{
+ struct pci_dn *pdn = PCI_DN(dn);
+ u32 status;
+
+ if (!pdn)
+ return 0;
+
+ rtas_read_config(pdn, PCI_STATUS, 2, &status);
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ return PCI_CAPABILITY_LIST;
+}
+
+
+static int pseries_eeh_find_cap(struct device_node *dn, int cap)
+{
+ struct pci_dn *pdn = PCI_DN(dn);
+ int pos = pseries_eeh_cap_start(dn);
+ int cnt = 48; /* Maximal number of capabilities */
+ u32 id;
+
+ if (!pos)
+ return 0;
+
+ while (cnt--) {
+ rtas_read_config(pdn, pos, 1, &pos);
+ if (pos < 0x40)
+ break;
+ pos &= ~3;
+ rtas_read_config(pdn, pos + PCI_CAP_LIST_ID, 1, &id);
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+ pos += PCI_CAP_LIST_NEXT;
+ }
+
+ return 0;
+}
+
/**
* pseries_eeh_of_probe - EEH probe on the given device
* @dn: OF node
@@ -146,14 +188,16 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
{
struct eeh_dev *edev;
struct eeh_pe pe;
+ struct pci_dn *pdn = PCI_DN(dn);
const u32 *class_code, *vendor_id, *device_id;
const u32 *regs;
+ u32 pcie_flags;
int enable = 0;
int ret;
/* Retrieve OF node and eeh device */
edev = of_node_to_eeh_dev(dn);
- if (!of_device_is_available(dn))
+ if (edev->pe || !of_device_is_available(dn))
return NULL;
/* Retrieve class/vendor/device IDs */
@@ -167,9 +211,26 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
if (dn->type && !strcmp(dn->type, "isa"))
return NULL;
- /* Update class code and mode of eeh device */
+ /*
+ * Update class code and mode of eeh device. We need
+ * correctly reflects that current device is root port
+ * or PCIe switch downstream port.
+ */
edev->class_code = *class_code;
- edev->mode = 0;
+ edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP);
+ edev->mode &= 0xFFFFFF00;
+ if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ edev->mode |= EEH_DEV_BRIDGE;
+ if (edev->pcie_cap) {
+ rtas_read_config(pdn, edev->pcie_cap + PCI_EXP_FLAGS,
+ 2, &pcie_flags);
+ pcie_flags = (pcie_flags & PCI_EXP_FLAGS_TYPE) >> 4;
+ if (pcie_flags == PCI_EXP_TYPE_ROOT_PORT)
+ edev->mode |= EEH_DEV_ROOT_PORT;
+ else if (pcie_flags == PCI_EXP_TYPE_DOWNSTREAM)
+ edev->mode |= EEH_DEV_DS_PORT;
+ }
+ }
/* Retrieve the device address */
regs = of_get_property(dn, "reg", NULL);
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 02d6e21619bb..8bad880bd177 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -146,7 +146,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
flags = 0;
/* Make pHyp happy */
- if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU))
+ if ((rflags & _PAGE_NO_CACHE) && !(rflags & _PAGE_WRITETHRU))
hpte_r &= ~_PAGE_COHERENT;
if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N))
flags |= H_COALESCE_CAND;
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 9f8671a44551..6a5f2b1f32ca 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -569,35 +569,6 @@ error:
return ret;
}
-static int unzip_oops(char *oops_buf, char *big_buf)
-{
- struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
- u64 timestamp = oops_hdr->timestamp;
- char *big_oops_data = NULL;
- char *oops_data_buf = NULL;
- size_t big_oops_data_sz;
- int unzipped_len;
-
- big_oops_data = big_buf + sizeof(struct oops_log_info);
- big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info);
- oops_data_buf = oops_buf + sizeof(struct oops_log_info);
-
- unzipped_len = nvram_decompress(oops_data_buf, big_oops_data,
- oops_hdr->report_length,
- big_oops_data_sz);
-
- if (unzipped_len < 0) {
- pr_err("nvram: decompression failed; returned %d\n",
- unzipped_len);
- return -1;
- }
- oops_hdr = (struct oops_log_info *)big_buf;
- oops_hdr->version = OOPS_HDR_VERSION;
- oops_hdr->report_length = (u16) unzipped_len;
- oops_hdr->timestamp = timestamp;
- return 0;
-}
-
static int nvram_pstore_open(struct pstore_info *psi)
{
/* Reset the iterator to start reading partitions again */
@@ -685,10 +656,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
unsigned int err_type, id_no, size = 0;
struct nvram_os_partition *part = NULL;
char *buff = NULL, *big_buff = NULL;
- int rc, sig = 0;
+ int sig = 0;
loff_t p;
-read_partition:
read_type++;
switch (nvram_type_ids[read_type]) {
@@ -749,30 +719,46 @@ read_partition:
*id = id_no;
if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
+ int length, unzipped_len;
+ size_t hdr_size;
+
oops_hdr = (struct oops_log_info *)buff;
- *buf = buff + sizeof(*oops_hdr);
+ if (oops_hdr->version < OOPS_HDR_VERSION) {
+ /* Old format oops header had 2-byte record size */
+ hdr_size = sizeof(u16);
+ length = oops_hdr->version;
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ } else {
+ hdr_size = sizeof(*oops_hdr);
+ length = oops_hdr->report_length;
+ time->tv_sec = oops_hdr->timestamp;
+ time->tv_nsec = 0;
+ }
+ *buf = kmalloc(length, GFP_KERNEL);
+ if (*buf == NULL)
+ return -ENOMEM;
+ memcpy(*buf, buff + hdr_size, length);
+ kfree(buff);
if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (!big_buff)
return -ENOMEM;
- rc = unzip_oops(buff, big_buff);
+ unzipped_len = nvram_decompress(*buf, big_buff,
+ length, big_oops_buf_sz);
- if (rc != 0) {
- kfree(buff);
+ if (unzipped_len < 0) {
+ pr_err("nvram: decompression failed, returned "
+ "rc %d\n", unzipped_len);
kfree(big_buff);
- goto read_partition;
+ } else {
+ *buf = big_buff;
+ length = unzipped_len;
}
-
- oops_hdr = (struct oops_log_info *)big_buff;
- *buf = big_buff + sizeof(*oops_hdr);
- kfree(buff);
}
-
- time->tv_sec = oops_hdr->timestamp;
- time->tv_nsec = 0;
- return oops_hdr->report_length;
+ return length;
}
*buf = buff;
@@ -816,6 +802,7 @@ static int nvram_pstore_init(void)
static void __init nvram_init_oops_partition(int rtas_partition_exists)
{
int rc;
+ size_t size;
rc = pseries_nvram_init_os_partition(&oops_log_partition);
if (rc != 0) {
@@ -844,8 +831,9 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
big_oops_buf_sz = (oops_data_sz * 100) / 45;
big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (big_oops_buf) {
- stream.workspace = kmalloc(zlib_deflate_workspacesize(
- WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
+ size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
+ zlib_inflate_workspacesize());
+ stream.workspace = kmalloc(size, GFP_KERNEL);
if (!stream.workspace) {
pr_err("nvram: No memory for compression workspace; "
"skipping compression of %s partition data\n",
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index 7b3cbde8c783..721c0586b284 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -287,6 +287,9 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
unsigned long *savep;
struct rtas_error_log *h, *errhdr = NULL;
+ /* Mask top two bits */
+ regs->gpr[3] &= ~(0x3UL << 62);
+
if (!VALID_FWNMI_BUFFER(regs->gpr[3])) {
printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]);
return NULL;