mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 00:10:09 +00:00
PCI/ACPI: Provide acpi_get_rc_resources() for ARM64 platform
The acpi_get_rc_resources() is used to get the RC register address that can not be described in MCFG. It takes the _HID & segment to look for and outputs the RC address resource. Use PNP0C02 devices to describe such RC address resource. Use _UID to match segment to tell which root bus the PNP0C02 resource belongs to. [bhelgaas: add dev argument, wrap in #ifdef CONFIG_PCI_QUIRKS] Signed-off-by: Dongdong Liu <liudongdong3@huawei.com> Signed-off-by: Tomasz Nowicki <tn@semihalf.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
5b69b85ba1
commit
169de969c0
2 changed files with 81 additions and 0 deletions
|
@ -29,6 +29,82 @@ const u8 pci_acpi_dsm_uuid[] = {
|
|||
0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64)
|
||||
static int acpi_get_rc_addr(struct acpi_device *adev, struct resource *res)
|
||||
{
|
||||
struct device *dev = &adev->dev;
|
||||
struct resource_entry *entry;
|
||||
struct list_head list;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
flags = IORESOURCE_MEM;
|
||||
ret = acpi_dev_get_resources(adev, &list,
|
||||
acpi_dev_filter_resource_type_cb,
|
||||
(void *) flags);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to parse _CRS method, error code %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
dev_err(dev, "no IO and memory resources present in _CRS\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entry = list_first_entry(&list, struct resource_entry, node);
|
||||
*res = *entry->res;
|
||||
acpi_dev_free_resource_list(&list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static acpi_status acpi_match_rc(acpi_handle handle, u32 lvl, void *context,
|
||||
void **retval)
|
||||
{
|
||||
u16 *segment = context;
|
||||
unsigned long long uid;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_evaluate_integer(handle, "_UID", NULL, &uid);
|
||||
if (ACPI_FAILURE(status) || uid != *segment)
|
||||
return AE_CTRL_DEPTH;
|
||||
|
||||
*(acpi_handle *)retval = handle;
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
|
||||
int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
|
||||
struct resource *res)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
acpi_status status;
|
||||
acpi_handle handle;
|
||||
int ret;
|
||||
|
||||
status = acpi_get_devices(hid, acpi_match_rc, &segment, &handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(dev, "can't find _HID %s device to locate resources\n",
|
||||
hid);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = acpi_bus_get_device(handle, &adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = acpi_get_rc_addr(adev, res);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't get resource from %s\n",
|
||||
dev_name(&adev->dev));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
|
||||
{
|
||||
acpi_status status = AE_NOT_EXIST;
|
||||
|
|
|
@ -356,4 +356,9 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64)
|
||||
int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
|
||||
struct resource *res);
|
||||
#endif
|
||||
|
||||
#endif /* DRIVERS_PCI_H */
|
||||
|
|
Loading…
Reference in a new issue