From patchwork Fri Aug 28 12:49:23 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dennis Chen X-Patchwork-Id: 7091751 Return-Path: X-Original-To: patchwork-linux-acpi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 3A5CA9F22E for ; Fri, 28 Aug 2015 12:50:04 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 58BFE2082F for ; Fri, 28 Aug 2015 12:50:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DC61320817 for ; Fri, 28 Aug 2015 12:49:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752057AbbH1Mt5 (ORCPT ); Fri, 28 Aug 2015 08:49:57 -0400 Received: from eu-smtp-delivery-143.mimecast.com ([146.101.78.143]:44016 "EHLO eu-smtp-delivery-143.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751848AbbH1Mt4 (ORCPT ); Fri, 28 Aug 2015 08:49:56 -0400 Received: from cam-owa2.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by eu-smtp-1.mimecast.com with ESMTP id uk-mta-11-mlYrG67NTuiAd_YC9lGHgw-1; Fri, 28 Aug 2015 13:49:53 +0100 Received: from dennis-ws.asiapac.arm.com ([10.1.2.79]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Fri, 28 Aug 2015 13:49:52 +0100 From: Dennis Chen To: linux-acpi@vger.kernel.org Cc: rjw@rjwysocki.net, linux-kernel@vger.kernel.org, catalin.marinas@arm.com, will.deacon@arm.com, dennis.chen@arm.com Subject: [PATCH] ACPI / ARM64: Get configuration base address of ECAM via ACPI MCFG table Date: Fri, 28 Aug 2015 20:49:23 +0800 Message-Id: <1440766163-12101-1-git-send-email-dennis.chen@arm.com> X-Mailer: git-send-email 1.9.1 X-OriginalArrivalTime: 28 Aug 2015 12:49:52.0842 (UTC) FILETIME=[088812A0:01D0E190] X-MC-Unique: mlYrG67NTuiAd_YC9lGHgw-1 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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,