From bd721b934323e4dcde892013a97e0e5674f4c884 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 6 Nov 2023 17:09:01 +0100 Subject: ACPI: scan: Extract CSI-2 connection graph from _CRS Find ACPI CSI-2 resource descriptors defined since ACPI 6.4 (for CSI-2 and camera configuration) in _CRS for all device objects in the given scope of the ACPI namespace that have them, identify the corresponding "remote endpoint" device objects for them and allocate memory for software nodes needed to create a DT-like data structure representing the CSI-2 connection graph for drivers. The code needed to populate these software nodes will be added by subsequent change sets. Link: https://uefi.org/specs/ACPI/6.5/06_Device_Configuration.html#camera-serial-interface-csi-2-connection-resource-descriptor Co-developed-by: Sakari Ailus Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki Tested-by: Sakari Ailus --- include/acpi/acpi_bus.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'include/acpi') diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index afeed6e72049..f122fa1c10a8 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -366,6 +366,24 @@ struct acpi_device_data { struct acpi_gpio_mapping; +struct acpi_device_software_node_port { + unsigned int port_nr; +}; + +/** + * struct acpi_device_software_nodes - Software nodes for an ACPI device + * @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 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; -- cgit v1.2.3 From 693c667b32ee1dd312000d4656b3383fffb3af2d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 6 Nov 2023 17:16:26 +0100 Subject: ACPI: scan: Extract _CRS CSI-2 connection information into swnodes Use the connection information extracted from the _CRS CSI-2 resource descriptors for all devices that have them to populate port names and the "reg", "bus-type" and "remote-endpoint" properties in the software nodes representing the CSI-2 connection graph. Link: https://uefi.org/specs/ACPI/6.5/06_Device_Configuration.html#camera-serial-interface-csi-2-connection-resource-descriptor Co-developed-by: Sakari Ailus Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki Tested-by: Sakari Ailus --- drivers/acpi/mipi-disco-img.c | 153 +++++++++++++++++++++++++++++++++++++++++- include/acpi/acpi_bus.h | 53 +++++++++++++++ 2 files changed, 205 insertions(+), 1 deletion(-) (limited to 'include/acpi') diff --git a/drivers/acpi/mipi-disco-img.c b/drivers/acpi/mipi-disco-img.c index 91281c8cb4f2..5ff72d83fad2 100644 --- a/drivers/acpi/mipi-disco-img.c +++ b/drivers/acpi/mipi-disco-img.c @@ -23,6 +23,8 @@ #include #include +#include + #include "internal.h" static LIST_HEAD(acpi_mipi_crs_csi2_list); @@ -237,6 +239,142 @@ static void alloc_crs_csi2_swnodes(struct crs_csi2 *csi2) 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 * @@ -275,9 +413,22 @@ void acpi_mipi_scan_crs_csi2(void) } list_splice(&aux_list, &acpi_mipi_crs_csi2_list); - /* Allocate software nodes for representing the CSI-2 information. */ + /* + * 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); } /** diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index f122fa1c10a8..a7fa24f1af46 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -366,8 +366,61 @@ struct acpi_device_data { struct acpi_gpio_mapping; +#define ACPI_DEVICE_CSI2_DATA_LANES 8 + +#define ACPI_DEVICE_SWNODE_PORT_NAME_LENGTH 8 + +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]; }; /** -- cgit v1.2.3 From a6cb0a611273767683d50fb908173b6f88052ce5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 7 Nov 2023 20:19:42 +0100 Subject: ACPI: scan: Extract MIPI DisCo for Imaging data into swnodes Add information extracted from the MIPI DisCo for Imaging device properties to software nodes created during the CSI-2 connection graph discovery. Link: https://www.mipi.org/specifications/mipi-disco-imaging Co-developed-by: Sakari Ailus Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki Tested-by: Sakari Ailus --- drivers/acpi/internal.h | 1 + drivers/acpi/mipi-disco-img.c | 252 +++++++++++++++++++++++++++++++++++++++++- drivers/acpi/scan.c | 12 +- include/acpi/acpi_bus.h | 17 +++ 4 files changed, 278 insertions(+), 4 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 959a2bc61916..86b670637f2f 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -282,6 +282,7 @@ static inline void acpi_init_lpit(void) { } 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 index 5ff72d83fad2..dcbaba91d4fe 100644 --- a/drivers/acpi/mipi-disco-img.c +++ b/drivers/acpi/mipi-disco-img.c @@ -6,12 +6,16 @@ * * 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. + * 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. + * 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 @@ -431,6 +435,250 @@ void acpi_mipi_scan_crs_csi2(void) 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 bytes (%lu 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; + struct fwnode_handle *adev_fwnode; + struct acpi_device *adev; + acpi_status status; + unsigned int i; + 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); + + 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 */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 8e12c558b8db..b8df04779904 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2447,6 +2447,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); } @@ -2516,11 +2523,12 @@ int acpi_bus_scan(acpi_handle handle) return -ENODEV; /* - * Allocate ACPI _CRS CSI-2 software nodes using information extracted + * Set up ACPI _CRS CSI-2 software nodes using information extracted * from the _CRS CSI-2 resource descriptors during the ACPI namespace - * walk above. + * 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); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a7fa24f1af46..c299fb974e49 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -366,10 +366,24 @@ 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_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, @@ -425,12 +439,14 @@ struct acpi_device_software_node_port { /** * 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; @@ -455,6 +471,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; -- cgit v1.2.3 From f533e43a2a3117cc59886cbcd66ca32e42cf1ea9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 6 Nov 2023 17:28:40 +0100 Subject: ACPI: property: Dig "rotation" property for devices with CSI2 _CRS Find the "rotation" property value for devices with _CRS CSI-2 resource descriptors and use it to add the "rotation" property to the software nodes representing the CSI-2 connection graph. That value typically comes from the _PLD (Physical Location of Device) object if it is present for the given device. This way, camera sensor drivers that know the "rotation" property do not need to care about _PLD on systems using ACPI. Signed-off-by: Sakari Ailus [ rjw: Changelog edits, file rename ] Signed-off-by: Rafael J. Wysocki Tested-by: Sakari Ailus --- drivers/acpi/mipi-disco-img.c | 17 +++++++++++++++++ include/acpi/acpi_bus.h | 1 + 2 files changed, 18 insertions(+) (limited to 'include/acpi') diff --git a/drivers/acpi/mipi-disco-img.c b/drivers/acpi/mipi-disco-img.c index dcbaba91d4fe..b2c7a4922804 100644 --- a/drivers/acpi/mipi-disco-img.c +++ b/drivers/acpi/mipi-disco-img.c @@ -595,6 +595,7 @@ 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; @@ -614,6 +615,22 @@ static void init_crs_csi2_swnodes(struct crs_csi2 *csi2) 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); + } + } + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); if (ACPI_FAILURE(status)) { acpi_handle_info(handle, "Unable to get the path name\n"); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c299fb974e49..1e5d2e2c3444 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -380,6 +380,7 @@ struct acpi_gpio_mapping; #define ACPI_DEVICE_SWNODE_PORT_NAME_LENGTH 8 enum acpi_device_swnode_dev_props { + ACPI_DEVICE_SWNODE_DEV_ROTATION, ACPI_DEVICE_SWNODE_DEV_NUM_OF, ACPI_DEVICE_SWNODE_DEV_NUM_ENTRIES }; -- cgit v1.2.3 From 4cd57d6d527c3570827a6eb8bd790ae216a78ed9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 6 Nov 2023 17:31:18 +0100 Subject: ACPI: property: Replicate DT-aligned u32 properties from DisCo for Imaging MIPI DisCo for Imaging defines properties for camera sensors that functionally align with DT equivalents. Replicate these properties in the ACPI device swnodes so the code using the corresponding DT properties already does not need to be updated to deal with their MIPI counterparts directly. The replicated properties are: "mipi-img-clock-frequency" -> "clock-frequency" "mipi-img-led-max-current" -> "led-max-microamp" "mipi-img-flash-max-current" -> "flash-max-microamp" "mipi-img-flash-max-timeout" -> "flash-max-timeout-us" Signed-off-by: Sakari Ailus [ rjw: Changelog edits, removal of redundant braces ] Signed-off-by: Rafael J. Wysocki Tested-by: Sakari Ailus --- drivers/acpi/mipi-disco-img.c | 17 +++++++++++++++++ include/acpi/acpi_bus.h | 4 ++++ 2 files changed, 21 insertions(+) (limited to 'include/acpi') diff --git a/drivers/acpi/mipi-disco-img.c b/drivers/acpi/mipi-disco-img.c index b2c7a4922804..cad72d1fc127 100644 --- a/drivers/acpi/mipi-disco-img.c +++ b/drivers/acpi/mipi-disco-img.c @@ -600,6 +600,7 @@ static void init_crs_csi2_swnodes(struct crs_csi2 *csi2) struct acpi_device *adev; acpi_status status; unsigned int i; + u32 val; int ret; /* @@ -631,6 +632,22 @@ static void init_crs_csi2_swnodes(struct crs_csi2 *csi2) } } + 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"); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 1e5d2e2c3444..989ea623b1c2 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -381,6 +381,10 @@ struct acpi_gpio_mapping; 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 }; -- cgit v1.2.3 From 52304886ea49ee662589aff05925ef226c17a6a6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 26 Oct 2023 15:53:03 +0200 Subject: ACPI: video: Add comment about acpi_video_backlight_use_native() usage Add a comment explaining that acpi_video_backlight_use_native() MUST only be used by GPU drivers and that it must NOT be used on other places. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- include/acpi/video.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include/acpi') diff --git a/include/acpi/video.h b/include/acpi/video.h index 4230392b5b0b..3d538d4178ab 100644 --- a/include/acpi/video.h +++ b/include/acpi/video.h @@ -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; -- cgit v1.2.3 From 57b8543ceee82ea72be1745a6dc3a9111d55a151 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Thu, 23 Nov 2023 15:36:13 +0530 Subject: ACPI: bus: update acpi_dev_uid_match() to support multiple types According to the ACPI specification, a _UID object can evaluate to either a numeric value or a string. Update acpi_dev_uid_match() to support _UID matching for both integer and string types. Suggested-by: Mika Westerberg Signed-off-by: Raag Jadav [ rjw: Rename auxiliary macros, relocate kerneldoc comment ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/utils.c | 19 ------------------- include/acpi/acpi_bus.h | 41 ++++++++++++++++++++++++++++++++++++++++- include/linux/acpi.h | 8 +++----- 3 files changed, 43 insertions(+), 25 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 28c75242fca9..fe7e850c6479 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -824,25 +824,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. diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 1216d72c650f..4bde0b417476 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -764,10 +764,49 @@ 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_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) + 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, diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 4db54e928b36..2abe81f074de 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -756,6 +756,9 @@ 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) + #include struct fwnode_handle; @@ -772,11 +775,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) { -- cgit v1.2.3 From b2b32a1738815155d4a0039bb7a6092d40f23e81 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Thu, 23 Nov 2023 15:36:14 +0530 Subject: ACPI: bus: update acpi_dev_hid_uid_match() to support multiple types Now that we have _UID matching support for both integer and string types, we can support them into acpi_dev_hid_uid_match() helper as well. Signed-off-by: Raag Jadav Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/utils.c | 29 ----------------------------- include/acpi/acpi_bus.h | 24 +++++++++++++++++++++++- include/linux/acpi.h | 7 +------ 3 files changed, 24 insertions(+), 36 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index fe7e850c6479..03f6de9a0807 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -824,35 +824,6 @@ bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs) } EXPORT_SYMBOL(acpi_check_dsm); -/** - * 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 diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 4bde0b417476..aae31552c574 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -764,9 +764,15 @@ static inline bool acpi_device_can_poweroff(struct acpi_device *adev) adev->power.states[ACPI_STATE_D3_HOT].flags.explicit_set); } -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); @@ -807,6 +813,22 @@ static inline bool acpi_int_uid_match(struct acpi_device *adev, u64 uid2) /* 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, diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 2abe81f074de..75274585656c 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -758,6 +758,7 @@ const char *acpi_get_subsystem_id(acpi_handle handle); /* 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 @@ -775,12 +776,6 @@ static inline bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) struct acpi_device; -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; -- cgit v1.2.3 From 6909e0f322b0527fee9fdc54685e6cad69008713 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 8 Dec 2023 21:06:04 +0100 Subject: ACPI: utils: Return bool from acpi_evaluate_reference() There are only 4 users of acpi_evaluate_reference() and none of them actually cares about the reason why it fails. All of them are only interested in whether or not it is successful, so it can return a bool value indicating that. Modify acpi_evaluate_reference() as per the observation above and update its callers accordingly so as to get rid of useless code and local variables. The observable behavior of the kernel is not expected to change after this modification of the code. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 5 +--- drivers/acpi/scan.c | 5 ++-- drivers/acpi/thermal.c | 4 +--- drivers/acpi/utils.c | 32 ++++++++++---------------- drivers/platform/surface/surface_acpi_notify.c | 4 +--- include/acpi/acpi_bus.h | 8 +++---- 6 files changed, 20 insertions(+), 38 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 79f4fc7d6871..1623af8d62bc 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -565,16 +565,13 @@ static struct device *acpi_lpss_find_device(const char *hid, const char *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)) { + if (!acpi_evaluate_reference(adev->handle, "_DEP", NULL, &dep_devices)) { dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n"); return false; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 02bb2cce423f..7b731958af5e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1984,7 +1984,6 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev) static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) { struct acpi_handle_list dep_devices; - acpi_status status; u32 count; int i; @@ -1998,8 +1997,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_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 +2006,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)) { diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f74d81abdbfc..15f09c71a5ec 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -247,7 +247,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 +254,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; } diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 5a7766c3fbbd..958dc651d467 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -329,19 +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) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *package; acpi_status status; + bool ret = false; u32 i; if (!list) - return AE_BAD_PARAMETER; + return false; /* Evaluate object. */ @@ -352,42 +351,35 @@ acpi_evaluate_reference(acpi_handle handle, package = buffer.pointer; if (buffer.length == 0 || !package || - package->type != ACPI_TYPE_PACKAGE || !package->package.count) { - status = AE_BAD_DATA; + package->type != ACPI_TYPE_PACKAGE || !package->package.count) goto err; - } list->count = package->package.count; list->handles = kcalloc(list->count, sizeof(*list->handles), GFP_KERNEL); - if (!list->handles) { - status = AE_NO_MEMORY; + if (!list->handles) goto err_clear; - } /* Extract package data. */ for (i = 0; i < list->count; i++) { union acpi_object *element = &(package->package.elements[i]); - if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { - status = AE_BAD_DATA; + if (element->type != ACPI_TYPE_LOCAL_REFERENCE || + !element->reference.handle) goto err_free; - } - if (!element->reference.handle) { - status = AE_NULL_ENTRY; - goto err_free; - } /* Get the acpi_handle. */ list->handles[i] = element->reference.handle; acpi_handle_debug(list->handles[i], "Found in reference list\n"); } + ret = true; + end: kfree(buffer.pointer); - return status; + return ret; err_free: kfree(list->handles); diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index e4dee920da18..96ec052d0940 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -740,15 +740,13 @@ 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)) { + if (!acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices)) { san_consumer_dbg(&pdev->dev, handle, "failed to evaluate _DEP\n"); return false; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index aae31552c574..fbe60af56b34 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -25,11 +25,9 @@ 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, -- cgit v1.2.3 From 4c660ffef34b7d645ae3144369bc50257f295212 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 8 Dec 2023 21:07:41 +0100 Subject: ACPI: utils: Fix white space in struct acpi_handle_list definition Fix inadvertently introduced white space damage in the struct acpi_handle_list definition. No functional impact. Fixes: 2e57d10a6591 ("ACPI: utils: Dynamically determine acpi_handle_list size") Signed-off-by: Rafael J. Wysocki --- include/acpi/acpi_bus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/acpi') diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index fbe60af56b34..3dcf07b41428 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -14,7 +14,7 @@ struct acpi_handle_list { u32 count; - acpi_handle* handles; + acpi_handle *handles; }; /* acpi_utils.h */ -- cgit v1.2.3 From d70d141bb15f328528f94557ddf754abeb027365 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 14 Dec 2023 12:07:55 +0100 Subject: ACPI: utils: Introduce helper for _DEP list lookup The ACPI LPSS driver and the Surface platform driver code use almost the same code pattern for checking if one ACPI device is present in the list returned by _DEP for another ACPI device. To reduce the resulting code duplication, introduce a helper for that called acpi_device_dep() and invoke it from both places. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/acpi_lpss.c | 29 ++-------------------- drivers/acpi/utils.c | 34 ++++++++++++++++++++++++++ drivers/platform/surface/surface_acpi_notify.c | 28 +-------------------- include/acpi/acpi_bus.h | 1 + 4 files changed, 38 insertions(+), 54 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 1623af8d62bc..920402dfe1ad 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -562,31 +562,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; - bool ret = false; - int i; - - if (!acpi_has_method(adev->handle, "_DEP")) - return false; - - if (!acpi_evaluate_reference(adev->handle, "_DEP", NULL, &dep_devices)) { - 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) { @@ -597,7 +572,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); @@ -613,7 +588,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); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 57663065dbf6..abac5cc25477 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -450,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) { diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index 96ec052d0940..20f3870915d2 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -736,32 +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); - bool ret = false; - int i; - - if (!acpi_has_method(handle, "_DEP")) - return false; - - if (!acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices)) { - 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) { @@ -770,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. */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 3dcf07b41428..b5c082e34539 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -33,6 +33,7 @@ bool acpi_handle_list_equal(struct acpi_handle_list *list1, 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); -- cgit v1.2.3