powerpc/powernv/pci: Dynamically allocate PHB diag data
authorRussell Currey <ruscur@russell.cc>
Wed, 14 Jun 2017 04:19:59 +0000 (14:19 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 27 Jun 2017 02:14:27 +0000 (12:14 +1000)
Diagnostic data for PHBs currently works by allocated a fixed-sized buffer.
This is simple, but either wastes memory (though only a few kilobytes) or
in the case of PHB4 isn't enough to fit the whole data blob.

For machines that don't describe the diagnostic data size in the device
tree, use the hardcoded buffer size as before.  For those that do, only
allocate exactly what's needed.

In the special case of P7IOC (which has two types of diag data), the larger
should be specified in the device tree.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/pci.h

index d12ea7b9fd47ba20dcc963b33a506ce0cff8a626..3f48f6df1cf3937e1f854f9d2bfcb84e27f946c6 100644 (file)
@@ -48,6 +48,7 @@ static int pnv_eeh_init(void)
 {
        struct pci_controller *hose;
        struct pnv_phb *phb;
+       int max_diag_size = PNV_PCI_DIAG_BUF_SIZE;
 
        if (!firmware_has_feature(FW_FEATURE_OPAL)) {
                pr_warn("%s: OPAL is required !\n",
@@ -69,6 +70,9 @@ static int pnv_eeh_init(void)
                if (phb->model == PNV_PHB_MODEL_P7IOC)
                        eeh_add_flag(EEH_ENABLE_IO_FOR_LOG);
 
+               if (phb->diag_data_size > max_diag_size)
+                       max_diag_size = phb->diag_data_size;
+
                /*
                 * PE#0 should be regarded as valid by EEH core
                 * if it's not the reserved one. Currently, we
@@ -82,6 +86,8 @@ static int pnv_eeh_init(void)
                break;
        }
 
+       eeh_set_pe_aux_size(max_diag_size);
+
        return 0;
 }
 
@@ -540,7 +546,7 @@ static void pnv_eeh_get_phb_diag(struct eeh_pe *pe)
        s64 rc;
 
        rc = opal_pci_get_phb_diag_data2(phb->opal_id, pe->data,
-                                        PNV_PCI_DIAG_BUF_SIZE);
+                                        phb->diag_data_size);
        if (rc != OPAL_SUCCESS)
                pr_warn("%s: Failure %lld getting PHB#%x diag-data\n",
                        __func__, rc, pe->phb->global_number);
@@ -1314,7 +1320,8 @@ static void pnv_eeh_dump_hub_diag_common(struct OpalIoP7IOCErrorData *data)
 static void pnv_eeh_get_and_dump_hub_diag(struct pci_controller *hose)
 {
        struct pnv_phb *phb = hose->private_data;
-       struct OpalIoP7IOCErrorData *data = &phb->diag.hub_diag;
+       struct OpalIoP7IOCErrorData *data =
+               (struct OpalIoP7IOCErrorData*)phb->diag_data;
        long rc;
 
        rc = opal_pci_get_hub_diag_data(phb->hub_id, data, sizeof(*data));
@@ -1549,10 +1556,10 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
 
                                /* Dump PHB diag-data */
                                rc = opal_pci_get_phb_diag_data2(phb->opal_id,
-                                       phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE);
+                                       phb->diag_data, phb->diag_data_size);
                                if (rc == OPAL_SUCCESS)
                                        pnv_pci_dump_phb_diag_data(hose,
-                                                       phb->diag.blob);
+                                                       phb->diag_data);
 
                                /* Try best to clear it */
                                opal_pci_eeh_freeze_clear(phb->opal_id,
@@ -1795,7 +1802,6 @@ static int __init eeh_powernv_init(void)
 {
        int ret = -EINVAL;
 
-       eeh_set_pe_aux_size(PNV_PCI_DIAG_BUF_SIZE);
        ret = eeh_ops_register(&pnv_eeh_ops);
        if (!ret)
                pr_info("EEH: PowerNV platform initialized\n");
index 283caf1070c95ee7c60d354e18cce8178440bc95..96d0156f48db88a6169d20b6611fb94a738f287a 100644 (file)
@@ -3123,13 +3123,13 @@ static int pnv_pci_diag_data_set(void *data, u64 val)
        phb = hose->private_data;
 
        /* Retrieve the diag data from firmware */
-       ret = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
-                                         PNV_PCI_DIAG_BUF_SIZE);
+       ret = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag_data,
+                                         phb->diag_data_size);
        if (ret != OPAL_SUCCESS)
                return -EIO;
 
        /* Print the diag data to the kernel log */
-       pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob);
+       pnv_pci_dump_phb_diag_data(phb->hose, phb->diag_data);
        return 0;
 }
 
@@ -3725,6 +3725,15 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
        else
                phb->model = PNV_PHB_MODEL_UNKNOWN;
 
+       /* Initialize diagnostic data buffer */
+       prop32 = of_get_property(np, "ibm,phb-diag-data-size", NULL);
+       if (prop32)
+               phb->diag_data_size = be32_to_cpup(prop32);
+       else
+               phb->diag_data_size = PNV_PCI_DIAG_BUF_SIZE;
+
+       phb->diag_data = memblock_virt_alloc(phb->diag_data_size, 0);
+
        /* Parse 32-bit and IO ranges (if any) */
        pci_process_bridge_OF_ranges(hose, np, !hose->global_number);
 
index 40071ad0bc4246755a510174dbd45736c328e44a..209ad47a3383e9603a47d85d0c9130640f7993f7 100644 (file)
@@ -456,8 +456,8 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
        spin_lock_irqsave(&phb->lock, flags);
 
        /* Fetch PHB diag-data */
-       rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
-                                        PNV_PCI_DIAG_BUF_SIZE);
+       rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag_data,
+                                        phb->diag_data_size);
        has_diag = (rc == OPAL_SUCCESS);
 
        /* If PHB supports compound PE, to handle it */
@@ -485,7 +485,7 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
         * with the normal errors generated when probing empty slots
         */
        if (has_diag && ret)
-               pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob);
+               pnv_pci_dump_phb_diag_data(phb->hose, phb->diag_data);
 
        spin_unlock_irqrestore(&phb->lock, flags);
 }
index 6abc77dd9261f5c3de6a0faf0f6e6deb518d7320..f16bc403ec03cff364ff79b7d27fb0f6168525f6 100644 (file)
@@ -172,13 +172,9 @@ struct pnv_phb {
                unsigned int            pe_rmap[0x10000];
        } ioda;
 
-       /* PHB and hub status structure */
-       union {
-               unsigned char                   blob[PNV_PCI_DIAG_BUF_SIZE];
-               struct OpalIoP7IOCPhbErrorData  p7ioc;
-               struct OpalIoPhb3ErrorData      phb3;
-               struct OpalIoP7IOCErrorData     hub_diag;
-       } diag;
+       /* PHB and hub diagnostics */
+       unsigned int            diag_data_size;
+       u8                      *diag_data;
 
        /* Nvlink2 data */
        struct npu {