diff mbox

ACPI / ARM64: Get configuration base address of ECAM via ACPI MCFG table

Message ID 1440766163-12101-1-git-send-email-dennis.chen@arm.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Dennis Chen Aug. 28, 2015, 12:49 p.m. UTC
This patch will fall back to ACPI MCFG table if _CBA method fails
to get the configuration base address of ECAM. Firmware on ARM
platform uses MCFG table instead of _CBA method. This is needed
to scan the PCIe root complex for ARM SoC.

Signed-off-by: Dennis Chen <dennis.chen@arm.com>
---
 drivers/pci/pci-acpi.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 97 insertions(+), 5 deletions(-)

Comments

Lorenzo Pieralisi Aug. 28, 2015, 2:39 p.m. UTC | #1
Hi Dennis,

You should CC linux-pci@vger.kernel.org and the PCI subsystem
maintainer next time.

On Fri, Aug 28, 2015 at 01:49:23PM +0100, Dennis Chen wrote:
> This patch will fall back to ACPI MCFG table if _CBA method fails
> to get the configuration base address of ECAM. Firmware on ARM
> platform uses MCFG table instead of _CBA method. This is needed
> to scan the PCIe root complex for ARM SoC.

Code to enumerate PCI with ACPI on ARM64 is under review:

https://lkml.org/lkml/2015/6/8/443

Having said that, I do not think this patch will be needed,
you can't add code in the kernel because it may be needed in
the future, I do not see how it can be possibly useful at present
on ARM64 unless you pulled some patch dependencies; if that's the
case you should have listed them.

This patch can't be review standalone since it has no use in
the current kernel (at least for ARM64, it should be tested
on x86 though).

Thanks,
Lorenzo

> Signed-off-by: Dennis Chen <dennis.chen@arm.com>
> ---
>  drivers/pci/pci-acpi.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 97 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> index 314a625..211b9d9 100644
> --- a/drivers/pci/pci-acpi.c
> +++ b/drivers/pci/pci-acpi.c
> @@ -27,18 +27,110 @@ const u8 pci_acpi_dsm_uuid[] = {
>  	0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d
>  };
>  
> +static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg)
> +{
> +	if (mcfg->header.revision != 1) {
> +		pr_err("invalid header revision:%d in ACPI MCFG table\n",
> +			mcfg->header.revision);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static phys_addr_t __init acpi_get_mcfg_cba(u16 segment, u8 bus)
> +{
> +	struct acpi_table_header *table = NULL;
> +	acpi_size tbl_size;
> +	struct acpi_table_mcfg *mcfg = NULL;
> +	struct acpi_mcfg_allocation *cfg_table, *cfg;
> +	acpi_status status;
> +	phys_addr_t cba = 0;
> +	unsigned long i;
> +	int entries;
> +
> +	if (acpi_disabled)
> +		return 0;
> +
> +	status = acpi_get_table_with_size(ACPI_SIG_MCFG, 0, &table, &tbl_size);
> +	if (ACPI_FAILURE(status)) {
> +		const char *msg = acpi_format_exception(status);
> +
> +		pr_err("Failed to get MCFG table, %s\n", msg);
> +		return 0;
> +	}
> +
> +	if (table)
> +		mcfg = (struct acpi_table_mcfg *)table;
> +
> +	entries = 0;
> +	i = table->length - sizeof(struct acpi_table_mcfg);
> +	while (i >= sizeof(struct acpi_mcfg_allocation)) {
> +		entries++;
> +		i -= sizeof(struct acpi_mcfg_allocation);
> +	}
> +	if (entries == 0) {
> +		pr_err("ACPI MCFG table has no entries\n");
> +		goto out;
> +	}
> +
> +	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
> +	for (i = 0; i < entries; i++) {
> +		cfg = &cfg_table[i];
> +		if (acpi_mcfg_check_entry(mcfg))
> +			goto out;
> +
> +		if (cfg->pci_segment == segment &&
> +			cfg->start_bus_number <= bus &&
> +			bus <= cfg->end_bus_number) {
> +			cba = (phys_addr_t)cfg->address;
> +			goto out;
> +		}
> +	}
> +out:
> +	/*
> +	 * acpi_get_table_with_size() creates MCFG table mapping that
> +	 * should be released after parsing and before resuming boot
> +	 */
> +	early_acpi_os_unmap_memory(table, tbl_size);
> +	return cba;
> +}
> +
>  phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
>  {
>  	acpi_status status = AE_NOT_EXIST;
> -	unsigned long long mcfg_addr;
> +	unsigned long long mcfg_addr, mcfg_seg, mcfg_bus;
> +	u16 seg;
> +	u8 bus;
> +
> +	if (!handle)
> +		return 0;
>  
> -	if (handle)
> -		status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
> +	status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
>  					       NULL, &mcfg_addr);
> +	if (ACPI_SUCCESS(status))
> +		return (phys_addr_t)mcfg_addr;
> +
> +	pr_info("ACPI: Falling back to acpi mcfg table\n");
> +
> +	/*
> +	 * Fall back to MCFG table if _CBA failed:
> +	 * get the mcfg_addr via ACPI MCFG table. PCI Firmware v3.2 spec: 4.1.2
> +	 */
> +	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG,
> +						NULL, &mcfg_seg);
>  	if (ACPI_FAILURE(status))
> -		return 0;
> +		mcfg_seg = 0;
> +
> +	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN,
> +						NULL, &mcfg_bus);
> +	if (ACPI_FAILURE(status))
> +		mcfg_bus = 0;
> +
> +	seg = mcfg_seg & 0xFFFF;
> +	bus = mcfg_bus & 0xFF;
>  
> -	return (phys_addr_t)mcfg_addr;
> +	return acpi_get_mcfg_cba(seg, bus);
>  }
>  
>  static acpi_status decode_type0_hpx_record(union acpi_object *record,
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dennis Chen Aug. 31, 2015, 5:51 a.m. UTC | #2
On Fri, Aug 28, 2015 at 03:39:43PM +0100, Lorenzo Pieralisi wrote:
> Hi Dennis,
> 
> You should CC linux-pci@vger.kernel.org and the PCI subsystem
> maintainer next time.
>
>

Good reminder! Thanks, mate ;-)
 
> On Fri, Aug 28, 2015 at 01:49:23PM +0100, Dennis Chen wrote:
> > This patch will fall back to ACPI MCFG table if _CBA method fails
> > to get the configuration base address of ECAM. Firmware on ARM
> > platform uses MCFG table instead of _CBA method. This is needed
> > to scan the PCIe root complex for ARM SoC.
> 
> Code to enumerate PCI with ACPI on ARM64 is under review:
> 
> https://lkml.org/lkml/2015/6/8/443
>

Oops,seems I am late, just go through the code to scan the root:
https://lkml.org/lkml/2015/5/26/215
a little bit complicated, to be honest. Maybe I can have some input then.
 
> Having said that, I do not think this patch will be needed,
> you can't add code in the kernel because it may be needed in
> the future, I do not see how it can be possibly useful at present
> on ARM64 unless you pulled some patch dependencies; if that's the
> case you should have listed them.
> 
> This patch can't be review standalone since it has no use in
> the current kernel (at least for ARM64, it should be tested
> on x86 though).

I do have a patch set to enumerate all the downstream devices of
the PCIe root bridge. With this patch, I can focus on the enabling/fixing
of the drivers of those devices. As you can imagine, the patch have some 
redundant codes with PCI/ACPI codes now under x86 directory. It's reasonable 
to move those arch-agnostic codes to a common place. I am OK to keep
them pending as private as a test code base for me  

As for this patch, it's used to get the ecam address from MCFG instead of
_CBA which x86 is using, see acpi_pci_root_get_mcfg_addr() code.
So, it's for ARM64 and can be tested with uefi definitely. I'm missing some 
context here?


> Thanks,
> Lorenzo
> 
> > Signed-off-by: Dennis Chen <dennis.chen@arm.com>
> > ---
> >  drivers/pci/pci-acpi.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++---
> >  1 file changed, 97 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> > index 314a625..211b9d9 100644
> > --- a/drivers/pci/pci-acpi.c
> > +++ b/drivers/pci/pci-acpi.c
> > @@ -27,18 +27,110 @@ const u8 pci_acpi_dsm_uuid[] = {
> >  	0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d
> >  };
> >  
> > +static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg)
> > +{
> > +	if (mcfg->header.revision != 1) {
> > +		pr_err("invalid header revision:%d in ACPI MCFG table\n",
> > +			mcfg->header.revision);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static phys_addr_t __init acpi_get_mcfg_cba(u16 segment, u8 bus)
> > +{
> > +	struct acpi_table_header *table = NULL;
> > +	acpi_size tbl_size;
> > +	struct acpi_table_mcfg *mcfg = NULL;
> > +	struct acpi_mcfg_allocation *cfg_table, *cfg;
> > +	acpi_status status;
> > +	phys_addr_t cba = 0;
> > +	unsigned long i;
> > +	int entries;
> > +
> > +	if (acpi_disabled)
> > +		return 0;
> > +
> > +	status = acpi_get_table_with_size(ACPI_SIG_MCFG, 0, &table, &tbl_size);
> > +	if (ACPI_FAILURE(status)) {
> > +		const char *msg = acpi_format_exception(status);
> > +
> > +		pr_err("Failed to get MCFG table, %s\n", msg);
> > +		return 0;
> > +	}
> > +
> > +	if (table)
> > +		mcfg = (struct acpi_table_mcfg *)table;
> > +
> > +	entries = 0;
> > +	i = table->length - sizeof(struct acpi_table_mcfg);
> > +	while (i >= sizeof(struct acpi_mcfg_allocation)) {
> > +		entries++;
> > +		i -= sizeof(struct acpi_mcfg_allocation);
> > +	}
> > +	if (entries == 0) {
> > +		pr_err("ACPI MCFG table has no entries\n");
> > +		goto out;
> > +	}
> > +
> > +	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
> > +	for (i = 0; i < entries; i++) {
> > +		cfg = &cfg_table[i];
> > +		if (acpi_mcfg_check_entry(mcfg))
> > +			goto out;
> > +
> > +		if (cfg->pci_segment == segment &&
> > +			cfg->start_bus_number <= bus &&
> > +			bus <= cfg->end_bus_number) {
> > +			cba = (phys_addr_t)cfg->address;
> > +			goto out;
> > +		}
> > +	}
> > +out:
> > +	/*
> > +	 * acpi_get_table_with_size() creates MCFG table mapping that
> > +	 * should be released after parsing and before resuming boot
> > +	 */
> > +	early_acpi_os_unmap_memory(table, tbl_size);
> > +	return cba;
> > +}
> > +
> >  phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
> >  {
> >  	acpi_status status = AE_NOT_EXIST;
> > -	unsigned long long mcfg_addr;
> > +	unsigned long long mcfg_addr, mcfg_seg, mcfg_bus;
> > +	u16 seg;
> > +	u8 bus;
> > +
> > +	if (!handle)
> > +		return 0;
> >  
> > -	if (handle)
> > -		status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
> > +	status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
> >  					       NULL, &mcfg_addr);
> > +	if (ACPI_SUCCESS(status))
> > +		return (phys_addr_t)mcfg_addr;
> > +
> > +	pr_info("ACPI: Falling back to acpi mcfg table\n");
> > +
> > +	/*
> > +	 * Fall back to MCFG table if _CBA failed:
> > +	 * get the mcfg_addr via ACPI MCFG table. PCI Firmware v3.2 spec: 4.1.2
> > +	 */
> > +	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG,
> > +						NULL, &mcfg_seg);
> >  	if (ACPI_FAILURE(status))
> > -		return 0;
> > +		mcfg_seg = 0;
> > +
> > +	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN,
> > +						NULL, &mcfg_bus);
> > +	if (ACPI_FAILURE(status))
> > +		mcfg_bus = 0;
> > +
> > +	seg = mcfg_seg & 0xFFFF;
> > +	bus = mcfg_bus & 0xFF;
> >  
> > -	return (phys_addr_t)mcfg_addr;
> > +	return acpi_get_mcfg_cba(seg, bus);
> >  }
> >  
> >  static acpi_status decode_type0_hpx_record(union acpi_object *record,
> > -- 
> > 1.9.1
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> 

Regards,
Dennis

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lorenzo Pieralisi Sept. 1, 2015, 10:19 a.m. UTC | #3
On Mon, Aug 31, 2015 at 06:51:58AM +0100, Dennis Chen wrote:
> On Fri, Aug 28, 2015 at 03:39:43PM +0100, Lorenzo Pieralisi wrote:
> > Hi Dennis,
> > 
> > You should CC linux-pci@vger.kernel.org and the PCI subsystem
> > maintainer next time.
> >
> >
> 
> Good reminder! Thanks, mate ;-)
>  
> > On Fri, Aug 28, 2015 at 01:49:23PM +0100, Dennis Chen wrote:
> > > This patch will fall back to ACPI MCFG table if _CBA method fails
> > > to get the configuration base address of ECAM. Firmware on ARM
> > > platform uses MCFG table instead of _CBA method. This is needed
> > > to scan the PCIe root complex for ARM SoC.
> > 
> > Code to enumerate PCI with ACPI on ARM64 is under review:
> > 
> > https://lkml.org/lkml/2015/6/8/443
> >
> 
> Oops,seems I am late, just go through the code to scan the root:
> https://lkml.org/lkml/2015/5/26/215
> a little bit complicated, to be honest. Maybe I can have some input then.
>  
> > Having said that, I do not think this patch will be needed,
> > you can't add code in the kernel because it may be needed in
> > the future, I do not see how it can be possibly useful at present
> > on ARM64 unless you pulled some patch dependencies; if that's the
> > case you should have listed them.
> > 
> > This patch can't be review standalone since it has no use in
> > the current kernel (at least for ARM64, it should be tested
> > on x86 though).
> 
> I do have a patch set to enumerate all the downstream devices of
> the PCIe root bridge. With this patch, I can focus on the enabling/fixing
> of the drivers of those devices. As you can imagine, the patch have some 
> redundant codes with PCI/ACPI codes now under x86 directory. It's reasonable 
> to move those arch-agnostic codes to a common place. I am OK to keep
> them pending as private as a test code base for me  
> 
> As for this patch, it's used to get the ecam address from MCFG instead of
> _CBA which x86 is using, see acpi_pci_root_get_mcfg_addr() code.
> So, it's for ARM64 and can be tested with uefi definitely. I'm missing some 
> context here?

No, but as I said this patch is no use standalone (and again it has to
be tested on x86), there is no reason for it to go upstream given the
patch dependencies you mentioned. When the dust settles on the ACPI/PCI
enablement we will have a look at this patch and see if it is still
needed, there is no point in merging it as-is, it serves no purpose
at present.

Lorenzo
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 314a625..211b9d9 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -27,18 +27,110 @@  const u8 pci_acpi_dsm_uuid[] = {
 	0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d
 };
 
+static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg)
+{
+	if (mcfg->header.revision != 1) {
+		pr_err("invalid header revision:%d in ACPI MCFG table\n",
+			mcfg->header.revision);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static phys_addr_t __init acpi_get_mcfg_cba(u16 segment, u8 bus)
+{
+	struct acpi_table_header *table = NULL;
+	acpi_size tbl_size;
+	struct acpi_table_mcfg *mcfg = NULL;
+	struct acpi_mcfg_allocation *cfg_table, *cfg;
+	acpi_status status;
+	phys_addr_t cba = 0;
+	unsigned long i;
+	int entries;
+
+	if (acpi_disabled)
+		return 0;
+
+	status = acpi_get_table_with_size(ACPI_SIG_MCFG, 0, &table, &tbl_size);
+	if (ACPI_FAILURE(status)) {
+		const char *msg = acpi_format_exception(status);
+
+		pr_err("Failed to get MCFG table, %s\n", msg);
+		return 0;
+	}
+
+	if (table)
+		mcfg = (struct acpi_table_mcfg *)table;
+
+	entries = 0;
+	i = table->length - sizeof(struct acpi_table_mcfg);
+	while (i >= sizeof(struct acpi_mcfg_allocation)) {
+		entries++;
+		i -= sizeof(struct acpi_mcfg_allocation);
+	}
+	if (entries == 0) {
+		pr_err("ACPI MCFG table has no entries\n");
+		goto out;
+	}
+
+	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
+	for (i = 0; i < entries; i++) {
+		cfg = &cfg_table[i];
+		if (acpi_mcfg_check_entry(mcfg))
+			goto out;
+
+		if (cfg->pci_segment == segment &&
+			cfg->start_bus_number <= bus &&
+			bus <= cfg->end_bus_number) {
+			cba = (phys_addr_t)cfg->address;
+			goto out;
+		}
+	}
+out:
+	/*
+	 * acpi_get_table_with_size() creates MCFG table mapping that
+	 * should be released after parsing and before resuming boot
+	 */
+	early_acpi_os_unmap_memory(table, tbl_size);
+	return cba;
+}
+
 phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
 {
 	acpi_status status = AE_NOT_EXIST;
-	unsigned long long mcfg_addr;
+	unsigned long long mcfg_addr, mcfg_seg, mcfg_bus;
+	u16 seg;
+	u8 bus;
+
+	if (!handle)
+		return 0;
 
-	if (handle)
-		status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
+	status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
 					       NULL, &mcfg_addr);
+	if (ACPI_SUCCESS(status))
+		return (phys_addr_t)mcfg_addr;
+
+	pr_info("ACPI: Falling back to acpi mcfg table\n");
+
+	/*
+	 * Fall back to MCFG table if _CBA failed:
+	 * get the mcfg_addr via ACPI MCFG table. PCI Firmware v3.2 spec: 4.1.2
+	 */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG,
+						NULL, &mcfg_seg);
 	if (ACPI_FAILURE(status))
-		return 0;
+		mcfg_seg = 0;
+
+	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN,
+						NULL, &mcfg_bus);
+	if (ACPI_FAILURE(status))
+		mcfg_bus = 0;
+
+	seg = mcfg_seg & 0xFFFF;
+	bus = mcfg_bus & 0xFF;
 
-	return (phys_addr_t)mcfg_addr;
+	return acpi_get_mcfg_cba(seg, bus);
 }
 
 static acpi_status decode_type0_hpx_record(union acpi_object *record,