diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 80f945cbec8a..800f97868448 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -118,6 +118,11 @@ static const struct apd_device_desc wt_i2c_desc = { .fixed_clk_rate = 150000000, }; +static const struct apd_device_desc wt_i3c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 125000000, +}; + static struct property_entry uart_properties[] = { PROPERTY_ENTRY_U32("reg-io-width", 4), PROPERTY_ENTRY_U32("reg-shift", 2), @@ -231,6 +236,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { { "AMD0030", }, { "AMD0040", APD_ADDR(fch_misc_desc)}, { "AMDI0010", APD_ADDR(wt_i2c_desc) }, + { "AMDI0015", APD_ADDR(wt_i3c_desc) }, { "AMDI0019", APD_ADDR(wt_i2c_desc) }, { "AMDI0020", APD_ADDR(cz_uart_desc) }, { "AMDI0022", APD_ADDR(cz_uart_desc) }, diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index 23373faa35ec..3961fc47152c 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -439,23 +439,33 @@ static ssize_t description_show(struct device *dev, char *buf) { struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *str_obj; + acpi_status status; int result; - if (acpi_dev->pnp.str_obj == NULL) - return 0; + status = acpi_evaluate_object_typed(acpi_dev->handle, "_STR", + NULL, &buffer, + ACPI_TYPE_BUFFER); + if (ACPI_FAILURE(status)) + return -EIO; + + str_obj = buffer.pointer; /* * The _STR object contains a Unicode identifier for a device. * We need to convert to utf-8 so it can be displayed. */ result = utf16s_to_utf8s( - (wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer, - acpi_dev->pnp.str_obj->buffer.length, + (wchar_t *)str_obj->buffer.pointer, + str_obj->buffer.length, UTF16_LITTLE_ENDIAN, buf, PAGE_SIZE - 1); buf[result++] = '\n'; + kfree(str_obj); + return result; } static DEVICE_ATTR_RO(description); @@ -507,96 +517,97 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(status); -/** - * acpi_device_setup_files - Create sysfs attributes of an ACPI device. - * @dev: ACPI device object. - */ -int acpi_device_setup_files(struct acpi_device *dev) -{ - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_status status; - int result = 0; +static struct attribute *acpi_attrs[] = { + &dev_attr_path.attr, + &dev_attr_hid.attr, + &dev_attr_modalias.attr, + &dev_attr_description.attr, + &dev_attr_adr.attr, + &dev_attr_uid.attr, + &dev_attr_sun.attr, + &dev_attr_hrv.attr, + &dev_attr_status.attr, + &dev_attr_eject.attr, + &dev_attr_power_state.attr, + &dev_attr_real_power_state.attr, + NULL +}; +static bool acpi_show_attr(struct acpi_device *dev, const struct device_attribute *attr) +{ /* * Devices gotten from FADT don't have a "path" attribute */ - if (dev->handle) { - result = device_create_file(&dev->dev, &dev_attr_path); - if (result) - goto end; - } + if (attr == &dev_attr_path) + return dev->handle; - if (!list_empty(&dev->pnp.ids)) { - result = device_create_file(&dev->dev, &dev_attr_hid); - if (result) - goto end; + if (attr == &dev_attr_hid || attr == &dev_attr_modalias) + return !list_empty(&dev->pnp.ids); - result = device_create_file(&dev->dev, &dev_attr_modalias); - if (result) - goto end; - } + if (attr == &dev_attr_description) + return acpi_has_method(dev->handle, "_STR"); - /* - * If device has _STR, 'description' file is created - */ - if (acpi_has_method(dev->handle, "_STR")) { - status = acpi_evaluate_object(dev->handle, "_STR", - NULL, &buffer); - if (ACPI_FAILURE(status)) - buffer.pointer = NULL; - dev->pnp.str_obj = buffer.pointer; - result = device_create_file(&dev->dev, &dev_attr_description); - if (result) - goto end; - } + if (attr == &dev_attr_adr) + return dev->pnp.type.bus_address; - if (dev->pnp.type.bus_address) - result = device_create_file(&dev->dev, &dev_attr_adr); - if (acpi_device_uid(dev)) - result = device_create_file(&dev->dev, &dev_attr_uid); + if (attr == &dev_attr_uid) + return acpi_device_uid(dev); - if (acpi_has_method(dev->handle, "_SUN")) { - result = device_create_file(&dev->dev, &dev_attr_sun); - if (result) - goto end; - } + if (attr == &dev_attr_sun) + return acpi_has_method(dev->handle, "_SUN"); - if (acpi_has_method(dev->handle, "_HRV")) { - result = device_create_file(&dev->dev, &dev_attr_hrv); - if (result) - goto end; - } + if (attr == &dev_attr_hrv) + return acpi_has_method(dev->handle, "_HRV"); - if (acpi_has_method(dev->handle, "_STA")) { - result = device_create_file(&dev->dev, &dev_attr_status); - if (result) - goto end; - } + if (attr == &dev_attr_status) + return acpi_has_method(dev->handle, "_STA"); /* * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. */ - if (acpi_has_method(dev->handle, "_EJ0")) { - result = device_create_file(&dev->dev, &dev_attr_eject); - if (result) - return result; - } + if (attr == &dev_attr_eject) + return acpi_has_method(dev->handle, "_EJ0"); - if (dev->flags.power_manageable) { - result = device_create_file(&dev->dev, &dev_attr_power_state); - if (result) - return result; + if (attr == &dev_attr_power_state) + return dev->flags.power_manageable; - if (dev->power.flags.power_resources) - result = device_create_file(&dev->dev, - &dev_attr_real_power_state); - } + if (attr == &dev_attr_real_power_state) + return dev->flags.power_manageable && dev->power.flags.power_resources; + dev_warn_once(&dev->dev, "Unexpected attribute: %s\n", attr->attr.name); + return false; +} + +static umode_t acpi_attr_is_visible(struct kobject *kobj, + struct attribute *attr, + int attrno) +{ + struct acpi_device *dev = to_acpi_device(kobj_to_dev(kobj)); + + if (acpi_show_attr(dev, container_of(attr, struct device_attribute, attr))) + return attr->mode; + else + return 0; +} + +static const struct attribute_group acpi_group = { + .attrs = acpi_attrs, + .is_visible = acpi_attr_is_visible, +}; + +const struct attribute_group *acpi_groups[] = { + &acpi_group, + NULL +}; + +/** + * acpi_device_setup_files - Create sysfs attributes of an ACPI device. + * @dev: ACPI device object. + */ +void acpi_device_setup_files(struct acpi_device *dev) +{ acpi_expose_nondev_subnodes(&dev->dev.kobj, &dev->data); - -end: - return result; } /** @@ -606,41 +617,4 @@ end: void acpi_device_remove_files(struct acpi_device *dev) { acpi_hide_nondev_subnodes(&dev->data); - - if (dev->flags.power_manageable) { - device_remove_file(&dev->dev, &dev_attr_power_state); - if (dev->power.flags.power_resources) - device_remove_file(&dev->dev, - &dev_attr_real_power_state); - } - - /* - * If device has _STR, remove 'description' file - */ - if (acpi_has_method(dev->handle, "_STR")) { - kfree(dev->pnp.str_obj); - device_remove_file(&dev->dev, &dev_attr_description); - } - /* - * If device has _EJ0, remove 'eject' file. - */ - if (acpi_has_method(dev->handle, "_EJ0")) - device_remove_file(&dev->dev, &dev_attr_eject); - - if (acpi_has_method(dev->handle, "_SUN")) - device_remove_file(&dev->dev, &dev_attr_sun); - - if (acpi_has_method(dev->handle, "_HRV")) - device_remove_file(&dev->dev, &dev_attr_hrv); - - if (acpi_device_uid(dev)) - device_remove_file(&dev->dev, &dev_attr_uid); - if (dev->pnp.type.bus_address) - device_remove_file(&dev->dev, &dev_attr_adr); - device_remove_file(&dev->dev, &dev_attr_modalias); - device_remove_file(&dev->dev, &dev_attr_hid); - if (acpi_has_method(dev->handle, "_STA")) - device_remove_file(&dev->dev, &dev_attr_status); - if (dev->handle) - device_remove_file(&dev->dev, &dev_attr_path); } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 38d2f6e6b12b..25399f6dde7e 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -783,6 +783,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, unsigned long tmp; int ret = 0; + if (t->rdata) + memset(t->rdata, 0, t->rlen); + /* start transaction */ spin_lock_irqsave(&ec->lock, tmp); /* Enable GPE for command processing (IBF=0/OBF=1) */ @@ -819,8 +822,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) return -EINVAL; - if (t->rdata) - memset(t->rdata, 0, t->rlen); mutex_lock(&ec->mutex); if (ec->global_lock) { @@ -847,7 +848,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec) .wdata = NULL, .rdata = &d, .wlen = 0, .rlen = 1}; - return acpi_ec_transaction(ec, &t); + return acpi_ec_transaction_unlocked(ec, &t); } static int acpi_ec_burst_disable(struct acpi_ec *ec) @@ -857,7 +858,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec) .wlen = 0, .rlen = 0}; return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ? - acpi_ec_transaction(ec, &t) : 0; + acpi_ec_transaction_unlocked(ec, &t) : 0; } static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) @@ -873,6 +874,19 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) return result; } +static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data) +{ + int result; + u8 d; + struct transaction t = {.command = ACPI_EC_COMMAND_READ, + .wdata = &address, .rdata = &d, + .wlen = 1, .rlen = 1}; + + result = acpi_ec_transaction_unlocked(ec, &t); + *data = d; + return result; +} + static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) { u8 wdata[2] = { address, data }; @@ -883,6 +897,16 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) return acpi_ec_transaction(ec, &t); } +static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data) +{ + u8 wdata[2] = { address, data }; + struct transaction t = {.command = ACPI_EC_COMMAND_WRITE, + .wdata = wdata, .rdata = NULL, + .wlen = 2, .rlen = 0}; + + return acpi_ec_transaction_unlocked(ec, &t); +} + int ec_read(u8 addr, u8 *val) { int err; @@ -1323,6 +1347,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, struct acpi_ec *ec = handler_context; int result = 0, i, bytes = bits / 8; u8 *value = (u8 *)value64; + u32 glk; if ((address > 0xFF) || !value || !handler_context) return AE_BAD_PARAMETER; @@ -1330,13 +1355,25 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, if (function != ACPI_READ && function != ACPI_WRITE) return AE_BAD_PARAMETER; + mutex_lock(&ec->mutex); + + if (ec->global_lock) { + acpi_status status; + + status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); + if (ACPI_FAILURE(status)) { + result = -ENODEV; + goto unlock; + } + } + if (ec->busy_polling || bits > 8) acpi_ec_burst_enable(ec); for (i = 0; i < bytes; ++i, ++address, ++value) { result = (function == ACPI_READ) ? - acpi_ec_read(ec, address, value) : - acpi_ec_write(ec, address, *value); + acpi_ec_read_unlocked(ec, address, value) : + acpi_ec_write_unlocked(ec, address, *value); if (result < 0) break; } @@ -1344,6 +1381,12 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, if (ec->busy_polling || bits > 8) acpi_ec_burst_disable(ec); + if (ec->global_lock) + acpi_release_global_lock(glk); + +unlock: + mutex_unlock(&ec->mutex); + switch (result) { case -EINVAL: return AE_BAD_PARAMETER; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index aadd4c218b32..ced7dff9a5db 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -118,8 +118,9 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, int type, void (*release)(struct device *)); int acpi_tie_acpi_dev(struct acpi_device *adev); int acpi_device_add(struct acpi_device *device); -int acpi_device_setup_files(struct acpi_device *dev); +void acpi_device_setup_files(struct acpi_device *dev); void acpi_device_remove_files(struct acpi_device *dev); +extern const struct attribute_group *acpi_groups[]; void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); bool acpi_device_is_enabled(const struct acpi_device *adev); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index eba282c86edd..7ecc401fb97f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -795,10 +795,7 @@ int acpi_device_add(struct acpi_device *device) goto err; } - result = acpi_device_setup_files(device); - if (result) - pr_err("Error creating sysfs interface for device %s\n", - dev_name(&device->dev)); + acpi_device_setup_files(device); return 0; @@ -1825,6 +1822,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, device->dev.parent = parent ? &parent->dev : NULL; device->dev.release = release; device->dev.bus = &acpi_bus_type; + device->dev.groups = acpi_groups; fwnode_init(&device->fwnode, &acpi_device_fwnode_ops); acpi_set_device_status(device, ACPI_STA_DEFAULT); acpi_device_get_busid(device); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index ae9384282273..6de542d99518 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -801,7 +801,8 @@ acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 func, if (ret != AE_NOT_FOUND) acpi_handle_warn(handle, - "failed to evaluate _DSM %pUb (0x%x)\n", guid, ret); + "failed to evaluate _DSM %pUb rev:%lld func:%lld (0x%x)\n", + guid, rev, func, ret); return NULL; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index af72a5d9de99..c5d4c85c0cd9 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -255,7 +255,6 @@ struct acpi_device_pnp { struct list_head ids; /* _HID and _CIDs */ acpi_device_name device_name; /* Driver-determined */ acpi_device_class device_class; /* " */ - union acpi_object *str_obj; /* unicode string for _STR method */ }; #define acpi_device_bid(d) ((d)->pnp.bus_id)