powerpc/powernv/pci: Dynamically allocate PHB diag data

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>
This commit is contained in:
Russell Currey 2017-06-14 14:19:59 +10:00 коммит произвёл Michael Ellerman
Родитель 31bbd45af3
Коммит 5cb1f8fddd
4 изменённых файлов: 29 добавлений и 18 удалений

Просмотреть файл

@ -48,6 +48,7 @@ static int pnv_eeh_init(void)
{ {
struct pci_controller *hose; struct pci_controller *hose;
struct pnv_phb *phb; struct pnv_phb *phb;
int max_diag_size = PNV_PCI_DIAG_BUF_SIZE;
if (!firmware_has_feature(FW_FEATURE_OPAL)) { if (!firmware_has_feature(FW_FEATURE_OPAL)) {
pr_warn("%s: OPAL is required !\n", pr_warn("%s: OPAL is required !\n",
@ -69,6 +70,9 @@ static int pnv_eeh_init(void)
if (phb->model == PNV_PHB_MODEL_P7IOC) if (phb->model == PNV_PHB_MODEL_P7IOC)
eeh_add_flag(EEH_ENABLE_IO_FOR_LOG); 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 * PE#0 should be regarded as valid by EEH core
* if it's not the reserved one. Currently, we * if it's not the reserved one. Currently, we
@ -82,6 +86,8 @@ static int pnv_eeh_init(void)
break; break;
} }
eeh_set_pe_aux_size(max_diag_size);
return 0; return 0;
} }
@ -540,7 +546,7 @@ static void pnv_eeh_get_phb_diag(struct eeh_pe *pe)
s64 rc; s64 rc;
rc = opal_pci_get_phb_diag_data2(phb->opal_id, pe->data, 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) if (rc != OPAL_SUCCESS)
pr_warn("%s: Failure %lld getting PHB#%x diag-data\n", pr_warn("%s: Failure %lld getting PHB#%x diag-data\n",
__func__, rc, pe->phb->global_number); __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) static void pnv_eeh_get_and_dump_hub_diag(struct pci_controller *hose)
{ {
struct pnv_phb *phb = hose->private_data; struct pnv_phb *phb = hose->private_data;
struct OpalIoP7IOCErrorData *data = &phb->diag.hub_diag; struct OpalIoP7IOCErrorData *data =
(struct OpalIoP7IOCErrorData*)phb->diag_data;
long rc; long rc;
rc = opal_pci_get_hub_diag_data(phb->hub_id, data, sizeof(*data)); 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 */ /* Dump PHB diag-data */
rc = opal_pci_get_phb_diag_data2(phb->opal_id, 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) if (rc == OPAL_SUCCESS)
pnv_pci_dump_phb_diag_data(hose, pnv_pci_dump_phb_diag_data(hose,
phb->diag.blob); phb->diag_data);
/* Try best to clear it */ /* Try best to clear it */
opal_pci_eeh_freeze_clear(phb->opal_id, opal_pci_eeh_freeze_clear(phb->opal_id,
@ -1795,7 +1802,6 @@ static int __init eeh_powernv_init(void)
{ {
int ret = -EINVAL; int ret = -EINVAL;
eeh_set_pe_aux_size(PNV_PCI_DIAG_BUF_SIZE);
ret = eeh_ops_register(&pnv_eeh_ops); ret = eeh_ops_register(&pnv_eeh_ops);
if (!ret) if (!ret)
pr_info("EEH: PowerNV platform initialized\n"); pr_info("EEH: PowerNV platform initialized\n");

Просмотреть файл

@ -3123,13 +3123,13 @@ static int pnv_pci_diag_data_set(void *data, u64 val)
phb = hose->private_data; phb = hose->private_data;
/* Retrieve the diag data from firmware */ /* Retrieve the diag data from firmware */
ret = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob, ret = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag_data,
PNV_PCI_DIAG_BUF_SIZE); phb->diag_data_size);
if (ret != OPAL_SUCCESS) if (ret != OPAL_SUCCESS)
return -EIO; return -EIO;
/* Print the diag data to the kernel log */ /* 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; return 0;
} }
@ -3725,6 +3725,15 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
else else
phb->model = PNV_PHB_MODEL_UNKNOWN; 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) */ /* Parse 32-bit and IO ranges (if any) */
pci_process_bridge_OF_ranges(hose, np, !hose->global_number); pci_process_bridge_OF_ranges(hose, np, !hose->global_number);

Просмотреть файл

@ -456,8 +456,8 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
spin_lock_irqsave(&phb->lock, flags); spin_lock_irqsave(&phb->lock, flags);
/* Fetch PHB diag-data */ /* Fetch PHB diag-data */
rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob, rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag_data,
PNV_PCI_DIAG_BUF_SIZE); phb->diag_data_size);
has_diag = (rc == OPAL_SUCCESS); has_diag = (rc == OPAL_SUCCESS);
/* If PHB supports compound PE, to handle it */ /* 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 * with the normal errors generated when probing empty slots
*/ */
if (has_diag && ret) 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); spin_unlock_irqrestore(&phb->lock, flags);
} }

Просмотреть файл

@ -172,13 +172,9 @@ struct pnv_phb {
unsigned int pe_rmap[0x10000]; unsigned int pe_rmap[0x10000];
} ioda; } ioda;
/* PHB and hub status structure */ /* PHB and hub diagnostics */
union { unsigned int diag_data_size;
unsigned char blob[PNV_PCI_DIAG_BUF_SIZE]; u8 *diag_data;
struct OpalIoP7IOCPhbErrorData p7ioc;
struct OpalIoPhb3ErrorData phb3;
struct OpalIoP7IOCErrorData hub_diag;
} diag;
/* Nvlink2 data */ /* Nvlink2 data */
struct npu { struct npu {