-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
PCI/ACPI: Add generic MCFG table handling
On ACPI systems that support memory-mapped config space access, i.e., ECAM, the PCI Firmware Specification says the OS can learn where the ECAM space is from either: - the static MCFG table (for non-hotpluggable bridges), or - the _CBA method (for hotpluggable bridges) The current MCFG table handling code cannot be easily generalized owing to x86-specific quirks, which makes it hard to reuse on other architectures. Implement generic MCFG handling from scratch, including: - Simple MCFG table parsing (via pci_mmcfg_late_init() as in current x86) - MCFG region lookup for a (domain, bus_start, bus_end) tuple [bhelgaas: changelog] Signed-off-by: Tomasz Nowicki <tn@semihalf.com> Signed-off-by: Jayachandran C <jchandra@broadcom.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
- Loading branch information
Tomasz Nowicki
authored and
Bjorn Helgaas
committed
Jun 10, 2016
1 parent
0a70abb
commit 935c760
Showing
5 changed files
with
99 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* Copyright (C) 2016 Broadcom | ||
* Author: Jayachandran C <jchandra@broadcom.com> | ||
* Copyright (C) 2016 Semihalf | ||
* Author: Tomasz Nowicki <tn@semihalf.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License, version 2, as | ||
* published by the Free Software Foundation (the "GPL"). | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License version 2 (GPLv2) for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* version 2 (GPLv2) along with this source code. | ||
*/ | ||
|
||
#define pr_fmt(fmt) "ACPI: " fmt | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/pci.h> | ||
#include <linux/pci-acpi.h> | ||
|
||
/* Structure to hold entries from the MCFG table */ | ||
struct mcfg_entry { | ||
struct list_head list; | ||
phys_addr_t addr; | ||
u16 segment; | ||
u8 bus_start; | ||
u8 bus_end; | ||
}; | ||
|
||
/* List to save MCFG entries */ | ||
static LIST_HEAD(pci_mcfg_list); | ||
|
||
phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res) | ||
{ | ||
struct mcfg_entry *e; | ||
|
||
/* | ||
* We expect exact match, unless MCFG entry end bus covers more than | ||
* specified by caller. | ||
*/ | ||
list_for_each_entry(e, &pci_mcfg_list, list) { | ||
if (e->segment == seg && e->bus_start == bus_res->start && | ||
e->bus_end >= bus_res->end) | ||
return e->addr; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static __init int pci_mcfg_parse(struct acpi_table_header *header) | ||
{ | ||
struct acpi_table_mcfg *mcfg; | ||
struct acpi_mcfg_allocation *mptr; | ||
struct mcfg_entry *e, *arr; | ||
int i, n; | ||
|
||
if (header->length < sizeof(struct acpi_table_mcfg)) | ||
return -EINVAL; | ||
|
||
n = (header->length - sizeof(struct acpi_table_mcfg)) / | ||
sizeof(struct acpi_mcfg_allocation); | ||
mcfg = (struct acpi_table_mcfg *)header; | ||
mptr = (struct acpi_mcfg_allocation *) &mcfg[1]; | ||
|
||
arr = kcalloc(n, sizeof(*arr), GFP_KERNEL); | ||
if (!arr) | ||
return -ENOMEM; | ||
|
||
for (i = 0, e = arr; i < n; i++, mptr++, e++) { | ||
e->segment = mptr->pci_segment; | ||
e->addr = mptr->address; | ||
e->bus_start = mptr->start_bus_number; | ||
e->bus_end = mptr->end_bus_number; | ||
list_add(&e->list, &pci_mcfg_list); | ||
} | ||
|
||
pr_info("MCFG table detected, %d entries\n", n); | ||
return 0; | ||
} | ||
|
||
/* Interface called by ACPI - parse and save MCFG table */ | ||
void __init pci_mmcfg_late_init(void) | ||
{ | ||
int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse); | ||
if (err) | ||
pr_err("Failed to parse MCFG (%d)\n", err); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters