diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index a09636a4168e..373c94de7590 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,36 @@ static struct notifier_block acpi_platform_notifier = { .notifier_call = acpi_platform_device_remove_notify, }; +static unsigned int acpi_platform_adjust_resources(struct acpi_device *adev, + struct resource *new_res, + struct resource *resources, + unsigned int count) +{ + unsigned int i; + + if (!(new_res->flags & (IORESOURCE_IO | IORESOURCE_MEM))) + return count; + + for (i = 0; i < count; ) { + struct resource *res = &resources[i]; + + if (resource_type(new_res) != resource_type(res) || + !resource_union(new_res, res, new_res)) { + i++; + continue; + } + + dev_info(&adev->dev, "%pR expanded due to overlap\n", new_res); + /* + * Eliminate the previously processed resource that overlapped + * with the new one because it is not necessary any more. + */ + memmove(res, res + 1, (--count - i) * sizeof(*res)); + } + + return count; +} + static void acpi_platform_fill_resource(struct acpi_device *adev, const struct resource *src, struct resource *dest) { @@ -151,10 +182,14 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev, return ERR_PTR(-ENOMEM); } count = 0; - list_for_each_entry(rentry, &resource_list, node) + list_for_each_entry(rentry, &resource_list, node) { + count = acpi_platform_adjust_resources(adev, + rentry->res, + resources, + count); acpi_platform_fill_resource(adev, rentry->res, &resources[count++]); - + } acpi_dev_free_resource_list(&resource_list); } } diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c index fc43df083738..45459a4cafae 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,8 @@ static bool acpi_tad_rt_is_invalid(struct acpi_tad_rt *rt) rt->daylight > 3; } +static DEFINE_MUTEX(acpi_tad_aml_lock); + static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt) { acpi_handle handle = ACPI_HANDLE(dev); @@ -113,6 +116,8 @@ static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt) if (PM_RUNTIME_ACQUIRE_ERR(&pm)) return -ENXIO; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval); if (ACPI_FAILURE(status) || retval) return -EIO; @@ -124,30 +129,27 @@ static int acpi_tad_evaluate_grt(struct device *dev, struct acpi_tad_rt *rt) { acpi_handle handle = ACPI_HANDLE(dev); struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER }; - union acpi_object *out_obj; - struct acpi_tad_rt *data; acpi_status status; int ret = -EIO; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_object(handle, "_GRT", NULL, &output); - if (ACPI_FAILURE(status)) - goto out_free; + if (ACPI_SUCCESS(status)) { + union acpi_object *out_obj; - out_obj = output.pointer; - if (out_obj->type != ACPI_TYPE_BUFFER) - goto out_free; + out_obj = output.pointer; + if (out_obj->type == ACPI_TYPE_BUFFER && + out_obj->buffer.length == sizeof(*rt)) { + struct acpi_tad_rt *data; - if (out_obj->buffer.length != sizeof(*rt)) - goto out_free; - - data = (struct acpi_tad_rt *)(out_obj->buffer.pointer); - if (!data->valid) - goto out_free; - - memcpy(rt, data, sizeof(*rt)); - ret = 0; - -out_free: + data = (struct acpi_tad_rt *)(out_obj->buffer.pointer); + if (data->valid) { + memcpy(rt, data, sizeof(*rt)); + ret = 0; + } + } + } ACPI_FREE(output.pointer); return ret; } @@ -193,6 +195,8 @@ static int __acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id, args[0].integer.value = timer_id; args[1].integer.value = value; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, method, &arg_list, &retval); if (ACPI_FAILURE(status) || retval) return -EIO; @@ -215,6 +219,8 @@ static int __acpi_tad_wake_read(struct device *dev, char *method, u32 timer_id, args[0].integer.value = timer_id; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, method, &arg_list, retval); if (ACPI_FAILURE(status)) return -EIO; @@ -416,6 +422,8 @@ static int acpi_tad_clear_status(struct device *dev, u32 timer_id) if (PM_RUNTIME_ACQUIRE_ERR(&pm)) return -ENXIO; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, "_CWS", &arg_list, &retval); if (ACPI_FAILURE(status) || retval) return -EIO; @@ -456,6 +464,8 @@ static ssize_t acpi_tad_status_read(struct device *dev, char *buf, u32 timer_id) if (PM_RUNTIME_ACQUIRE_ERR(&pm)) return -ENXIO; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, "_GWS", &arg_list, &retval); if (ACPI_FAILURE(status)) return -EIO; diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index f93e877f87f6..4d6fd9f6e9ad 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1048,7 +1048,7 @@ static int acpi_video_bus_check(struct acpi_video_bus *video) if (!video) return -EINVAL; - dev = acpi_get_pci_dev(video->device->handle); + dev = acpi_dev_get_pci_dev(video->device); if (!dev) return -ENODEV; pci_dev_put(dev); @@ -1702,7 +1702,6 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) { struct backlight_properties props; struct pci_dev *pdev; - acpi_handle acpi_parent; struct device *parent = NULL; int result; static int count; @@ -1717,13 +1716,9 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) return; count++; - if (ACPI_SUCCESS(acpi_get_parent(device->dev->handle, &acpi_parent))) { - pdev = acpi_get_pci_dev(acpi_parent); - if (pdev) { - parent = &pdev->dev; - pci_dev_put(pdev); - } - } + pdev = acpi_dev_get_pci_dev(acpi_dev_parent(device->dev)); + if (pdev) + parent = &pdev->dev; memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_FIRMWARE; @@ -1734,6 +1729,7 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) device, &acpi_backlight_ops, &props); + put_device(parent); kfree(name); if (IS_ERR(device->backlight)) { device->backlight = NULL; diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index bf65e3461531..15ab797641cf 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -108,7 +108,7 @@ static inline u64 erst_get_timeout(void) if (erst_erange.attr & ERST_RANGE_SLOW) { timeout = ((erst_erange.timings & ERST_EXEC_TIMING_MAX_MASK) >> - ERST_EXEC_TIMING_MAX_SHIFT) * NSEC_PER_MSEC; + ERST_EXEC_TIMING_MAX_SHIFT) * NSEC_PER_USEC; if (timeout < FIRMWARE_TIMEOUT) timeout = FIRMWARE_TIMEOUT; } diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 3236a3ce79d6..bc1dfa3398b4 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -576,7 +576,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, return false; p = (char *)(err + 1); - length -= sizeof(err); + length -= sizeof(*err); for (i = 0; i < err->err_info_num; i++) { struct cper_arm_err_info *err_info; @@ -1383,8 +1383,16 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes, ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx); /* This error has been reported before, don't process it again. */ - if (ghes_estatus_cached(estatus)) + if (ghes_estatus_cached(estatus)) { + /* + * Return failure on duplicate SEA entries so that the + * subsequent SEA handler invocation sends a SIGBUS signal to + * the task to prevent it from re-entering the handler loop. + */ + if (is_hest_sync_notify(ghes)) + rc = -ECANCELED; goto no_work; + } llist_add(&estatus_node->llnode, &ghes_estatus_llist); @@ -1397,8 +1405,8 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes, return rc; } -static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list, - enum fixed_addresses fixmap_idx) +static int __maybe_unused ghes_in_nmi_spool_from_list(struct list_head *rcu_list, + enum fixed_addresses fixmap_idx) { int ret = -ENOENT; struct ghes *ghes; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 4c06c3ffd0cb..88c65f34e305 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) "ACPI: " fmt +#include #include #include #include @@ -292,41 +293,37 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) EXPORT_SYMBOL_GPL(acpi_pci_find_root); /** - * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev - * @handle: the handle in question + * acpi_dev_get_pci_dev - Get a struct pci_dev for a given ACPI device + * @adev: Target ACPI device. * - * Given an ACPI CA handle, the desired PCI device is located in the - * list of PCI devices. + * Find the PCI device associated with @adev, if any, and bump up its reference + * counter. * - * If the device is found, its reference count is increased and this - * function returns a pointer to its data structure. The caller must - * decrement the reference count by calling pci_dev_put(). - * If no device is found, %NULL is returned. + * Callers are responsible for dropping the PCI device reference obtained by + * this function. + * + * Return: The struct pci_dev pointer of a reference-counted PCI device on + * success or NULL on failure. */ -struct pci_dev *acpi_get_pci_dev(acpi_handle handle) +struct pci_dev *acpi_dev_get_pci_dev(struct acpi_device *adev) { - struct acpi_device *adev = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; - struct pci_dev *pci_dev = NULL; if (!adev) return NULL; - mutex_lock(&adev->physical_node_lock); + guard(mutex)(&adev->physical_node_lock); list_for_each_entry(pn, &adev->physical_node_list, node) { if (dev_is_pci(pn->dev)) { get_device(pn->dev); - pci_dev = to_pci_dev(pn->dev); - break; + return to_pci_dev(pn->dev); } } - mutex_unlock(&adev->physical_node_lock); - - return pci_dev; + return NULL; } -EXPORT_SYMBOL_GPL(acpi_get_pci_dev); +EXPORT_SYMBOL_GPL(acpi_dev_get_pci_dev); /** * acpi_pci_osc_control_set - Request control of PCI root _OSC features. @@ -574,6 +571,13 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) return; } + if (!is_pcie(root) && !is_cxl(root) && !acpi_has_method(handle, "_OSC")) { + dev_dbg(&device->dev, "Non-PCIe host bridge without _OSC, skipping\n"); + + *no_aspm = 1; + return; + } + support = calculate_support(); decode_osc_support(root, "OS supports", support); @@ -615,10 +619,6 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) */ *no_aspm = 1; - /* _OSC is optional for PCI host bridges */ - if (status == AE_NOT_FOUND && !is_pcie(root)) - return; - if (control) { decode_osc_control(root, "OS requested", requested); decode_osc_control(root, "platform willing to grant", control); @@ -725,7 +725,6 @@ static int acpi_pci_root_add(struct acpi_device *device, dev_err(&device->dev, "Bus %04x:%02x not present in PCI namespace\n", root->segment, (unsigned int)root->secondary.start); - device->driver_data = NULL; result = -ENODEV; goto remove_dmar; } @@ -765,6 +764,7 @@ static int acpi_pci_root_add(struct acpi_device *device, if (hotadd) dmar_device_remove(handle); end: + device->driver_data = NULL; kfree(root); return result; } @@ -788,6 +788,7 @@ static void acpi_pci_root_remove(struct acpi_device *device) pci_unlock_rescan_remove(); + device->driver_data = NULL; kfree(root); } diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 458efa4fe9d4..c5b08c19e847 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -73,7 +73,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv) }; if (acpi_dev && !acpi_match_device_ids(acpi_dev, video_ids)) { - dev = acpi_get_pci_dev(handle); + dev = acpi_dev_get_pci_dev(acpi_dev); if (!dev) return AE_OK; pci_dev_put(dev); diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 402b97d12138..bff2ca035fcf 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -59,14 +59,19 @@ int acpi_pci_link_free_irq(acpi_handle handle); struct pci_bus; #ifdef CONFIG_PCI -struct pci_dev *acpi_get_pci_dev(acpi_handle); +struct pci_dev *acpi_dev_get_pci_dev(struct acpi_device *adev); #else -static inline struct pci_dev *acpi_get_pci_dev(acpi_handle handle) +static inline struct pci_dev *acpi_dev_get_pci_dev(struct acpi_device *adev) { return NULL; } #endif +static inline struct pci_dev *acpi_get_pci_dev(acpi_handle handle) +{ + return acpi_dev_get_pci_dev(acpi_fetch_acpi_dev(handle)); +} + /* Arch-defined function to add a bus to the system */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root);