Merge branches 'acpi-resource', 'acpi-numa', 'acpi-soc' and 'acpi-misc'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 4 Jan 2024 12:23:31 +0000 (13:23 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 4 Jan 2024 12:23:31 +0000 (13:23 +0100)
Merge ACPI resources management quirks, ACPI NUMA updates, an ACPI LPSS
(Intel SoC) driver update and an ACPI watchdog driver fixup for 6.8-rc1:

 - Add IRQ override quirks for some Infinity laptops and for TongFang
   GMxXGxx (David McFarland, Hans de Goede).

 - Clean up the ACPI NUMA code and fix it to ensure that fake_pxm is not
   the same as one of the real pxm values (Yuntao Wang).

 - Fix the fractional clock divider flags in the ACPI LPSS (Intel SoC)
   driver so as to prevent miscalculation of the values in the clock
   divider (Andy Shevchenko).

 - Adjust comments in the ACPI watchdog driver to prevent kernel-doc
   from complaining during documentation builds (Randy Dunlap).

* acpi-resource:
  ACPI: resource: Add Infinity laptops to irq1_edge_low_force_override
  ACPI: resource: Add another DMI match for the TongFang GMxXGxx

* acpi-numa:
  ACPI: NUMA: Fix the logic of getting the fake_pxm value
  ACPI: NUMA: Optimize the check for the availability of node values
  ACPI: NUMA: Remove unnecessary check in acpi_parse_gi_affinity()

* acpi-soc:
  ACPI: LPSS: Fix the fractional clock divider flags

* acpi-misc:
  ACPI: watchdog: fix kernel-doc warnings

40 files changed:
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_extlog.c
drivers/acpi/acpi_lpit.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_video.c
drivers/acpi/acpi_watchdog.c
drivers/acpi/apei/einj.c
drivers/acpi/apei/ghes.c
drivers/acpi/arm64/Makefile
drivers/acpi/arm64/thermal_cpufreq.c [new file with mode: 0644]
drivers/acpi/bus.c
drivers/acpi/button.c
drivers/acpi/ec.c
drivers/acpi/internal.h
drivers/acpi/mipi-disco-img.c [new file with mode: 0644]
drivers/acpi/numa/srat.c
drivers/acpi/osl.c
drivers/acpi/processor_thermal.c
drivers/acpi/property.c
drivers/acpi/scan.c
drivers/acpi/thermal.c
drivers/acpi/thermal_lib.c [new file with mode: 0644]
drivers/acpi/utils.c
drivers/firmware/efi/dev-path-parser.c
drivers/perf/arm_cspmu/arm_cspmu.c
drivers/platform/chrome/cros_ec_debugfs.c
drivers/platform/surface/surface_acpi_notify.c
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/intel/Kconfig
drivers/thermal/intel/int340x_thermal/Kconfig
drivers/thermal/thermal_acpi.c [deleted file]
fs/debugfs/file.c
include/acpi/acpi_bus.h
include/acpi/video.h
include/linux/acpi.h
include/linux/property.h
include/linux/thermal.h
lib/fw_table.c

index f819e760ff195a902aba7e8fd5073c0dc4d67a4c..6f2bfcf7645ce6c94732bb0b43512feac90762e3 100644 (file)
@@ -61,6 +61,10 @@ config ACPI_CCA_REQUIRED
 config ACPI_TABLE_LIB
        bool
 
+config ACPI_THERMAL_LIB
+       depends on THERMAL
+       bool
+
 config ACPI_DEBUGGER
        bool "AML debugger interface"
        select ACPI_DEBUG
@@ -327,6 +331,7 @@ config ACPI_THERMAL
        tristate "Thermal Zone"
        depends on ACPI_PROCESSOR
        select THERMAL
+       select ACPI_THERMAL_LIB
        default y
        help
          This driver supports ACPI thermal zones.  Most mobile and
index eaa09bf52f17609ffbb24fef7d7fccf12afe4024..12ef8180d272c71c8b09370571d18204f579ec8e 100644 (file)
@@ -37,7 +37,7 @@ acpi-$(CONFIG_ACPI_SLEEP)     += proc.o
 # ACPI Bus and Device Drivers
 #
 acpi-y                         += bus.o glue.o
-acpi-y                         += scan.o
+acpi-y                         += scan.o mipi-disco-img.o
 acpi-y                         += resource.o
 acpi-y                         += acpi_processor.o
 acpi-y                         += processor_core.o
@@ -89,6 +89,7 @@ obj-$(CONFIG_ACPI_TAD)                += acpi_tad.o
 obj-$(CONFIG_ACPI_PCI_SLOT)    += pci_slot.o
 obj-$(CONFIG_ACPI_PROCESSOR)   += processor.o
 obj-$(CONFIG_ACPI)             += container.o
+obj-$(CONFIG_ACPI_THERMAL_LIB) += thermal_lib.o
 obj-$(CONFIG_ACPI_THERMAL)     += thermal.o
 obj-$(CONFIG_ACPI_PLATFORM_PROFILE)    += platform_profile.o
 obj-$(CONFIG_ACPI_NFIT)                += nfit/
index e120a96e1eaee803c5beb0741072471de98a7bcf..ca87a093913599ea4681c0179ea2c6a85e18bfb3 100644 (file)
@@ -145,9 +145,14 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
        static u32 err_seq;
 
        estatus = extlog_elog_entry_check(cpu, bank);
-       if (estatus == NULL || (mce->kflags & MCE_HANDLED_CEC))
+       if (!estatus)
                return NOTIFY_DONE;
 
+       if (mce->kflags & MCE_HANDLED_CEC) {
+               estatus->block_status = 0;
+               return NOTIFY_DONE;
+       }
+
        memcpy(elog_buf, (void *)estatus, ELOG_ENTRY_LEN);
        /* clear record status to enable BIOS to update it again */
        estatus->block_status = 0;
@@ -303,9 +308,10 @@ err:
 static void __exit extlog_exit(void)
 {
        mce_unregister_decode_chain(&extlog_mce_dec);
-       ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN;
-       if (extlog_l1_addr)
+       if (extlog_l1_addr) {
+               ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN;
                acpi_os_unmap_iomem(extlog_l1_addr, l1_size);
+       }
        if (elog_addr)
                acpi_os_unmap_iomem(elog_addr, elog_size);
        release_mem_region(elog_base, elog_size);
index c5598b6d5db8b0c8154e804a68d1ee2a45bc5323..794962c5c88e95656175c5fea743a5c4d2ffaa4f 100644 (file)
@@ -105,7 +105,7 @@ static void lpit_update_residency(struct lpit_residency_info *info,
                return;
 
        info->frequency = lpit_native->counter_frequency ?
-                               lpit_native->counter_frequency : tsc_khz * 1000;
+                               lpit_native->counter_frequency : mul_u32_u32(tsc_khz, 1000U);
        if (!info->frequency)
                info->frequency = 1;
 
index 875de44961bf4b47f0d37a43632b3fa1c2500405..04e273167e92a66b3ce50d83fc084c41f77c12a8 100644 (file)
@@ -167,13 +167,9 @@ static struct pwm_lookup byt_pwm_lookup[] = {
 
 static void byt_pwm_setup(struct lpss_private_data *pdata)
 {
-       u64 uid;
-
        /* Only call pwm_add_table for the first PWM controller */
-       if (acpi_dev_uid_to_integer(pdata->adev, &uid) || uid != 1)
-               return;
-
-       pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup));
+       if (acpi_dev_uid_match(pdata->adev, 1))
+               pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup));
 }
 
 #define LPSS_I2C_ENABLE                        0x6c
@@ -218,13 +214,9 @@ static struct pwm_lookup bsw_pwm_lookup[] = {
 
 static void bsw_pwm_setup(struct lpss_private_data *pdata)
 {
-       u64 uid;
-
        /* Only call pwm_add_table for the first PWM controller */
-       if (acpi_dev_uid_to_integer(pdata->adev, &uid) || uid != 1)
-               return;
-
-       pwm_add_table(bsw_pwm_lookup, ARRAY_SIZE(bsw_pwm_lookup));
+       if (acpi_dev_uid_match(pdata->adev, 1))
+               pwm_add_table(bsw_pwm_lookup, ARRAY_SIZE(bsw_pwm_lookup));
 }
 
 static const struct property_entry lpt_spi_properties[] = {
@@ -461,8 +453,9 @@ static int register_device_clock(struct acpi_device *adev,
                if (!clk_name)
                        return -ENOMEM;
                clk = clk_register_fractional_divider(NULL, clk_name, parent,
+                                                     0, prv_base, 1, 15, 16, 15,
                                                      CLK_FRAC_DIVIDER_POWER_OF_TWO_PS,
-                                                     prv_base, 1, 15, 16, 15, 0, NULL);
+                                                     NULL);
                parent = clk_name;
 
                clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
@@ -570,34 +563,6 @@ static struct device *acpi_lpss_find_device(const char *hid, const char *uid)
        return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid);
 }
 
-static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle)
-{
-       struct acpi_handle_list dep_devices;
-       acpi_status status;
-       bool ret = false;
-       int i;
-
-       if (!acpi_has_method(adev->handle, "_DEP"))
-               return false;
-
-       status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
-                                        &dep_devices);
-       if (ACPI_FAILURE(status)) {
-               dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n");
-               return false;
-       }
-
-       for (i = 0; i < dep_devices.count; i++) {
-               if (dep_devices.handles[i] == handle) {
-                       ret = true;
-                       break;
-               }
-       }
-
-       acpi_handle_list_free(&dep_devices);
-       return ret;
-}
-
 static void acpi_lpss_link_consumer(struct device *dev1,
                                    const struct lpss_device_links *link)
 {
@@ -608,7 +573,7 @@ static void acpi_lpss_link_consumer(struct device *dev1,
                return;
 
        if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids))
-           || acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1)))
+           || acpi_device_dep(ACPI_HANDLE(dev2), ACPI_HANDLE(dev1)))
                device_link_add(dev2, dev1, link->flags);
 
        put_device(dev2);
@@ -624,7 +589,7 @@ static void acpi_lpss_link_supplier(struct device *dev1,
                return;
 
        if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids))
-           || acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2)))
+           || acpi_device_dep(ACPI_HANDLE(dev1), ACPI_HANDLE(dev2)))
                device_link_add(dev1, dev2, link->flags);
 
        put_device(dev2);
index 6cee536c229a6377ca902ed19b2a8f579e4ca3ae..4afdda9db0195c804a29e9cb983f6f09f01a4331 100644 (file)
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(hw_changes_brightness,
 static bool device_id_scheme = false;
 module_param(device_id_scheme, bool, 0444);
 
-static int only_lcd = -1;
+static int only_lcd;
 module_param(only_lcd, int, 0444);
 
 static bool may_report_brightness_keys;
@@ -500,6 +500,15 @@ static const struct dmi_system_id video_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"),
                },
        },
+       {
+        .callback = video_set_report_key_events,
+        .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS),
+        .ident = "COLORFUL X15 AT 23",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "COLORFUL"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "X15 AT 23"),
+               },
+       },
        /*
         * Some machines change the brightness themselves when a brightness
         * hotkey gets pressed, despite us telling them not to. In this case
@@ -1713,12 +1722,12 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
                return;
        count++;
 
-       acpi_get_parent(device->dev->handle, &acpi_parent);
-
-       pdev = acpi_get_pci_dev(acpi_parent);
-       if (pdev) {
-               parent = &pdev->dev;
-               pci_dev_put(pdev);
+       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);
+               }
        }
 
        memset(&props, 0, sizeof(struct backlight_properties));
@@ -2137,57 +2146,6 @@ static int __init intel_opregion_present(void)
        return opregion;
 }
 
-/* Check if the chassis-type indicates there is no builtin LCD panel */
-static bool dmi_is_desktop(void)
-{
-       const char *chassis_type;
-       unsigned long type;
-
-       chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
-       if (!chassis_type)
-               return false;
-
-       if (kstrtoul(chassis_type, 10, &type) != 0)
-               return false;
-
-       switch (type) {
-       case 0x03: /* Desktop */
-       case 0x04: /* Low Profile Desktop */
-       case 0x05: /* Pizza Box */
-       case 0x06: /* Mini Tower */
-       case 0x07: /* Tower */
-       case 0x10: /* Lunch Box */
-       case 0x11: /* Main Server Chassis */
-               return true;
-       }
-
-       return false;
-}
-
-/*
- * We're seeing a lot of bogus backlight interfaces on newer machines
- * without a LCD such as desktops, servers and HDMI sticks. Checking the
- * lcd flag fixes this, enable this by default on any machines which are:
- * 1.  Win8 ready (where we also prefer the native backlight driver, so
- *     normally the acpi_video code should not register there anyways); *and*
- * 2.1 Report a desktop/server DMI chassis-type, or
- * 2.2 Are an ACPI-reduced-hardware platform (and thus won't use the EC for
-       backlight control)
- */
-static bool should_check_lcd_flag(void)
-{
-       if (!acpi_osi_is_win8())
-               return false;
-
-       if (dmi_is_desktop())
-               return true;
-
-       if (acpi_reduced_hardware())
-               return true;
-
-       return false;
-}
-
 int acpi_video_register(void)
 {
        int ret = 0;
@@ -2201,9 +2159,6 @@ int acpi_video_register(void)
                goto leave;
        }
 
-       if (only_lcd == -1)
-               only_lcd = should_check_lcd_flag();
-
        dmi_check_system(video_dmi_table);
 
        ret = acpi_bus_register_driver(&acpi_video_bus);
index ca28183f4d1329ea22aa4c775c66334da91c7d06..8e9e001da38f54296a78c44dbe78f6b7e46355b8 100644 (file)
@@ -81,7 +81,7 @@ static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void)
        return wdat;
 }
 
-/**
+/*
  * Returns true if this system should prefer ACPI based watchdog instead of
  * the native one (which are typically the same hardware).
  */
index 013eb621dc92a7c11b00577a890c06fc64453a2c..89fb9331c611e44500b80701b48ef5b57d8a8df1 100644 (file)
@@ -73,6 +73,7 @@ static u32 notrigger;
 
 static u32 vendor_flags;
 static struct debugfs_blob_wrapper vendor_blob;
+static struct debugfs_blob_wrapper vendor_errors;
 static char vendor_dev[64];
 
 /*
@@ -182,6 +183,21 @@ static int einj_timedout(u64 *t)
        return 0;
 }
 
+static void get_oem_vendor_struct(u64 paddr, int offset,
+                                 struct vendor_error_type_extension *v)
+{
+       unsigned long vendor_size;
+       u64 target_pa = paddr + offset + sizeof(struct vendor_error_type_extension);
+
+       vendor_size = v->length - sizeof(struct vendor_error_type_extension);
+
+       if (vendor_size)
+               vendor_errors.data = acpi_os_map_memory(target_pa, vendor_size);
+
+       if (vendor_errors.data)
+               vendor_errors.size = vendor_size;
+}
+
 static void check_vendor_extension(u64 paddr,
                                   struct set_error_type_with_address *v5param)
 {
@@ -194,6 +210,7 @@ static void check_vendor_extension(u64 paddr,
        v = acpi_os_map_iomem(paddr + offset, sizeof(*v));
        if (!v)
                return;
+       get_oem_vendor_struct(paddr, offset, v);
        sbdf = v->pcie_sbdf;
        sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n",
                sbdf >> 24, (sbdf >> 16) & 0xff,
@@ -577,38 +594,40 @@ static u64 error_param2;
 static u64 error_param3;
 static u64 error_param4;
 static struct dentry *einj_debug_dir;
-static const char * const einj_error_type_string[] = {
-       "0x00000001\tProcessor Correctable\n",
-       "0x00000002\tProcessor Uncorrectable non-fatal\n",
-       "0x00000004\tProcessor Uncorrectable fatal\n",
-       "0x00000008\tMemory Correctable\n",
-       "0x00000010\tMemory Uncorrectable non-fatal\n",
-       "0x00000020\tMemory Uncorrectable fatal\n",
-       "0x00000040\tPCI Express Correctable\n",
-       "0x00000080\tPCI Express Uncorrectable non-fatal\n",
-       "0x00000100\tPCI Express Uncorrectable fatal\n",
-       "0x00000200\tPlatform Correctable\n",
-       "0x00000400\tPlatform Uncorrectable non-fatal\n",
-       "0x00000800\tPlatform Uncorrectable fatal\n",
-       "0x00001000\tCXL.cache Protocol Correctable\n",
-       "0x00002000\tCXL.cache Protocol Uncorrectable non-fatal\n",
-       "0x00004000\tCXL.cache Protocol Uncorrectable fatal\n",
-       "0x00008000\tCXL.mem Protocol Correctable\n",
-       "0x00010000\tCXL.mem Protocol Uncorrectable non-fatal\n",
-       "0x00020000\tCXL.mem Protocol Uncorrectable fatal\n",
+static struct { u32 mask; const char *str; } const einj_error_type_string[] = {
+       { BIT(0), "Processor Correctable" },
+       { BIT(1), "Processor Uncorrectable non-fatal" },
+       { BIT(2), "Processor Uncorrectable fatal" },
+       { BIT(3), "Memory Correctable" },
+       { BIT(4), "Memory Uncorrectable non-fatal" },
+       { BIT(5), "Memory Uncorrectable fatal" },
+       { BIT(6), "PCI Express Correctable" },
+       { BIT(7), "PCI Express Uncorrectable non-fatal" },
+       { BIT(8), "PCI Express Uncorrectable fatal" },
+       { BIT(9), "Platform Correctable" },
+       { BIT(10), "Platform Uncorrectable non-fatal" },
+       { BIT(11), "Platform Uncorrectable fatal"},
+       { BIT(12), "CXL.cache Protocol Correctable" },
+       { BIT(13), "CXL.cache Protocol Uncorrectable non-fatal" },
+       { BIT(14), "CXL.cache Protocol Uncorrectable fatal" },
+       { BIT(15), "CXL.mem Protocol Correctable" },
+       { BIT(16), "CXL.mem Protocol Uncorrectable non-fatal" },
+       { BIT(17), "CXL.mem Protocol Uncorrectable fatal" },
+       { BIT(31), "Vendor Defined Error Types" },
 };
 
 static int available_error_type_show(struct seq_file *m, void *v)
 {
        int rc;
-       u32 available_error_type = 0;
+       u32 error_type = 0;
 
-       rc = einj_get_available_error_type(&available_error_type);
+       rc = einj_get_available_error_type(&error_type);
        if (rc)
                return rc;
        for (int pos = 0; pos < ARRAY_SIZE(einj_error_type_string); pos++)
-               if (available_error_type & BIT(pos))
-                       seq_puts(m, einj_error_type_string[pos]);
+               if (error_type & einj_error_type_string[pos].mask)
+                       seq_printf(m, "0x%08x\t%s\n", einj_error_type_string[pos].mask,
+                                  einj_error_type_string[pos].str);
 
        return 0;
 }
@@ -767,6 +786,10 @@ static int __init einj_init(void)
                                   einj_debug_dir, &vendor_flags);
        }
 
+       if (vendor_errors.size)
+               debugfs_create_blob("oem_error", 0600, einj_debug_dir,
+                                   &vendor_errors);
+
        pr_info("Error INJection is initialized.\n");
 
        return 0;
@@ -792,6 +815,8 @@ static void __exit einj_exit(void)
                        sizeof(struct einj_parameter);
 
                acpi_os_unmap_iomem(einj_param, size);
+               if (vendor_errors.size)
+                       acpi_os_unmap_memory(vendor_errors.data, vendor_errors.size);
        }
        einj_exec_ctx_init(&ctx);
        apei_exec_post_unmap_gars(&ctx);
index 63ad0541db3817419ddc9d7fc7e51be2182ac229..ab2a82cb1b0b48ab21682bdb87c052707f19d282 100644 (file)
@@ -101,6 +101,20 @@ static inline bool is_hest_type_generic_v2(struct ghes *ghes)
        return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2;
 }
 
+/*
+ * A platform may describe one error source for the handling of synchronous
+ * errors (e.g. MCE or SEA), or for handling asynchronous errors (e.g. SCI
+ * or External Interrupt). On x86, the HEST notifications are always
+ * asynchronous, so only SEA on ARM is delivered as a synchronous
+ * notification.
+ */
+static inline bool is_hest_sync_notify(struct ghes *ghes)
+{
+       u8 notify_type = ghes->generic->notify.type;
+
+       return notify_type == ACPI_HEST_NOTIFY_SEA;
+}
+
 /*
  * This driver isn't really modular, however for the time being,
  * continuing to use module_param is the easiest way to remain
@@ -489,7 +503,7 @@ static bool ghes_do_memory_failure(u64 physical_addr, int flags)
 }
 
 static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
-                                      int sev)
+                                      int sev, bool sync)
 {
        int flags = -1;
        int sec_sev = ghes_severity(gdata->error_severity);
@@ -503,7 +517,7 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
            (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED))
                flags = MF_SOFT_OFFLINE;
        if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
-               flags = 0;
+               flags = sync ? MF_ACTION_REQUIRED : 0;
 
        if (flags != -1)
                return ghes_do_memory_failure(mem_err->physical_addr, flags);
@@ -511,9 +525,11 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
        return false;
 }
 
-static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int sev)
+static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
+                                      int sev, bool sync)
 {
        struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
+       int flags = sync ? MF_ACTION_REQUIRED : 0;
        bool queued = false;
        int sec_sev, i;
        char *p;
@@ -538,7 +554,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int s
                 * and don't filter out 'corrected' error here.
                 */
                if (is_cache && has_pa) {
-                       queued = ghes_do_memory_failure(err_info->physical_fault_addr, 0);
+                       queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags);
                        p += err_info->length;
                        continue;
                }
@@ -666,6 +682,7 @@ static bool ghes_do_proc(struct ghes *ghes,
        const guid_t *fru_id = &guid_null;
        char *fru_text = "";
        bool queued = false;
+       bool sync = is_hest_sync_notify(ghes);
 
        sev = ghes_severity(estatus->error_severity);
        apei_estatus_for_each_section(estatus, gdata) {
@@ -683,13 +700,13 @@ static bool ghes_do_proc(struct ghes *ghes,
                        atomic_notifier_call_chain(&ghes_report_chain, sev, mem_err);
 
                        arch_apei_report_mem_error(sev, mem_err);
-                       queued = ghes_handle_memory_failure(gdata, sev);
+                       queued = ghes_handle_memory_failure(gdata, sev, sync);
                }
                else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
                        ghes_handle_aer(gdata);
                }
                else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
-                       queued = ghes_handle_arm_hw_error(gdata, sev);
+                       queued = ghes_handle_arm_hw_error(gdata, sev, sync);
                } else {
                        void *err = acpi_hest_get_payload(gdata);
 
index 143debc1ba4a9d9dae6147c3c1dfc4408d05c5e9..726944648c9bcefa5d0462d855e72556513c15d9 100644 (file)
@@ -5,3 +5,4 @@ obj-$(CONFIG_ACPI_GTDT)         += gtdt.o
 obj-$(CONFIG_ACPI_APMT)        += apmt.o
 obj-$(CONFIG_ARM_AMBA)         += amba.o
 obj-y                          += dma.o init.o
+obj-y                          += thermal_cpufreq.o
diff --git a/drivers/acpi/arm64/thermal_cpufreq.c b/drivers/acpi/arm64/thermal_cpufreq.c
new file mode 100644 (file)
index 0000000..5828549
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/acpi.h>
+#include <linux/export.h>
+
+#include "../internal.h"
+
+#define SMCCC_SOC_ID_T241      0x036b0241
+
+int acpi_arch_thermal_cpufreq_pctg(void)
+{
+       s32 soc_id = arm_smccc_get_soc_id_version();
+
+       /*
+        * Check JEP106 code for NVIDIA Tegra241 chip (036b:0241) and
+        * reduce the CPUFREQ Thermal reduction percentage to 5%.
+        */
+       if (soc_id == SMCCC_SOC_ID_T241)
+               return 5;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_arch_thermal_cpufreq_pctg);
index 72e64c0718c9a346ff6d3030d877b53c123cb9f1..569bd15f211be9d190dc557820ffedbf5ee8a046 100644 (file)
@@ -408,7 +408,7 @@ static void acpi_bus_decode_usb_osc(const char *msg, u32 bits)
 static u8 sb_usb_uuid_str[] = "23A0D13A-26AB-486C-9C5F-0FFA525A575A";
 static void acpi_bus_osc_negotiate_usb_control(void)
 {
-       u32 capbuf[3];
+       u32 capbuf[3], *capbuf_ret;
        struct acpi_osc_context context = {
                .uuid_str = sb_usb_uuid_str,
                .rev = 1,
@@ -428,7 +428,12 @@ static void acpi_bus_osc_negotiate_usb_control(void)
        control = OSC_USB_USB3_TUNNELING | OSC_USB_DP_TUNNELING |
                  OSC_USB_PCIE_TUNNELING | OSC_USB_XDOMAIN;
 
-       capbuf[OSC_QUERY_DWORD] = 0;
+       /*
+        * Run _OSC first with query bit set, trying to get control over
+        * all tunneling. The platform can then clear out bits in the
+        * control dword that it does not want to grant to the OS.
+        */
+       capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE;
        capbuf[OSC_SUPPORT_DWORD] = 0;
        capbuf[OSC_CONTROL_DWORD] = control;
 
@@ -441,8 +446,29 @@ static void acpi_bus_osc_negotiate_usb_control(void)
                goto out_free;
        }
 
+       /*
+        * Run _OSC again now with query bit clear and the control dword
+        * matching what the platform granted (which may not have all
+        * the control bits set).
+        */
+       capbuf_ret = context.ret.pointer;
+
+       capbuf[OSC_QUERY_DWORD] = 0;
+       capbuf[OSC_CONTROL_DWORD] = capbuf_ret[OSC_CONTROL_DWORD];
+
+       kfree(context.ret.pointer);
+
+       status = acpi_run_osc(handle, &context);
+       if (ACPI_FAILURE(status))
+               return;
+
+       if (context.ret.length != sizeof(capbuf)) {
+               pr_info("USB4 _OSC: returned invalid length buffer\n");
+               goto out_free;
+       }
+
        osc_sb_native_usb4_control =
-               control &  acpi_osc_ctx_get_pci_control(&context);
+               control & acpi_osc_ctx_get_pci_control(&context);
 
        acpi_bus_decode_usb_osc("USB4 _OSC: OS supports", control);
        acpi_bus_decode_usb_osc("USB4 _OSC: OS controls",
index 1e76a64cce0a911ceca550086fe2b1256ac98a02..cc61020756beb8711cc9e703becba6972765fbfa 100644 (file)
@@ -480,6 +480,7 @@ static int acpi_button_suspend(struct device *dev)
 
 static int acpi_button_resume(struct device *dev)
 {
+       struct input_dev *input;
        struct acpi_device *device = to_acpi_device(dev);
        struct acpi_button *button = acpi_driver_data(device);
 
@@ -489,6 +490,14 @@ static int acpi_button_resume(struct device *dev)
                button->last_time = ktime_get();
                acpi_lid_initialize_state(device);
        }
+
+       if (button->type == ACPI_BUTTON_TYPE_POWER) {
+               input = button->input;
+               input_report_key(input, KEY_WAKEUP, 1);
+               input_sync(input);
+               input_report_key(input, KEY_WAKEUP, 0);
+               input_sync(input);
+       }
        return 0;
 }
 #endif
@@ -579,6 +588,7 @@ static int acpi_button_add(struct acpi_device *device)
        switch (button->type) {
        case ACPI_BUTTON_TYPE_POWER:
                input_set_capability(input, EV_KEY, KEY_POWER);
+               input_set_capability(input, EV_KEY, KEY_WAKEUP);
                break;
 
        case ACPI_BUTTON_TYPE_SLEEP:
index a59c11df737542ebf80f1b8c51b3927b26ae23c2..dbdee2924594a921f27fead574fcf1855c4e471b 100644 (file)
@@ -525,12 +525,10 @@ static void acpi_ec_clear(struct acpi_ec *ec)
 
 static void acpi_ec_enable_event(struct acpi_ec *ec)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        if (acpi_ec_started(ec))
                __acpi_ec_enable_event(ec);
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
 
        /* Drain additional events if hardware requires that */
        if (EC_FLAGS_CLEAR_ON_RESUME)
@@ -546,11 +544,9 @@ static void __acpi_ec_flush_work(void)
 
 static void acpi_ec_disable_event(struct acpi_ec *ec)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        __acpi_ec_disable_event(ec);
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
 
        /*
         * When ec_freeze_events is true, we need to flush events in
@@ -571,10 +567,9 @@ void acpi_ec_flush_work(void)
 
 static bool acpi_ec_guard_event(struct acpi_ec *ec)
 {
-       unsigned long flags;
        bool guarded;
 
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        /*
         * If firmware SCI_EVT clearing timing is "event", we actually
         * don't know when the SCI_EVT will be cleared by firmware after
@@ -590,31 +585,29 @@ static bool acpi_ec_guard_event(struct acpi_ec *ec)
        guarded = ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
                ec->event_state != EC_EVENT_READY &&
                (!ec->curr || ec->curr->command != ACPI_EC_COMMAND_QUERY);
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
        return guarded;
 }
 
 static int ec_transaction_polled(struct acpi_ec *ec)
 {
-       unsigned long flags;
        int ret = 0;
 
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_POLL))
                ret = 1;
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
        return ret;
 }
 
 static int ec_transaction_completed(struct acpi_ec *ec)
 {
-       unsigned long flags;
        int ret = 0;
 
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
                ret = 1;
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
        return ret;
 }
 
@@ -756,7 +749,6 @@ static int ec_guard(struct acpi_ec *ec)
 
 static int ec_poll(struct acpi_ec *ec)
 {
-       unsigned long flags;
        int repeat = 5; /* number of command restarts */
 
        while (repeat--) {
@@ -765,14 +757,14 @@ static int ec_poll(struct acpi_ec *ec)
                do {
                        if (!ec_guard(ec))
                                return 0;
-                       spin_lock_irqsave(&ec->lock, flags);
+                       spin_lock(&ec->lock);
                        advance_transaction(ec, false);
-                       spin_unlock_irqrestore(&ec->lock, flags);
+                       spin_unlock(&ec->lock);
                } while (time_before(jiffies, delay));
                pr_debug("controller reset, restart transaction\n");
-               spin_lock_irqsave(&ec->lock, flags);
+               spin_lock(&ec->lock);
                start_transaction(ec);
-               spin_unlock_irqrestore(&ec->lock, flags);
+               spin_unlock(&ec->lock);
        }
        return -ETIME;
 }
@@ -780,11 +772,10 @@ static int ec_poll(struct acpi_ec *ec)
 static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
                                        struct transaction *t)
 {
-       unsigned long tmp;
        int ret = 0;
 
        /* start transaction */
-       spin_lock_irqsave(&ec->lock, tmp);
+       spin_lock(&ec->lock);
        /* Enable GPE for command processing (IBF=0/OBF=1) */
        if (!acpi_ec_submit_flushable_request(ec)) {
                ret = -EINVAL;
@@ -795,11 +786,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
        ec->curr = t;
        ec_dbg_req("Command(%s) started", acpi_ec_cmd_string(t->command));
        start_transaction(ec);
-       spin_unlock_irqrestore(&ec->lock, tmp);
+       spin_unlock(&ec->lock);
 
        ret = ec_poll(ec);
 
-       spin_lock_irqsave(&ec->lock, tmp);
+       spin_lock(&ec->lock);
        if (t->irq_count == ec_storm_threshold)
                acpi_ec_unmask_events(ec);
        ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
@@ -808,7 +799,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
        acpi_ec_complete_request(ec);
        ec_dbg_ref(ec, "Decrease command");
 unlock:
-       spin_unlock_irqrestore(&ec->lock, tmp);
+       spin_unlock(&ec->lock);
        return ret;
 }
 
@@ -936,9 +927,7 @@ EXPORT_SYMBOL(ec_get_handle);
 
 static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
                ec_dbg_drv("Starting EC");
                /* Enable GPE for event processing (SCI_EVT=1) */
@@ -948,31 +937,28 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
                }
                ec_log_drv("EC started");
        }
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
 }
 
 static bool acpi_ec_stopped(struct acpi_ec *ec)
 {
-       unsigned long flags;
        bool flushed;
 
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        flushed = acpi_ec_flushed(ec);
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
        return flushed;
 }
 
 static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        if (acpi_ec_started(ec)) {
                ec_dbg_drv("Stopping EC");
                set_bit(EC_FLAGS_STOPPED, &ec->flags);
-               spin_unlock_irqrestore(&ec->lock, flags);
+               spin_unlock(&ec->lock);
                wait_event(ec->wait, acpi_ec_stopped(ec));
-               spin_lock_irqsave(&ec->lock, flags);
+               spin_lock(&ec->lock);
                /* Disable GPE for event processing (SCI_EVT=1) */
                if (!suspending) {
                        acpi_ec_complete_request(ec);
@@ -983,29 +969,25 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
                clear_bit(EC_FLAGS_STOPPED, &ec->flags);
                ec_log_drv("EC stopped");
        }
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
 }
 
 static void acpi_ec_enter_noirq(struct acpi_ec *ec)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        ec->busy_polling = true;
        ec->polling_guard = 0;
        ec_log_drv("interrupt blocked");
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
 }
 
 static void acpi_ec_leave_noirq(struct acpi_ec *ec)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
        ec->busy_polling = ec_busy_polling;
        ec->polling_guard = ec_polling_guard;
        ec_log_drv("interrupt unblocked");
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
 }
 
 void acpi_ec_block_transactions(void)
@@ -1137,9 +1119,9 @@ static void acpi_ec_event_processor(struct work_struct *work)
 
        ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);
 
-       spin_lock_irq(&ec->lock);
+       spin_lock(&ec->lock);
        ec->queries_in_progress--;
-       spin_unlock_irq(&ec->lock);
+       spin_unlock(&ec->lock);
 
        acpi_ec_put_query_handler(handler);
        kfree(q);
@@ -1202,12 +1184,12 @@ static int acpi_ec_submit_query(struct acpi_ec *ec)
         */
        ec_dbg_evt("Query(0x%02x) scheduled", value);
 
-       spin_lock_irq(&ec->lock);
+       spin_lock(&ec->lock);
 
        ec->queries_in_progress++;
        queue_work(ec_query_wq, &q->work);
 
-       spin_unlock_irq(&ec->lock);
+       spin_unlock(&ec->lock);
 
        return 0;
 
@@ -1223,14 +1205,14 @@ static void acpi_ec_event_handler(struct work_struct *work)
 
        ec_dbg_evt("Event started");
 
-       spin_lock_irq(&ec->lock);
+       spin_lock(&ec->lock);
 
        while (ec->events_to_process) {
-               spin_unlock_irq(&ec->lock);
+               spin_unlock(&ec->lock);
 
                acpi_ec_submit_query(ec);
 
-               spin_lock_irq(&ec->lock);
+               spin_lock(&ec->lock);
 
                ec->events_to_process--;
        }
@@ -1247,11 +1229,11 @@ static void acpi_ec_event_handler(struct work_struct *work)
 
                ec_dbg_evt("Event stopped");
 
-               spin_unlock_irq(&ec->lock);
+               spin_unlock(&ec->lock);
 
                guard_timeout = !!ec_guard(ec);
 
-               spin_lock_irq(&ec->lock);
+               spin_lock(&ec->lock);
 
                /* Take care of SCI_EVT unless someone else is doing that. */
                if (guard_timeout && !ec->curr)
@@ -1264,7 +1246,7 @@ static void acpi_ec_event_handler(struct work_struct *work)
 
        ec->events_in_progress--;
 
-       spin_unlock_irq(&ec->lock);
+       spin_unlock(&ec->lock);
 }
 
 static void clear_gpe_and_advance_transaction(struct acpi_ec *ec, bool interrupt)
@@ -1289,13 +1271,11 @@ static void clear_gpe_and_advance_transaction(struct acpi_ec *ec, bool interrupt
 
 static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ec->lock, flags);
+       spin_lock(&ec->lock);
 
        clear_gpe_and_advance_transaction(ec, true);
 
-       spin_unlock_irqrestore(&ec->lock, flags);
+       spin_unlock(&ec->lock);
 }
 
 static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
@@ -1458,8 +1438,8 @@ static bool install_gpe_event_handler(struct acpi_ec *ec)
 
 static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
 {
-       return request_irq(ec->irq, acpi_ec_irq_handler, IRQF_SHARED,
-                          "ACPI EC", ec) >= 0;
+       return request_threaded_irq(ec->irq, NULL, acpi_ec_irq_handler,
+                                   IRQF_SHARED | IRQF_ONESHOT, "ACPI EC", ec) >= 0;
 }
 
 /**
@@ -2105,7 +2085,7 @@ bool acpi_ec_dispatch_gpe(void)
         * Dispatch the EC GPE in-band, but do not report wakeup in any case
         * to allow the caller to process events properly after that.
         */
-       spin_lock_irq(&first_ec->lock);
+       spin_lock(&first_ec->lock);
 
        if (acpi_ec_gpe_status_set(first_ec)) {
                pm_pr_dbg("ACPI EC GPE status set\n");
@@ -2114,7 +2094,7 @@ bool acpi_ec_dispatch_gpe(void)
                work_in_progress = acpi_ec_work_in_progress(first_ec);
        }
 
-       spin_unlock_irq(&first_ec->lock);
+       spin_unlock(&first_ec->lock);
 
        if (!work_in_progress)
                return false;
@@ -2127,11 +2107,11 @@ bool acpi_ec_dispatch_gpe(void)
 
                pm_pr_dbg("ACPI EC work flushed\n");
 
-               spin_lock_irq(&first_ec->lock);
+               spin_lock(&first_ec->lock);
 
                work_in_progress = acpi_ec_work_in_progress(first_ec);
 
-               spin_unlock_irq(&first_ec->lock);
+               spin_unlock(&first_ec->lock);
        } while (work_in_progress && !pm_wakeup_pending());
 
        return false;
index 866c7c4ed2331710736606664e19098b49a4098e..6588525c45efaa3b620d3f8bf6dc031932f43234 100644 (file)
@@ -85,6 +85,20 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
 acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context);
 void acpi_scan_table_notify(void);
 
+int acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp);
+int acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp);
+int acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp);
+int acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp);
+
+#ifdef CONFIG_ARM64
+int acpi_arch_thermal_cpufreq_pctg(void);
+#else
+static inline int acpi_arch_thermal_cpufreq_pctg(void)
+{
+       return 0;
+}
+#endif
+
 /* --------------------------------------------------------------------------
                      Device Node Initialization / Removal
    -------------------------------------------------------------------------- */
@@ -148,8 +162,11 @@ int acpi_wakeup_device_init(void);
 #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC
 void acpi_early_processor_control_setup(void);
 void acpi_early_processor_set_pdc(void);
-
+#ifdef CONFIG_X86
 void acpi_proc_quirk_mwait_check(void);
+#else
+static inline void acpi_proc_quirk_mwait_check(void) {}
+#endif
 bool processor_physically_present(acpi_handle handle);
 #else
 static inline void acpi_early_processor_control_setup(void) {}
@@ -276,4 +293,13 @@ void acpi_init_lpit(void);
 static inline void acpi_init_lpit(void) { }
 #endif
 
+/*--------------------------------------------------------------------------
+               ACPI _CRS CSI-2 and MIPI DisCo for Imaging
+  -------------------------------------------------------------------------- */
+
+void acpi_mipi_check_crs_csi2(acpi_handle handle);
+void acpi_mipi_scan_crs_csi2(void);
+void acpi_mipi_init_crs_csi2_swnodes(void);
+void acpi_mipi_crs_csi2_cleanup(void);
+
 #endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/mipi-disco-img.c b/drivers/acpi/mipi-disco-img.c
new file mode 100644 (file)
index 0000000..7286cf4
--- /dev/null
@@ -0,0 +1,725 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MIPI DisCo for Imaging support.
+ *
+ * Copyright (C) 2023 Intel Corporation
+ *
+ * Support MIPI DisCo for Imaging by parsing ACPI _CRS CSI-2 records defined in
+ * Section 6.4.3.8.2.4 "Camera Serial Interface (CSI-2) Connection Resource
+ * Descriptor" of ACPI 6.5 and using device properties defined by the MIPI DisCo
+ * for Imaging specification.
+ *
+ * The implementation looks for the information in the ACPI namespace (CSI-2
+ * resource descriptors in _CRS) and constructs software nodes compatible with
+ * Documentation/firmware-guide/acpi/dsd/graph.rst to represent the CSI-2
+ * connection graph.  The software nodes are then populated with the data
+ * extracted from the _CRS CSI-2 resource descriptors and the MIPI DisCo
+ * for Imaging device properties present in _DSD for the ACPI device objects
+ * with CSI-2 connections.
+ */
+
+#include <linux/acpi.h>
+#include <linux/limits.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <media/v4l2-fwnode.h>
+
+#include "internal.h"
+
+static LIST_HEAD(acpi_mipi_crs_csi2_list);
+
+static void acpi_mipi_data_tag(acpi_handle handle, void *context)
+{
+}
+
+/* Connection data extracted from one _CRS CSI-2 resource descriptor. */
+struct crs_csi2_connection {
+       struct list_head entry;
+       struct acpi_resource_csi2_serialbus csi2_data;
+       acpi_handle remote_handle;
+       char remote_name[];
+};
+
+/* Data extracted from _CRS CSI-2 resource descriptors for one device. */
+struct crs_csi2 {
+       struct list_head entry;
+       acpi_handle handle;
+       struct acpi_device_software_nodes *swnodes;
+       struct list_head connections;
+       u32 port_count;
+};
+
+struct csi2_resources_walk_data {
+       acpi_handle handle;
+       struct list_head connections;
+};
+
+static acpi_status parse_csi2_resource(struct acpi_resource *res, void *context)
+{
+       struct csi2_resources_walk_data *crwd = context;
+       struct acpi_resource_csi2_serialbus *csi2_res;
+       struct acpi_resource_source *csi2_res_src;
+       u16 csi2_res_src_length;
+       struct crs_csi2_connection *conn;
+       acpi_handle remote_handle;
+
+       if (res->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+               return AE_OK;
+
+       csi2_res = &res->data.csi2_serial_bus;
+
+       if (csi2_res->type != ACPI_RESOURCE_SERIAL_TYPE_CSI2)
+               return AE_OK;
+
+       csi2_res_src = &csi2_res->resource_source;
+       if (ACPI_FAILURE(acpi_get_handle(NULL, csi2_res_src->string_ptr,
+                                        &remote_handle))) {
+               acpi_handle_debug(crwd->handle,
+                                 "unable to find resource source\n");
+               return AE_OK;
+       }
+       csi2_res_src_length = csi2_res_src->string_length;
+       if (!csi2_res_src_length) {
+               acpi_handle_debug(crwd->handle,
+                                 "invalid resource source string length\n");
+               return AE_OK;
+       }
+
+       conn = kmalloc(struct_size(conn, remote_name, csi2_res_src_length + 1),
+                      GFP_KERNEL);
+       if (!conn)
+               return AE_OK;
+
+       conn->csi2_data = *csi2_res;
+       strscpy(conn->remote_name, csi2_res_src->string_ptr, csi2_res_src_length);
+       conn->csi2_data.resource_source.string_ptr = conn->remote_name;
+       conn->remote_handle = remote_handle;
+
+       list_add(&conn->entry, &crwd->connections);
+
+       return AE_OK;
+}
+
+static struct crs_csi2 *acpi_mipi_add_crs_csi2(acpi_handle handle,
+                                              struct list_head *list)
+{
+       struct crs_csi2 *csi2;
+
+       csi2 = kzalloc(sizeof(*csi2), GFP_KERNEL);
+       if (!csi2)
+               return NULL;
+
+       csi2->handle = handle;
+       INIT_LIST_HEAD(&csi2->connections);
+       csi2->port_count = 1;
+
+       if (ACPI_FAILURE(acpi_attach_data(handle, acpi_mipi_data_tag, csi2))) {
+               kfree(csi2);
+               return NULL;
+       }
+
+       list_add(&csi2->entry, list);
+
+       return csi2;
+}
+
+static struct crs_csi2 *acpi_mipi_get_crs_csi2(acpi_handle handle)
+{
+       struct crs_csi2 *csi2;
+
+       if (ACPI_FAILURE(acpi_get_data_full(handle, acpi_mipi_data_tag,
+                                           (void **)&csi2, NULL)))
+               return NULL;
+
+       return csi2;
+}
+
+static void csi_csr2_release_connections(struct list_head *list)
+{
+       struct crs_csi2_connection *conn, *conn_tmp;
+
+       list_for_each_entry_safe(conn, conn_tmp, list, entry) {
+               list_del(&conn->entry);
+               kfree(conn);
+       }
+}
+
+static void acpi_mipi_del_crs_csi2(struct crs_csi2 *csi2)
+{
+       list_del(&csi2->entry);
+       acpi_detach_data(csi2->handle, acpi_mipi_data_tag);
+       kfree(csi2->swnodes);
+       csi_csr2_release_connections(&csi2->connections);
+       kfree(csi2);
+}
+
+/**
+ * acpi_mipi_check_crs_csi2 - Look for CSI-2 resources in _CRS
+ * @handle: Device object handle to evaluate _CRS for.
+ *
+ * Find all CSI-2 resource descriptors in the given device's _CRS
+ * and collect them into a list.
+ */
+void acpi_mipi_check_crs_csi2(acpi_handle handle)
+{
+       struct csi2_resources_walk_data crwd = {
+               .handle = handle,
+               .connections = LIST_HEAD_INIT(crwd.connections),
+       };
+       struct crs_csi2 *csi2;
+
+       /*
+        * Avoid allocating _CRS CSI-2 objects for devices without any CSI-2
+        * resource descriptions in _CRS to reduce overhead.
+        */
+       acpi_walk_resources(handle, METHOD_NAME__CRS, parse_csi2_resource, &crwd);
+       if (list_empty(&crwd.connections))
+               return;
+
+       /*
+        * Create a _CRS CSI-2 entry to store the extracted connection
+        * information and add it to the global list.
+        */
+       csi2 = acpi_mipi_add_crs_csi2(handle, &acpi_mipi_crs_csi2_list);
+       if (!csi2) {
+               csi_csr2_release_connections(&crwd.connections);
+               return; /* Nothing really can be done about this. */
+       }
+
+       list_replace(&crwd.connections, &csi2->connections);
+}
+
+#define NO_CSI2_PORT (UINT_MAX - 1)
+
+static void alloc_crs_csi2_swnodes(struct crs_csi2 *csi2)
+{
+       size_t port_count = csi2->port_count;
+       struct acpi_device_software_nodes *swnodes;
+       size_t alloc_size;
+       unsigned int i;
+
+       /*
+        * Allocate memory for ports, node pointers (number of nodes +
+        * 1 (guardian), nodes (root + number of ports * 2 (because for
+        * every port there is an endpoint)).
+        */
+       if (check_mul_overflow(sizeof(*swnodes->ports) +
+                              sizeof(*swnodes->nodes) * 2 +
+                              sizeof(*swnodes->nodeptrs) * 2,
+                              port_count, &alloc_size) ||
+           check_add_overflow(sizeof(*swnodes) +
+                              sizeof(*swnodes->nodes) +
+                              sizeof(*swnodes->nodeptrs) * 2,
+                              alloc_size, &alloc_size)) {
+               acpi_handle_info(csi2->handle,
+                                "too many _CRS CSI-2 resource handles (%zu)",
+                                port_count);
+               return;
+       }
+
+       swnodes = kmalloc(alloc_size, GFP_KERNEL);
+       if (!swnodes)
+               return;
+
+       swnodes->ports = (struct acpi_device_software_node_port *)(swnodes + 1);
+       swnodes->nodes = (struct software_node *)(swnodes->ports + port_count);
+       swnodes->nodeptrs = (const struct software_node **)(swnodes->nodes + 1 +
+                               2 * port_count);
+       swnodes->num_ports = port_count;
+
+       for (i = 0; i < 2 * port_count + 1; i++)
+               swnodes->nodeptrs[i] = &swnodes->nodes[i];
+
+       swnodes->nodeptrs[i] = NULL;
+
+       for (i = 0; i < port_count; i++)
+               swnodes->ports[i].port_nr = NO_CSI2_PORT;
+
+       csi2->swnodes = swnodes;
+}
+
+#define ACPI_CRS_CSI2_PHY_TYPE_C       0
+#define ACPI_CRS_CSI2_PHY_TYPE_D       1
+
+static unsigned int next_csi2_port_index(struct acpi_device_software_nodes *swnodes,
+                                        unsigned int port_nr)
+{
+       unsigned int i;
+
+       for (i = 0; i < swnodes->num_ports; i++) {
+               struct acpi_device_software_node_port *port = &swnodes->ports[i];
+
+               if (port->port_nr == port_nr)
+                       return i;
+
+               if (port->port_nr == NO_CSI2_PORT) {
+                       port->port_nr = port_nr;
+                       return i;
+               }
+       }
+
+       return NO_CSI2_PORT;
+}
+
+/* Print graph port name into a buffer, return non-zero on failure. */
+#define GRAPH_PORT_NAME(var, num)                                          \
+       (snprintf((var), sizeof(var), SWNODE_GRAPH_PORT_NAME_FMT, (num)) >= \
+        sizeof(var))
+
+static void extract_crs_csi2_conn_info(acpi_handle local_handle,
+                                      struct acpi_device_software_nodes *local_swnodes,
+                                      struct crs_csi2_connection *conn)
+{
+       struct crs_csi2 *remote_csi2 = acpi_mipi_get_crs_csi2(conn->remote_handle);
+       struct acpi_device_software_nodes *remote_swnodes;
+       struct acpi_device_software_node_port *local_port, *remote_port;
+       struct software_node *local_node, *remote_node;
+       unsigned int local_index, remote_index;
+       unsigned int bus_type;
+
+       /*
+        * If the previous steps have failed to make room for a _CRS CSI-2
+        * representation for the remote end of the given connection, skip it.
+        */
+       if (!remote_csi2)
+               return;
+
+       remote_swnodes = remote_csi2->swnodes;
+       if (!remote_swnodes)
+               return;
+
+       switch (conn->csi2_data.phy_type) {
+       case ACPI_CRS_CSI2_PHY_TYPE_C:
+               bus_type = V4L2_FWNODE_BUS_TYPE_CSI2_CPHY;
+               break;
+
+       case ACPI_CRS_CSI2_PHY_TYPE_D:
+               bus_type = V4L2_FWNODE_BUS_TYPE_CSI2_DPHY;
+               break;
+
+       default:
+               acpi_handle_info(local_handle, "unknown CSI-2 PHY type %u\n",
+                                conn->csi2_data.phy_type);
+               return;
+       }
+
+       local_index = next_csi2_port_index(local_swnodes,
+                                          conn->csi2_data.local_port_instance);
+       if (WARN_ON_ONCE(local_index >= local_swnodes->num_ports))
+               return;
+
+       remote_index = next_csi2_port_index(remote_swnodes,
+                                           conn->csi2_data.resource_source.index);
+       if (WARN_ON_ONCE(remote_index >= remote_swnodes->num_ports))
+               return;
+
+       local_port = &local_swnodes->ports[local_index];
+       local_node = &local_swnodes->nodes[ACPI_DEVICE_SWNODE_EP(local_index)];
+       local_port->crs_csi2_local = true;
+
+       remote_port = &remote_swnodes->ports[remote_index];
+       remote_node = &remote_swnodes->nodes[ACPI_DEVICE_SWNODE_EP(remote_index)];
+
+       local_port->remote_ep[0] = SOFTWARE_NODE_REFERENCE(remote_node);
+       remote_port->remote_ep[0] = SOFTWARE_NODE_REFERENCE(local_node);
+
+       local_port->ep_props[ACPI_DEVICE_SWNODE_EP_REMOTE_EP] =
+                       PROPERTY_ENTRY_REF_ARRAY("remote-endpoint",
+                                                local_port->remote_ep);
+
+       local_port->ep_props[ACPI_DEVICE_SWNODE_EP_BUS_TYPE] =
+                       PROPERTY_ENTRY_U32("bus-type", bus_type);
+
+       local_port->ep_props[ACPI_DEVICE_SWNODE_EP_REG] =
+                       PROPERTY_ENTRY_U32("reg", 0);
+
+       local_port->port_props[ACPI_DEVICE_SWNODE_PORT_REG] =
+                       PROPERTY_ENTRY_U32("reg", conn->csi2_data.local_port_instance);
+
+       if (GRAPH_PORT_NAME(local_port->port_name,
+                           conn->csi2_data.local_port_instance))
+               acpi_handle_info(local_handle, "local port %u name too long",
+                                conn->csi2_data.local_port_instance);
+
+       remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_REMOTE_EP] =
+                       PROPERTY_ENTRY_REF_ARRAY("remote-endpoint",
+                                                remote_port->remote_ep);
+
+       remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_BUS_TYPE] =
+                       PROPERTY_ENTRY_U32("bus-type", bus_type);
+
+       remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_REG] =
+                       PROPERTY_ENTRY_U32("reg", 0);
+
+       remote_port->port_props[ACPI_DEVICE_SWNODE_PORT_REG] =
+                       PROPERTY_ENTRY_U32("reg", conn->csi2_data.resource_source.index);
+
+       if (GRAPH_PORT_NAME(remote_port->port_name,
+                           conn->csi2_data.resource_source.index))
+               acpi_handle_info(local_handle, "remote port %u name too long",
+                                conn->csi2_data.resource_source.index);
+}
+
+static void prepare_crs_csi2_swnodes(struct crs_csi2 *csi2)
+{
+       struct acpi_device_software_nodes *local_swnodes = csi2->swnodes;
+       acpi_handle local_handle = csi2->handle;
+       struct crs_csi2_connection *conn;
+
+       /* Bail out if the allocation of swnodes has failed. */
+       if (!local_swnodes)
+               return;
+
+       list_for_each_entry(conn, &csi2->connections, entry)
+               extract_crs_csi2_conn_info(local_handle, local_swnodes, conn);
+}
+
+/**
+ * acpi_mipi_scan_crs_csi2 - Create ACPI _CRS CSI-2 software nodes
+ *
+ * Note that this function must be called before any struct acpi_device objects
+ * are bound to any ACPI drivers or scan handlers, so it cannot assume the
+ * existence of struct acpi_device objects for every device present in the ACPI
+ * namespace.
+ *
+ * acpi_scan_lock in scan.c must be held when calling this function.
+ */
+void acpi_mipi_scan_crs_csi2(void)
+{
+       struct crs_csi2 *csi2;
+       LIST_HEAD(aux_list);
+
+       /* Count references to each ACPI handle in the CSI-2 connection graph. */
+       list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry) {
+               struct crs_csi2_connection *conn;
+
+               list_for_each_entry(conn, &csi2->connections, entry) {
+                       struct crs_csi2 *remote_csi2;
+
+                       csi2->port_count++;
+
+                       remote_csi2 = acpi_mipi_get_crs_csi2(conn->remote_handle);
+                       if (remote_csi2) {
+                               remote_csi2->port_count++;
+                               continue;
+                       }
+                       /*
+                        * The remote endpoint has no _CRS CSI-2 list entry yet,
+                        * so create one for it and add it to the list.
+                        */
+                       acpi_mipi_add_crs_csi2(conn->remote_handle, &aux_list);
+               }
+       }
+       list_splice(&aux_list, &acpi_mipi_crs_csi2_list);
+
+       /*
+        * Allocate software nodes for representing the CSI-2 information.
+        *
+        * This needs to be done for all of the list entries in one go, because
+        * they may point to each other without restrictions and the next step
+        * relies on the availability of swnodes memory for each list entry.
+        */
+       list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry)
+               alloc_crs_csi2_swnodes(csi2);
+
+       /*
+        * Set up software node properties using data from _CRS CSI-2 resource
+        * descriptors.
+        */
+       list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry)
+               prepare_crs_csi2_swnodes(csi2);
+}
+
+/*
+ * Get the index of the next property in the property array, with a given
+ * maximum value.
+ */
+#define NEXT_PROPERTY(index, max)                      \
+       (WARN_ON((index) > ACPI_DEVICE_SWNODE_##max) ?  \
+        ACPI_DEVICE_SWNODE_##max : (index)++)
+
+static void init_csi2_port_local(struct acpi_device *adev,
+                                struct acpi_device_software_node_port *port,
+                                struct fwnode_handle *port_fwnode,
+                                unsigned int index)
+{
+       acpi_handle handle = acpi_device_handle(adev);
+       unsigned int num_link_freqs;
+       int ret;
+
+       ret = fwnode_property_count_u64(port_fwnode, "mipi-img-link-frequencies");
+       if (ret <= 0)
+               return;
+
+       num_link_freqs = ret;
+       if (num_link_freqs > ACPI_DEVICE_CSI2_DATA_LANES) {
+               acpi_handle_info(handle, "Too many link frequencies: %u\n",
+                                num_link_freqs);
+               num_link_freqs = ACPI_DEVICE_CSI2_DATA_LANES;
+       }
+
+       ret = fwnode_property_read_u64_array(port_fwnode,
+                                            "mipi-img-link-frequencies",
+                                            port->link_frequencies,
+                                            num_link_freqs);
+       if (ret) {
+               acpi_handle_info(handle, "Unable to get link frequencies (%d)\n",
+                                ret);
+               return;
+       }
+
+       port->ep_props[NEXT_PROPERTY(index, EP_LINK_FREQUENCIES)] =
+                               PROPERTY_ENTRY_U64_ARRAY_LEN("link-frequencies",
+                                                            port->link_frequencies,
+                                                            num_link_freqs);
+}
+
+static void init_csi2_port(struct acpi_device *adev,
+                          struct acpi_device_software_nodes *swnodes,
+                          struct acpi_device_software_node_port *port,
+                          struct fwnode_handle *port_fwnode,
+                          unsigned int port_index)
+{
+       unsigned int ep_prop_index = ACPI_DEVICE_SWNODE_EP_CLOCK_LANES;
+       acpi_handle handle = acpi_device_handle(adev);
+       u8 val[ACPI_DEVICE_CSI2_DATA_LANES];
+       int num_lanes = 0;
+       int ret;
+
+       if (GRAPH_PORT_NAME(port->port_name, port->port_nr))
+               return;
+
+       swnodes->nodes[ACPI_DEVICE_SWNODE_PORT(port_index)] =
+                       SOFTWARE_NODE(port->port_name, port->port_props,
+                                     &swnodes->nodes[ACPI_DEVICE_SWNODE_ROOT]);
+
+       ret = fwnode_property_read_u8(port_fwnode, "mipi-img-clock-lane", val);
+       if (!ret)
+               port->ep_props[NEXT_PROPERTY(ep_prop_index, EP_CLOCK_LANES)] =
+                       PROPERTY_ENTRY_U32("clock-lanes", val[0]);
+
+       ret = fwnode_property_count_u8(port_fwnode, "mipi-img-data-lanes");
+       if (ret > 0) {
+               num_lanes = ret;
+
+               if (num_lanes > ACPI_DEVICE_CSI2_DATA_LANES) {
+                       acpi_handle_info(handle, "Too many data lanes: %u\n",
+                                        num_lanes);
+                       num_lanes = ACPI_DEVICE_CSI2_DATA_LANES;
+               }
+
+               ret = fwnode_property_read_u8_array(port_fwnode,
+                                                   "mipi-img-data-lanes",
+                                                   val, num_lanes);
+               if (!ret) {
+                       unsigned int i;
+
+                       for (i = 0; i < num_lanes; i++)
+                               port->data_lanes[i] = val[i];
+
+                       port->ep_props[NEXT_PROPERTY(ep_prop_index, EP_DATA_LANES)] =
+                               PROPERTY_ENTRY_U32_ARRAY_LEN("data-lanes",
+                                                            port->data_lanes,
+                                                            num_lanes);
+               }
+       }
+
+       ret = fwnode_property_count_u8(port_fwnode, "mipi-img-lane-polarities");
+       if (ret < 0) {
+               acpi_handle_debug(handle, "Lane polarity bytes missing\n");
+       } else if (ret * BITS_PER_TYPE(u8) < num_lanes + 1) {
+               acpi_handle_info(handle, "Too few lane polarity bits (%zu vs. %d)\n",
+                                ret * BITS_PER_TYPE(u8), num_lanes + 1);
+       } else {
+               unsigned long mask = 0;
+               int byte_count = ret;
+               unsigned int i;
+
+               /*
+                * The total number of lanes is ACPI_DEVICE_CSI2_DATA_LANES + 1
+                * (data lanes + clock lane).  It is not expected to ever be
+                * greater than the number of bits in an unsigned long
+                * variable, but ensure that this is the case.
+                */
+               BUILD_BUG_ON(BITS_PER_TYPE(unsigned long) <= ACPI_DEVICE_CSI2_DATA_LANES);
+
+               if (byte_count > sizeof(mask)) {
+                       acpi_handle_info(handle, "Too many lane polarities: %d\n",
+                                        byte_count);
+                       byte_count = sizeof(mask);
+               }
+               fwnode_property_read_u8_array(port_fwnode, "mipi-img-lane-polarities",
+                                             val, byte_count);
+
+               for (i = 0; i < byte_count; i++)
+                       mask |= (unsigned long)val[i] << BITS_PER_TYPE(u8) * i;
+
+               for (i = 0; i <= num_lanes; i++)
+                       port->lane_polarities[i] = test_bit(i, &mask);
+
+               port->ep_props[NEXT_PROPERTY(ep_prop_index, EP_LANE_POLARITIES)] =
+                               PROPERTY_ENTRY_U32_ARRAY_LEN("lane-polarities",
+                                                            port->lane_polarities,
+                                                            num_lanes + 1);
+       }
+
+       swnodes->nodes[ACPI_DEVICE_SWNODE_EP(port_index)] =
+               SOFTWARE_NODE("endpoint@0", swnodes->ports[port_index].ep_props,
+                             &swnodes->nodes[ACPI_DEVICE_SWNODE_PORT(port_index)]);
+
+       if (port->crs_csi2_local)
+               init_csi2_port_local(adev, port, port_fwnode, ep_prop_index);
+}
+
+#define MIPI_IMG_PORT_PREFIX "mipi-img-port-"
+
+static struct fwnode_handle *get_mipi_port_handle(struct fwnode_handle *adev_fwnode,
+                                                 unsigned int port_nr)
+{
+       char port_name[sizeof(MIPI_IMG_PORT_PREFIX) + 2];
+
+       if (snprintf(port_name, sizeof(port_name), "%s%u",
+                    MIPI_IMG_PORT_PREFIX, port_nr) >= sizeof(port_name))
+               return NULL;
+
+       return fwnode_get_named_child_node(adev_fwnode, port_name);
+}
+
+static void init_crs_csi2_swnodes(struct crs_csi2 *csi2)
+{
+       struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER };
+       struct acpi_device_software_nodes *swnodes = csi2->swnodes;
+       acpi_handle handle = csi2->handle;
+       unsigned int prop_index = 0;
+       struct fwnode_handle *adev_fwnode;
+       struct acpi_device *adev;
+       acpi_status status;
+       unsigned int i;
+       u32 val;
+       int ret;
+
+       /*
+        * Bail out if the swnodes are not available (either they have not been
+        * allocated or they have been assigned to the device already).
+        */
+       if (!swnodes)
+               return;
+
+       adev = acpi_fetch_acpi_dev(handle);
+       if (!adev)
+               return;
+
+       adev_fwnode = acpi_fwnode_handle(adev);
+
+       /*
+        * If the "rotation" property is not present, but _PLD is there,
+        * evaluate it to get the "rotation" value.
+        */
+       if (!fwnode_property_present(adev_fwnode, "rotation")) {
+               struct acpi_pld_info *pld;
+
+               status = acpi_get_physical_device_location(handle, &pld);
+               if (ACPI_SUCCESS(status)) {
+                       swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_ROTATION)] =
+                                       PROPERTY_ENTRY_U32("rotation",
+                                                          pld->rotation * 45U);
+                       kfree(pld);
+               }
+       }
+
+       if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-clock-frequency", &val))
+               swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_CLOCK_FREQUENCY)] =
+                       PROPERTY_ENTRY_U32("clock-frequency", val);
+
+       if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-led-max-current", &val))
+               swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_LED_MAX_MICROAMP)] =
+                       PROPERTY_ENTRY_U32("led-max-microamp", val);
+
+       if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-flash-max-current", &val))
+               swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_FLASH_MAX_MICROAMP)] =
+                       PROPERTY_ENTRY_U32("flash-max-microamp", val);
+
+       if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-flash-max-timeout-us", &val))
+               swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_FLASH_MAX_TIMEOUT_US)] =
+                       PROPERTY_ENTRY_U32("flash-max-timeout-us", val);
+
+       status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+       if (ACPI_FAILURE(status)) {
+               acpi_handle_info(handle, "Unable to get the path name\n");
+               return;
+       }
+
+       swnodes->nodes[ACPI_DEVICE_SWNODE_ROOT] =
+                       SOFTWARE_NODE(buffer.pointer, swnodes->dev_props, NULL);
+
+       for (i = 0; i < swnodes->num_ports; i++) {
+               struct acpi_device_software_node_port *port = &swnodes->ports[i];
+               struct fwnode_handle *port_fwnode;
+
+               /*
+                * The MIPI DisCo for Imaging specification defines _DSD device
+                * properties for providing CSI-2 port parameters that can be
+                * accessed through the generic device properties framework.  To
+                * access them, it is first necessary to find the data node
+                * representing the port under the given ACPI device object.
+                */
+               port_fwnode = get_mipi_port_handle(adev_fwnode, port->port_nr);
+               if (!port_fwnode) {
+                       acpi_handle_info(handle,
+                                        "MIPI port name too long for port %u\n",
+                                        port->port_nr);
+                       continue;
+               }
+
+               init_csi2_port(adev, swnodes, port, port_fwnode, i);
+
+               fwnode_handle_put(port_fwnode);
+       }
+
+       ret = software_node_register_node_group(swnodes->nodeptrs);
+       if (ret < 0) {
+               acpi_handle_info(handle,
+                                "Unable to register software nodes (%d)\n", ret);
+               return;
+       }
+
+       adev->swnodes = swnodes;
+       adev_fwnode->secondary = software_node_fwnode(swnodes->nodes);
+
+       /*
+        * Prevents the swnodes from this csi2 entry from being assigned again
+        * or freed prematurely.
+        */
+       csi2->swnodes = NULL;
+}
+
+/**
+ * acpi_mipi_init_crs_csi2_swnodes - Initialize _CRS CSI-2 software nodes
+ *
+ * Use MIPI DisCo for Imaging device properties to finalize the initialization
+ * of CSI-2 software nodes for all ACPI device objects that have been already
+ * enumerated.
+ */
+void acpi_mipi_init_crs_csi2_swnodes(void)
+{
+       struct crs_csi2 *csi2, *csi2_tmp;
+
+       list_for_each_entry_safe(csi2, csi2_tmp, &acpi_mipi_crs_csi2_list, entry)
+               init_crs_csi2_swnodes(csi2);
+}
+
+/**
+ * acpi_mipi_crs_csi2_cleanup - Free _CRS CSI-2 temporary data
+ */
+void acpi_mipi_crs_csi2_cleanup(void)
+{
+       struct crs_csi2 *csi2, *csi2_tmp;
+
+       list_for_each_entry_safe(csi2, csi2_tmp, &acpi_mipi_crs_csi2_list, entry)
+               acpi_mipi_del_crs_csi2(csi2);
+}
index 12f330b0eac01a3653906889b3107c923917acb3..0214518fc582f47b6ed43faa7154ea60a9d8ae48 100644 (file)
@@ -67,9 +67,9 @@ int acpi_map_pxm_to_node(int pxm)
        node = pxm_to_node_map[pxm];
 
        if (node == NUMA_NO_NODE) {
-               if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
-                       return NUMA_NO_NODE;
                node = first_unset_node(nodes_found_map);
+               if (node >= MAX_NUMNODES)
+                       return NUMA_NO_NODE;
                __acpi_map_pxm_to_node(pxm, node);
                node_set(node, nodes_found_map);
        }
@@ -183,7 +183,7 @@ static int __init slit_valid(struct acpi_table_slit *slit)
        int i, j;
        int d = slit->locality_count;
        for (i = 0; i < d; i++) {
-               for (j = 0; j < d; j++)  {
+               for (j = 0; j < d; j++) {
                        u8 val = slit->entry[d*i + j];
                        if (i == j) {
                                if (val != LOCAL_DISTANCE)
@@ -430,7 +430,7 @@ acpi_parse_gi_affinity(union acpi_subtable_headers *header,
                return -EINVAL;
 
        node = acpi_map_pxm_to_node(gi_affinity->proximity_domain);
-       if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) {
+       if (node == NUMA_NO_NODE) {
                pr_err("SRAT: Too many proximity domains.\n");
                return -EINVAL;
        }
@@ -532,7 +532,7 @@ int __init acpi_numa_init(void)
         */
 
        /* fake_pxm is the next unused PXM value after SRAT parsing */
-       for (i = 0, fake_pxm = -1; i < MAX_NUMNODES - 1; i++) {
+       for (i = 0, fake_pxm = -1; i < MAX_NUMNODES; i++) {
                if (node_to_pxm_map[i] > fake_pxm)
                        fake_pxm = node_to_pxm_map[i];
        }
index c09cc3c68633daa93b1f51d680dd81dd4491b35f..70af3fbbebe54c459ad5e58e6f45c0f468db8496 100644 (file)
@@ -544,11 +544,7 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
 
 static irqreturn_t acpi_irq(int irq, void *dev_id)
 {
-       u32 handled;
-
-       handled = (*acpi_irq_handler) (acpi_irq_context);
-
-       if (handled) {
+       if ((*acpi_irq_handler)(acpi_irq_context)) {
                acpi_irq_handled++;
                return IRQ_HANDLED;
        } else {
@@ -582,7 +578,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
 
        acpi_irq_handler = handler;
        acpi_irq_context = context;
-       if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
+       if (request_threaded_irq(irq, NULL, acpi_irq, IRQF_SHARED | IRQF_ONESHOT,
+                                "acpi", acpi_irq)) {
                pr_err("SCI (IRQ%d) allocation failed\n", irq);
                acpi_irq_handler = NULL;
                return AE_NOT_ACQUIRED;
@@ -1063,9 +1060,7 @@ int __init acpi_debugger_init(void)
 acpi_status acpi_os_execute(acpi_execute_type type,
                            acpi_osd_exec_callback function, void *context)
 {
-       acpi_status status = AE_OK;
        struct acpi_os_dpc *dpc;
-       struct workqueue_struct *queue;
        int ret;
 
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
@@ -1076,9 +1071,9 @@ acpi_status acpi_os_execute(acpi_execute_type type,
                ret = acpi_debugger_create_thread(function, context);
                if (ret) {
                        pr_err("Kernel thread creation failed\n");
-                       status = AE_ERROR;
+                       return AE_ERROR;
                }
-               goto out_thread;
+               return AE_OK;
        }
 
        /*
@@ -1096,43 +1091,41 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 
        dpc->function = function;
        dpc->context = context;
+       INIT_WORK(&dpc->work, acpi_os_execute_deferred);
 
        /*
         * To prevent lockdep from complaining unnecessarily, make sure that
         * there is a different static lockdep key for each workqueue by using
         * INIT_WORK() for each of them separately.
         */
-       if (type == OSL_NOTIFY_HANDLER) {
-               queue = kacpi_notify_wq;
-               INIT_WORK(&dpc->work, acpi_os_execute_deferred);
-       } else if (type == OSL_GPE_HANDLER) {
-               queue = kacpid_wq;
-               INIT_WORK(&dpc->work, acpi_os_execute_deferred);
-       } else {
+       switch (type) {
+       case OSL_NOTIFY_HANDLER:
+               ret = queue_work(kacpi_notify_wq, &dpc->work);
+               break;
+       case OSL_GPE_HANDLER:
+               /*
+                * On some machines, a software-initiated SMI causes corruption
+                * unless the SMI runs on CPU 0.  An SMI can be initiated by
+                * any AML, but typically it's done in GPE-related methods that
+                * are run via workqueues, so we can avoid the known corruption
+                * cases by always queueing on CPU 0.
+                */
+               ret = queue_work_on(0, kacpid_wq, &dpc->work);
+               break;
+       default:
                pr_err("Unsupported os_execute type %d.\n", type);
-               status = AE_ERROR;
+               goto err;
        }
-
-       if (ACPI_FAILURE(status))
-               goto err_workqueue;
-
-       /*
-        * On some machines, a software-initiated SMI causes corruption unless
-        * the SMI runs on CPU 0.  An SMI can be initiated by any AML, but
-        * typically it's done in GPE-related methods that are run via
-        * workqueues, so we can avoid the known corruption cases by always
-        * queueing on CPU 0.
-        */
-       ret = queue_work_on(0, queue, &dpc->work);
        if (!ret) {
                pr_err("Unable to queue work\n");
-               status = AE_ERROR;
+               goto err;
        }
-err_workqueue:
-       if (ACPI_FAILURE(status))
-               kfree(dpc);
-out_thread:
-       return status;
+
+       return AE_OK;
+
+err:
+       kfree(dpc);
+       return AE_ERROR;
 }
 EXPORT_SYMBOL(acpi_os_execute);
 
@@ -1522,20 +1515,18 @@ void acpi_os_delete_lock(acpi_spinlock handle)
 acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
        __acquires(lockp)
 {
-       acpi_cpu_flags flags;
-
-       spin_lock_irqsave(lockp, flags);
-       return flags;
+       spin_lock(lockp);
+       return 0;
 }
 
 /*
  * Release a spinlock. See above.
  */
 
-void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
+void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags not_used)
        __releases(lockp)
 {
-       spin_unlock_irqrestore(lockp, flags);
+       spin_unlock(lockp);
 }
 
 #ifndef ACPI_USE_LOCAL_CACHE
@@ -1672,7 +1663,7 @@ acpi_status __init acpi_os_initialize(void)
 acpi_status __init acpi_os_initialize1(void)
 {
        kacpid_wq = alloc_workqueue("kacpid", 0, 1);
-       kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
+       kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 0);
        kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
        BUG_ON(!kacpid_wq);
        BUG_ON(!kacpi_notify_wq);
index b7c6287eccca28c17908646a52af083d9e31a5dd..1219adb11ab927cae52b8d106a09c2cb0f17f390 100644 (file)
@@ -17,6 +17,8 @@
 #include <acpi/processor.h>
 #include <linux/uaccess.h>
 
+#include "internal.h"
+
 #ifdef CONFIG_CPU_FREQ
 
 /* If a passive cooling situation is detected, primarily CPUfreq is used, as it
  */
 
 #define CPUFREQ_THERMAL_MIN_STEP 0
-#define CPUFREQ_THERMAL_MAX_STEP 3
 
-static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);
+static int cpufreq_thermal_max_step __read_mostly = 3;
+
+/*
+ * Minimum throttle percentage for processor_thermal cooling device.
+ * The processor_thermal driver uses it to calculate the percentage amount by
+ * which cpu frequency must be reduced for each cooling state. This is also used
+ * to calculate the maximum number of throttling steps or cooling states.
+ */
+static int cpufreq_thermal_reduction_pctg __read_mostly = 20;
 
-#define reduction_pctg(cpu) \
-       per_cpu(cpufreq_thermal_reduction_pctg, phys_package_first_cpu(cpu))
+static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_step);
+
+#define reduction_step(cpu) \
+       per_cpu(cpufreq_thermal_reduction_step, phys_package_first_cpu(cpu))
 
 /*
  * Emulate "per package data" using per cpu data (which should really be
@@ -71,7 +82,7 @@ static int cpufreq_get_max_state(unsigned int cpu)
        if (!cpu_has_cpufreq(cpu))
                return 0;
 
-       return CPUFREQ_THERMAL_MAX_STEP;
+       return cpufreq_thermal_max_step;
 }
 
 static int cpufreq_get_cur_state(unsigned int cpu)
@@ -79,7 +90,7 @@ static int cpufreq_get_cur_state(unsigned int cpu)
        if (!cpu_has_cpufreq(cpu))
                return 0;
 
-       return reduction_pctg(cpu);
+       return reduction_step(cpu);
 }
 
 static int cpufreq_set_cur_state(unsigned int cpu, int state)
@@ -92,7 +103,7 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
        if (!cpu_has_cpufreq(cpu))
                return 0;
 
-       reduction_pctg(cpu) = state;
+       reduction_step(cpu) = state;
 
        /*
         * Update all the CPUs in the same package because they all
@@ -113,7 +124,8 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
                if (!policy)
                        return -EINVAL;
 
-               max_freq = (policy->cpuinfo.max_freq * (100 - reduction_pctg(i) * 20)) / 100;
+               max_freq = (policy->cpuinfo.max_freq *
+                           (100 - reduction_step(i) * cpufreq_thermal_reduction_pctg)) / 100;
 
                cpufreq_cpu_put(policy);
 
@@ -126,10 +138,29 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
        return 0;
 }
 
+static void acpi_thermal_cpufreq_config(void)
+{
+       int cpufreq_pctg = acpi_arch_thermal_cpufreq_pctg();
+
+       if (!cpufreq_pctg)
+               return;
+
+       cpufreq_thermal_reduction_pctg = cpufreq_pctg;
+
+       /*
+        * Derive the MAX_STEP from minimum throttle percentage so that the reduction
+        * percentage doesn't end up becoming negative. Also, cap the MAX_STEP so that
+        * the CPU performance doesn't become 0.
+        */
+       cpufreq_thermal_max_step = (100 / cpufreq_pctg) - 2;
+}
+
 void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy)
 {
        unsigned int cpu;
 
+       acpi_thermal_cpufreq_config();
+
        for_each_cpu(cpu, policy->related_cpus) {
                struct acpi_processor *pr = per_cpu(processors, cpu);
                int ret;
@@ -190,7 +221,7 @@ static int acpi_processor_max_state(struct acpi_processor *pr)
 
        /*
         * There exists four states according to
-        * cpufreq_thermal_reduction_pctg. 0, 1, 2, 3
+        * cpufreq_thermal_reduction_step. 0, 1, 2, 3
         */
        max_state += cpufreq_get_max_state(pr->id);
        if (pr->flags.throttling)
index 6979a3f9f90a841529ffccc6ef32c20bdcaa824b..07d76fb740b6d6e73e119d54c35089cf8b4cb173 100644 (file)
@@ -2,14 +2,17 @@
 /*
  * ACPI device specific properties support.
  *
- * Copyright (C) 2014, Intel Corporation
+ * Copyright (C) 2014 - 2023, Intel Corporation
  * All rights reserved.
  *
  * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
  *          Darren Hart <dvhart@linux.intel.com>
  *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *          Sakari Ailus <sakari.ailus@linux.intel.com>
  */
 
+#define pr_fmt(fmt) "ACPI: " fmt
+
 #include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/export.h>
@@ -800,28 +803,16 @@ static int acpi_get_ref_args(struct fwnode_reference_args *args,
 {
        u32 nargs = 0, i;
 
-       /*
-        * Find the referred data extension node under the
-        * referred device node.
-        */
-       for (; *element < end && (*element)->type == ACPI_TYPE_STRING;
-            (*element)++) {
-               const char *child_name = (*element)->string.pointer;
-
-               ref_fwnode = acpi_fwnode_get_named_child_node(ref_fwnode, child_name);
-               if (!ref_fwnode)
-                       return -EINVAL;
-       }
-
        /*
         * Assume the following integer elements are all args. Stop counting on
-        * the first reference or end of the package arguments. In case of
-        * neither reference, nor integer, return an error, we can't parse it.
+        * the first reference (possibly represented as a string) or end of the
+        * package arguments. In case of neither reference, nor integer, return
+        * an error, we can't parse it.
         */
        for (i = 0; (*element) + i < end && i < num_args; i++) {
                acpi_object_type type = (*element)[i].type;
 
-               if (type == ACPI_TYPE_LOCAL_REFERENCE)
+               if (type == ACPI_TYPE_LOCAL_REFERENCE || type == ACPI_TYPE_STRING)
                        break;
 
                if (type == ACPI_TYPE_INTEGER)
@@ -845,6 +836,44 @@ static int acpi_get_ref_args(struct fwnode_reference_args *args,
        return 0;
 }
 
+static struct fwnode_handle *acpi_parse_string_ref(const struct fwnode_handle *fwnode,
+                                                  const char *refstring)
+{
+       acpi_handle scope, handle;
+       struct acpi_data_node *dn;
+       struct acpi_device *device;
+       acpi_status status;
+
+       if (is_acpi_device_node(fwnode)) {
+               scope = to_acpi_device_node(fwnode)->handle;
+       } else if (is_acpi_data_node(fwnode)) {
+               scope = to_acpi_data_node(fwnode)->handle;
+       } else {
+               pr_debug("Bad node type for node %pfw\n", fwnode);
+               return NULL;
+       }
+
+       status = acpi_get_handle(scope, refstring, &handle);
+       if (ACPI_FAILURE(status)) {
+               acpi_handle_debug(scope, "Unable to get an ACPI handle for %s\n",
+                                 refstring);
+               return NULL;
+       }
+
+       device = acpi_fetch_acpi_dev(handle);
+       if (device)
+               return acpi_fwnode_handle(device);
+
+       status = acpi_get_data_full(handle, acpi_nondev_subnode_tag,
+                                   (void **)&dn, NULL);
+       if (ACPI_FAILURE(status) || !dn) {
+               acpi_handle_debug(handle, "Subnode not found\n");
+               return NULL;
+       }
+
+       return &dn->fwnode;
+}
+
 /**
  * __acpi_node_get_property_reference - returns handle to the referenced object
  * @fwnode: Firmware node to get the property from
@@ -887,6 +916,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
        const union acpi_object *element, *end;
        const union acpi_object *obj;
        const struct acpi_device_data *data;
+       struct fwnode_handle *ref_fwnode;
        struct acpi_device *device;
        int ret, idx = 0;
 
@@ -910,16 +940,30 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
 
                args->fwnode = acpi_fwnode_handle(device);
                args->nargs = 0;
+
+               return 0;
+       case ACPI_TYPE_STRING:
+               if (index)
+                       return -ENOENT;
+
+               ref_fwnode = acpi_parse_string_ref(fwnode, obj->string.pointer);
+               if (!ref_fwnode)
+                       return -EINVAL;
+
+               args->fwnode = ref_fwnode;
+               args->nargs = 0;
+
                return 0;
        case ACPI_TYPE_PACKAGE:
                /*
                 * If it is not a single reference, then it is a package of
-                * references followed by number of ints as follows:
+                * references, followed by number of ints as follows:
                 *
                 *  Package () { REF, INT, REF, INT, INT }
                 *
-                * The index argument is then used to determine which reference
-                * the caller wants (along with the arguments).
+                * Here, REF may be either a local reference or a string. The
+                * index argument is then used to determine which reference the
+                * caller wants (along with the arguments).
                 */
                break;
        default:
@@ -950,6 +994,24 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
                        if (idx == index)
                                return 0;
 
+                       break;
+               case ACPI_TYPE_STRING:
+                       ref_fwnode = acpi_parse_string_ref(fwnode,
+                                                          element->string.pointer);
+                       if (!ref_fwnode)
+                               return -EINVAL;
+
+                       element++;
+
+                       ret = acpi_get_ref_args(idx == index ? args : NULL,
+                                               ref_fwnode, &element, end,
+                                               num_args);
+                       if (ret < 0)
+                               return ret;
+
+                       if (idx == index)
+                               return 0;
+
                        break;
                case ACPI_TYPE_INTEGER:
                        if (idx == index)
index 02bb2cce423f47d6bc1a1c4e6563a6de6369514d..950d3b02a2a9472acc4f2cc7a5a914a5e00bc557 100644 (file)
@@ -1981,10 +1981,9 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
        }
 }
 
-static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
+static u32 acpi_scan_check_dep(acpi_handle handle)
 {
        struct acpi_handle_list dep_devices;
-       acpi_status status;
        u32 count;
        int i;
 
@@ -1994,12 +1993,10 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
         * 2. ACPI nodes describing USB ports.
         * Still, checking for _HID catches more then just these cases ...
         */
-       if (!check_dep || !acpi_has_method(handle, "_DEP") ||
-           !acpi_has_method(handle, "_HID"))
+       if (!acpi_has_method(handle, "_DEP") || !acpi_has_method(handle, "_HID"))
                return 0;
 
-       status = acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices);
-       if (ACPI_FAILURE(status)) {
+       if (!acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices)) {
                acpi_handle_debug(handle, "Failed to evaluate _DEP.\n");
                return 0;
        }
@@ -2008,6 +2005,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
                struct acpi_device_info *info;
                struct acpi_dep_data *dep;
                bool skip, honor_dep;
+               acpi_status status;
 
                status = acpi_get_object_info(dep_devices.handles[i], &info);
                if (ACPI_FAILURE(status)) {
@@ -2041,7 +2039,13 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
        return count;
 }
 
-static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
+static acpi_status acpi_scan_check_crs_csi2_cb(acpi_handle handle, u32 a, void *b, void **c)
+{
+       acpi_mipi_check_crs_csi2(handle);
+       return AE_OK;
+}
+
+static acpi_status acpi_bus_check_add(acpi_handle handle, bool first_pass,
                                      struct acpi_device **adev_p)
 {
        struct acpi_device *device = acpi_fetch_acpi_dev(handle);
@@ -2059,9 +2063,25 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
                if (acpi_device_should_be_hidden(handle))
                        return AE_OK;
 
-               /* Bail out if there are dependencies. */
-               if (acpi_scan_check_dep(handle, check_dep) > 0)
-                       return AE_CTRL_DEPTH;
+               if (first_pass) {
+                       acpi_mipi_check_crs_csi2(handle);
+
+                       /* Bail out if there are dependencies. */
+                       if (acpi_scan_check_dep(handle) > 0) {
+                               /*
+                                * The entire CSI-2 connection graph needs to be
+                                * extracted before any drivers or scan handlers
+                                * are bound to struct device objects, so scan
+                                * _CRS CSI-2 resource descriptors for all
+                                * devices below the current handle.
+                                */
+                               acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+                                                   ACPI_UINT32_MAX,
+                                                   acpi_scan_check_crs_csi2_cb,
+                                                   NULL, NULL, NULL);
+                               return AE_CTRL_DEPTH;
+                       }
+               }
 
                fallthrough;
        case ACPI_TYPE_ANY:     /* for ACPI_ROOT_OBJECT */
@@ -2084,10 +2104,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
        }
 
        /*
-        * If check_dep is true at this point, the device has no dependencies,
+        * If first_pass is true at this point, the device has no dependencies,
         * or the creation of the device object would have been postponed above.
         */
-       acpi_add_single_object(&device, handle, type, !check_dep);
+       acpi_add_single_object(&device, handle, type, !first_pass);
        if (!device)
                return AE_CTRL_DEPTH;
 
@@ -2431,6 +2451,13 @@ static void acpi_scan_postponed_branch(acpi_handle handle)
 
        acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
                            acpi_bus_check_add_2, NULL, NULL, (void **)&adev);
+
+       /*
+        * Populate the ACPI _CRS CSI-2 software nodes for the ACPI devices that
+        * have been added above.
+        */
+       acpi_mipi_init_crs_csi2_swnodes();
+
        acpi_bus_attach(adev, NULL);
 }
 
@@ -2499,12 +2526,22 @@ int acpi_bus_scan(acpi_handle handle)
        if (!device)
                return -ENODEV;
 
+       /*
+        * Set up ACPI _CRS CSI-2 software nodes using information extracted
+        * from the _CRS CSI-2 resource descriptors during the ACPI namespace
+        * walk above and MIPI DisCo for Imaging device properties.
+        */
+       acpi_mipi_scan_crs_csi2();
+       acpi_mipi_init_crs_csi2_swnodes();
+
        acpi_bus_attach(device, (void *)true);
 
        /* Pass 2: Enumerate all of the remaining devices. */
 
        acpi_scan_postponed();
 
+       acpi_mipi_crs_csi2_cleanup();
+
        return 0;
 }
 EXPORT_SYMBOL(acpi_bus_scan);
index f74d81abdbfc073aa68273e786a11cabfa826f2e..1208ab0ed45fb6570e38e683aad8e1e8d0caffe3 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/uaccess.h>
 #include <linux/units.h>
 
+#include "internal.h"
+
 #define ACPI_THERMAL_CLASS             "thermal_zone"
 #define ACPI_THERMAL_DEVICE_NAME       "Thermal Zone"
 #define ACPI_THERMAL_NOTIFY_TEMPERATURE        0x80
@@ -90,7 +92,7 @@ struct acpi_thermal_passive {
        struct acpi_thermal_trip trip;
        unsigned long tc1;
        unsigned long tc2;
-       unsigned long tsp;
+       unsigned long delay;
 };
 
 struct acpi_thermal_active {
@@ -188,24 +190,19 @@ static int active_trip_index(struct acpi_thermal *tz,
 
 static long get_passive_temp(struct acpi_thermal *tz)
 {
-       unsigned long long tmp;
-       acpi_status status;
+       int temp;
 
-       status = acpi_evaluate_integer(tz->device->handle, "_PSV", NULL, &tmp);
-       if (ACPI_FAILURE(status))
+       if (acpi_passive_trip_temp(tz->device, &temp))
                return THERMAL_TEMP_INVALID;
 
-       return tmp;
+       return temp;
 }
 
 static long get_active_temp(struct acpi_thermal *tz, int index)
 {
-       char method[] = { '_', 'A', 'C', '0' + index, '\0' };
-       unsigned long long tmp;
-       acpi_status status;
+       int temp;
 
-       status = acpi_evaluate_integer(tz->device->handle, method, NULL, &tmp);
-       if (ACPI_FAILURE(status))
+       if (acpi_active_trip_temp(tz->device, index, &temp))
                return THERMAL_TEMP_INVALID;
 
        /*
@@ -215,10 +212,10 @@ static long get_active_temp(struct acpi_thermal *tz, int index)
        if (act > 0) {
                unsigned long long override = celsius_to_deci_kelvin(act);
 
-               if (tmp > override)
-                       tmp = override;
+               if (temp > override)
+                       return override;
        }
-       return tmp;
+       return temp;
 }
 
 static void acpi_thermal_update_trip(struct acpi_thermal *tz,
@@ -247,7 +244,6 @@ static bool update_trip_devices(struct acpi_thermal *tz,
 {
        struct acpi_handle_list devices = { 0 };
        char method[] = "_PSL";
-       acpi_status status;
 
        if (index != ACPI_THERMAL_TRIP_PASSIVE) {
                method[1] = 'A';
@@ -255,8 +251,7 @@ static bool update_trip_devices(struct acpi_thermal *tz,
                method[3] = '0' + index;
        }
 
-       status = acpi_evaluate_reference(tz->device->handle, method, NULL, &devices);
-       if (ACPI_FAILURE(status)) {
+       if (!acpi_evaluate_reference(tz->device->handle, method, NULL, &devices)) {
                acpi_handle_info(tz->device->handle, "%s evaluation failure\n", method);
                return false;
        }
@@ -339,13 +334,12 @@ static void acpi_thermal_trips_update(struct acpi_thermal *tz, u32 event)
                                        dev_name(&adev->dev), event, 0);
 }
 
-static long acpi_thermal_get_critical_trip(struct acpi_thermal *tz)
+static int acpi_thermal_get_critical_trip(struct acpi_thermal *tz)
 {
-       unsigned long long tmp;
-       acpi_status status;
+       int temp;
 
        if (crt > 0) {
-               tmp = celsius_to_deci_kelvin(crt);
+               temp = celsius_to_deci_kelvin(crt);
                goto set;
        }
        if (crt == -1) {
@@ -353,38 +347,34 @@ static long acpi_thermal_get_critical_trip(struct acpi_thermal *tz)
                return THERMAL_TEMP_INVALID;
        }
 
-       status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, &tmp);
-       if (ACPI_FAILURE(status)) {
-               acpi_handle_debug(tz->device->handle, "No critical threshold\n");
+       if (acpi_critical_trip_temp(tz->device, &temp))
                return THERMAL_TEMP_INVALID;
-       }
-       if (tmp <= 2732) {
+
+       if (temp <= 2732) {
                /*
                 * Below zero (Celsius) values clearly aren't right for sure,
                 * so discard them as invalid.
                 */
-               pr_info(FW_BUG "Invalid critical threshold (%llu)\n", tmp);
+               pr_info(FW_BUG "Invalid critical threshold (%d)\n", temp);
                return THERMAL_TEMP_INVALID;
        }
 
 set:
-       acpi_handle_debug(tz->device->handle, "Critical threshold [%llu]\n", tmp);
-       return tmp;
+       acpi_handle_debug(tz->device->handle, "Critical threshold [%d]\n", temp);
+       return temp;
 }
 
-static long acpi_thermal_get_hot_trip(struct acpi_thermal *tz)
+static int acpi_thermal_get_hot_trip(struct acpi_thermal *tz)
 {
-       unsigned long long tmp;
-       acpi_status status;
+       int temp;
 
-       status = acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, &tmp);
-       if (ACPI_FAILURE(status)) {
+       if (acpi_hot_trip_temp(tz->device, &temp) || temp == THERMAL_TEMP_INVALID) {
                acpi_handle_debug(tz->device->handle, "No hot threshold\n");
                return THERMAL_TEMP_INVALID;
        }
 
-       acpi_handle_debug(tz->device->handle, "Hot threshold [%llu]\n", tmp);
-       return tmp;
+       acpi_handle_debug(tz->device->handle, "Hot threshold [%d]\n", temp);
+       return temp;
 }
 
 static bool passive_trip_params_init(struct acpi_thermal *tz)
@@ -404,11 +394,17 @@ static bool passive_trip_params_init(struct acpi_thermal *tz)
 
        tz->trips.passive.tc2 = tmp;
 
+       status = acpi_evaluate_integer(tz->device->handle, "_TFP", NULL, &tmp);
+       if (ACPI_SUCCESS(status)) {
+               tz->trips.passive.delay = tmp;
+               return true;
+       }
+
        status = acpi_evaluate_integer(tz->device->handle, "_TSP", NULL, &tmp);
        if (ACPI_FAILURE(status))
                return false;
 
-       tz->trips.passive.tsp = tmp;
+       tz->trips.passive.delay = tmp * 100;
 
        return true;
 }
@@ -904,7 +900,7 @@ static int acpi_thermal_add(struct acpi_device *device)
 
        acpi_trip = &tz->trips.passive.trip;
        if (acpi_thermal_trip_valid(acpi_trip)) {
-               passive_delay = tz->trips.passive.tsp * 100;
+               passive_delay = tz->trips.passive.delay;
 
                trip->type = THERMAL_TRIP_PASSIVE;
                trip->temperature = acpi_thermal_temp(tz, acpi_trip->temp_dk);
@@ -1142,6 +1138,7 @@ static void __exit acpi_thermal_exit(void)
 module_init(acpi_thermal_init);
 module_exit(acpi_thermal_exit);
 
+MODULE_IMPORT_NS(ACPI_THERMAL);
 MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/thermal_lib.c b/drivers/acpi/thermal_lib.c
new file mode 100644 (file)
index 0000000..4e0519c
--- /dev/null
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 Linaro Limited
+ * Copyright 2023 Intel Corporation
+ *
+ * Library routines for retrieving trip point temperature values from the
+ * platform firmware via ACPI.
+ */
+#include <linux/acpi.h>
+#include <linux/units.h>
+#include <linux/thermal.h>
+#include "internal.h"
+
+/*
+ * Minimum temperature for full military grade is 218°K (-55°C) and
+ * max temperature is 448°K (175°C). We can consider those values as
+ * the boundaries for the [trips] temperature returned by the
+ * firmware. Any values out of these boundaries may be considered
+ * bogus and we can assume the firmware has no data to provide.
+ */
+#define TEMP_MIN_DECIK 2180ULL
+#define TEMP_MAX_DECIK 4480ULL
+
+static int acpi_trip_temp(struct acpi_device *adev, char *obj_name,
+                         int *ret_temp)
+{
+       unsigned long long temp;
+       acpi_status status;
+
+       status = acpi_evaluate_integer(adev->handle, obj_name, NULL, &temp);
+       if (ACPI_FAILURE(status)) {
+               acpi_handle_debug(adev->handle, "%s evaluation failed\n", obj_name);
+               return -ENODATA;
+       }
+
+       if (temp >= TEMP_MIN_DECIK && temp <= TEMP_MAX_DECIK) {
+               *ret_temp = temp;
+       } else {
+               acpi_handle_debug(adev->handle, "%s result %llu out of range\n",
+                                 obj_name, temp);
+               *ret_temp = THERMAL_TEMP_INVALID;
+       }
+
+       return 0;
+}
+
+int acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp)
+{
+       char obj_name[] = {'_', 'A', 'C', '0' + id, '\0'};
+
+       if (id < 0 || id > 9)
+               return -EINVAL;
+
+       return acpi_trip_temp(adev, obj_name, ret_temp);
+}
+EXPORT_SYMBOL_NS_GPL(acpi_active_trip_temp, ACPI_THERMAL);
+
+int acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+       return acpi_trip_temp(adev, "_PSV", ret_temp);
+}
+EXPORT_SYMBOL_NS_GPL(acpi_passive_trip_temp, ACPI_THERMAL);
+
+int acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+       return acpi_trip_temp(adev, "_HOT", ret_temp);
+}
+EXPORT_SYMBOL_NS_GPL(acpi_hot_trip_temp, ACPI_THERMAL);
+
+int acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+       return acpi_trip_temp(adev, "_CRT", ret_temp);
+}
+EXPORT_SYMBOL_NS_GPL(acpi_critical_trip_temp, ACPI_THERMAL);
+
+static int thermal_temp(int error, int temp_decik, int *ret_temp)
+{
+       if (error)
+               return error;
+
+       if (temp_decik == THERMAL_TEMP_INVALID)
+               *ret_temp = THERMAL_TEMP_INVALID;
+       else
+               *ret_temp = deci_kelvin_to_millicelsius(temp_decik);
+
+       return 0;
+}
+
+/**
+ * thermal_acpi_active_trip_temp - Retrieve active trip point temperature
+ * @adev: Target thermal zone ACPI device object.
+ * @id: Active cooling level (0 - 9).
+ * @ret_temp: Address to store the retrieved temperature value on success.
+ *
+ * Evaluate the _ACx object for the thermal zone represented by @adev to obtain
+ * the temperature of the active cooling trip point corresponding to the active
+ * cooling level given by @id.
+ *
+ * Return 0 on success or a negative error value on failure.
+ */
+int thermal_acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp)
+{
+       int temp_decik;
+       int ret = acpi_active_trip_temp(adev, id, &temp_decik);
+
+       return thermal_temp(ret, temp_decik, ret_temp);
+}
+EXPORT_SYMBOL_GPL(thermal_acpi_active_trip_temp);
+
+/**
+ * thermal_acpi_passive_trip_temp - Retrieve passive trip point temperature
+ * @adev: Target thermal zone ACPI device object.
+ * @ret_temp: Address to store the retrieved temperature value on success.
+ *
+ * Evaluate the _PSV object for the thermal zone represented by @adev to obtain
+ * the temperature of the passive cooling trip point.
+ *
+ * Return 0 on success or -ENODATA on failure.
+ */
+int thermal_acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+       int temp_decik;
+       int ret = acpi_passive_trip_temp(adev, &temp_decik);
+
+       return thermal_temp(ret, temp_decik, ret_temp);
+}
+EXPORT_SYMBOL_GPL(thermal_acpi_passive_trip_temp);
+
+/**
+ * thermal_acpi_hot_trip_temp - Retrieve hot trip point temperature
+ * @adev: Target thermal zone ACPI device object.
+ * @ret_temp: Address to store the retrieved temperature value on success.
+ *
+ * Evaluate the _HOT object for the thermal zone represented by @adev to obtain
+ * the temperature of the trip point at which the system is expected to be put
+ * into the S4 sleep state.
+ *
+ * Return 0 on success or -ENODATA on failure.
+ */
+int thermal_acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+       int temp_decik;
+       int ret = acpi_hot_trip_temp(adev, &temp_decik);
+
+       return thermal_temp(ret, temp_decik, ret_temp);
+}
+EXPORT_SYMBOL_GPL(thermal_acpi_hot_trip_temp);
+
+/**
+ * thermal_acpi_critical_trip_temp - Retrieve critical trip point temperature
+ * @adev: Target thermal zone ACPI device object.
+ * @ret_temp: Address to store the retrieved temperature value on success.
+ *
+ * Evaluate the _CRT object for the thermal zone represented by @adev to obtain
+ * the temperature of the critical cooling trip point.
+ *
+ * Return 0 on success or -ENODATA on failure.
+ */
+int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+       int temp_decik;
+       int ret = acpi_critical_trip_temp(adev, &temp_decik);
+
+       return thermal_temp(ret, temp_decik, ret_temp);
+}
+EXPORT_SYMBOL_GPL(thermal_acpi_critical_trip_temp);
index 62944e35fcee2980446a743c0099c8bfc26cbf6e..abac5cc254774d2eb5d593068bb1bada6a2fde17 100644 (file)
@@ -329,21 +329,18 @@ const char *acpi_get_subsystem_id(acpi_handle handle)
 }
 EXPORT_SYMBOL_GPL(acpi_get_subsystem_id);
 
-acpi_status
-acpi_evaluate_reference(acpi_handle handle,
-                       acpi_string pathname,
-                       struct acpi_object_list *arguments,
-                       struct acpi_handle_list *list)
+bool acpi_evaluate_reference(acpi_handle handle, acpi_string pathname,
+                            struct acpi_object_list *arguments,
+                            struct acpi_handle_list *list)
 {
-       acpi_status status = AE_OK;
-       union acpi_object *package = NULL;
-       union acpi_object *element = NULL;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       u32 i = 0;
-
+       union acpi_object *package;
+       acpi_status status;
+       bool ret = false;
+       u32 i;
 
        if (!list)
-               return AE_BAD_PARAMETER;
+               return false;
 
        /* Evaluate object. */
 
@@ -353,62 +350,47 @@ acpi_evaluate_reference(acpi_handle handle,
 
        package = buffer.pointer;
 
-       if ((buffer.length == 0) || !package) {
-               status = AE_BAD_DATA;
-               acpi_util_eval_error(handle, pathname, status);
-               goto end;
-       }
-       if (package->type != ACPI_TYPE_PACKAGE) {
-               status = AE_BAD_DATA;
-               acpi_util_eval_error(handle, pathname, status);
-               goto end;
-       }
-       if (!package->package.count) {
-               status = AE_BAD_DATA;
-               acpi_util_eval_error(handle, pathname, status);
-               goto end;
-       }
+       if (buffer.length == 0 || !package ||
+           package->type != ACPI_TYPE_PACKAGE || !package->package.count)
+               goto err;
 
-       list->handles = kcalloc(package->package.count, sizeof(*list->handles), GFP_KERNEL);
-       if (!list->handles) {
-               kfree(package);
-               return AE_NO_MEMORY;
-       }
        list->count = package->package.count;
+       list->handles = kcalloc(list->count, sizeof(*list->handles), GFP_KERNEL);
+       if (!list->handles)
+               goto err_clear;
 
        /* Extract package data. */
 
        for (i = 0; i < list->count; i++) {
+               union acpi_object *element = &(package->package.elements[i]);
 
-               element = &(package->package.elements[i]);
+               if (element->type != ACPI_TYPE_LOCAL_REFERENCE ||
+                   !element->reference.handle)
+                       goto err_free;
 
-               if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
-                       status = AE_BAD_DATA;
-                       acpi_util_eval_error(handle, pathname, status);
-                       break;
-               }
-
-               if (!element->reference.handle) {
-                       status = AE_NULL_ENTRY;
-                       acpi_util_eval_error(handle, pathname, status);
-                       break;
-               }
                /* Get the  acpi_handle. */
 
                list->handles[i] = element->reference.handle;
                acpi_handle_debug(list->handles[i], "Found in reference list\n");
        }
 
-       if (ACPI_FAILURE(status)) {
-               list->count = 0;
-               kfree(list->handles);
-               list->handles = NULL;
-       }
+       ret = true;
 
 end:
        kfree(buffer.pointer);
 
-       return status;
+       return ret;
+
+err_free:
+       kfree(list->handles);
+       list->handles = NULL;
+
+err_clear:
+       list->count = 0;
+
+err:
+       acpi_util_eval_error(handle, pathname, status);
+       goto end;
 }
 
 EXPORT_SYMBOL(acpi_evaluate_reference);
@@ -426,7 +408,7 @@ bool acpi_handle_list_equal(struct acpi_handle_list *list1,
 {
        return list1->count == list2->count &&
                !memcmp(list1->handles, list2->handles,
-                       list1->count * sizeof(acpi_handle));
+                       list1->count * sizeof(*list1->handles));
 }
 EXPORT_SYMBOL_GPL(acpi_handle_list_equal);
 
@@ -468,6 +450,40 @@ void acpi_handle_list_free(struct acpi_handle_list *list)
 }
 EXPORT_SYMBOL_GPL(acpi_handle_list_free);
 
+/**
+ * acpi_device_dep - Check ACPI device dependency
+ * @target: ACPI handle of the target ACPI device.
+ * @match: ACPI handle to look up in the target's _DEP list.
+ *
+ * Return true if @match is present in the list returned by _DEP for
+ * @target or false otherwise.
+ */
+bool acpi_device_dep(acpi_handle target, acpi_handle match)
+{
+       struct acpi_handle_list dep_devices;
+       bool ret = false;
+       int i;
+
+       if (!acpi_has_method(target, "_DEP"))
+               return false;
+
+       if (!acpi_evaluate_reference(target, "_DEP", NULL, &dep_devices)) {
+               acpi_handle_debug(target, "Failed to evaluate _DEP.\n");
+               return false;
+       }
+
+       for (i = 0; i < dep_devices.count; i++) {
+               if (dep_devices.handles[i] == match) {
+                       ret = true;
+                       break;
+               }
+       }
+
+       acpi_handle_list_free(&dep_devices);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(acpi_device_dep);
+
 acpi_status
 acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld)
 {
@@ -824,54 +840,6 @@ bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs)
 }
 EXPORT_SYMBOL(acpi_check_dsm);
 
-/**
- * acpi_dev_uid_match - Match device by supplied UID
- * @adev: ACPI device to match.
- * @uid2: Unique ID of the device.
- *
- * Matches UID in @adev with given @uid2.
- *
- * Returns:
- *  - %true if matches.
- *  - %false otherwise.
- */
-bool acpi_dev_uid_match(struct acpi_device *adev, const char *uid2)
-{
-       const char *uid1 = acpi_device_uid(adev);
-
-       return uid1 && uid2 && !strcmp(uid1, uid2);
-}
-EXPORT_SYMBOL_GPL(acpi_dev_uid_match);
-
-/**
- * acpi_dev_hid_uid_match - Match device by supplied HID and UID
- * @adev: ACPI device to match.
- * @hid2: Hardware ID of the device.
- * @uid2: Unique ID of the device, pass NULL to not check _UID.
- *
- * Matches HID and UID in @adev with given @hid2 and @uid2. Absence of @uid2
- * will be treated as a match. If user wants to validate @uid2, it should be
- * done before calling this function.
- *
- * Returns:
- *  - %true if matches or @uid2 is NULL.
- *  - %false otherwise.
- */
-bool acpi_dev_hid_uid_match(struct acpi_device *adev,
-                           const char *hid2, const char *uid2)
-{
-       const char *hid1 = acpi_device_hid(adev);
-
-       if (strcmp(hid1, hid2))
-               return false;
-
-       if (!uid2)
-               return true;
-
-       return acpi_dev_uid_match(adev, uid2);
-}
-EXPORT_SYMBOL(acpi_dev_hid_uid_match);
-
 /**
  * acpi_dev_uid_to_integer - treat ACPI device _UID as integer
  * @adev: ACPI device to get _UID from
index f80d87c199c3c35adfc73e752b1016a3e3bb749f..937be269fee86d5d71256758aed94741e794431c 100644 (file)
@@ -18,8 +18,6 @@ static long __init parse_acpi_path(const struct efi_dev_path *node,
        struct acpi_device *adev;
        struct device *phys_dev;
        char hid[ACPI_ID_LEN];
-       u64 uid;
-       int ret;
 
        if (node->header.length != 12)
                return -EINVAL;
@@ -31,10 +29,9 @@ static long __init parse_acpi_path(const struct efi_dev_path *node,
                        node->acpi.hid >> 16);
 
        for_each_acpi_dev_match(adev, hid, NULL, -1) {
-               ret = acpi_dev_uid_to_integer(adev, &uid);
-               if (ret == 0 && node->acpi.uid == uid)
+               if (acpi_dev_uid_match(adev, node->acpi.uid))
                        break;
-               if (ret == -ENODATA && node->acpi.uid == 0)
+               if (!acpi_device_uid(adev) && node->acpi.uid == 0)
                        break;
        }
        if (!adev)
index 2cc35dded0079f9f3a59289e476fd1f579114556..50b89b989ce759fd9dddb22f9d300c85461753bf 100644 (file)
@@ -1108,7 +1108,6 @@ static int arm_cspmu_request_irq(struct arm_cspmu *cspmu)
 
 static inline int arm_cspmu_find_cpu_container(int cpu, u32 container_uid)
 {
-       u64 acpi_uid;
        struct device *cpu_dev;
        struct acpi_device *acpi_dev;
 
@@ -1118,8 +1117,7 @@ static inline int arm_cspmu_find_cpu_container(int cpu, u32 container_uid)
 
        acpi_dev = ACPI_COMPANION(cpu_dev);
        while (acpi_dev) {
-               if (acpi_dev_hid_uid_match(acpi_dev, ACPI_PROCESSOR_CONTAINER_HID, NULL) &&
-                   !acpi_dev_uid_to_integer(acpi_dev, &acpi_uid) && acpi_uid == container_uid)
+               if (acpi_dev_hid_uid_match(acpi_dev, ACPI_PROCESSOR_CONTAINER_HID, container_uid))
                        return 0;
 
                acpi_dev = acpi_dev_parent(acpi_dev);
index 091fdc154d79132111b30f7c9ff5d64ec397b8b3..6bf6f0e7b59766991123ee572e46e1321d442e3d 100644 (file)
@@ -454,7 +454,7 @@ static int cros_ec_create_panicinfo(struct cros_ec_debugfs *debug_info)
        debug_info->panicinfo_blob.data = data;
        debug_info->panicinfo_blob.size = ret;
 
-       debugfs_create_blob("panicinfo", S_IFREG | 0444, debug_info->dir,
+       debugfs_create_blob("panicinfo", 0444, debug_info->dir,
                            &debug_info->panicinfo_blob);
 
        return 0;
index e4dee920da185094a59a0f4a7177b2a319945423..20f3870915d2b7f7b9d14fb24023b23b7abb131a 100644 (file)
@@ -736,34 +736,6 @@ do {                                                                               \
 #define san_consumer_warn(dev, handle, fmt, ...) \
        san_consumer_printk(warn, dev, handle, fmt, ##__VA_ARGS__)
 
-static bool is_san_consumer(struct platform_device *pdev, acpi_handle handle)
-{
-       struct acpi_handle_list dep_devices;
-       acpi_handle supplier = ACPI_HANDLE(&pdev->dev);
-       acpi_status status;
-       bool ret = false;
-       int i;
-
-       if (!acpi_has_method(handle, "_DEP"))
-               return false;
-
-       status = acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices);
-       if (ACPI_FAILURE(status)) {
-               san_consumer_dbg(&pdev->dev, handle, "failed to evaluate _DEP\n");
-               return false;
-       }
-
-       for (i = 0; i < dep_devices.count; i++) {
-               if (dep_devices.handles[i] == supplier) {
-                       ret = true;
-                       break;
-               }
-       }
-
-       acpi_handle_list_free(&dep_devices);
-       return ret;
-}
-
 static acpi_status san_consumer_setup(acpi_handle handle, u32 lvl,
                                      void *context, void **rv)
 {
@@ -772,7 +744,7 @@ static acpi_status san_consumer_setup(acpi_handle handle, u32 lvl,
        struct acpi_device *adev;
        struct device_link *link;
 
-       if (!is_san_consumer(pdev, handle))
+       if (!acpi_device_dep(handle, ACPI_HANDLE(&pdev->dev)))
                return AE_OK;
 
        /* Ignore ACPI devices that are not present. */
index c81a00fbca7db936285d48f10a3bd2c437a1bc24..59883502eff48f03ec72e7b840f279f3f314d18f 100644 (file)
@@ -76,10 +76,6 @@ config THERMAL_OF
          Say 'Y' here if you need to build thermal infrastructure
          based on device tree.
 
-config THERMAL_ACPI
-       depends on ACPI
-       bool
-
 config THERMAL_WRITABLE_TRIPS
        bool "Enable writable trip points"
        help
index c934cab309ae0cbf5e7e94b6e2dc250bb21adbef..a8318d6710367c789a802d50d8b533608dec7177 100644 (file)
@@ -13,7 +13,6 @@ thermal_sys-$(CONFIG_THERMAL_NETLINK)         += thermal_netlink.o
 # interface to/from other layers providing sensors
 thermal_sys-$(CONFIG_THERMAL_HWMON)            += thermal_hwmon.o
 thermal_sys-$(CONFIG_THERMAL_OF)               += thermal_of.o
-thermal_sys-$(CONFIG_THERMAL_ACPI)             += thermal_acpi.o
 
 # governors
 CFLAGS_gov_power_allocator.o                   := -I$(src)
index ecd7e07eece0b49ba1c1037df3a9f37a459a3fe1..b43953b5539f6b718efbc4d8b180ba73a4668f8f 100644 (file)
@@ -85,7 +85,7 @@ config INTEL_BXT_PMIC_THERMAL
 config INTEL_PCH_THERMAL
        tristate "Intel PCH Thermal Reporting Driver"
        depends on X86 && PCI
-       select THERMAL_ACPI if ACPI
+       select ACPI_THERMAL_LIB if ACPI
        help
          Enable this to support thermal reporting on certain intel PCHs.
          Thermal reporting device will provide temperature reading,
index 300ea53e9b3327ad9f7d596afa329b428ee8a50b..e76b13e44d03fa896132e5d065db873a88efb588 100644 (file)
@@ -9,7 +9,7 @@ config INT340X_THERMAL
        select THERMAL_GOV_USER_SPACE
        select ACPI_THERMAL_REL
        select ACPI_FAN
-       select THERMAL_ACPI
+       select ACPI_THERMAL_LIB
        select INTEL_SOC_DTS_IOSF_CORE
        select INTEL_TCC
        select PROC_THERMAL_MMIO_RAPL if POWERCAP
diff --git a/drivers/thermal/thermal_acpi.c b/drivers/thermal/thermal_acpi.c
deleted file mode 100644 (file)
index 43eaf0f..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright 2023 Linaro Limited
- * Copyright 2023 Intel Corporation
- *
- * Library routines for populating a generic thermal trip point structure
- * with data obtained by evaluating a specific object in the ACPI Namespace.
- */
-#include <linux/acpi.h>
-#include <linux/units.h>
-#include <linux/thermal.h>
-
-/*
- * Minimum temperature for full military grade is 218°K (-55°C) and
- * max temperature is 448°K (175°C). We can consider those values as
- * the boundaries for the [trips] temperature returned by the
- * firmware. Any values out of these boundaries may be considered
- * bogus and we can assume the firmware has no data to provide.
- */
-#define TEMP_MIN_DECIK 2180
-#define TEMP_MAX_DECIK 4480
-
-static int thermal_acpi_trip_temp(struct acpi_device *adev, char *obj_name,
-                                 int *ret_temp)
-{
-       unsigned long long temp;
-       acpi_status status;
-
-       status = acpi_evaluate_integer(adev->handle, obj_name, NULL, &temp);
-       if (ACPI_FAILURE(status)) {
-               acpi_handle_debug(adev->handle, "%s evaluation failed\n", obj_name);
-               return -ENODATA;
-       }
-
-       if (temp >= TEMP_MIN_DECIK && temp <= TEMP_MAX_DECIK) {
-               *ret_temp = deci_kelvin_to_millicelsius(temp);
-       } else {
-               acpi_handle_debug(adev->handle, "%s result %llu out of range\n",
-                                 obj_name, temp);
-               *ret_temp = THERMAL_TEMP_INVALID;
-       }
-
-       return 0;
-}
-
-/**
- * thermal_acpi_active_trip_temp - Retrieve active trip point temperature
- * @adev: Target thermal zone ACPI device object.
- * @id: Active cooling level (0 - 9).
- * @ret_temp: Address to store the retrieved temperature value on success.
- *
- * Evaluate the _ACx object for the thermal zone represented by @adev to obtain
- * the temperature of the active cooling trip point corresponding to the active
- * cooling level given by @id.
- *
- * Return 0 on success or a negative error value on failure.
- */
-int thermal_acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp)
-{
-       char obj_name[] = {'_', 'A', 'C', '0' + id, '\0'};
-
-       if (id < 0 || id > 9)
-               return -EINVAL;
-
-       return thermal_acpi_trip_temp(adev, obj_name, ret_temp);
-}
-EXPORT_SYMBOL_GPL(thermal_acpi_active_trip_temp);
-
-/**
- * thermal_acpi_passive_trip_temp - Retrieve passive trip point temperature
- * @adev: Target thermal zone ACPI device object.
- * @ret_temp: Address to store the retrieved temperature value on success.
- *
- * Evaluate the _PSV object for the thermal zone represented by @adev to obtain
- * the temperature of the passive cooling trip point.
- *
- * Return 0 on success or -ENODATA on failure.
- */
-int thermal_acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp)
-{
-       return thermal_acpi_trip_temp(adev, "_PSV", ret_temp);
-}
-EXPORT_SYMBOL_GPL(thermal_acpi_passive_trip_temp);
-
-/**
- * thermal_acpi_hot_trip_temp - Retrieve hot trip point temperature
- * @adev: Target thermal zone ACPI device object.
- * @ret_temp: Address to store the retrieved temperature value on success.
- *
- * Evaluate the _HOT object for the thermal zone represented by @adev to obtain
- * the temperature of the trip point at which the system is expected to be put
- * into the S4 sleep state.
- *
- * Return 0 on success or -ENODATA on failure.
- */
-int thermal_acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp)
-{
-       return thermal_acpi_trip_temp(adev, "_HOT", ret_temp);
-}
-EXPORT_SYMBOL_GPL(thermal_acpi_hot_trip_temp);
-
-/**
- * thermal_acpi_critical_trip_temp - Retrieve critical trip point temperature
- * @adev: Target thermal zone ACPI device object.
- * @ret_temp: Address to store the retrieved temperature value on success.
- *
- * Evaluate the _CRT object for the thermal zone represented by @adev to obtain
- * the temperature of the critical cooling trip point.
- *
- * Return 0 on success or -ENODATA on failure.
- */
-int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp)
-{
-       return thermal_acpi_trip_temp(adev, "_CRT", ret_temp);
-}
-EXPORT_SYMBOL_GPL(thermal_acpi_critical_trip_temp);
index 6d7c1a49581f7ab10d3249d4c161c483274f9ab4..c6f4a9a98b85353686b50b98e57d3263a2dfbc47 100644 (file)
@@ -1100,17 +1100,35 @@ static ssize_t read_file_blob(struct file *file, char __user *user_buf,
        return r;
 }
 
+static ssize_t write_file_blob(struct file *file, const char __user *user_buf,
+                              size_t count, loff_t *ppos)
+{
+       struct debugfs_blob_wrapper *blob = file->private_data;
+       struct dentry *dentry = F_DENTRY(file);
+       ssize_t r;
+
+       r = debugfs_file_get(dentry);
+       if (unlikely(r))
+               return r;
+       r = simple_write_to_buffer(blob->data, blob->size, ppos, user_buf,
+                                  count);
+
+       debugfs_file_put(dentry);
+       return r;
+}
+
 static const struct file_operations fops_blob = {
        .read =         read_file_blob,
+       .write =        write_file_blob,
        .open =         simple_open,
        .llseek =       default_llseek,
 };
 
 /**
- * debugfs_create_blob - create a debugfs file that is used to read a binary blob
+ * debugfs_create_blob - create a debugfs file that is used to read and write
+ * a binary blob
  * @name: a pointer to a string containing the name of the file to create.
- * @mode: the read permission that the file should have (other permissions are
- *       masked out)
+ * @mode: the permission that the file should have
  * @parent: a pointer to the parent dentry for this file.  This should be a
  *          directory dentry if set.  If this parameter is %NULL, then the
  *          file will be created in the root of the debugfs filesystem.
@@ -1119,7 +1137,7 @@ static const struct file_operations fops_blob = {
  *
  * This function creates a file in debugfs with the given name that exports
  * @blob->data as a binary blob. If the @mode variable is so set it can be
- * read from. Writing is not supported.
+ * read from and written to.
  *
  * This function will return a pointer to a dentry if it succeeds.  This
  * pointer must be passed to the debugfs_remove() function when the file is
@@ -1134,7 +1152,7 @@ struct dentry *debugfs_create_blob(const char *name, umode_t mode,
                                   struct dentry *parent,
                                   struct debugfs_blob_wrapper *blob)
 {
-       return debugfs_create_file_unsafe(name, mode & 0444, parent, blob, &fops_blob);
+       return debugfs_create_file_unsafe(name, mode & 0644, parent, blob, &fops_blob);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_blob);
 
index 1216d72c650faee69165b6b9f1545f41b3b9954c..2b3ae51f950df0639f35a17450a3d9b2a7ce9be6 100644 (file)
@@ -14,7 +14,7 @@
 
 struct acpi_handle_list {
        u32 count;
-       acpi_handlehandles;
+       acpi_handle *handles;
 };
 
 /* acpi_utils.h */
@@ -25,16 +25,15 @@ acpi_status
 acpi_evaluate_integer(acpi_handle handle,
                      acpi_string pathname,
                      struct acpi_object_list *arguments, unsigned long long *data);
-acpi_status
-acpi_evaluate_reference(acpi_handle handle,
-                       acpi_string pathname,
-                       struct acpi_object_list *arguments,
-                       struct acpi_handle_list *list);
+bool acpi_evaluate_reference(acpi_handle handle, acpi_string pathname,
+                            struct acpi_object_list *arguments,
+                            struct acpi_handle_list *list);
 bool acpi_handle_list_equal(struct acpi_handle_list *list1,
                            struct acpi_handle_list *list2);
 void acpi_handle_list_replace(struct acpi_handle_list *dst,
                              struct acpi_handle_list *src);
 void acpi_handle_list_free(struct acpi_handle_list *list);
+bool acpi_device_dep(acpi_handle target, acpi_handle match);
 acpi_status
 acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
                  struct acpi_buffer *status_buf);
@@ -366,6 +365,98 @@ struct acpi_device_data {
 
 struct acpi_gpio_mapping;
 
+#define ACPI_DEVICE_SWNODE_ROOT                        0
+
+/*
+ * The maximum expected number of CSI-2 data lanes.
+ *
+ * This number is not expected to ever have to be equal to or greater than the
+ * number of bits in an unsigned long variable, but if it needs to be increased
+ * above that limit, code will need to be adjusted accordingly.
+ */
+#define ACPI_DEVICE_CSI2_DATA_LANES            8
+
+#define ACPI_DEVICE_SWNODE_PORT_NAME_LENGTH    8
+
+enum acpi_device_swnode_dev_props {
+       ACPI_DEVICE_SWNODE_DEV_ROTATION,
+       ACPI_DEVICE_SWNODE_DEV_CLOCK_FREQUENCY,
+       ACPI_DEVICE_SWNODE_DEV_LED_MAX_MICROAMP,
+       ACPI_DEVICE_SWNODE_DEV_FLASH_MAX_MICROAMP,
+       ACPI_DEVICE_SWNODE_DEV_FLASH_MAX_TIMEOUT_US,
+       ACPI_DEVICE_SWNODE_DEV_NUM_OF,
+       ACPI_DEVICE_SWNODE_DEV_NUM_ENTRIES
+};
+
+enum acpi_device_swnode_port_props {
+       ACPI_DEVICE_SWNODE_PORT_REG,
+       ACPI_DEVICE_SWNODE_PORT_NUM_OF,
+       ACPI_DEVICE_SWNODE_PORT_NUM_ENTRIES
+};
+
+enum acpi_device_swnode_ep_props {
+       ACPI_DEVICE_SWNODE_EP_REMOTE_EP,
+       ACPI_DEVICE_SWNODE_EP_BUS_TYPE,
+       ACPI_DEVICE_SWNODE_EP_REG,
+       ACPI_DEVICE_SWNODE_EP_CLOCK_LANES,
+       ACPI_DEVICE_SWNODE_EP_DATA_LANES,
+       ACPI_DEVICE_SWNODE_EP_LANE_POLARITIES,
+       /* TX only */
+       ACPI_DEVICE_SWNODE_EP_LINK_FREQUENCIES,
+       ACPI_DEVICE_SWNODE_EP_NUM_OF,
+       ACPI_DEVICE_SWNODE_EP_NUM_ENTRIES
+};
+
+/*
+ * Each device has a root software node plus two times as many nodes as the
+ * number of CSI-2 ports.
+ */
+#define ACPI_DEVICE_SWNODE_PORT(port)  (2 * (port) + 1)
+#define ACPI_DEVICE_SWNODE_EP(endpoint)        \
+               (ACPI_DEVICE_SWNODE_PORT(endpoint) + 1)
+
+/**
+ * struct acpi_device_software_node_port - MIPI DisCo for Imaging CSI-2 port
+ * @port_name: Port name.
+ * @data_lanes: "data-lanes" property values.
+ * @lane_polarities: "lane-polarities" property values.
+ * @link_frequencies: "link_frequencies" property values.
+ * @port_nr: Port number.
+ * @crs_crs2_local: _CRS CSI2 record present (i.e. this is a transmitter one).
+ * @port_props: Port properties.
+ * @ep_props: Endpoint properties.
+ * @remote_ep: Reference to the remote endpoint.
+ */
+struct acpi_device_software_node_port {
+       char port_name[ACPI_DEVICE_SWNODE_PORT_NAME_LENGTH + 1];
+       u32 data_lanes[ACPI_DEVICE_CSI2_DATA_LANES];
+       u32 lane_polarities[ACPI_DEVICE_CSI2_DATA_LANES + 1 /* clock lane */];
+       u64 link_frequencies[ACPI_DEVICE_CSI2_DATA_LANES];
+       unsigned int port_nr;
+       bool crs_csi2_local;
+
+       struct property_entry port_props[ACPI_DEVICE_SWNODE_PORT_NUM_ENTRIES];
+       struct property_entry ep_props[ACPI_DEVICE_SWNODE_EP_NUM_ENTRIES];
+
+       struct software_node_ref_args remote_ep[1];
+};
+
+/**
+ * struct acpi_device_software_nodes - Software nodes for an ACPI device
+ * @dev_props: Device properties.
+ * @nodes: Software nodes for root as well as ports and endpoints.
+ * @nodeprts: Array of software node pointers, for (un)registering them.
+ * @ports: Information related to each port and endpoint within a port.
+ * @num_ports: The number of ports.
+ */
+struct acpi_device_software_nodes {
+       struct property_entry dev_props[ACPI_DEVICE_SWNODE_DEV_NUM_ENTRIES];
+       struct software_node *nodes;
+       const struct software_node **nodeptrs;
+       struct acpi_device_software_node_port *ports;
+       unsigned int num_ports;
+};
+
 /* Device */
 struct acpi_device {
        u32 pld_crc;
@@ -384,6 +475,7 @@ struct acpi_device {
        struct acpi_device_data data;
        struct acpi_scan_handler *handler;
        struct acpi_hotplug_context *hp;
+       struct acpi_device_software_nodes *swnodes;
        const struct acpi_gpio_mapping *driver_gpios;
        void *driver_data;
        struct device dev;
@@ -764,10 +856,71 @@ static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
                adev->power.states[ACPI_STATE_D3_HOT].flags.explicit_set);
 }
 
-bool acpi_dev_uid_match(struct acpi_device *adev, const char *uid2);
-bool acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2);
 int acpi_dev_uid_to_integer(struct acpi_device *adev, u64 *integer);
 
+static inline bool acpi_dev_hid_match(struct acpi_device *adev, const char *hid2)
+{
+       const char *hid1 = acpi_device_hid(adev);
+
+       return hid1 && hid2 && !strcmp(hid1, hid2);
+}
+
+static inline bool acpi_str_uid_match(struct acpi_device *adev, const char *uid2)
+{
+       const char *uid1 = acpi_device_uid(adev);
+
+       return uid1 && uid2 && !strcmp(uid1, uid2);
+}
+
+static inline bool acpi_int_uid_match(struct acpi_device *adev, u64 uid2)
+{
+       u64 uid1;
+
+       return !acpi_dev_uid_to_integer(adev, &uid1) && uid1 == uid2;
+}
+
+#define TYPE_ENTRY(type, x)                    \
+       const type: x,                          \
+       type: x
+
+#define ACPI_STR_TYPES(match)                  \
+       TYPE_ENTRY(unsigned char *, match),     \
+       TYPE_ENTRY(signed char *, match),               \
+       TYPE_ENTRY(char *, match),              \
+       TYPE_ENTRY(void *, match)
+
+/**
+ * acpi_dev_uid_match - Match device by supplied UID
+ * @adev: ACPI device to match.
+ * @uid2: Unique ID of the device.
+ *
+ * Matches UID in @adev with given @uid2.
+ *
+ * Returns: %true if matches, %false otherwise.
+ */
+#define acpi_dev_uid_match(adev, uid2)                                 \
+       _Generic(uid2,                                                  \
+                /* Treat @uid2 as a string for acpi string types */    \
+                ACPI_STR_TYPES(acpi_str_uid_match),                    \
+                /* Treat as an integer otherwise */                    \
+                default: acpi_int_uid_match)(adev, uid2)
+
+/**
+ * acpi_dev_hid_uid_match - Match device by supplied HID and UID
+ * @adev: ACPI device to match.
+ * @hid2: Hardware ID of the device.
+ * @uid2: Unique ID of the device, pass 0 or NULL to not check _UID.
+ *
+ * Matches HID and UID in @adev with given @hid2 and @uid2. Absence of @uid2
+ * will be treated as a match. If user wants to validate @uid2, it should be
+ * done before calling this function.
+ *
+ * Returns: %true if matches or @uid2 is 0 or NULL, %false otherwise.
+ */
+#define acpi_dev_hid_uid_match(adev, hid2, uid2)                       \
+       (acpi_dev_hid_match(adev, hid2) &&                              \
+               (!(uid2) || acpi_dev_uid_match(adev, uid2)))
+
 void acpi_dev_clear_dependencies(struct acpi_device *supplier);
 bool acpi_dev_ready_for_enumeration(const struct acpi_device *device);
 struct acpi_device *acpi_dev_get_next_consumer_dev(struct acpi_device *supplier,
index 4230392b5b0b4f209636e7bbbdb3c8d04b6530ff..3d538d4178abb1a324adb8def3d5132abd71925c 100644 (file)
@@ -75,6 +75,15 @@ static inline enum acpi_backlight_type acpi_video_get_backlight_type(void)
        return __acpi_video_get_backlight_type(false, NULL);
 }
 
+/*
+ * This function MUST only be called by GPU drivers to check if the driver
+ * should register a backlight class device. This function not only checks
+ * if a GPU native backlight device should be registered it *also* tells
+ * the ACPI video-detect code that native GPU backlight control is available.
+ * Therefor calling this from any place other then the GPU driver is wrong!
+ * To check if GPU native backlight control is used in other places instead use:
+ *   if (acpi_video_get_backlight_type() == acpi_backlight_native) { ... }
+ */
 static inline bool acpi_video_backlight_use_native(void)
 {
        return __acpi_video_get_backlight_type(true, NULL) == acpi_backlight_native;
index 4db54e928b36d0d9646d78dfcb78cea6e15c4684..118a18b7ff844a357cba99eeb5272bbdc2165f7d 100644 (file)
@@ -424,6 +424,13 @@ extern int acpi_blacklisted(void);
 extern void acpi_osi_setup(char *str);
 extern bool acpi_osi_is_win8(void);
 
+#ifdef CONFIG_ACPI_THERMAL_LIB
+int thermal_acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp);
+int thermal_acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp);
+int thermal_acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp);
+int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp);
+#endif
+
 #ifdef CONFIG_ACPI_NUMA
 int acpi_map_pxm_to_node(int pxm);
 int acpi_get_node(acpi_handle handle);
@@ -756,6 +763,10 @@ const char *acpi_get_subsystem_id(acpi_handle handle);
 #define ACPI_HANDLE(dev)               (NULL)
 #define ACPI_HANDLE_FWNODE(fwnode)     (NULL)
 
+/* Get rid of the -Wunused-variable for adev */
+#define acpi_dev_uid_match(adev, uid2)                 (adev && false)
+#define acpi_dev_hid_uid_match(adev, hid2, uid2)       (adev && false)
+
 #include <acpi/acpi_numa.h>
 
 struct fwnode_handle;
@@ -772,17 +783,6 @@ static inline bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
 
 struct acpi_device;
 
-static inline bool acpi_dev_uid_match(struct acpi_device *adev, const char *uid2)
-{
-       return false;
-}
-
-static inline bool
-acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2)
-{
-       return false;
-}
-
 static inline int acpi_dev_uid_to_integer(struct acpi_device *adev, u64 *integer)
 {
        return -ENODEV;
index 9f2585d705a867ce2f7d35da322a1e9ee6292360..97f901c0914e34e04633046a4486fd8962619c72 100644 (file)
@@ -489,6 +489,13 @@ struct software_node {
        const struct property_entry *properties;
 };
 
+#define SOFTWARE_NODE(_name_, _properties_, _parent_)  \
+       (struct software_node) {                        \
+               .name = _name_,                         \
+               .properties = _properties_,             \
+               .parent = _parent_,                     \
+       }
+
 bool is_software_node(const struct fwnode_handle *fwnode);
 const struct software_node *
 to_software_node(const struct fwnode_handle *fwnode);
index cee814d5d1accf632971eb1718f370cfd5a004c8..35f6200594569b55bee8583cb551ade1c68a94ca 100644 (file)
@@ -294,13 +294,6 @@ int thermal_zone_get_num_trips(struct thermal_zone_device *tz);
 
 int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp);
 
-#ifdef CONFIG_THERMAL_ACPI
-int thermal_acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp);
-int thermal_acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp);
-int thermal_acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp);
-int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp);
-#endif
-
 #ifdef CONFIG_THERMAL
 struct thermal_zone_device *thermal_zone_device_register_with_trips(
                                        const char *type,
index 294df54e33b6fea2e328863ff00413825d78d46c..c49a09ee3853cda00d60fa73f711d44094abdfb4 100644 (file)
@@ -85,11 +85,6 @@ acpi_get_subtable_type(char *id)
        return ACPI_SUBTABLE_COMMON;
 }
 
-static __init_or_acpilib bool has_handler(struct acpi_subtable_proc *proc)
-{
-       return proc->handler || proc->handler_arg;
-}
-
 static __init_or_acpilib int call_handler(struct acpi_subtable_proc *proc,
                                          union acpi_subtable_headers *hdr,
                                          unsigned long end)
@@ -133,7 +128,6 @@ acpi_parse_entries_array(char *id, unsigned long table_size,
        unsigned long table_end, subtable_len, entry_len;
        struct acpi_subtable_entry entry;
        int count = 0;
-       int errs = 0;
        int i;
 
        table_end = (unsigned long)table_header + table_header->length;
@@ -145,25 +139,19 @@ acpi_parse_entries_array(char *id, unsigned long table_size,
            ((unsigned long)table_header + table_size);
        subtable_len = acpi_get_subtable_header_length(&entry);
 
-       while (((unsigned long)entry.hdr) + subtable_len  < table_end) {
-               if (max_entries && count >= max_entries)
-                       break;
-
+       while (((unsigned long)entry.hdr) + subtable_len < table_end) {
                for (i = 0; i < proc_num; i++) {
                        if (acpi_get_entry_type(&entry) != proc[i].id)
                                continue;
-                       if (!has_handler(&proc[i]) ||
-                           (!errs &&
-                            call_handler(&proc[i], entry.hdr, table_end))) {
-                               errs++;
-                               continue;
-                       }
+
+                       if (!max_entries || count < max_entries)
+                               if (call_handler(&proc[i], entry.hdr, table_end))
+                                       return -EINVAL;
 
                        proc[i].count++;
+                       count++;
                        break;
                }
-               if (i != proc_num)
-                       count++;
 
                /*
                 * If entry->length is 0, break from this loop to avoid
@@ -180,9 +168,9 @@ acpi_parse_entries_array(char *id, unsigned long table_size,
        }
 
        if (max_entries && count > max_entries) {
-               pr_warn("[%4.4s:0x%02x] found the maximum %i entries\n",
-                       id, proc->id, count);
+               pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
+                       id, proc->id, count - max_entries, count);
        }
 
-       return errs ? -EINVAL : count;
+       return count;
 }