diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/arm64/iort.c | 83 | ||||
-rw-r--r-- | drivers/acpi/device_pm.c | 4 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 2 | ||||
-rw-r--r-- | drivers/acpi/property.c | 117 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 10 |
5 files changed, 188 insertions, 28 deletions
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index d048f72c23f8..a3215ee671c1 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -31,6 +31,11 @@ #define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \ (1 << ACPI_IORT_NODE_SMMU_V3)) +/* Until ACPICA headers cover IORT rev. C */ +#ifndef ACPI_IORT_SMMU_V3_CAVIUM_CN99XX +#define ACPI_IORT_SMMU_V3_CAVIUM_CN99XX 0x2 +#endif + struct iort_its_msi_chip { struct list_head list; struct fwnode_handle *fw_node; @@ -819,6 +824,36 @@ static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node) return num_res; } +static bool arm_smmu_v3_is_combined_irq(struct acpi_iort_smmu_v3 *smmu) +{ + /* + * Cavium ThunderX2 implementation doesn't not support unique + * irq line. Use single irq line for all the SMMUv3 interrupts. + */ + if (smmu->model != ACPI_IORT_SMMU_V3_CAVIUM_CN99XX) + return false; + + /* + * ThunderX2 doesn't support MSIs from the SMMU, so we're checking + * SPI numbers here. + */ + return smmu->event_gsiv == smmu->pri_gsiv && + smmu->event_gsiv == smmu->gerr_gsiv && + smmu->event_gsiv == smmu->sync_gsiv; +} + +static unsigned long arm_smmu_v3_resource_size(struct acpi_iort_smmu_v3 *smmu) +{ + /* + * Override the size, for Cavium ThunderX2 implementation + * which doesn't support the page 1 SMMU register space. + */ + if (smmu->model == ACPI_IORT_SMMU_V3_CAVIUM_CN99XX) + return SZ_64K; + + return SZ_128K; +} + static void __init arm_smmu_v3_init_resources(struct resource *res, struct acpi_iort_node *node) { @@ -829,30 +864,38 @@ static void __init arm_smmu_v3_init_resources(struct resource *res, smmu = (struct acpi_iort_smmu_v3 *)node->node_data; res[num_res].start = smmu->base_address; - res[num_res].end = smmu->base_address + SZ_128K - 1; + res[num_res].end = smmu->base_address + + arm_smmu_v3_resource_size(smmu) - 1; res[num_res].flags = IORESOURCE_MEM; num_res++; + if (arm_smmu_v3_is_combined_irq(smmu)) { + if (smmu->event_gsiv) + acpi_iort_register_irq(smmu->event_gsiv, "combined", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + } else { - if (smmu->event_gsiv) - acpi_iort_register_irq(smmu->event_gsiv, "eventq", - ACPI_EDGE_SENSITIVE, - &res[num_res++]); - - if (smmu->pri_gsiv) - acpi_iort_register_irq(smmu->pri_gsiv, "priq", - ACPI_EDGE_SENSITIVE, - &res[num_res++]); - - if (smmu->gerr_gsiv) - acpi_iort_register_irq(smmu->gerr_gsiv, "gerror", - ACPI_EDGE_SENSITIVE, - &res[num_res++]); - - if (smmu->sync_gsiv) - acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync", - ACPI_EDGE_SENSITIVE, - &res[num_res++]); + if (smmu->event_gsiv) + acpi_iort_register_irq(smmu->event_gsiv, "eventq", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + + if (smmu->pri_gsiv) + acpi_iort_register_irq(smmu->pri_gsiv, "priq", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + + if (smmu->gerr_gsiv) + acpi_iort_register_irq(smmu->gerr_gsiv, "gerror", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + + if (smmu->sync_gsiv) + acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + } } static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 28938b5a334e..2ed6935d4483 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -262,8 +262,10 @@ int acpi_bus_init_power(struct acpi_device *device) return -EINVAL; device->power.state = ACPI_STATE_UNKNOWN; - if (!acpi_device_is_present(device)) + if (!acpi_device_is_present(device)) { + device->flags.initialized = false; return -ENXIO; + } result = acpi_device_get_power(device, &state); if (result) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index be79f7db1850..9531d3276f65 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -111,7 +111,7 @@ int acpi_device_setup_files(struct acpi_device *dev); void acpi_device_remove_files(struct acpi_device *dev); void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); -bool acpi_device_is_present(struct acpi_device *adev); +bool acpi_device_is_present(const struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); bool acpi_device_is_first_physical_node(struct acpi_device *adev, const struct device *dev); diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 9364398204e9..917c789f953d 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -57,6 +57,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc, dn->name = link->package.elements[0].string.pointer; dn->fwnode.type = FWNODE_ACPI_DATA; + dn->fwnode.ops = &acpi_fwnode_ops; dn->parent = parent; INIT_LIST_HEAD(&dn->data.subnodes); @@ -1119,3 +1120,119 @@ int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode, return 0; } + +static bool acpi_fwnode_device_is_available(struct fwnode_handle *fwnode) +{ + if (!is_acpi_device_node(fwnode)) + return false; + + return acpi_device_is_present(to_acpi_device_node(fwnode)); +} + +static bool acpi_fwnode_property_present(struct fwnode_handle *fwnode, + const char *propname) +{ + return !acpi_node_prop_get(fwnode, propname, NULL); +} + +static int acpi_fwnode_property_read_int_array(struct fwnode_handle *fwnode, + const char *propname, + unsigned int elem_size, + void *val, size_t nval) +{ + enum dev_prop_type type; + + switch (elem_size) { + case sizeof(u8): + type = DEV_PROP_U8; + break; + case sizeof(u16): + type = DEV_PROP_U16; + break; + case sizeof(u32): + type = DEV_PROP_U32; + break; + case sizeof(u64): + type = DEV_PROP_U64; + break; + default: + return -ENXIO; + } + + return acpi_node_prop_read(fwnode, propname, type, val, nval); +} + +static int acpi_fwnode_property_read_string_array(struct fwnode_handle *fwnode, + const char *propname, + const char **val, size_t nval) +{ + return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, + val, nval); +} + +static struct fwnode_handle * +acpi_fwnode_get_named_child_node(struct fwnode_handle *fwnode, + const char *childname) +{ + struct fwnode_handle *child; + + /* + * Find first matching named child node of this fwnode. + * For ACPI this will be a data only sub-node. + */ + fwnode_for_each_child_node(fwnode, child) + if (acpi_data_node_match(child, childname)) + return child; + + return NULL; +} + +static struct fwnode_handle * +acpi_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode, + struct fwnode_handle *prev) +{ + struct fwnode_handle *endpoint; + + endpoint = acpi_graph_get_next_endpoint(fwnode, prev); + if (IS_ERR(endpoint)) + return NULL; + + return endpoint; +} + +static struct fwnode_handle * +acpi_fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *endpoint = NULL; + + acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, &endpoint); + + return endpoint; +} + +static int acpi_fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode, + struct fwnode_endpoint *endpoint) +{ + struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode); + + endpoint->local_fwnode = fwnode; + + fwnode_property_read_u32(port_fwnode, "port", &endpoint->port); + fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id); + + return 0; +} + +const struct fwnode_operations acpi_fwnode_ops = { + .device_is_available = acpi_fwnode_device_is_available, + .property_present = acpi_fwnode_property_present, + .property_read_int_array = acpi_fwnode_property_read_int_array, + .property_read_string_array = acpi_fwnode_property_read_string_array, + .get_parent = acpi_node_get_parent, + .get_next_child_node = acpi_get_next_subnode, + .get_named_child_node = acpi_fwnode_get_named_child_node, + .graph_get_next_endpoint = acpi_fwnode_graph_get_next_endpoint, + .graph_get_remote_endpoint = acpi_fwnode_graph_get_remote_endpoint, + .graph_get_port_parent = acpi_node_get_parent, + .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, +}; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 59ebbd5f7b83..33897298f03e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1468,6 +1468,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, device->handle = handle; device->parent = acpi_bus_get_parent(handle); device->fwnode.type = FWNODE_ACPI; + device->fwnode.ops = &acpi_fwnode_ops; acpi_set_device_status(device, sta); acpi_device_get_busid(device); acpi_set_pnp_ids(handle, &device->pnp, type); @@ -1600,13 +1601,9 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, return 0; } -bool acpi_device_is_present(struct acpi_device *adev) +bool acpi_device_is_present(const struct acpi_device *adev) { - if (adev->status.present || adev->status.functional) - return true; - - adev->flags.initialized = false; - return false; + return adev->status.present || adev->status.functional; } static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, @@ -1839,6 +1836,7 @@ static void acpi_bus_attach(struct acpi_device *device) acpi_bus_get_status(device); /* Skip devices that are not present. */ if (!acpi_device_is_present(device)) { + device->flags.initialized = false; acpi_device_clear_enumerated(device); device->flags.power_manageable = 0; return; |