Merge tag 'acpi-7.4-rc1' into loongarch-next

LoongArch architecture changes for 7.4 need the acpi changes to add new
features, so merge 'acpi-7.4-rc1' to create a base.
This commit is contained in:
Huacai Chen 2026-10-22 21:02:37 +08:00
commit 15107b81b8
75 changed files with 997 additions and 588 deletions

View File

@ -180,8 +180,10 @@ function are specified using param1::
| segment | bus | device | function | reserved |
+-------------------------------------------------+
Anyway, you get the idea, if there's doubt just take a look at the code
in drivers/acpi/apei/einj.c.
Anyway, you get the idea, if there's doubt just take a look at the code:
drivers/acpi/apei/einj-core.c holds the core logic, while CXL-specific
handling lives in drivers/acpi/apei/einj-cxl.c and the shared plumbing
in drivers/acpi/apei/apei-internal.h.
An ACPI 5.0 BIOS may also allow vendor-specific errors to be injected.
In this case a file named vendor will contain identifying information

View File

@ -134,22 +134,30 @@ static int print_extlog_rcd(const char *pfx,
}
static void extlog_print_pcie(struct cper_sec_pcie *pcie_err,
int severity)
int severity, u32 len)
{
#ifdef ACPI_APEI_PCIEAER
struct aer_capability_regs *aer;
#ifdef CONFIG_ACPI_APEI_PCIEAER
struct aer_capability_regs aer_regs = {};
struct pci_dev *pdev;
unsigned int devfn;
unsigned int bus;
int aer_severity;
int domain;
if (len < sizeof(*pcie_err)) {
pr_warn_ratelimited(FW_WARN
"PCIe error section too small (%u)\n", len);
return;
}
if (!(pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO))
return;
aer_severity = cper_severity_to_aer(severity);
aer = (struct aer_capability_regs *)pcie_err->aer_info;
aer_cap_regs_unpack(&aer_regs, pcie_err->aer_info, sizeof(pcie_err->aer_info));
domain = pcie_err->device_id.segment;
bus = pcie_err->device_id.bus;
devfn = PCI_DEVFN(pcie_err->device_id.device,
@ -158,28 +166,11 @@ static void extlog_print_pcie(struct cper_sec_pcie *pcie_err,
if (!pdev)
return;
pci_print_aer(pdev, aer_severity, aer);
pci_print_aer(pdev, aer_severity, &aer_regs);
pci_dev_put(pdev);
#endif
}
static void
extlog_cxl_cper_handle_prot_err(struct cxl_cper_sec_prot_err *prot_err,
int severity)
{
#ifdef ACPI_APEI_PCIEAER
struct cxl_cper_prot_err_work_data wd;
if (cxl_cper_sec_prot_err_valid(prot_err))
return;
if (cxl_cper_setup_prot_err_work_data(&wd, prot_err, severity))
return;
cxl_cper_handle_prot_err(&wd);
#endif
}
static int extlog_print(struct notifier_block *nb, unsigned long val,
void *data)
{
@ -208,6 +199,15 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
tmp = (struct acpi_hest_generic_status *)elog_buf;
/*
* Bound the length before cper_estatus_check() walks the sections: it
* iterates over data_length, which is not yet known to fit elog_buf.
* cper_estatus_check_header() then rejects a length that wrapped, which
* the bound cannot see.
*/
if (cper_estatus_len(tmp) > ELOG_ENTRY_LEN || cper_estatus_check(tmp))
return NOTIFY_DONE;
if (!ras_userspace_consumers()) {
print_extlog_rcd(NULL, tmp, cpu);
goto out;
@ -235,12 +235,14 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
struct cxl_cper_sec_prot_err *prot_err =
acpi_hest_get_payload(gdata);
extlog_cxl_cper_handle_prot_err(prot_err,
gdata->error_severity);
cxl_cper_post_prot_err(prot_err,
gdata->error_severity,
gdata->error_data_length);
} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);
extlog_print_pcie(pcie_err, gdata->error_severity);
extlog_print_pcie(pcie_err, gdata->error_severity,
gdata->error_data_length);
} else {
void *err = acpi_hest_get_payload(gdata);

View File

@ -36,17 +36,11 @@ static u32 mrrm_mem_entry_num;
static int get_node_num(struct mrrm_mem_range_entry *e)
{
unsigned int nid;
struct zone *zone;
for_each_online_node(nid) {
for (int z = 0; z < MAX_NR_ZONES; z++) {
struct zone *zone = NODE_DATA(nid)->node_zones + z;
if (!populated_zone(zone))
continue;
if (zone_intersects(zone, PHYS_PFN(e->base), PHYS_PFN(e->length)))
return zone_to_nid(zone);
}
for_each_populated_zone(zone) {
if (zone_intersects(zone, PHYS_PFN(e->base), PHYS_PFN(e->length)))
return zone_to_nid(zone);
}
return -ENOENT;

View File

@ -28,6 +28,7 @@
* to PCC commands
*/
#define PCC_CMD_WAIT_RETRIES_NUM 500ULL
#define PCC_SIGNATURE_SIZE sizeof(u32)
struct pcc_data {
struct pcc_mbox_chan *pcc_chan;
@ -49,10 +50,24 @@ static acpi_status
acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
void *handler_context, void **region_context)
{
struct pcc_data *data;
struct acpi_pcc_info *ctx = handler_context;
struct pcc_mbox_chan *pcc_chan;
struct pcc_data *data;
acpi_status ret;
u64 usecs_lat;
if (function == ACPI_REGION_DEACTIVATE) {
data = *region_context;
if (data) {
pcc_mbox_free_channel(data->pcc_chan);
kfree(data);
*region_context = NULL;
}
return AE_OK;
}
if (function != ACPI_REGION_ACTIVATE)
return AE_BAD_PARAMETER;
data = kzalloc_obj(*data);
if (!data)
@ -74,6 +89,14 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
}
pcc_chan = data->pcc_chan;
if (pcc_chan->shmem_size < PCC_SIGNATURE_SIZE ||
ctx->length > pcc_chan->shmem_size - PCC_SIGNATURE_SIZE) {
pr_err("PCC channel-%d shared memory is too small.\n",
ctx->subspace_id);
ret = AE_AML_REGION_LIMIT;
goto err_free_channel;
}
if (!pcc_chan->mchan->mbox->txdone_irq) {
pr_err("This channel-%d does not support interrupt.\n",
ctx->subspace_id);
@ -81,6 +104,16 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
goto err_free_channel;
}
/*
* pcc_chan->latency is just a Nominal value. In reality the remote
* processor could be much slower to reply. So add an arbitrary
* amount of wait on top of Nominal.
*/
usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * pcc_chan->latency;
data->cl.tx_tout = DIV_ROUND_UP_ULL(usecs_lat, 1000);
if (!data->cl.tx_tout)
data->cl.tx_tout = 1;
*region_context = data;
return AE_OK;
@ -97,27 +130,23 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
u32 bits, acpi_integer *value,
void *handler_context, void *region_context)
{
int ret;
struct pcc_data *data = region_context;
u64 usecs_lat;
void __iomem *pcc_opregion;
int ret;
pcc_opregion = data->pcc_chan->shmem + PCC_SIGNATURE_SIZE;
reinit_completion(&data->done);
/* Write to Shared Memory */
memcpy_toio(data->pcc_chan->shmem, (void *)value, data->ctx.length);
/* Write to the PCC OperationRegion after the shared memory signature. */
memcpy_toio(pcc_opregion, (void *)value, data->ctx.length);
ret = mbox_send_message(data->pcc_chan->mchan, NULL);
if (ret < 0)
return AE_ERROR;
/*
* pcc_chan->latency is just a Nominal value. In reality the remote
* processor could be much slower to reply. So add an arbitrary
* amount of wait on top of Nominal.
*/
usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency;
ret = wait_for_completion_timeout(&data->done,
usecs_to_jiffies(usecs_lat));
msecs_to_jiffies(data->cl.tx_tout));
if (ret == 0) {
pr_err("PCC command executed timeout!\n");
return AE_TIME;
@ -125,7 +154,7 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
mbox_chan_txdone(data->pcc_chan->mchan, ret);
memcpy_fromio(value, data->pcc_chan->shmem, data->ctx.length);
memcpy_fromio(value, pcc_opregion, data->ctx.length);
return AE_OK;
}

View File

@ -1700,9 +1700,9 @@ static int acpi_video_resume(struct notifier_block *nb,
static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
{
struct device *phys_dev, *parent = NULL;
struct backlight_properties props;
struct pci_dev *pdev;
struct device *parent = NULL;
int result;
static int count;
char *name;
@ -1729,11 +1729,10 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
device,
&acpi_backlight_ops,
&props);
put_device(parent);
kfree(name);
if (IS_ERR(device->backlight)) {
device->backlight = NULL;
return;
goto put_parent;
}
/*
@ -1743,8 +1742,12 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
device->backlight->props.brightness =
acpi_video_get_brightness(device->backlight);
device->cooling_dev = thermal_cooling_device_register("LCD", device,
&video_cooling_ops);
phys_dev = acpi_bus_get_primary_device(device->dev);
if (!phys_dev)
phys_dev = get_device(parent);
device->cooling_dev = thermal_cooling_device_create(phys_dev, "LCD", device,
&video_cooling_ops);
if (IS_ERR(device->cooling_dev)) {
/*
* Set cooling_dev to NULL so we don't crash trying to free it.
@ -1753,21 +1756,17 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
* -- dtor
*/
device->cooling_dev = NULL;
return;
goto put_phys_dev;
}
dev_info(&device->dev->dev, "registered as cooling_device%d\n",
device->cooling_dev->id);
result = sysfs_create_link(&device->dev->dev.kobj,
&device->cooling_dev->device.kobj,
"thermal_cooling");
if (result)
pr_info("sysfs link creation failed\n");
dev_info(&device->cooling_dev->device, "Using ACPI device %s\n",
acpi_dev_name(device->dev));
result = sysfs_create_link(&device->cooling_dev->device.kobj,
&device->dev->dev.kobj, "device");
if (result)
pr_info("Reverse sysfs link creation failed\n");
put_phys_dev:
put_device(phys_dev);
put_parent:
put_device(parent);
}
static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video)
@ -1825,6 +1824,10 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device)
{
if (device->cooling_dev) {
thermal_cooling_device_unregister(device->cooling_dev);
device->cooling_dev = NULL;
}
if (device->backlight) {
backlight_device_unregister(device->backlight);
device->backlight = NULL;
@ -1834,12 +1837,6 @@ static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device
kfree(device->brightness);
device->brightness = NULL;
}
if (device->cooling_dev) {
sysfs_remove_link(&device->dev->dev.kobj, "thermal_cooling");
sysfs_remove_link(&device->cooling_dev->device.kobj, "device");
thermal_cooling_device_unregister(device->cooling_dev);
device->cooling_dev = NULL;
}
}
static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video)

View File

@ -522,7 +522,8 @@ acpi_ds_create_field(union acpi_parse_object *op,
}
if (info.region_node->object->region.space_id ==
ACPI_ADR_SPACE_PLATFORM_COMM) {
ACPI_ADR_SPACE_PLATFORM_COMM &&
!region_node->object->field.internal_pcc_buffer) {
region_node->object->field.internal_pcc_buffer =
ACPI_ALLOCATE_ZEROED(info.region_node->object->region.
length);

View File

@ -45,12 +45,13 @@ static const u8 acpi_protocol_lengths[] = {
/*
* The following macros determine a given offset is a COMD field.
* According to the specification, generic subspaces (types 0-2) contains a
* 2-byte COMD field at offset 4 and master subspaces (type 3) contains a 4-byte
* COMD field starting at offset 12.
* According to the specification, the PCC OperationRegion begins after
* the PCC signature. The raw shared memory COMD offsets of 4 for generic
* subspaces (types 0-2) and 12 for master subspaces (type 3) therefore
* appear at OperationRegion offsets 0 and 8.
*/
#define GENERIC_SUBSPACE_COMMAND(a) (4 == a || a == 5)
#define MASTER_SUBSPACE_COMMAND(a) (12 <= a && a <= 15)
#define GENERIC_SUBSPACE_COMMAND(a) (0 == a || a == 1)
#define MASTER_SUBSPACE_COMMAND(a) (8 <= a && a <= 11)
/*******************************************************************************
*

View File

@ -603,7 +603,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
* and don't filter out 'corrected' error here.
*/
if (is_cache && has_pa) {
queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags);
queued |= ghes_do_memory_failure(err_info->physical_fault_addr, flags);
p += err_info->length;
continue;
}
@ -642,11 +642,14 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
#ifdef CONFIG_ACPI_APEI_PCIEAER
struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);
if (gdata->error_data_length < sizeof(*pcie_err))
return;
if (pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
struct aer_capability_regs *aer_info;
unsigned int devfn;
int aer_severity;
u8 *aer_info;
devfn = PCI_DEVFN(pcie_err->device_id.device,
pcie_err->device_id.function);
@ -664,13 +667,12 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
sizeof(struct aer_capability_regs));
if (!aer_info)
return;
memcpy(aer_info, pcie_err->aer_info, sizeof(struct aer_capability_regs));
aer_cap_regs_unpack(aer_info, pcie_err->aer_info, sizeof(pcie_err->aer_info));
aer_recover_queue(pcie_err->device_id.segment,
pcie_err->device_id.bus,
devfn, aer_severity,
(struct aer_capability_regs *)
aer_info);
devfn, aer_severity, aer_info);
}
#endif
}
@ -752,13 +754,13 @@ static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data,
static DEFINE_RAW_SPINLOCK(cxl_cper_prot_err_work_lock);
struct work_struct *cxl_cper_prot_err_work;
static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
int severity)
void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
int severity, u32 len)
{
#ifdef CONFIG_ACPI_APEI_PCIEAER
struct cxl_cper_prot_err_work_data wd;
if (cxl_cper_sec_prot_err_valid(prot_err))
if (cxl_cper_sec_prot_err_valid(prot_err, len))
return;
guard(raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
@ -777,6 +779,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
schedule_work(cxl_cper_prot_err_work);
#endif
}
EXPORT_SYMBOL_FOR_MODULES(cxl_cper_post_prot_err, "acpi_extlog");
void cxl_cper_register_prot_err_work(struct work_struct *work)
{
@ -823,10 +826,15 @@ static DEFINE_RAW_SPINLOCK(cxl_cper_work_lock);
struct work_struct *cxl_cper_work;
static void cxl_cper_post_event(enum cxl_event_type event_type,
struct cxl_cper_event_rec *rec)
struct cxl_cper_event_rec *rec, u32 len)
{
struct cxl_cper_work_data wd;
if (len < sizeof(*rec)) {
pr_err(FW_WARN "CXL CPER section too small (%u)\n", len);
return;
}
if (rec->hdr.length <= sizeof(rec->hdr) ||
rec->hdr.length > sizeof(*rec)) {
pr_err(FW_WARN "CXL CPER Invalid section length (%u)\n",
@ -923,6 +931,28 @@ static void ghes_log_hwerr(int sev, guid_t *sec_type)
hwerr_log_error_type(HWERR_RECOV_OTHERS);
}
/*
* The fields from "extended" on are absent from the 73-byte UEFI 2.1/2.2
* layout that older firmware still emits. Return the length needed for the
* fields the validation bits claim, so over-claiming is rejected without
* rejecting an honest short record.
*/
static u32 ghes_mem_err_min_len(u64 validation_bits)
{
u32 len = sizeof(struct cper_sec_mem_err_old);
if (validation_bits & (CPER_MEM_VALID_ROW_EXT | CPER_MEM_VALID_CHIP_ID))
len = offsetof(struct cper_sec_mem_err, rank);
if (validation_bits & CPER_MEM_VALID_RANK_NUMBER)
len = offsetof(struct cper_sec_mem_err, mem_array_handle);
if (validation_bits & CPER_MEM_VALID_CARD_HANDLE)
len = offsetof(struct cper_sec_mem_err, mem_dev_handle);
if (validation_bits & CPER_MEM_VALID_MODULE_HANDLE)
len = sizeof(struct cper_sec_mem_err);
return len;
}
static void ghes_do_proc(struct ghes *ghes,
const struct acpi_hest_generic_status *estatus)
{
@ -948,30 +978,53 @@ static void ghes_do_proc(struct ghes *ghes,
if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
/*
* Check once for all three consumers below. The 73-byte
* UEFI 2.1/2.2 layout is the floor, matching
* cper_estatus_print_section() and making
* validation_bits safe to read.
*/
if (gdata->error_data_length <
sizeof(struct cper_sec_mem_err_old))
continue;
/* Then require what the claimed fields actually need. */
if (gdata->error_data_length <
ghes_mem_err_min_len(mem_err->validation_bits)) {
pr_warn_ratelimited(FW_WARN GHES_PFX
"memory error section too small (%u) for the fields it claims\n",
gdata->error_data_length);
continue;
}
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, sync);
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, sync);
queued |= ghes_handle_arm_hw_error(gdata, sev, sync);
} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
cxl_cper_post_prot_err(prot_err, gdata->error_severity);
cxl_cper_post_prot_err(prot_err, gdata->error_severity,
gdata->error_data_length);
} else if (guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID)) {
struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
cxl_cper_post_event(CXL_CPER_EVENT_GEN_MEDIA, rec);
cxl_cper_post_event(CXL_CPER_EVENT_GEN_MEDIA, rec,
gdata->error_data_length);
} else if (guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID)) {
struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
cxl_cper_post_event(CXL_CPER_EVENT_DRAM, rec);
cxl_cper_post_event(CXL_CPER_EVENT_DRAM, rec,
gdata->error_data_length);
} else if (guid_equal(sec_type, &CPER_SEC_CXL_MEM_MODULE_GUID)) {
struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
cxl_cper_post_event(CXL_CPER_EVENT_MEM_MODULE, rec);
cxl_cper_post_event(CXL_CPER_EVENT_MEM_MODULE, rec,
gdata->error_data_length);
} else {
void *err = acpi_hest_get_payload(gdata);

View File

@ -5,8 +5,15 @@
#include <linux/aer.h>
#include <cxl/event.h>
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err, u32 len)
{
if (len < sizeof(*prot_err)) {
pr_err_ratelimited(FW_WARN
"CXL CPER prot err section too small (%u)\n",
len);
return -EINVAL;
}
if (!(prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS)) {
pr_err_ratelimited("CXL CPER invalid agent type\n");
return -EINVAL;
@ -23,6 +30,15 @@ int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
return -EINVAL;
}
/* The RAS Capability block sits after a firmware-sized DVSEC. */
if (sizeof(*prot_err) + prot_err->dvsec_len +
sizeof(struct cxl_ras_capability_regs) > len) {
pr_err_ratelimited(FW_WARN
"CXL CPER prot err DVSEC (%u) overruns section (%u)\n",
prot_err->dvsec_len, len);
return -EINVAL;
}
if ((prot_err->agent_type == RCD || prot_err->agent_type == DEVICE ||
prot_err->agent_type == LD || prot_err->agent_type == FMLD) &&
!(prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER))

View File

@ -87,11 +87,12 @@ static int amba_handler_attach(struct acpi_device *adev,
* the amba device we are about to create.
*/
if (parent)
dev->dev.parent = acpi_get_first_physical_node(parent);
dev->dev.parent = acpi_bus_get_primary_device(parent);
device_set_node(&dev->dev, acpi_fwnode_handle(adev));
ret = amba_device_add(dev, &iomem_resource);
put_device(dev->dev.parent);
if (ret) {
dev_err(&adev->dev, "%s(): amba_device_add() failed (%d)\n",
__func__, ret);

View File

@ -341,7 +341,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
return ret;
}
static const enum power_supply_property charge_battery_props[] = {
/* For devices supporting the _BIX ACPI control method */
static const enum power_supply_property charge_battery_extended_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
@ -359,7 +361,7 @@ static const enum power_supply_property charge_battery_props[] = {
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
static const enum power_supply_property charge_battery_full_cap_broken_props[] = {
static const enum power_supply_property charge_battery_full_cap_broken_extended_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
@ -373,7 +375,7 @@ static const enum power_supply_property charge_battery_full_cap_broken_props[] =
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
static const enum power_supply_property energy_battery_props[] = {
static const enum power_supply_property energy_battery_extended_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
@ -391,7 +393,7 @@ static const enum power_supply_property energy_battery_props[] = {
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
static const enum power_supply_property energy_battery_full_cap_broken_props[] = {
static const enum power_supply_property energy_battery_full_cap_broken_extended_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
@ -405,6 +407,68 @@ static const enum power_supply_property energy_battery_full_cap_broken_props[] =
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
/* For devices supporting only the _BIF ACPI control method */
static const enum power_supply_property charge_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
static const enum power_supply_property charge_battery_full_cap_broken_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
static const enum power_supply_property energy_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_POWER_NOW,
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
POWER_SUPPLY_PROP_ENERGY_FULL,
POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
static const enum power_supply_property energy_battery_full_cap_broken_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_POWER_NOW,
POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
/* Battery Management */
struct acpi_offsets {
size_t offset; /* offset inside struct acpi_sbs_battery */
@ -904,6 +968,7 @@ static void __exit battery_hook_exit(void)
static int sysfs_add_battery(struct acpi_battery *battery)
{
bool extended_info_available = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
struct power_supply_config psy_cfg = {
.drv_data = battery,
.attr_grp = acpi_battery_groups,
@ -922,25 +987,55 @@ static int sysfs_add_battery(struct acpi_battery *battery)
if (power_unit == ACPI_BATTERY_POWER_UNIT_MA) {
if (full_cap_broken) {
battery->bat_desc.properties =
charge_battery_full_cap_broken_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(charge_battery_full_cap_broken_props);
if (extended_info_available) {
battery->bat_desc.properties =
charge_battery_full_cap_broken_extended_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(charge_battery_full_cap_broken_extended_props);
} else {
battery->bat_desc.properties =
charge_battery_full_cap_broken_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(charge_battery_full_cap_broken_props);
}
} else {
battery->bat_desc.properties = charge_battery_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(charge_battery_props);
if (extended_info_available) {
battery->bat_desc.properties =
charge_battery_extended_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(charge_battery_extended_props);
} else {
battery->bat_desc.properties =
charge_battery_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(charge_battery_props);
}
}
} else {
if (full_cap_broken) {
battery->bat_desc.properties =
energy_battery_full_cap_broken_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(energy_battery_full_cap_broken_props);
if (extended_info_available) {
battery->bat_desc.properties =
energy_battery_full_cap_broken_extended_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(energy_battery_full_cap_broken_extended_props);
} else {
battery->bat_desc.properties =
energy_battery_full_cap_broken_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(energy_battery_full_cap_broken_props);
}
} else {
battery->bat_desc.properties = energy_battery_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(energy_battery_props);
if (extended_info_available) {
battery->bat_desc.properties =
energy_battery_extended_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(energy_battery_extended_props);
} else {
battery->bat_desc.properties =
energy_battery_props;
battery->bat_desc.num_properties =
ARRAY_SIZE(energy_battery_props);
}
}
}

View File

@ -809,24 +809,14 @@ struct device *acpi_bus_get_primary_device(struct acpi_device *adev)
}
EXPORT_SYMBOL_GPL(acpi_bus_get_primary_device);
/**
* acpi_get_first_physical_node - Find first physical node of an ACPI device
* @adev: ACPI device in question
*
* Return: First physical node of ACPI device @adev
*/
struct device *acpi_get_first_physical_node(struct acpi_device *adev)
{
guard(mutex)(&adev->physical_node_lock);
return primary_physical_device(adev);
}
EXPORT_SYMBOL_GPL(acpi_get_first_physical_node);
static struct acpi_device *acpi_primary_dev_companion(struct acpi_device *adev,
const struct device *dev)
{
const struct device *phys_dev = acpi_get_first_physical_node(adev);
const struct device *phys_dev;
guard(mutex)(&adev->physical_node_lock);
phys_dev = primary_physical_device(adev);
return phys_dev && phys_dev == dev ? adev : NULL;
}
@ -1120,11 +1110,6 @@ EXPORT_SYMBOL_GPL(acpi_driver_match_device);
ACPI Bus operations
-------------------------------------------------------------------------- */
static int acpi_bus_match(struct device *dev, const struct device_driver *drv)
{
return 0;
}
static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
return __acpi_device_uevent_modalias(to_acpi_device(dev), env);
@ -1132,7 +1117,6 @@ static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env *
const struct bus_type acpi_bus_type = {
.name = "acpi",
.match = acpi_bus_match,
.uevent = acpi_device_uevent,
};
@ -1451,7 +1435,7 @@ static int __init acpi_bus_init(void)
*/
acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
result = bus_register(&acpi_bus_type);
result = companion_bus_register(&acpi_bus_type);
if (!result)
return 0;

View File

@ -144,6 +144,18 @@ static const struct dmi_system_id dmi_lid_quirks[] = {
},
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
},
{
/*
* Razer Blade Stealth 13 early 2020, when the lid is opened
* while suspended the open notification is lost and _LID keeps
* returning closed after resume, causing spurious re-suspends.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Blade Stealth 13 (Early 2020) - RZ09-0310"),
},
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
},
{
/*
* Samsung galaxybook2 ,initial _LID device notification returns

View File

@ -23,6 +23,8 @@
#include "fan.h"
#include "internal.h"
#define ACPI_D_STATE_INVALID ACPI_D_STATE_COUNT
/**
* acpi_power_state_string - String representation of ACPI device power state.
* @state: ACPI device power state to return the string representation of.
@ -75,15 +77,14 @@ static int acpi_dev_pm_explicit_get(struct acpi_device *device, int *state)
int acpi_device_get_power(struct acpi_device *device, int *state)
{
int result = ACPI_STATE_UNKNOWN;
struct acpi_device *parent;
int error;
if (!device || !state)
return -EINVAL;
parent = acpi_dev_parent(device);
if (!device->flags.power_manageable) {
struct acpi_device *parent = acpi_dev_parent(device);
/* TBD: Non-recursive algorithm for walking up hierarchy. */
*state = parent ? parent->power.state : ACPI_STATE_D0;
goto out;
@ -119,16 +120,6 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_HOT : psc;
}
/*
* If we were unsure about the device parent's power state up to this
* point, the fact that the device is in D0 implies that the parent has
* to be in D0 too, except if ignore_parent is set.
*/
if (!device->power.flags.ignore_parent && parent &&
parent->power.state == ACPI_STATE_UNKNOWN &&
result == ACPI_STATE_D0)
parent->power.state = ACPI_STATE_D0;
*state = result;
out:
@ -304,24 +295,28 @@ int acpi_bus_set_power(acpi_handle handle, int state)
}
EXPORT_SYMBOL(acpi_bus_set_power);
int acpi_bus_init_power(struct acpi_device *device)
static int acpi_device_init_power(struct acpi_device *device)
{
int state;
int result;
if (!device)
return -EINVAL;
device->power.state = ACPI_STATE_UNKNOWN;
if (!acpi_device_is_present(device)) {
device->flags.initialized = false;
return -ENXIO;
}
result = acpi_device_get_power(device, &state);
if (result)
return result;
/*
* If the current power state of the device is D0 and it has a parent
* whose power state is not ignored, and the parent's power state
* initialization has failed, the parent's power state can be updated to
* D0 for consistency.
*/
if (!device->power.flags.ignore_parent && state == ACPI_STATE_D0) {
struct acpi_device *parent = acpi_dev_parent(device);
if (parent && parent->power.state == ACPI_D_STATE_INVALID)
parent->power.state = ACPI_STATE_D0;
}
if (state < ACPI_STATE_D3_COLD && device->power.flags.power_resources) {
/* Reference count the power resources. */
result = acpi_power_on_resources(device, state);
@ -351,9 +346,36 @@ int acpi_bus_init_power(struct acpi_device *device)
state = ACPI_STATE_D0;
}
device->power.state = state;
acpi_handle_debug(device->handle, "Initial power state: %s\n",
acpi_power_state_string(state));
return 0;
}
int acpi_bus_init_power(struct acpi_device *device)
{
int result;
if (device->power.state != ACPI_STATE_UNKNOWN)
return 0;
/*
* The ACPI device power state can be only initialized once. If this
* fails, ACPI power management will not be used for the device going
* forward.
*/
result = acpi_device_init_power(device);
if (result) {
device->flags.power_manageable = 0;
device->power.state = ACPI_D_STATE_INVALID;
acpi_handle_info(device->handle,
"Initial power state undetermined, ACPI PM disabled\n");
}
return result;
}
/**
* acpi_device_fix_up_power - Force device with missing _PSC into D0.
* @device: Device object whose power state is to be fixed up.
@ -475,8 +497,13 @@ static int acpi_power_up_if_adr_present(struct acpi_device *adev, void *not_used
if (!(adev->flags.power_manageable && adev->pnp.type.bus_address))
return 0;
acpi_handle_debug(adev->handle, "Power state: %s\n",
acpi_power_state_string(adev->power.state));
/*
* This is done during the PCI root initialization which occurs before
* acpi_bus_attach() is called for the device, so the ACPI power state
* of the device needs to be initialized here.
*/
if (acpi_bus_init_power(adev))
return 0;
if (adev->power.state == ACPI_STATE_D3_COLD)
return acpi_device_set_power(adev, ACPI_STATE_D0);

View File

@ -445,6 +445,15 @@ int dock_notify(struct acpi_device *adev, u32 event)
break;
}
hotplug_dock_devices(ds, event);
/*
* The dock platform device already exists when an empty battery
* bay becomes occupied, but its driver may not have bound while
* the battery was absent. Retry after the ACPI scan updates its
* status, since the scan only attaches the ACPI device.
*/
if (ds->flags & DOCK_IS_BAT)
device_initial_probe(&ds->dock_device->dev);
complete_dock(ds);
dock_event(ds, event, DOCK_EVENT);
acpi_evaluate_lck(ds->handle, 1);

View File

@ -52,7 +52,7 @@ struct acpi_fan_fst {
};
struct acpi_fan {
acpi_handle handle;
struct acpi_device *adev;
bool acpi4;
bool has_fst;
struct acpi_fan_fif fif;

View File

@ -54,8 +54,7 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids);
static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
*state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_fan *fan = acpi_driver_data(device);
struct acpi_fan *fan = cdev->devdata;
if (fan->acpi4) {
if (fan->fif.fine_grain_ctrl)
@ -72,42 +71,34 @@ static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
int acpi_fan_get_fst(acpi_handle handle, struct acpi_fan_fst *fst)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
int ret = 0;
status = acpi_evaluate_object(handle, "_FST", NULL, &buffer);
if (ACPI_FAILURE(status))
return -EIO;
return -ENXIO;
obj = buffer.pointer;
union acpi_object *obj __free(acpi_object_free) = buffer.pointer;
if (!obj)
return -ENODATA;
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) {
ret = -EPROTO;
goto err;
}
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3)
return -EPROTO;
if (obj->package.elements[0].type != ACPI_TYPE_INTEGER ||
obj->package.elements[1].type != ACPI_TYPE_INTEGER ||
obj->package.elements[2].type != ACPI_TYPE_INTEGER) {
ret = -EPROTO;
goto err;
}
obj->package.elements[2].type != ACPI_TYPE_INTEGER)
return -EPROTO;
fst->revision = obj->package.elements[0].integer.value;
fst->control = obj->package.elements[1].integer.value;
fst->speed = obj->package.elements[2].integer.value;
err:
kfree(obj);
return ret;
return 0;
}
static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
static int fan_get_state_acpi4(struct acpi_fan *fan, unsigned long *state)
{
struct acpi_fan *fan = acpi_driver_data(device);
struct acpi_device *device = fan->adev;
struct acpi_fan_fst fst;
int status, i;
@ -159,13 +150,12 @@ static int fan_get_state(struct acpi_device *device, unsigned long *state)
static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
*state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_fan *fan = acpi_driver_data(device);
struct acpi_fan *fan = cdev->devdata;
if (fan->acpi4)
return fan_get_state_acpi4(device, state);
return fan_get_state_acpi4(fan, state);
else
return fan_get_state(device, state);
return fan_get_state(fan->adev, state);
}
static int fan_set_state(struct acpi_device *device, unsigned long state)
@ -177,9 +167,9 @@ static int fan_set_state(struct acpi_device *device, unsigned long state)
state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
}
static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
static int fan_set_state_acpi4(struct acpi_fan *fan, unsigned long state)
{
struct acpi_fan *fan = acpi_driver_data(device);
struct acpi_device *device = fan->adev;
acpi_status status;
u64 value = state;
int max_state;
@ -213,13 +203,12 @@ static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
static int
fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_fan *fan = acpi_driver_data(device);
struct acpi_fan *fan = cdev->devdata;
if (fan->acpi4)
return fan_set_state_acpi4(device, state);
return fan_set_state_acpi4(fan, state);
else
return fan_set_state(device, state);
return fan_set_state(fan->adev, state);
}
static const struct thermal_cooling_device_ops fan_cooling_ops = {
@ -240,25 +229,22 @@ static int acpi_fan_get_fif(struct acpi_device *device)
struct acpi_buffer format = { sizeof("NNNN"), "NNNN" };
u64 fields[4];
struct acpi_buffer fif = { sizeof(fields), fields };
union acpi_object *obj;
acpi_status status;
status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer);
if (ACPI_FAILURE(status))
return status;
return -ENXIO;
obj = buffer.pointer;
union acpi_object *obj __free(acpi_object_free) = buffer.pointer;
if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
dev_err(&device->dev, "Invalid _FIF data\n");
status = -EINVAL;
goto err;
return -ENODATA;
}
status = acpi_extract_package(obj, &format, &fif);
if (ACPI_FAILURE(status)) {
dev_err(&device->dev, "Invalid _FIF element\n");
status = -EINVAL;
goto err;
return -ENODATA;
}
fan->fif.revision = fields[0];
@ -272,9 +258,8 @@ static int acpi_fan_get_fif(struct acpi_device *device)
/* If step size > 9, change to 9 (by spec valid values 1-9) */
else if (fan->fif.step_size > 9)
fan->fif.step_size = 9;
err:
kfree(obj);
return status;
return 0;
}
static int acpi_fan_speed_cmp(const void *a, const void *b)
@ -284,34 +269,28 @@ static int acpi_fan_speed_cmp(const void *a, const void *b)
return fps1->speed - fps2->speed;
}
static int acpi_fan_get_fps(struct acpi_device *device)
static int acpi_fan_get_fps(struct device *dev, struct acpi_device *device)
{
struct acpi_fan *fan = acpi_driver_data(device);
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
int i;
status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer);
if (ACPI_FAILURE(status))
return status;
return -ENXIO;
obj = buffer.pointer;
union acpi_object *obj __free(acpi_object_free) = buffer.pointer;
if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
dev_err(&device->dev, "Invalid _FPS data\n");
status = -EINVAL;
goto err;
return -ENODATA;
}
fan->fps_count = obj->package.count - 1; /* minus revision field */
fan->fps = devm_kcalloc(&device->dev,
fan->fps_count, sizeof(struct acpi_fan_fps),
GFP_KERNEL);
if (!fan->fps) {
dev_err(&device->dev, "Not enough memory\n");
status = -ENOMEM;
goto err;
}
fan->fps = devm_kcalloc(dev, fan->fps_count, sizeof(*fan->fps), GFP_KERNEL);
if (!fan->fps)
return -ENOMEM;
for (i = 0; i < fan->fps_count; i++) {
struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
struct acpi_buffer fps = { offsetof(struct acpi_fan_fps, name),
@ -320,7 +299,7 @@ static int acpi_fan_get_fps(struct acpi_device *device)
&format, &fps);
if (ACPI_FAILURE(status)) {
dev_err(&device->dev, "Invalid _FPS element\n");
goto err;
return -ENODATA;
}
}
@ -328,9 +307,7 @@ static int acpi_fan_get_fps(struct acpi_device *device)
sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
acpi_fan_speed_cmp, NULL);
err:
kfree(obj);
return status;
return 0;
}
static int acpi_fan_dsm_init(struct device *dev)
@ -343,30 +320,28 @@ static int acpi_fan_dsm_init(struct device *dev)
},
};
struct acpi_fan *fan = dev_get_drvdata(dev);
union acpi_object *obj;
int ret = 0;
acpi_handle fan_handle = fan->adev->handle;
if (!acpi_check_dsm(fan->handle, &acpi_fan_microsoft_guid, 0,
if (!acpi_check_dsm(fan_handle, &acpi_fan_microsoft_guid, 0,
BIT(ACPI_FAN_DSM_GET_TRIP_POINT_GRANULARITY) |
BIT(ACPI_FAN_DSM_SET_TRIP_POINTS)))
return 0;
dev_info(dev, "Using Microsoft fan extensions\n");
obj = acpi_evaluate_dsm_typed(fan->handle, &acpi_fan_microsoft_guid, 0,
ACPI_FAN_DSM_GET_TRIP_POINT_GRANULARITY, &dummy,
ACPI_TYPE_INTEGER);
union acpi_object *obj __free(acpi_object_free) =
acpi_evaluate_dsm_typed(fan_handle, &acpi_fan_microsoft_guid, 0,
ACPI_FAN_DSM_GET_TRIP_POINT_GRANULARITY,
&dummy, ACPI_TYPE_INTEGER);
if (!obj)
return -EIO;
return -ENXIO;
if (obj->integer.value > U32_MAX)
ret = -EOVERFLOW;
else
fan->fan_trip_granularity = obj->integer.value;
return -EOVERFLOW;
kfree(obj);
fan->fan_trip_granularity = obj->integer.value;
return ret;
return 0;
}
static int acpi_fan_dsm_set_trip_points(struct device *dev, u64 upper, u64 lower)
@ -395,9 +370,9 @@ static int acpi_fan_dsm_set_trip_points(struct device *dev, u64 upper, u64 lower
};
union acpi_object *obj;
obj = acpi_evaluate_dsm(fan->handle, &acpi_fan_microsoft_guid, 0,
ACPI_FAN_DSM_SET_TRIP_POINTS, &in);
kfree(obj);
obj = acpi_evaluate_dsm(fan->adev->handle, &acpi_fan_microsoft_guid,
0, ACPI_FAN_DSM_SET_TRIP_POINTS, &in);
ACPI_FREE(obj);
return 0;
}
@ -506,7 +481,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
return -ENOMEM;
}
fan->handle = device->handle;
fan->adev = device;
device->driver_data = fan;
platform_set_drvdata(pdev, fan);
@ -522,7 +497,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
if (result)
return result;
result = acpi_fan_get_fps(device);
result = acpi_fan_get_fps(&pdev->dev, device);
if (result)
return result;
}
@ -567,8 +542,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
else
name = acpi_device_bid(device);
cdev = thermal_cooling_device_register(name, device,
&fan_cooling_ops);
cdev = thermal_cooling_device_create(&pdev->dev, name, fan, &fan_cooling_ops);
if (IS_ERR(cdev)) {
result = PTR_ERR(cdev);
goto err_end;
@ -577,28 +551,9 @@ static int acpi_fan_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id);
fan->cdev = cdev;
result = sysfs_create_link(&pdev->dev.kobj,
&cdev->device.kobj,
"thermal_cooling");
if (result) {
dev_err(&pdev->dev, "Failed to create sysfs link 'thermal_cooling'\n");
goto err_unregister;
}
result = sysfs_create_link(&cdev->device.kobj,
&pdev->dev.kobj,
"device");
if (result) {
dev_err(&pdev->dev, "Failed to create sysfs link 'device'\n");
goto err_remove_link;
}
return 0;
err_remove_link:
sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
err_unregister:
thermal_cooling_device_unregister(cdev);
err_end:
if (fan->has_fst)
acpi_fan_delete_attributes(device);
@ -615,8 +570,6 @@ static void acpi_fan_remove(struct platform_device *pdev)
acpi_fan_delete_attributes(device);
}
sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
sysfs_remove_link(&fan->cdev->device.kobj, "device");
thermal_cooling_device_unregister(fan->cdev);
}

View File

@ -94,7 +94,7 @@ static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
struct acpi_fan_fst fst;
int ret;
ret = acpi_fan_get_fst(fan->handle, &fst);
ret = acpi_fan_get_fst(fan->adev->handle, &fst);
if (ret < 0)
return ret;

View File

@ -59,19 +59,37 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type)
}
EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
static struct acpi_device *acpi_companion_lookup(struct device *dev)
{
struct acpi_bus_type *tmp, *ret = NULL;
struct acpi_bus_type *type;
down_read(&bus_type_sem);
list_for_each_entry(tmp, &bus_type_list, list) {
if (tmp->match(dev)) {
ret = tmp;
break;
if (!dev->type)
return NULL;
guard(rwsem_read)(&bus_type_sem);
list_for_each_entry(type, &bus_type_list, list) {
struct acpi_device *adev;
if (!type->match(dev))
continue;
adev = type->find_companion(dev);
if (!adev) {
dev_dbg(dev, "ACPI companion not found\n");
return NULL;
}
if (acpi_bind_one(dev, adev)) {
dev_dbg(dev, "Binding to ACPI companion failed\n");
return NULL;
}
if (type->setup)
type->setup(dev);
return adev;
}
up_read(&bus_type_sem);
return ret;
return NULL;
}
#define FIND_CHILD_MIN_SCORE 1
@ -228,31 +246,25 @@ static void acpi_physnode_link_name(char *buf, unsigned int node_id)
int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
{
struct acpi_device_physical_node *physical_node, *pn;
struct acpi_device *comp_dev = ACPI_COMPANION(dev);
char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
struct list_head *physnode_list;
unsigned int node_id;
int retval = -EINVAL;
if (has_acpi_companion(dev)) {
if (acpi_dev) {
dev_warn(dev, "ACPI companion already set\n");
if (!acpi_dev) {
if (!comp_dev)
return -EINVAL;
} else {
acpi_dev = ACPI_COMPANION(dev);
}
}
if (!acpi_dev)
return -EINVAL;
acpi_dev_get(acpi_dev);
get_device(dev);
physical_node = kzalloc_obj(*physical_node);
if (!physical_node) {
retval = -ENOMEM;
goto err;
/* If the companion has been set upfront, pick it up. */
acpi_dev = comp_dev;
} else if (comp_dev && acpi_dev != comp_dev) {
dev_warn(dev, "ACPI companion already set to %s which is not %s\n",
acpi_dev_name(comp_dev), acpi_dev_name(acpi_dev));
return -EEXIST;
}
mutex_lock(&acpi_dev->physical_node_lock);
guard(mutex)(&acpi_dev->physical_node_lock);
/*
* Keep the list sorted by node_id so that the IDs of removed nodes can
@ -263,15 +275,12 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {
/* Sanity check. */
if (pn->dev == dev) {
mutex_unlock(&acpi_dev->physical_node_lock);
dev_warn(dev, "Already associated with ACPI node\n");
kfree(physical_node);
if (ACPI_COMPANION(dev) != acpi_dev)
goto err;
put_device(dev);
acpi_dev_put(acpi_dev);
if (!comp_dev) {
/* Really unexpected. */
ACPI_COMPANION_SET(dev, acpi_dev);
dev_warn(&acpi_dev->dev,
"Physical device list corruption fixed up\n");
}
return 0;
}
if (pn->node_id == node_id) {
@ -280,12 +289,19 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
}
}
physical_node = kzalloc_obj(*physical_node);
if (!physical_node)
return -ENOMEM;
acpi_dev_get(acpi_dev);
get_device(dev);
physical_node->node_id = node_id;
physical_node->dev = dev;
list_add(&physical_node->node, physnode_list);
acpi_dev->physical_node_count++;
if (!has_acpi_companion(dev))
if (!comp_dev)
ACPI_COMPANION_SET(dev, acpi_dev);
acpi_physnode_link_name(physical_node_name, node_id);
@ -301,28 +317,20 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
dev_err(dev, "Failed to create link firmware_node (%d)\n",
retval);
mutex_unlock(&acpi_dev->physical_node_lock);
if (acpi_dev->wakeup.flags.valid)
device_set_wakeup_capable(dev, true);
return 0;
err:
ACPI_COMPANION_SET(dev, NULL);
put_device(dev);
acpi_dev_put(acpi_dev);
return retval;
}
EXPORT_SYMBOL_GPL(acpi_bind_one);
int acpi_unbind_one(struct device *dev)
void acpi_unbind_one(struct device *dev)
{
struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
struct acpi_device_physical_node *entry;
if (!acpi_dev)
return 0;
return;
mutex_lock(&acpi_dev->physical_node_lock);
@ -337,15 +345,17 @@ int acpi_unbind_one(struct device *dev)
sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
sysfs_remove_link(&dev->kobj, "firmware_node");
ACPI_COMPANION_SET(dev, NULL);
mutex_unlock(&acpi_dev->physical_node_lock);
/* Drop references taken by acpi_bind_one(). */
put_device(dev);
acpi_dev_put(acpi_dev);
kfree(entry);
break;
return;
}
mutex_unlock(&acpi_dev->physical_node_lock);
return 0;
}
EXPORT_SYMBOL_GPL(acpi_unbind_one);
@ -354,48 +364,29 @@ void acpi_device_notify(struct device *dev)
struct acpi_device *adev;
int ret;
/* ACPI devices have no ACPI companions. */
if (dev->bus == &acpi_bus_type)
return;
ret = acpi_bind_one(dev, NULL);
if (ret) {
struct acpi_bus_type *type = acpi_get_bus_type(dev);
if (!type)
goto err;
adev = type->find_companion(dev);
if (!adev) {
dev_dbg(dev, "ACPI companion not found\n");
goto err;
}
ret = acpi_bind_one(dev, adev);
if (ret)
goto err;
if (type->setup) {
type->setup(dev);
goto done;
}
adev = acpi_companion_lookup(dev);
if (!adev)
return;
} else {
adev = ACPI_COMPANION(dev);
if (dev_is_pci(dev)) {
pci_acpi_setup(dev, adev);
goto done;
} else if (dev_is_platform(dev)) {
acpi_configure_pmsi_domain(dev);
if (adev->handler && adev->handler->bind)
adev->handler->bind(dev);
}
}
if (adev->handler && adev->handler->bind)
adev->handler->bind(dev);
done:
acpi_handle_debug(ACPI_HANDLE(dev), "Bound to device %s\n",
dev_name(dev));
return;
err:
dev_dbg(dev, "No ACPI support\n");
dev_dbg(dev, "Bound to ACPI device %s\n", acpi_dev_name(adev));
}
void acpi_device_notify_remove(struct device *dev)

View File

@ -157,6 +157,7 @@ void acpi_turn_off_unused_power_resources(void);
Device Power Management
-------------------------------------------------------------------------- */
int acpi_device_get_power(struct acpi_device *device, int *state);
int acpi_bus_init_power(struct acpi_device *device);
int acpi_wakeup_device_init(void);
/* --------------------------------------------------------------------------

View File

@ -995,7 +995,7 @@ static int hmat_calculate_adistance(struct notifier_block *self,
return NOTIFY_STOP;
}
static struct notifier_block hmat_adist_nb __meminitdata = {
static struct notifier_block hmat_adist_nb = {
.notifier_call = hmat_calculate_adistance,
.priority = 100,
};

View File

@ -111,7 +111,7 @@ int __init fix_pxm_node_maps(int max_nid)
for (j = 0; j <= max_nid; j++) {
if ((emu_nid_to_phys[j] == i) &&
WARN(node_to_pxm_map_copy[j] != PXM_INVAL,
"Node %d is already binded to PXM %d\n",
"Node %d is already bound to PXM %d\n",
j, node_to_pxm_map_copy[j]))
return -1;
if (emu_nid_to_phys[j] == i) {

View File

@ -159,7 +159,7 @@ void __printf(1, 0) acpi_os_vprintf(const char *fmt, va_list args)
{
static char buffer[512];
vsprintf(buffer, fmt, args);
vsnprintf(buffer, sizeof(buffer), fmt, args);
#ifdef ENABLE_DEBUGGER
if (acpi_in_debugger) {

View File

@ -787,6 +787,7 @@ static void acpi_pci_link_remove(struct acpi_device *device)
list_del(&link->list);
mutex_unlock(&acpi_link_lock);
device->driver_data = NULL;
kfree(link);
}

View File

@ -422,7 +422,7 @@ static int start_update(int action, struct pfru_device *pfru_dev)
static long pfru_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct pfru_update_cap_info cap_hdr;
struct pfru_update_cap_info cap_hdr = {};
struct pfru_device *pfru_dev = to_pfru_dev(file);
void __user *p = (void __user *)arg;
u32 rev;

View File

@ -1121,6 +1121,44 @@ static const struct dmi_system_id dmi_leave_unused_power_resources_on[] = {
}
},
{
/*
* Acer Swift 3 SF314-56G with NVIDIA MX250 suffers from the
* same ACPI power resource regression as the Thunderobot ZERO.
* The power resource controlling the dGPU is incorrectly turned off
* during initialization, causing the GPU to fall off the bus (D3cold).
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Swift SF314-56G"),
}
},
{
/*
* CASPER EXCALIBUR G900 laptop: Keep unused ACPI power
* resources on to prevent the NVIDIA dGPU and NVMe #2
* from becoming inaccessible.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "CASPER BILGISAYAR SISTEMLERI"),
DMI_MATCH(DMI_PRODUCT_NAME, "EXCALIBUR G900"),
DMI_MATCH(DMI_BOARD_NAME, "NLCC 001"),
},
},
{
/*
* Acer Aspire A515-53G: Two SSDTs both define power resources
* for the dGPU root port RP05 ('PC01' and 'PCRP'). Only PC01 ends
* up in RP05's _PR0/_PR3, so 'PCRP' is shut down on
* initialization, cutting power to the NVIDIA dGPU behind the
* back of 'PC01' and making the dGPU unavailable.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A515-53G"),
},
},
{}
};

View File

@ -164,7 +164,7 @@ static int __acpi_processor_start(struct acpi_device *device)
acpi_pss_perf_init(pr);
result = acpi_processor_thermal_init(pr, device);
result = acpi_processor_thermal_init(pr);
if (result)
goto err_power_exit;
@ -179,7 +179,7 @@ static int __acpi_processor_start(struct acpi_device *device)
return 0;
err_thermal_exit:
acpi_processor_thermal_exit(pr, device);
acpi_processor_thermal_exit(pr);
err_power_exit:
acpi_processor_power_exit(pr);
return result;
@ -203,7 +203,7 @@ static int acpi_processor_stop(struct device *dev)
acpi_cppc_processor_exit(pr);
acpi_processor_thermal_exit(pr, device);
acpi_processor_thermal_exit(pr);
return 0;
}

View File

@ -235,15 +235,7 @@ static int
processor_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr;
if (!device)
return -EINVAL;
pr = acpi_driver_data(device);
if (!pr)
return -EINVAL;
struct acpi_processor *pr = cdev->devdata;
*state = acpi_processor_max_state(pr);
return 0;
@ -253,15 +245,7 @@ static int
processor_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *cur_state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr;
if (!device)
return -EINVAL;
pr = acpi_driver_data(device);
if (!pr)
return -EINVAL;
struct acpi_processor *pr = cdev->devdata;
*cur_state = cpufreq_get_cur_state(pr->id);
if (pr->flags.throttling)
@ -273,18 +257,10 @@ static int
processor_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr;
struct acpi_processor *pr = cdev->devdata;
int result = 0;
int max_pstate;
if (!device)
return -EINVAL;
pr = acpi_driver_data(device);
if (!pr)
return -EINVAL;
max_pstate = cpufreq_get_max_state(pr->id);
if (state > acpi_processor_max_state(pr))
@ -308,55 +284,21 @@ const struct thermal_cooling_device_ops processor_cooling_ops = {
.set_cur_state = processor_set_cur_state,
};
int acpi_processor_thermal_init(struct acpi_processor *pr,
struct acpi_device *device)
int acpi_processor_thermal_init(struct acpi_processor *pr)
{
int result = 0;
pr->cdev = thermal_cooling_device_create(pr->dev, "Processor", pr,
&processor_cooling_ops);
if (IS_ERR(pr->cdev))
return PTR_ERR(pr->cdev);
pr->cdev = thermal_cooling_device_register("Processor", device,
&processor_cooling_ops);
if (IS_ERR(pr->cdev)) {
result = PTR_ERR(pr->cdev);
return result;
}
dev_dbg(&device->dev, "registered as cooling_device%d\n",
pr->cdev->id);
result = sysfs_create_link(&device->dev.kobj,
&pr->cdev->device.kobj,
"thermal_cooling");
if (result) {
dev_err(&device->dev,
"Failed to create sysfs link 'thermal_cooling'\n");
goto err_thermal_unregister;
}
result = sysfs_create_link(&pr->cdev->device.kobj,
&device->dev.kobj,
"device");
if (result) {
dev_err(&pr->cdev->device,
"Failed to create sysfs link 'device'\n");
goto err_remove_sysfs_thermal;
}
dev_dbg(pr->dev, "registered as cooling_device%d\n", pr->cdev->id);
return 0;
err_remove_sysfs_thermal:
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
err_thermal_unregister:
thermal_cooling_device_unregister(pr->cdev);
return result;
}
void acpi_processor_thermal_exit(struct acpi_processor *pr,
struct acpi_device *device)
void acpi_processor_thermal_exit(struct acpi_processor *pr)
{
if (pr->cdev) {
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&pr->cdev->device.kobj, "device");
if (!IS_ERR_OR_NULL(pr->cdev)) {
thermal_cooling_device_unregister(pr->cdev);
pr->cdev = NULL;
}

View File

@ -318,7 +318,7 @@ static struct acpi_battery_reader state_readers[] = {
{0x0a, SMBUS_READ_WORD, offsetof(struct acpi_battery, rate_now)},
{0x0b, SMBUS_READ_WORD, offsetof(struct acpi_battery, rate_avg)},
{0x0f, SMBUS_READ_WORD, offsetof(struct acpi_battery, capacity_now)},
{0x0e, SMBUS_READ_WORD, offsetof(struct acpi_battery, state_of_charge)},
{0x0d, SMBUS_READ_WORD, offsetof(struct acpi_battery, state_of_charge)},
{0x16, SMBUS_READ_WORD, offsetof(struct acpi_battery, state)},
};
@ -639,10 +639,8 @@ static int acpi_sbs_probe(struct platform_device *pdev)
return -ENODEV;
sbs = kzalloc_obj(struct acpi_sbs);
if (!sbs) {
result = -ENOMEM;
goto end;
}
if (!sbs)
return -ENOMEM;
mutex_init(&sbs->lock);

View File

@ -20,6 +20,7 @@
#include <linux/kthread.h>
#include <linux/dmi.h>
#include <linux/dma-map-ops.h>
#include <linux/pci.h>
#include <linux/platform_data/x86/apple.h>
#include <linux/pgtable.h>
#include <linux/crc32.h>
@ -637,10 +638,9 @@ static struct acpi_device *handle_to_device(acpi_handle handle,
status = acpi_get_data_full(handle, acpi_scan_drop_device,
(void **)&adev, callback);
if (ACPI_FAILURE(status) || !adev) {
acpi_handle_debug(handle, "No context!\n");
if (ACPI_FAILURE(status) || !adev)
return NULL;
}
return adev;
}
@ -1143,8 +1143,7 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
}
if (acpi_bus_init_power(device))
device->flags.power_manageable = 0;
device->power.state = ACPI_STATE_UNKNOWN;
}
static void acpi_bus_get_flags(struct acpi_device *device)
@ -2338,50 +2337,57 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
static int acpi_bus_attach(struct acpi_device *device, void *first_pass)
{
bool skip = !first_pass && device->flags.visited;
struct pci_dev *pci;
acpi_handle ejd;
int ret;
if (skip)
goto ok;
device->flags.initialized = true;
if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd)))
register_dock_dependent_device(device, ejd);
acpi_bus_get_status(device);
/* Skip devices that are not ready for enumeration (e.g. not present) */
if (!acpi_dev_ready_for_enumeration(device)) {
device->flags.initialized = false;
/*
* If the given ACPI device object has been already associated with a
* PCI device found on the bus, its status is effectively "present and
* enabled", and dependencies are not tracked for PCI devices, so it is
* not necessary or even useful to check the device's readiness in that
* case.
*/
pci = acpi_dev_get_pci_dev(device);
if (pci) {
acpi_handle_debug(device->handle, "PCI companion %s found\n",
pci_name(pci));
if (!acpi_device_is_present(device))
pci_info(pci, FW_BUG "ACPI status differs from reality\n");
pci_dev_put(pci);
} else if (!acpi_dev_ready_for_enumeration(device)) {
/* The device is not ready (e.g. not present), so skip it. */
acpi_device_clear_enumerated(device);
device->flags.power_manageable = 0;
return 0;
}
if (device->handler)
goto ok;
acpi_ec_register_opregions(device);
if (!device->flags.initialized) {
device->flags.power_manageable =
device->power.states[ACPI_STATE_D0].flags.valid;
if (acpi_bus_init_power(device))
device->flags.power_manageable = 0;
acpi_bus_init_power(device);
device->flags.initialized = true;
} else if (device->flags.visited) {
if (device->flags.visited)
goto ok;
}
ret = acpi_scan_attach_handler(device);
if (ret < 0)
return 0;
if (ret > 0 && !device->flags.enumeration_by_parent) {
acpi_device_set_enumerated(device);
goto ok;
}
if (device->pnp.type.platform_id || device->pnp.type.backlight ||
device->flags.enumeration_by_parent)
if (device->flags.enumeration_by_parent ||
(!ret && (device->pnp.type.platform_id || device->pnp.type.backlight)))
acpi_default_enumeration(device);
else
acpi_device_set_enumerated(device);

View File

@ -548,7 +548,6 @@ static void acpi_pm_end(void)
acpi_sleep_tts_switch(acpi_target_sleep_state);
}
#else /* !CONFIG_ACPI_SLEEP */
#define sleep_no_lps0 (1)
#define acpi_target_sleep_state ACPI_STATE_S0
#define acpi_sleep_default_s3 (1)
static inline void acpi_sleep_dmi_check(void) {}

View File

@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/kstrtox.h>
#include <linux/moduleparam.h>
#include <linux/string.h>
#include "internal.h"
@ -181,10 +182,10 @@ static int param_set_trace_method_name(const char *val,
/* This is a hack. We can't kmalloc in early boot. */
if (is_abs_path)
strcpy(trace_method_name, val);
strscpy(trace_method_name, val, sizeof(trace_method_name));
else {
trace_method_name[0] = '\\';
strcpy(trace_method_name+1, val);
strscpy(trace_method_name + 1, val, sizeof(trace_method_name) - 1);
}
/* Restore the original tracer state */

View File

@ -560,6 +560,9 @@ acpi_table_initrd_override(struct acpi_table_header *existing_table,
while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
table = acpi_os_map_memory(acpi_tables_addr + table_offset,
ACPI_HEADER_SIZE);
if (!table)
return AE_NO_MEMORY;
if (table_offset + table->length > all_tables_size) {
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
WARN_ON(1);

View File

@ -564,17 +564,20 @@ static bool acpi_thermal_should_bind_cdev(struct thermal_zone_device *thermal,
struct cooling_spec *c)
{
struct acpi_thermal_trip *acpi_trip = trip->priv;
struct acpi_device *cdev_adev = cdev->devdata;
struct device *parent = cdev->device.parent;
acpi_handle parent_handle;
int i;
/* Skip critical and hot trips. */
if (!acpi_trip)
/* Skip critical and hot trips and parentless cooling devices. */
if (!acpi_trip || !parent)
return false;
parent_handle = ACPI_HANDLE(parent);
if (!parent_handle)
return false;
for (i = 0; i < acpi_trip->devices.count; i++) {
acpi_handle handle = acpi_trip->devices.handles[i];
if (acpi_fetch_acpi_dev(handle) == cdev_adev)
if (acpi_trip->devices.handles[i] == parent_handle)
return true;
}
@ -738,7 +741,9 @@ static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz)
*/
static void acpi_thermal_guess_offset(struct acpi_thermal *tz, long crit_temp)
{
if (crit_temp != THERMAL_TEMP_INVALID && crit_temp % 5 == 1)
if (crit_temp != THERMAL_TEMP_INVALID && crit_temp % 5 == 0)
tz->kelvin_offset = 273000;
else if (crit_temp != THERMAL_TEMP_INVALID && crit_temp % 5 == 1)
tz->kelvin_offset = 273100;
else
tz->kelvin_offset = 273200;

View File

@ -883,6 +883,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 7770 AIO"),
},
},
{
.callback = video_detect_force_native,
/* Dell OptiPlex AIO 7410 35W */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex AIO 7410 35W"),
},
},
/*
* Models which have nvidia-ec-wmi support, but should not use it.
@ -929,6 +937,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Nitro AN515-46"),
},
},
{
.callback = video_detect_force_native,
/* Acer Nitro AN515-58 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Nitro AN515-58"),
},
},
/*
* x86 android tablets which directly control the backlight through

View File

@ -24,6 +24,34 @@
#ifdef CONFIG_SUSPEND
static void acpi_setup_ixx_gpes(void)
{
acpi_handle gpe_root;
unsigned int i;
char gpe_nr_str[5];
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_GPE", &gpe_root)))
return;
for (i = 0; i <= 0xff; i++) {
scnprintf(gpe_nr_str, sizeof(gpe_nr_str), "_I%02X", i);
if (!acpi_has_method(gpe_root, gpe_nr_str))
continue;
/*
* Enable the GPE if it has a handler method because marking it
* as wake-capable causes acpi_update_all_gpes() to skip it.
*/
if (ACPI_FAILURE(acpi_enable_gpe_cond(NULL, i, ACPI_GPE_DISPATCH_METHOD)))
continue;
acpi_mark_gpe_for_wake(NULL, i);
acpi_set_gpe_wake_mask(NULL, i, ACPI_GPE_ENABLE);
pm_pr_dbg("ACPI: GPE0x%02x armed for wake via %s\n", i, gpe_nr_str);
}
}
static bool sleep_no_lps0 __read_mostly;
module_param(sleep_no_lps0, bool, 0644);
MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface");
@ -649,6 +677,7 @@ void __init acpi_s2idle_setup(void)
{
acpi_scan_add_handler(&lps0_handler);
s2idle_set_ops(&acpi_s2idle_ops_lps0);
acpi_setup_ixx_gpes();
}
int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg)

View File

@ -27,6 +27,7 @@
* @drivers_autoprobe: gate whether new devices are automatically attached to
* registered drivers, or new drivers automatically attach
* to existing devices.
* @no_drivers: gate whether drivers can be registered.
* @bus: pointer back to the struct bus_type that this structure is associated
* with.
* @dev_root: Default device to use as the parent.
@ -51,6 +52,7 @@ struct subsys_private {
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
unsigned int no_drivers:1;
const struct bus_type *bus;
struct device *dev_root;

View File

@ -738,6 +738,11 @@ int bus_add_driver(struct device_driver *drv)
if (!sp)
return -EINVAL;
if (sp->no_drivers) {
error = -ENXIO;
goto out_put_bus;
}
/*
* Reference in sp is now incremented and will be dropped when
* the driver is removed from the bus
@ -930,15 +935,7 @@ static ssize_t bus_uevent_store(const struct bus_type *bus,
static struct bus_attribute bus_attr_uevent = __ATTR(uevent, 0200, NULL,
bus_uevent_store);
/**
* bus_register - register a driver-core subsystem
* @bus: bus to register
*
* Once we have that, we register the bus with the kobject
* infrastructure, then register the children subsystems it has:
* the devices and drivers that belong to the subsystem.
*/
int bus_register(const struct bus_type *bus)
static int bus_register_internal(const struct bus_type *bus, bool use_drivers)
{
int retval;
struct subsys_private *priv;
@ -960,7 +957,8 @@ int bus_register(const struct bus_type *bus)
bus_kobj->kset = bus_kset;
bus_kobj->ktype = &bus_ktype;
priv->drivers_autoprobe = 1;
priv->drivers_autoprobe = use_drivers;
priv->no_drivers = !use_drivers;
retval = kset_register(&priv->subsys);
if (retval)
@ -976,6 +974,10 @@ int bus_register(const struct bus_type *bus)
goto bus_devices_fail;
}
/*
* Create the drivers kset even if use_drivers is unset to prevent some
* older versions of systemd from failing.
*/
priv->drivers_kset = kset_create_and_add("drivers", NULL, bus_kobj);
if (!priv->drivers_kset) {
retval = -ENOMEM;
@ -989,9 +991,11 @@ int bus_register(const struct bus_type *bus)
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&priv->klist_drivers, NULL, NULL);
retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;
if (use_drivers) {
retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;
}
retval = sysfs_create_groups(bus_kobj, bus->bus_groups);
if (retval)
@ -1016,8 +1020,40 @@ int bus_register(const struct bus_type *bus)
kfree(priv);
return retval;
}
/**
* bus_register - register a driver-core subsystem
* @bus: bus to register
*
* Once we have that, we register the bus with the kobject
* infrastructure, then register the children subsystems it has:
* the devices and drivers that belong to the subsystem.
*/
int bus_register(const struct bus_type *bus)
{
return bus_register_internal(bus, true);
}
EXPORT_SYMBOL_GPL(bus_register);
/**
* companion_bus_register - register a companion bus type
* @bus: companion bus to register
*
* A companion bus is a bus without drivers. Devices that belong to it can be
* bound to other devices as their "companions" and represent interfaces that
* can be used by the drivers of those other devices. They may also be used for
* the enumeration of those other devices.
*
* The ACPI bus is a specific example of a companion bus.
*
* Registering a companion bus is like registering a regular bus except that it
* skips the creation of sysfs interfaces related to drivers for @bus.
*/
int companion_bus_register(const struct bus_type *bus)
{
return bus_register_internal(bus, false);
}
/**
* bus_unregister - remove a bus from the system
* @bus: bus.
@ -1415,6 +1451,11 @@ struct device_driver *driver_find(const char *name, const struct bus_type *bus)
if (!sp)
return NULL;
if (sp->no_drivers) {
subsys_put(sp);
return NULL;
}
k = kset_find_obj(sp->drivers_kset, name);
subsys_put(sp);
if (!k)

View File

@ -77,7 +77,7 @@ static int match_memdev_by_parent(struct device *dev, const void *uport)
return 0;
}
void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
{
unsigned int devfn = PCI_DEVFN(data->prot_err.agent_addr.device,
data->prot_err.agent_addr.function);
@ -118,7 +118,6 @@ void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
else
cxl_cper_trace_uncorr_prot_err(cxlmd, data->ras_cap);
}
EXPORT_SYMBOL_GPL(cxl_cper_handle_prot_err);
static void cxl_cper_prot_err_work_fn(struct work_struct *work)
{

View File

@ -19,7 +19,7 @@ void cxl_dport_map_rch_aer(struct cxl_dport *dport)
aer_phys = aer_cap + dport->rcrb.base;
dport->regs.dport_aer =
devm_cxl_iomap_block(host, aer_phys,
sizeof(struct aer_capability_regs));
PCIE_AER_CAP_HW_SIZE);
}
}
@ -58,31 +58,20 @@ void cxl_disable_rch_root_ints(struct cxl_dport *dport)
static bool cxl_rch_get_aer_info(void __iomem *aer_base,
struct aer_capability_regs *aer_regs)
{
/*
* Bound the copy to the physically-defined AER registers (header
* through the 16-byte Header Log). struct aer_capability_regs is a
* software layout whose embedded struct pcie_tlp_log is larger than
* the on-wire AER capability; copying sizeof(*aer_regs) would
* over-read the RCRB-mapped MMIO block.
*/
int read_cnt = (PCI_ERR_HEADER_LOG + 16) / sizeof(u32);
u32 *aer_regs_buf = (u32 *)aer_regs;
int n;
/* A flat copy cannot fill the struct; aer_cap_regs_unpack() places it. */
__le32 raw[PCIE_AER_CAP_HW_SIZE / sizeof(__le32)];
if (!aer_base)
return false;
/*
* Zero the destination so the software-only tail fields
* (e.g. header_log.header_len) are deterministic rather than
* left as uninitialized stack, which could drive a bogus loop
* length in pcie_print_tlp_log().
* Use readl() to guarantee 32-bit accesses; it returns host order, so
* put the registers back little-endian for aer_cap_regs_unpack().
*/
memset(aer_regs, 0, sizeof(*aer_regs));
for (int n = 0; n < ARRAY_SIZE(raw); n++)
raw[n] = cpu_to_le32(readl(aer_base + n * sizeof(u32)));
/* Use readl() to guarantee 32-bit accesses */
for (n = 0; n < read_cnt; n++)
aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
aer_cap_regs_unpack(aer_regs, raw, sizeof(raw));
writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);

View File

@ -389,10 +389,28 @@ void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
cmem->requestor_id = mem->requestor_id;
cmem->responder_id = mem->responder_id;
cmem->target_id = mem->target_id;
cmem->extended = mem->extended;
cmem->rank = mem->rank;
cmem->mem_array_handle = mem->mem_array_handle;
cmem->mem_dev_handle = mem->mem_dev_handle;
/*
* These four sit past the end of the UEFI 2.1/2.2 layout, which older
* firmware still emits, so reading them unconditionally runs off a
* short record. Every consumer of the compact record gates them on the
* same validation bits, so leave them zero when firmware does not
* claim them.
*/
cmem->extended = 0;
cmem->rank = 0;
cmem->mem_array_handle = 0;
cmem->mem_dev_handle = 0;
if (mem->validation_bits &
(CPER_MEM_VALID_ROW_EXT | CPER_MEM_VALID_CHIP_ID))
cmem->extended = mem->extended;
if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
cmem->rank = mem->rank;
if (mem->validation_bits & CPER_MEM_VALID_CARD_HANDLE)
cmem->mem_array_handle = mem->mem_array_handle;
if (mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE)
cmem->mem_dev_handle = mem->mem_dev_handle;
}
EXPORT_SYMBOL_GPL(cper_mem_err_pack);
@ -745,6 +763,17 @@ int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
return -EINVAL;
/*
* cper_estatus_len() sums these into a u32, and a wrapped sum reads
* back smaller than the record. Reject a length that cannot be
* expressed so no caller is handed the short value.
*/
if ((u64)sizeof(*estatus) + estatus->data_length > U32_MAX)
return -EINVAL;
if (estatus->raw_data_length &&
(u64)estatus->raw_data_offset + estatus->raw_data_length > U32_MAX)
return -EINVAL;
return 0;
}
EXPORT_SYMBOL_GPL(cper_estatus_check_header);
@ -752,7 +781,7 @@ EXPORT_SYMBOL_GPL(cper_estatus_check_header);
int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
{
struct acpi_hest_generic_data *gdata;
unsigned int data_len, record_size;
unsigned int data_len;
int rc;
rc = cper_estatus_check_header(estatus);
@ -762,10 +791,18 @@ int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
data_len = estatus->data_length;
apei_estatus_for_each_section(estatus, gdata) {
if (acpi_hest_get_size(gdata) > data_len)
int record_size;
/*
* The <acpi/ghes.h> helpers sum these as a signed int, so a
* huge error_data_length wraps small rather than large and the
* walk then advances by that wrapped value. Reject a size an
* int cannot carry.
*/
if (check_add_overflow(acpi_hest_get_size(gdata),
gdata->error_data_length, &record_size))
return -EINVAL;
record_size = acpi_hest_get_record_size(gdata);
if (record_size > data_len)
return -EINVAL;

View File

@ -37,9 +37,9 @@ static long __init parse_acpi_path(const struct efi_dev_path *node,
if (!adev)
return -ENODEV;
phys_dev = acpi_get_first_physical_node(adev);
phys_dev = acpi_bus_get_primary_device(adev);
if (phys_dev) {
*child = get_device(phys_dev);
*child = phys_dev;
acpi_dev_put(adev);
} else
*child = &adev->dev;

View File

@ -5307,7 +5307,7 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
if (adev) {
/* Tegra241 CMDQV driver is responsible for put_device() */
smmu->impl_dev = get_device(acpi_get_first_physical_node(adev));
smmu->impl_dev = acpi_bus_get_primary_device(adev);
smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
dev_info(smmu->dev, "found companion CMDQV device: %s\n",
dev_name(smmu->impl_dev));

View File

@ -8,8 +8,11 @@
#include <linux/aer.h>
#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/build_bug.h>
#include <linux/minmax.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/unaligned.h>
#include "../pci.h"
@ -92,6 +95,91 @@ int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
return 0;
}
/* The Prefix Log registers hold dw[4..13] in Flit mode. */
static_assert((PCI_ERR_PREFIX_LOG +
(PCIE_STD_MAX_TLP_HEADERLOG - PCIE_STD_NUM_TLP_HEADERLOG) *
sizeof(u32)) == PCIE_AER_CAP_HW_SIZE);
/**
* aer_cap_regs_unpack - Convert a raw AER Capability image to the kernel layout
* @regs: Destination, fully initialised
* @raw: AER Capability register block in hardware order, little-endian
* @raw_len: Bytes readable at @raw
*
* struct aer_capability_regs is not the hardware layout: struct pcie_tlp_log
* spans 60 bytes where the Header Log it stands in for is 16, so a flat copy
* misplaces everything behind it. Map the registers one by one instead,
* taking the TLP Log layout from the Flit bit as pcie_read_tlp_log() does.
*
* @raw is not necessarily aligned. Registers past @raw_len are left zero, so
* a short image cannot be read past.
*/
void aer_cap_regs_unpack(struct aer_capability_regs *regs, const void *raw,
size_t raw_len)
{
unsigned int i, tlp_len;
bool flit;
memset(regs, 0, sizeof(*regs));
if (raw_len < PCI_ERR_HEADER_LOG)
return;
/* The Extended Capability Header, at offset 0, has no define */
regs->header = get_unaligned_le32(raw);
regs->uncor_status = get_unaligned_le32(raw + PCI_ERR_UNCOR_STATUS);
regs->uncor_mask = get_unaligned_le32(raw + PCI_ERR_UNCOR_MASK);
regs->uncor_severity = get_unaligned_le32(raw + PCI_ERR_UNCOR_SEVER);
regs->cor_status = get_unaligned_le32(raw + PCI_ERR_COR_STATUS);
regs->cor_mask = get_unaligned_le32(raw + PCI_ERR_COR_MASK);
regs->cap_control = get_unaligned_le32(raw + PCI_ERR_CAP);
flit = FIELD_GET(PCI_ERR_CAP_TLP_LOG_FLIT, regs->cap_control);
if (flit) {
tlp_len = FIELD_GET(PCI_ERR_CAP_TLP_LOG_SIZE, regs->cap_control);
} else {
/*
* dw[4..7] alias the Prefix Log. Take all four whatever
* eetlp_prefix_max says; pcie_print_tlp_log() stops at the
* first zero one.
*/
tlp_len = PCIE_STD_NUM_TLP_HEADERLOG + PCIE_STD_MAX_TLP_PREFIXLOG;
}
tlp_len = min(tlp_len, ARRAY_SIZE(regs->header_log.dw));
for (i = 0; i < tlp_len; i++) {
unsigned int off;
if (i < PCIE_STD_NUM_TLP_HEADERLOG)
off = PCI_ERR_HEADER_LOG + i * sizeof(u32);
else
off = PCI_ERR_PREFIX_LOG +
(i - PCIE_STD_NUM_TLP_HEADERLOG) * sizeof(u32);
if (off + sizeof(u32) > raw_len)
break;
regs->header_log.dw[i] = get_unaligned_le32(raw + off);
}
/* @i may be short of tlp_len; non-Flit needs the TLP parsed, so cap at 4 */
regs->header_log.header_len = flit ? i : min(i, PCIE_STD_NUM_TLP_HEADERLOG);
regs->header_log.flit = flit;
if (raw_len >= PCI_ERR_ROOT_COMMAND + sizeof(u32))
regs->root_command = get_unaligned_le32(raw + PCI_ERR_ROOT_COMMAND);
if (raw_len >= PCI_ERR_ROOT_STATUS + sizeof(u32))
regs->root_status = get_unaligned_le32(raw + PCI_ERR_ROOT_STATUS);
if (raw_len >= PCI_ERR_ROOT_ERR_SRC + sizeof(u32)) {
u32 src = get_unaligned_le32(raw + PCI_ERR_ROOT_ERR_SRC);
/* One register: ERR_COR in 15:0, ERR_FATAL/NONFATAL in 31:16 */
regs->cor_err_source = src;
regs->uncor_err_source = src >> 16;
}
}
EXPORT_SYMBOL_GPL(aer_cap_regs_unpack);
#define EE_PREFIX_STR " E-E Prefixes:"
/**

View File

@ -353,13 +353,13 @@ static int yogabook_wmi_probe(struct wmi_device *wdev, const void *context)
goto error_put_devs;
}
data->kbd_dev = get_device(acpi_get_first_physical_node(data->kbd_adev));
data->kbd_dev = acpi_bus_get_primary_device(data->kbd_adev);
if (!data->kbd_dev || !data->kbd_dev->driver) {
r = -EPROBE_DEFER;
goto error_put_devs;
}
data->dig_dev = get_device(acpi_get_first_physical_node(data->dig_adev));
data->dig_dev = acpi_bus_get_primary_device(data->dig_adev);
if (!data->dig_dev || !data->dig_dev->driver) {
r = -EPROBE_DEFER;
goto error_put_devs;

View File

@ -74,8 +74,7 @@ get_serdev_controller(const char *serial_ctrl_hid,
return ERR_PTR(-ENODEV);
}
/* get_first_physical_node() returns a weak ref */
parent = get_device(acpi_get_first_physical_node(adev));
parent = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!parent) {
pr_err("error could not get %s/%s serial-ctrl physical node\n",

View File

@ -390,7 +390,6 @@ static int gpio_secondary_fwnode_init(struct device *parent,
{
const struct software_node *const *swnode;
struct fwnode_handle *fwnode;
struct device *phys_dev;
int ret;
if (!node_group)
@ -418,7 +417,8 @@ static int gpio_secondary_fwnode_init(struct device *parent,
if (WARN_ON(!fwnode))
return -ENOENT;
phys_dev = acpi_get_first_physical_node(to_acpi_device(dev));
struct device *phys_dev __free(put_device) =
acpi_bus_get_primary_device(to_acpi_device(dev));
if (!phys_dev)
return dev_err_probe(parent, -ENODEV,
"No physical device for ACPI GPIO dev: %pfwP\n",

View File

@ -96,13 +96,13 @@ static int pnp_device_probe(struct device *dev)
if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
error = pnp_activate_dev(pnp_dev);
if (error < 0)
return error;
goto fail;
}
} else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE)
== PNP_DRIVER_RES_DISABLE) {
error = pnp_disable_dev(pnp_dev);
if (error < 0)
return error;
goto fail;
}
error = 0;
if (pnp_drv->probe) {

View File

@ -1005,7 +1005,8 @@ thermal_cooling_device_alloc(const char *type, const struct thermal_cooling_devi
return ERR_PTR(ret);
}
int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdata)
int thermal_cooling_device_add(struct thermal_cooling_device *cdev,
struct device *parent, void *devdata)
{
unsigned long current_state;
int ret;
@ -1013,6 +1014,7 @@ int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdat
mutex_init(&cdev->lock);
INIT_LIST_HEAD(&cdev->thermal_instances);
cdev->updated = false;
cdev->device.parent = parent;
cdev->device.class = &thermal_class;
cdev->device.release = thermal_cdev_release;
device_initialize(&cdev->device);
@ -1062,21 +1064,23 @@ int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdat
}
/**
* thermal_cooling_device_register() - register a new thermal cooling device
* thermal_cooling_device_create() - register a new thermal cooling device
* @parent: parent device (optional).
* @type: the thermal cooling device type.
* @devdata: device private data.
* @ops: standard thermal cooling devices callbacks.
*
* This interface function adds a new thermal cooling device (fan/processor/...)
* to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
* to all the thermal zone devices registered at the same time.
* Allocate and register a new thermal cooling device under the given parent (if
* not NULL) and with the given type, device data, and operations. During the
* registration, it will be matched against all of the registered thermal zones
* and it will be bound to the matching ones.
*
* Return: a pointer to the created struct thermal_cooling_device or an
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
* Return: A pointer to the created struct thermal_cooling_device or an ERR_PTR.
* Callers must use IS_ERR*() helpers to check the return value.
*/
struct thermal_cooling_device *
thermal_cooling_device_register(const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
struct thermal_cooling_device *thermal_cooling_device_create(
struct device *parent, const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
struct thermal_cooling_device *cdev;
int ret;
@ -1085,13 +1089,13 @@ thermal_cooling_device_register(const char *type, void *devdata,
if (IS_ERR(cdev))
return cdev;
ret = thermal_cooling_device_add(cdev, devdata);
ret = thermal_cooling_device_add(cdev, parent, devdata);
if (ret)
return ERR_PTR(ret);
return cdev;
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_register);
EXPORT_SYMBOL_GPL(thermal_cooling_device_create);
static void thermal_cooling_device_release(void *data)
{

View File

@ -270,7 +270,8 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz,
struct thermal_cooling_device *
thermal_cooling_device_alloc(const char *type, const struct thermal_cooling_device_ops *ops);
int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdata);
int thermal_cooling_device_add(struct thermal_cooling_device *cdev,
struct device *parent, void *devdata);
/* Helpers */
#define for_each_trip_desc(__tz, __td) \

View File

@ -561,7 +561,7 @@ thermal_of_cooling_device_register(struct device_node *np, u32 cdev_id,
cdev->np = np;
cdev->cdev_id = cdev_id;
ret = thermal_cooling_device_add(cdev, devdata);
ret = thermal_cooling_device_add(cdev, NULL, devdata);
if (ret)
return ERR_PTR(ret);

View File

@ -17,8 +17,8 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
struct fwnode_handle *fwnode;
struct tb_nhi *nhi = data;
struct device *dev = NULL;
struct pci_dev *pdev;
struct device *dev;
if (!adev)
return AE_OK;
@ -37,7 +37,7 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
* USB3 ports might not even have a physical device yet if xHCI driver
* isn't bound yet.
*/
dev = acpi_get_first_physical_node(adev);
dev = acpi_bus_get_primary_device(adev);
if (!dev || !dev_is_pci(dev))
goto out_put;
@ -74,6 +74,7 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
}
out_put:
put_device(dev);
fwnode_handle_put(fwnode);
return AE_OK;
}

View File

@ -9,6 +9,8 @@
#ifndef __ACPI_BUS_H__
#define __ACPI_BUS_H__
#ifdef CONFIG_ACPI
#include <linux/completion.h>
#include <linux/container_of.h>
#include <linux/device.h>
@ -58,7 +60,6 @@ bool acpi_dock_match(acpi_handle handle);
bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs);
union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid,
u64 rev, u64 func, union acpi_object *argv4);
#ifdef CONFIG_ACPI
bool
acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld);
@ -77,7 +78,6 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const guid_t *guid, u64 rev,
return obj;
}
#endif
#define ACPI_INIT_DSM_ARGV4(cnt, eles) \
{ \
@ -90,8 +90,6 @@ bool acpi_dev_found(const char *hid);
bool acpi_dev_present(const char *hid, const char *uid, s64 hrv);
bool acpi_reduced_hardware(void);
#ifdef CONFIG_ACPI
struct proc_dir_entry;
#define ACPI_BUS_FILE_ROOT "acpi"
@ -435,9 +433,9 @@ struct acpi_device_software_nodes {
/* Device */
struct acpi_device {
acpi_handle handle; /* no handle for fixed hardware */
u32 pld_crc;
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
struct fwnode_handle fwnode;
struct list_head wakeup_list;
struct list_head del_list;
@ -613,7 +611,6 @@ int acpi_bus_get_status(struct acpi_device *device);
int acpi_bus_set_power(acpi_handle handle, int state);
const char *acpi_power_state_string(int state);
int acpi_device_set_power(struct acpi_device *device, int state);
int acpi_bus_init_power(struct acpi_device *device);
int acpi_device_fix_up_power(struct acpi_device *device);
void acpi_device_fix_up_power_extended(struct acpi_device *adev);
void acpi_device_fix_up_power_children(struct acpi_device *adev);
@ -665,7 +662,7 @@ struct acpi_bus_type {
int register_acpi_bus_type(struct acpi_bus_type *);
int unregister_acpi_bus_type(struct acpi_bus_type *);
int acpi_bind_one(struct device *dev, struct acpi_device *adev);
int acpi_unbind_one(struct device *dev);
void acpi_unbind_one(struct device *dev);
enum acpi_bridge_type {
ACPI_BRIDGE_TYPE_PCIE = 1,
@ -830,7 +827,15 @@ 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);
if (!uid1 || !uid2)
return false;
if (*uid1 == '\\' && uid1[1])
uid1++;
if (*uid2 == '\\' && uid2[1])
uid2++;
return !strcmp(uid1, uid2);
}
static inline bool acpi_int_uid_match(struct acpi_device *adev, u64 uid2)
@ -857,6 +862,10 @@ static inline bool acpi_int_uid_match(struct acpi_device *adev, u64 uid2)
*
* Matches UID in @adev with given @uid2.
*
* If both the UID in @adev and @uid2 are strings, they are compared
* after optionally skipping a leading backslash ('\') if the given
* string contains additional characters.
*
* Returns: %true if matches, %false otherwise.
*/
#define acpi_dev_uid_match(adev, uid2) \
@ -942,8 +951,21 @@ int acpi_wait_for_acpi_ipmi(void);
int acpi_scan_add_dep(acpi_handle handle, struct acpi_handle_list *dep_devices);
u32 arch_acpi_add_auto_dep(acpi_handle handle);
#else /* CONFIG_ACPI */
static inline struct acpi_device *
acpi_find_child_device(struct acpi_device *parent, u64 address,
bool check_children)
{
return NULL;
}
static inline bool acpi_has_method(acpi_handle handle, char *name)
{
return false;
}
static inline struct device *acpi_bus_get_primary_device(struct acpi_device *adev)
{
return NULL;
@ -959,6 +981,11 @@ static inline const char *acpi_device_hid(struct acpi_device *device)
return "";
}
static inline char *acpi_device_uid(struct acpi_device *device)
{
return NULL;
}
static inline bool
acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld)
{

View File

@ -919,6 +919,13 @@ struct acpi_iovt_iommu {
u32 device_entry_offset;
};
/* Masks for Flags field above */
#define ACPI_IOVT_IOMMU_PCI_DEVICE (1<<0)
#define ACPI_IOVT_IOMMU_PXM_VALID (1<<1)
#define ACPI_IOVT_IOMMU_MAGAGE_BY_SEGMENT (1<<2)
#define ACPI_IOVT_IOMMU_HW_CAP_SUPPORT (1<<3)
#define ACPI_IOVT_IOMMU_MSI_INT_BYPASS (1<<4)
struct acpi_iovt_device_entry {
u8 type;
u8 length;

View File

@ -85,6 +85,10 @@ int devm_ghes_register_vendor_record_notifier(struct device *dev,
struct list_head *ghes_get_devices(void);
void ghes_estatus_pool_region_free(unsigned long addr, u32 size);
struct cxl_cper_sec_prot_err;
void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
int severity, u32 len);
#else
static inline struct list_head *ghes_get_devices(void) { return NULL; }

View File

@ -427,10 +427,8 @@ int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi);
#endif /* CONFIG_ACPI_PROCESSOR_IDLE */
/* in processor_thermal.c */
int acpi_processor_thermal_init(struct acpi_processor *pr,
struct acpi_device *device);
void acpi_processor_thermal_exit(struct acpi_processor *pr,
struct acpi_device *device);
int acpi_processor_thermal_init(struct acpi_processor *pr);
void acpi_processor_thermal_exit(struct acpi_processor *pr);
extern const struct thermal_cooling_device_ops processor_cooling_ops;
#ifdef CONFIG_CPU_FREQ
void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy);

View File

@ -312,13 +312,13 @@ static inline int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data
#endif
#ifdef CONFIG_ACPI_APEI_PCIEAER
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err);
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err, u32 len);
int cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd,
struct cxl_cper_sec_prot_err *prot_err,
int severity);
#else
static inline int
cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err, u32 len)
{
return -EOPNOTSUPP;
}
@ -331,6 +331,4 @@ cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd,
}
#endif
void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *wd);
#endif /* _LINUX_CXL_EVENT_H */

View File

@ -25,17 +25,19 @@ struct irq_domain_ops;
#define _LINUX
#endif
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_numa.h>
#ifdef CONFIG_ACPI
DEFINE_FREE(acpi_object_free, union acpi_object *, if (_T) ACPI_FREE(_T));
#include <linux/list.h>
#include <linux/dynamic_debug.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/fw_table.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_io.h>
#include <asm/acpi.h>
@ -105,8 +107,6 @@ static inline const char *acpi_dev_name(struct acpi_device *adev)
return dev_name(&adev->dev);
}
struct device *acpi_get_first_physical_node(struct acpi_device *adev);
enum acpi_irq_model_id {
ACPI_IRQ_MODEL_PIC = 0,
ACPI_IRQ_MODEL_IOAPIC,
@ -434,7 +434,7 @@ extern acpi_handle ec_get_handle(void);
extern bool acpi_is_pnp_device(struct acpi_device *);
#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
#if IS_ENABLED(CONFIG_ACPI_WMI)
typedef void (*wmi_notify_handler) (union acpi_object *data, void *context);
@ -938,11 +938,6 @@ static inline const char *acpi_dev_name(struct acpi_device *adev)
return NULL;
}
static inline struct device *acpi_get_first_physical_node(struct acpi_device *adev)
{
return NULL;
}
static inline void acpi_early_init(void) { }
static inline void acpi_subsystem_init(void) { }
@ -1305,34 +1300,34 @@ void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const c
#endif
/*
* acpi_handle_<level>: Print message with ACPI prefix and object path
* acpi_handle_<level> - Print a message with ACPI prefix and object path
*
* These interfaces acquire the global namespace mutex to obtain an object
* path. In interrupt context, it shows the object path as <n/a>.
* In thread context, the global namespace mutex is acquired to obtain the
* object path. In interrupt context, the object path is shown as <n/a>.
*/
#define acpi_handle_emerg(handle, fmt, ...) \
acpi_handle_printk(KERN_EMERG, handle, fmt, ##__VA_ARGS__)
acpi_handle_printk(KERN_EMERG, handle, dev_fmt(fmt), ##__VA_ARGS__)
#define acpi_handle_alert(handle, fmt, ...) \
acpi_handle_printk(KERN_ALERT, handle, fmt, ##__VA_ARGS__)
acpi_handle_printk(KERN_ALERT, handle, dev_fmt(fmt), ##__VA_ARGS__)
#define acpi_handle_crit(handle, fmt, ...) \
acpi_handle_printk(KERN_CRIT, handle, fmt, ##__VA_ARGS__)
acpi_handle_printk(KERN_CRIT, handle, dev_fmt(fmt), ##__VA_ARGS__)
#define acpi_handle_err(handle, fmt, ...) \
acpi_handle_printk(KERN_ERR, handle, fmt, ##__VA_ARGS__)
acpi_handle_printk(KERN_ERR, handle, dev_fmt(fmt), ##__VA_ARGS__)
#define acpi_handle_warn(handle, fmt, ...) \
acpi_handle_printk(KERN_WARNING, handle, fmt, ##__VA_ARGS__)
acpi_handle_printk(KERN_WARNING, handle, dev_fmt(fmt), ##__VA_ARGS__)
#define acpi_handle_notice(handle, fmt, ...) \
acpi_handle_printk(KERN_NOTICE, handle, fmt, ##__VA_ARGS__)
acpi_handle_printk(KERN_NOTICE, handle, dev_fmt(fmt), ##__VA_ARGS__)
#define acpi_handle_info(handle, fmt, ...) \
acpi_handle_printk(KERN_INFO, handle, fmt, ##__VA_ARGS__)
acpi_handle_printk(KERN_INFO, handle, dev_fmt(fmt), ##__VA_ARGS__)
#if defined(DEBUG)
#define acpi_handle_debug(handle, fmt, ...) \
acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__)
acpi_handle_printk(KERN_DEBUG, handle, dev_fmt(fmt), ##__VA_ARGS__)
#else
#if defined(CONFIG_DYNAMIC_DEBUG)
#define acpi_handle_debug(handle, fmt, ...) \
_dynamic_func_call(fmt, __acpi_handle_debug, \
handle, pr_fmt(fmt), ##__VA_ARGS__)
handle, dev_fmt(fmt), ##__VA_ARGS__)
#else
#define acpi_handle_debug(handle, fmt, ...) \
({ \

View File

@ -24,6 +24,13 @@
#define PCIE_STD_MAX_TLP_PREFIXLOG 4
#define PCIE_STD_MAX_TLP_HEADERLOG (PCIE_STD_NUM_TLP_HEADERLOG + 10)
/*
* Size of the AER Capability register block in hardware, long enough for the
* longest Flit mode TLP Log. struct aer_capability_regs below is larger and
* laid out differently; use aer_cap_regs_unpack() to convert.
*/
#define PCIE_AER_CAP_HW_SIZE 96
struct pci_dev;
struct pcie_tlp_log {
@ -68,6 +75,8 @@ static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
void pci_print_aer(struct pci_dev *dev, int aer_severity,
struct aer_capability_regs *aer);
void aer_cap_regs_unpack(struct aer_capability_regs *regs, const void *raw,
size_t raw_len);
int cper_severity_to_aer(int cper_severity);
void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
int severity, struct aer_capability_regs *aer_regs);

View File

@ -109,7 +109,7 @@ static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, enum apple_gmux_ty
if (!adev)
return false;
dev = get_device(acpi_get_first_physical_node(adev));
dev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!dev)
return false;

View File

@ -113,6 +113,7 @@ struct bus_type {
bool need_parent_lock;
};
int __must_check companion_bus_register(const struct bus_type *bus);
int __must_check bus_register(const struct bus_type *bus);
void bus_unregister(const struct bus_type *bus);

View File

@ -293,8 +293,9 @@ struct device *thermal_zone_device(struct thermal_zone_device *tzd);
void thermal_zone_device_update(struct thermal_zone_device *,
enum thermal_notify_event);
struct thermal_cooling_device *thermal_cooling_device_register(const char *,
void *, const struct thermal_cooling_device_ops *);
struct thermal_cooling_device *thermal_cooling_device_create(
struct device *parent, const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops);
struct thermal_cooling_device *
devm_thermal_cooling_device_register(struct device *dev, const char *type, void *devdata,
@ -340,9 +341,9 @@ static inline void thermal_zone_device_update(struct thermal_zone_device *tz,
enum thermal_notify_event event)
{ }
static inline struct thermal_cooling_device *
thermal_cooling_device_register(const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
static inline struct thermal_cooling_device *thermal_cooling_device_create(
struct device *parent, const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{ return ERR_PTR(-ENODEV); }
static inline struct thermal_cooling_device *
@ -391,4 +392,12 @@ static inline void thermal_pm_prepare(void) {}
static inline void thermal_pm_complete(void) {}
#endif /* CONFIG_THERMAL */
static inline struct thermal_cooling_device *thermal_cooling_device_register(
const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
return thermal_cooling_device_create(NULL, type, devdata, ops);
}
#endif /* __THERMAL_H__ */

View File

@ -209,8 +209,7 @@ static int aw88399_hda_acpi_probe(struct aw88399_hda *aw88399)
return -ENODEV;
}
struct device *physdev __free(put_device) =
get_device(acpi_get_first_physical_node(adev));
struct device *physdev __free(put_device) = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!physdev)
return -ENODEV;

View File

@ -1926,8 +1926,7 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
}
cs35l41->dacpi = adev;
struct device *physdev __free(put_device) =
get_device(acpi_get_first_physical_node(adev));
struct device *physdev __free(put_device) = acpi_bus_get_primary_device(adev);
if (!physdev) {
acpi_dev_put(adev);
return -ENODEV;

View File

@ -100,8 +100,7 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
return -ENODEV;
}
struct device *physdev __free(put_device) =
get_device(acpi_get_first_physical_node(adev));
struct device *physdev __free(put_device) = acpi_bus_get_primary_device(adev);
ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);
if (ret < 0) {
dev_err(p->dev, "Failed to get ACPI resource.\n");

View File

@ -341,8 +341,7 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
strscpy(p->dev_name, hid, sizeof(p->dev_name));
struct device *physdev __free(put_device) =
get_device(acpi_get_first_physical_node(adev));
struct device *physdev __free(put_device) = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!physdev)
return -ENODEV;

View File

@ -198,7 +198,7 @@ static int st_es8336_late_probe(struct snd_soc_card *card)
if (!adev)
return -ENODEV;
codec_dev = acpi_get_first_physical_node(adev);
codec_dev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!codec_dev) {
dev_err(card->dev, "can not find codec dev\n");

View File

@ -428,7 +428,7 @@ static int acp3x_es83xx_probe(struct snd_soc_card *card)
return -ENXIO;
}
codec_dev = acpi_get_first_physical_node(adev);
codec_dev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!codec_dev) {
dev_warn(dev, "Error cannot find codec device, will defer probe\n");

View File

@ -601,11 +601,11 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
return -ENOENT;
}
codec_dev = acpi_get_first_physical_node(adev);
codec_dev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!codec_dev)
return -EPROBE_DEFER;
priv->codec_dev = get_device(codec_dev);
priv->codec_dev = codec_dev;
/* override platform name, if required */
byt_cht_es8316_card.dev = dev;

View File

@ -1744,11 +1744,11 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
return -ENOENT;
}
codec_dev = acpi_get_first_physical_node(adev);
codec_dev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (codec_dev) {
priv->codec_dev = get_device(codec_dev);
priv->codec_dev = codec_dev;
} else {
/*
* Special case for Android tablets where the codec i2c_client

View File

@ -960,11 +960,11 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
return -ENOENT;
}
codec_dev = acpi_get_first_physical_node(adev);
codec_dev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!codec_dev)
return -EPROBE_DEFER;
priv->codec_dev = get_device(codec_dev);
priv->codec_dev = codec_dev;
/*
* swap SSP0 if bytcr is detected

View File

@ -529,7 +529,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
const char *platform_name;
struct cht_mc_private *drv;
struct acpi_device *adev;
struct device *codec_dev;
bool sof_parent;
bool found = false;
bool is_bytcr = false;
@ -583,8 +582,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
return -ENOENT;
}
/* acpi_get_first_physical_node() returns a borrowed ref, no need to deref */
codec_dev = acpi_get_first_physical_node(adev);
struct device *codec_dev __free(put_device) = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!codec_dev)
return -EPROBE_DEFER;

View File

@ -168,7 +168,7 @@ static int cs35l41_compute_codec_conf(void)
cs35l41_name_prefixes[uid]);
continue;
}
physdev = get_device(acpi_get_first_physical_node(adev));
physdev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!physdev) {
pr_devel("Cannot find physical node for HID %s UID %u (%s)\n", CS35L41_HID,

View File

@ -702,11 +702,11 @@ static int sof_es8336_probe(struct platform_device *pdev)
return -ENOENT;
}
codec_dev = acpi_get_first_physical_node(adev);
codec_dev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!codec_dev)
return -EPROBE_DEFER;
priv->codec_dev = get_device(codec_dev);
priv->codec_dev = codec_dev;
ret = snd_soc_fixup_dai_links_platform_name(&sof_es8336_card,
mach->mach_params.platform);

View File

@ -196,7 +196,6 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
struct snd_soc_card *card = &data->snd_card;
const char *codec_dai_name;
struct acpi_device *adev;
struct device *phy_dev;
int i, ret;
/* fixup platform name based on reference node */
@ -204,7 +203,7 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
if (!adev)
return -ENOENT;
phy_dev = acpi_get_first_physical_node(adev);
struct device *phy_dev __free(put_device) = acpi_bus_get_primary_device(adev);
if (!phy_dev)
return -EPROBE_DEFER;