From 9ce90ea5c0d512ff66693b238167b56dbaef786b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 12 Sep 2014 15:23:14 -0600 Subject: PCI: Move pci_get_hp_params() to drivers/pci/pci-acpi.c Move pci_get_hp_params() and related functions from drivers/pci/hotplug/acpi_pcihp.c to drivers/pci/pci-acpi.c. Previously, pci_get_hp_params() was used only by hotplug drivers. But future changes will move this into the normal device enumeration process, so it will be used even when CONFIG_HOTPLUG_PCI is not set. No functional change. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) (limited to 'drivers/pci/pci-acpi.c') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 37263b0ebfe3..06e0b41c397e 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,255 @@ phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) return (phys_addr_t)mcfg_addr; } +static acpi_status +decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx) +{ + int i; + union acpi_object *fields = record->package.elements; + u32 revision = fields[1].integer.value; + + switch (revision) { + case 1: + if (record->package.count != 6) + return AE_ERROR; + for (i = 2; i < 6; i++) + if (fields[i].type != ACPI_TYPE_INTEGER) + return AE_ERROR; + hpx->t0 = &hpx->type0_data; + hpx->t0->revision = revision; + hpx->t0->cache_line_size = fields[2].integer.value; + hpx->t0->latency_timer = fields[3].integer.value; + hpx->t0->enable_serr = fields[4].integer.value; + hpx->t0->enable_perr = fields[5].integer.value; + break; + default: + printk(KERN_WARNING + "%s: Type 0 Revision %d record not supported\n", + __func__, revision); + return AE_ERROR; + } + return AE_OK; +} + +static acpi_status +decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx) +{ + int i; + union acpi_object *fields = record->package.elements; + u32 revision = fields[1].integer.value; + + switch (revision) { + case 1: + if (record->package.count != 5) + return AE_ERROR; + for (i = 2; i < 5; i++) + if (fields[i].type != ACPI_TYPE_INTEGER) + return AE_ERROR; + hpx->t1 = &hpx->type1_data; + hpx->t1->revision = revision; + hpx->t1->max_mem_read = fields[2].integer.value; + hpx->t1->avg_max_split = fields[3].integer.value; + hpx->t1->tot_max_split = fields[4].integer.value; + break; + default: + printk(KERN_WARNING + "%s: Type 1 Revision %d record not supported\n", + __func__, revision); + return AE_ERROR; + } + return AE_OK; +} + +static acpi_status +decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx) +{ + int i; + union acpi_object *fields = record->package.elements; + u32 revision = fields[1].integer.value; + + switch (revision) { + case 1: + if (record->package.count != 18) + return AE_ERROR; + for (i = 2; i < 18; i++) + if (fields[i].type != ACPI_TYPE_INTEGER) + return AE_ERROR; + hpx->t2 = &hpx->type2_data; + hpx->t2->revision = revision; + hpx->t2->unc_err_mask_and = fields[2].integer.value; + hpx->t2->unc_err_mask_or = fields[3].integer.value; + hpx->t2->unc_err_sever_and = fields[4].integer.value; + hpx->t2->unc_err_sever_or = fields[5].integer.value; + hpx->t2->cor_err_mask_and = fields[6].integer.value; + hpx->t2->cor_err_mask_or = fields[7].integer.value; + hpx->t2->adv_err_cap_and = fields[8].integer.value; + hpx->t2->adv_err_cap_or = fields[9].integer.value; + hpx->t2->pci_exp_devctl_and = fields[10].integer.value; + hpx->t2->pci_exp_devctl_or = fields[11].integer.value; + hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value; + hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value; + hpx->t2->sec_unc_err_sever_and = fields[14].integer.value; + hpx->t2->sec_unc_err_sever_or = fields[15].integer.value; + hpx->t2->sec_unc_err_mask_and = fields[16].integer.value; + hpx->t2->sec_unc_err_mask_or = fields[17].integer.value; + break; + default: + printk(KERN_WARNING + "%s: Type 2 Revision %d record not supported\n", + __func__, revision); + return AE_ERROR; + } + return AE_OK; +} + +static acpi_status +acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) +{ + acpi_status status; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *package, *record, *fields; + u32 type; + int i; + + /* Clear the return buffer with zeros */ + memset(hpx, 0, sizeof(struct hotplug_params)); + + status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer); + if (ACPI_FAILURE(status)) + return status; + + package = (union acpi_object *)buffer.pointer; + if (package->type != ACPI_TYPE_PACKAGE) { + status = AE_ERROR; + goto exit; + } + + for (i = 0; i < package->package.count; i++) { + record = &package->package.elements[i]; + if (record->type != ACPI_TYPE_PACKAGE) { + status = AE_ERROR; + goto exit; + } + + fields = record->package.elements; + if (fields[0].type != ACPI_TYPE_INTEGER || + fields[1].type != ACPI_TYPE_INTEGER) { + status = AE_ERROR; + goto exit; + } + + type = fields[0].integer.value; + switch (type) { + case 0: + status = decode_type0_hpx_record(record, hpx); + if (ACPI_FAILURE(status)) + goto exit; + break; + case 1: + status = decode_type1_hpx_record(record, hpx); + if (ACPI_FAILURE(status)) + goto exit; + break; + case 2: + status = decode_type2_hpx_record(record, hpx); + if (ACPI_FAILURE(status)) + goto exit; + break; + default: + printk(KERN_ERR "%s: Type %d record not supported\n", + __func__, type); + status = AE_ERROR; + goto exit; + } + } + exit: + kfree(buffer.pointer); + return status; +} + +static acpi_status +acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *package, *fields; + int i; + + memset(hpp, 0, sizeof(struct hotplug_params)); + + status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer); + if (ACPI_FAILURE(status)) + return status; + + package = (union acpi_object *) buffer.pointer; + if (package->type != ACPI_TYPE_PACKAGE || + package->package.count != 4) { + status = AE_ERROR; + goto exit; + } + + fields = package->package.elements; + for (i = 0; i < 4; i++) { + if (fields[i].type != ACPI_TYPE_INTEGER) { + status = AE_ERROR; + goto exit; + } + } + + hpp->t0 = &hpp->type0_data; + hpp->t0->revision = 1; + hpp->t0->cache_line_size = fields[0].integer.value; + hpp->t0->latency_timer = fields[1].integer.value; + hpp->t0->enable_serr = fields[2].integer.value; + hpp->t0->enable_perr = fields[3].integer.value; + +exit: + kfree(buffer.pointer); + return status; +} + +/* pci_get_hp_params + * + * @dev - the pci_dev for which we want parameters + * @hpp - allocated by the caller + */ +int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp) +{ + acpi_status status; + acpi_handle handle, phandle; + struct pci_bus *pbus; + + handle = NULL; + for (pbus = dev->bus; pbus; pbus = pbus->parent) { + handle = acpi_pci_get_bridge_handle(pbus); + if (handle) + break; + } + + /* + * _HPP settings apply to all child buses, until another _HPP is + * encountered. If we don't find an _HPP for the input pci dev, + * look for it in the parent device scope since that would apply to + * this pci dev. + */ + while (handle) { + status = acpi_run_hpx(handle, hpp); + if (ACPI_SUCCESS(status)) + return 0; + status = acpi_run_hpp(handle, hpp); + if (ACPI_SUCCESS(status)) + return 0; + if (acpi_is_root_bridge(handle)) + break; + status = acpi_get_parent(handle, &phandle); + if (ACPI_FAILURE(status)) + break; + handle = phandle; + } + return -ENODEV; +} +EXPORT_SYMBOL_GPL(pci_get_hp_params); + /* * _SxD returns the D-state with the highest power * (lowest D-state number) supported in the S-state "x". -- cgit v1.2.3 From abbfec34e1df3073429cd6b0fad1c26635597799 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 12 Sep 2014 15:29:55 -0600 Subject: PCI: Whitespace cleanup in pci-acpi.c Whitespace fixes only; no functional change. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/pci/pci-acpi.c') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 06e0b41c397e..e514d50eaddc 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -99,8 +99,8 @@ phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) return (phys_addr_t)mcfg_addr; } -static acpi_status -decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx) +static acpi_status decode_type0_hpx_record(union acpi_object *record, + struct hotplug_params *hpx) { int i; union acpi_object *fields = record->package.elements; @@ -129,8 +129,8 @@ decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx) return AE_OK; } -static acpi_status -decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx) +static acpi_status decode_type1_hpx_record(union acpi_object *record, + struct hotplug_params *hpx) { int i; union acpi_object *fields = record->package.elements; @@ -158,8 +158,8 @@ decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx) return AE_OK; } -static acpi_status -decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx) +static acpi_status decode_type2_hpx_record(union acpi_object *record, + struct hotplug_params *hpx) { int i; union acpi_object *fields = record->package.elements; @@ -200,8 +200,7 @@ decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx) return AE_OK; } -static acpi_status -acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) +static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) { acpi_status status; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; @@ -265,8 +264,7 @@ acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) return status; } -static acpi_status -acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) +static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) { acpi_status status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; -- cgit v1.2.3 From 5e3d234456e25f664e0755c23689173588f4ca9b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 12 Sep 2014 15:36:29 -0600 Subject: PCI: Shuffle pci-acpi.c functions to group them logically Move code around to put all the ACPI power management stuff together and all the pieces related to ACPI methods (_CBA, _HPP, _HPX) together. No functional change. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 134 ++++++++++++++++++++++++------------------------- 1 file changed, 67 insertions(+), 67 deletions(-) (limited to 'drivers/pci/pci-acpi.c') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index e514d50eaddc..6ebf8edc5f3c 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -18,73 +18,6 @@ #include #include "pci.h" -/** - * pci_acpi_wake_bus - Root bus wakeup notification fork function. - * @work: Work item to handle. - */ -static void pci_acpi_wake_bus(struct work_struct *work) -{ - struct acpi_device *adev; - struct acpi_pci_root *root; - - adev = container_of(work, struct acpi_device, wakeup.context.work); - root = acpi_driver_data(adev); - pci_pme_wakeup_bus(root->bus); -} - -/** - * pci_acpi_wake_dev - PCI device wakeup notification work function. - * @handle: ACPI handle of a device the notification is for. - * @work: Work item to handle. - */ -static void pci_acpi_wake_dev(struct work_struct *work) -{ - struct acpi_device_wakeup_context *context; - struct pci_dev *pci_dev; - - context = container_of(work, struct acpi_device_wakeup_context, work); - pci_dev = to_pci_dev(context->dev); - - if (pci_dev->pme_poll) - pci_dev->pme_poll = false; - - if (pci_dev->current_state == PCI_D3cold) { - pci_wakeup_event(pci_dev); - pm_runtime_resume(&pci_dev->dev); - return; - } - - /* Clear PME Status if set. */ - if (pci_dev->pme_support) - pci_check_pme_status(pci_dev); - - pci_wakeup_event(pci_dev); - pm_runtime_resume(&pci_dev->dev); - - if (pci_dev->subordinate) - pci_pme_wakeup_bus(pci_dev->subordinate); -} - -/** - * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus. - * @dev: PCI root bridge ACPI device. - */ -acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev) -{ - return acpi_add_pm_notifier(dev, NULL, pci_acpi_wake_bus); -} - -/** - * pci_acpi_add_pm_notifier - Register PM notifier for given PCI device. - * @dev: ACPI device to add the notifier for. - * @pci_dev: PCI device to check for the PME status if an event is signaled. - */ -acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, - struct pci_dev *pci_dev) -{ - return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev); -} - phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) { acpi_status status = AE_NOT_EXIST; @@ -346,6 +279,73 @@ int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp) } EXPORT_SYMBOL_GPL(pci_get_hp_params); +/** + * pci_acpi_wake_bus - Root bus wakeup notification fork function. + * @work: Work item to handle. + */ +static void pci_acpi_wake_bus(struct work_struct *work) +{ + struct acpi_device *adev; + struct acpi_pci_root *root; + + adev = container_of(work, struct acpi_device, wakeup.context.work); + root = acpi_driver_data(adev); + pci_pme_wakeup_bus(root->bus); +} + +/** + * pci_acpi_wake_dev - PCI device wakeup notification work function. + * @handle: ACPI handle of a device the notification is for. + * @work: Work item to handle. + */ +static void pci_acpi_wake_dev(struct work_struct *work) +{ + struct acpi_device_wakeup_context *context; + struct pci_dev *pci_dev; + + context = container_of(work, struct acpi_device_wakeup_context, work); + pci_dev = to_pci_dev(context->dev); + + if (pci_dev->pme_poll) + pci_dev->pme_poll = false; + + if (pci_dev->current_state == PCI_D3cold) { + pci_wakeup_event(pci_dev); + pm_runtime_resume(&pci_dev->dev); + return; + } + + /* Clear PME Status if set. */ + if (pci_dev->pme_support) + pci_check_pme_status(pci_dev); + + pci_wakeup_event(pci_dev); + pm_runtime_resume(&pci_dev->dev); + + if (pci_dev->subordinate) + pci_pme_wakeup_bus(pci_dev->subordinate); +} + +/** + * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus. + * @dev: PCI root bridge ACPI device. + */ +acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev) +{ + return acpi_add_pm_notifier(dev, NULL, pci_acpi_wake_bus); +} + +/** + * pci_acpi_add_pm_notifier - Register PM notifier for given PCI device. + * @dev: ACPI device to add the notifier for. + * @pci_dev: PCI device to check for the PME status if an event is signaled. + */ +acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, + struct pci_dev *pci_dev) +{ + return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev); +} + /* * _SxD returns the D-state with the highest power * (lowest D-state number) supported in the S-state "x". -- cgit v1.2.3