static ssize_t tpm_show_ppi_version(struct device *dev, struct device_attribute *attr, char *buf) { acpi_handle handle; acpi_status status; struct acpi_object_list input; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object params[4]; union acpi_object *obj; input.count = 4; ppi_assign_params(params, TPM_PPI_FN_VERSION); input.pointer = params; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, ppi_callback, NULL, tpm_device_name, &handle); if (ACPI_FAILURE(status)) return -ENXIO; status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, ACPI_TYPE_STRING); if (ACPI_FAILURE(status)) return -ENOMEM; obj = (union acpi_object *)output.pointer; status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer); kfree(output.pointer); return status; }
static int acpi_get_psd(struct cpc_desc *cpc_ptr, acpi_handle handle) { int result = -EFAULT; acpi_status status = AE_OK; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"}; struct acpi_buffer state = {0, NULL}; union acpi_object *psd = NULL; struct acpi_psd_package *pdomain; status = acpi_evaluate_object_typed(handle, "_PSD", NULL, &buffer, ACPI_TYPE_PACKAGE); if (ACPI_FAILURE(status)) return -ENODEV; psd = buffer.pointer; if (!psd || psd->package.count != 1) { pr_debug("Invalid _PSD data\n"); goto end; } pdomain = &(cpc_ptr->domain_info); state.length = sizeof(struct acpi_psd_package); state.pointer = pdomain; status = acpi_extract_package(&(psd->package.elements[0]), &format, &state); if (ACPI_FAILURE(status)) { pr_debug("Invalid _PSD data for CPU:%d\n", cpc_ptr->cpu_id); goto end; } if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { pr_debug("Unknown _PSD:num_entries for CPU:%d\n", cpc_ptr->cpu_id); goto end; } if (pdomain->revision != ACPI_PSD_REV0_REVISION) { pr_debug("Unknown _PSD:revision for CPU: %d\n", cpc_ptr->cpu_id); goto end; } if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL && pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY && pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) { pr_debug("Invalid _PSD:coord_type for CPU:%d\n", cpc_ptr->cpu_id); goto end; } result = 0; end: kfree(buffer.pointer); return result; }
void acpi_init_properties(struct acpi_device *adev) { struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; const union acpi_object *desc; acpi_status status; int i; status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf, ACPI_TYPE_PACKAGE); if (ACPI_FAILURE(status)) return; desc = buf.pointer; if (desc->package.count % 2) goto fail; /* Look for the device properties UUID. */ for (i = 0; i < desc->package.count; i += 2) { const union acpi_object *uuid, *properties; uuid = &desc->package.elements[i]; properties = &desc->package.elements[i + 1]; /* * The first element must be a UUID and the second one must be * a package. */ if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16 || properties->type != ACPI_TYPE_PACKAGE) break; if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid))) continue; /* * We found the matching UUID. Now validate the format of the * package immediately following it. */ if (!acpi_properties_format_valid(properties)) break; adev->data.pointer = buf.pointer; adev->data.properties = properties; return; } fail: dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n"); ACPI_FREE(buf.pointer); }
static ssize_t tpm_show_ppi_request(struct device *dev, struct device_attribute *attr, char *buf) { acpi_handle handle; acpi_status status; struct acpi_object_list input; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object params[4]; union acpi_object *ret_obj; input.count = 4; ppi_assign_params(params, TPM_PPI_FN_GETREQ); input.pointer = params; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, ppi_callback, NULL, tpm_device_name, &handle); if (ACPI_FAILURE(status)) return -ENXIO; status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, ACPI_TYPE_PACKAGE); if (ACPI_FAILURE(status)) return -ENOMEM; /* * output.pointer should be of package type, including two integers. * The first is function return code, 0 means success and 1 means * error. The second is pending TPM operation requested by the OS, 0 * means none and >0 means operation value. */ ret_obj = ((union acpi_object *)output.pointer)->package.elements; if (ret_obj->type == ACPI_TYPE_INTEGER) { if (ret_obj->integer.value) { status = -EFAULT; goto cleanup; } ret_obj++; if (ret_obj->type == ACPI_TYPE_INTEGER) status = scnprintf(buf, PAGE_SIZE, "%llu\n", ret_obj->integer.value); else status = -EINVAL; } else { status = -EINVAL; } cleanup: kfree(output.pointer); return status; }
static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level, void *context, void **ret) { struct acpi_device *adev; acpi_status status = AE_OK; struct snd_soc_acpi_package_context *pkg_ctx = context; pkg_ctx->data_valid = false; if (acpi_bus_get_device(handle, &adev)) return AE_OK; if (adev->status.present && adev->status.functional) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *myobj = NULL; status = acpi_evaluate_object_typed(handle, pkg_ctx->name, NULL, &buffer, ACPI_TYPE_PACKAGE); if (ACPI_FAILURE(status)) return AE_OK; myobj = buffer.pointer; if (!myobj || myobj->package.count != pkg_ctx->length) { kfree(buffer.pointer); return AE_OK; } status = acpi_extract_package(myobj, pkg_ctx->format, pkg_ctx->state); if (ACPI_FAILURE(status)) { kfree(buffer.pointer); return AE_OK; } kfree(buffer.pointer); pkg_ctx->data_valid = true; return AE_CTRL_TERMINATE; } return AE_OK; }
/** * acpi_cppc_processor_probe - Search for per CPU _CPC objects. * @pr: Ptr to acpi_processor containing this CPUs logical Id. * * Return: 0 for success or negative value for err. */ int acpi_cppc_processor_probe(struct acpi_processor *pr) { struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *out_obj, *cpc_obj; struct cpc_desc *cpc_ptr; struct cpc_reg *gas_t; acpi_handle handle = pr->handle; unsigned int num_ent, i, cpc_rev; acpi_status status; int ret = -EFAULT; /* Parse the ACPI _CPC table for this cpu. */ status = acpi_evaluate_object_typed(handle, "_CPC", NULL, &output, ACPI_TYPE_PACKAGE); if (ACPI_FAILURE(status)) { ret = -ENODEV; goto out_buf_free; } out_obj = (union acpi_object *) output.pointer; cpc_ptr = kzalloc(sizeof(struct cpc_desc), GFP_KERNEL); if (!cpc_ptr) { ret = -ENOMEM; goto out_buf_free; } /* First entry is NumEntries. */ cpc_obj = &out_obj->package.elements[0]; if (cpc_obj->type == ACPI_TYPE_INTEGER) { num_ent = cpc_obj->integer.value; } else { pr_debug("Unexpected entry type(%d) for NumEntries\n", cpc_obj->type); goto out_free; } /* Only support CPPCv2. Bail otherwise. */ if (num_ent != CPPC_NUM_ENT) { pr_debug("Firmware exports %d entries. Expected: %d\n", num_ent, CPPC_NUM_ENT); goto out_free; } /* Second entry should be revision. */ cpc_obj = &out_obj->package.elements[1]; if (cpc_obj->type == ACPI_TYPE_INTEGER) { cpc_rev = cpc_obj->integer.value; } else { pr_debug("Unexpected entry type(%d) for Revision\n", cpc_obj->type); goto out_free; } if (cpc_rev != CPPC_REV) { pr_debug("Firmware exports revision:%d. Expected:%d\n", cpc_rev, CPPC_REV); goto out_free; } /* Iterate through remaining entries in _CPC */ for (i = 2; i < num_ent; i++) { cpc_obj = &out_obj->package.elements[i]; if (cpc_obj->type == ACPI_TYPE_INTEGER) { cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_INTEGER; cpc_ptr->cpc_regs[i-2].cpc_entry.int_value = cpc_obj->integer.value; } else if (cpc_obj->type == ACPI_TYPE_BUFFER) { gas_t = (struct cpc_reg *) cpc_obj->buffer.pointer; /* * The PCC Subspace index is encoded inside * the CPC table entries. The same PCC index * will be used for all the PCC entries, * so extract it only once. */ if (gas_t->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { if (pcc_subspace_idx < 0) pcc_subspace_idx = gas_t->access_width; else if (pcc_subspace_idx != gas_t->access_width) { pr_debug("Mismatched PCC ids.\n"); goto out_free; } } else if (gas_t->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { /* Support only PCC and SYS MEM type regs */ pr_debug("Unsupported register type: %d\n", gas_t->space_id); goto out_free; } cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_BUFFER; memcpy(&cpc_ptr->cpc_regs[i-2].cpc_entry.reg, gas_t, sizeof(*gas_t)); } else { pr_debug("Err in entry:%d in CPC table of CPU:%d \n", i, pr->id); goto out_free; } } /* Store CPU Logical ID */ cpc_ptr->cpu_id = pr->id; /* Parse PSD data for this CPU */ ret = acpi_get_psd(cpc_ptr, handle); if (ret) goto out_free; /* Register PCC channel once for all CPUs. */ if (!pcc_channel_acquired) { ret = register_pcc_channel(pcc_subspace_idx); if (ret) goto out_free; } /* Plug PSD data into this CPUs CPC descriptor. */ per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr; /* Everything looks okay */ pr_debug("Parsed CPC struct for CPU: %d\n", pr->id); kfree(output.pointer); return 0; out_free: kfree(cpc_ptr); out_buf_free: kfree(output.pointer); return ret; }
static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) { char *str = buf; char version[PPI_VERSION_LEN + 1]; acpi_handle handle; acpi_status status; struct acpi_object_list input; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object params[4]; union acpi_object obj; int i; u32 ret; char *info[] = { "Not implemented", "BIOS only", "Blocked for OS by BIOS", "User required", "User not required", }; input.count = 4; ppi_assign_params(params, TPM_PPI_FN_VERSION); input.pointer = params; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, ppi_callback, NULL, tpm_device_name, &handle); if (ACPI_FAILURE(status)) return -ENXIO; status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, ACPI_TYPE_STRING); if (ACPI_FAILURE(status)) return -ENOMEM; strlcpy(version, ((union acpi_object *)output.pointer)->string.pointer, PPI_VERSION_LEN + 1); kfree(output.pointer); output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; if (strcmp(version, "1.2") == -1) return -EPERM; params[2].integer.value = TPM_PPI_FN_GETOPR; params[3].package.count = 1; obj.type = ACPI_TYPE_INTEGER; params[3].package.elements = &obj; for (i = start; i <= end; i++) { obj.integer.value = i; status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, ACPI_TYPE_INTEGER); if (ACPI_FAILURE(status)) return -ENOMEM; ret = ((union acpi_object *)output.pointer)->integer.value; if (ret > 0 && ret < ARRAY_SIZE(info)) str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", i, ret, info[ret]); kfree(output.pointer); output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; } return str - buf; }
static ssize_t tpm_show_ppi_response(struct device *dev, struct device_attribute *attr, char *buf) { acpi_handle handle; acpi_status status; struct acpi_object_list input; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object params[4]; union acpi_object *ret_obj; u64 req; input.count = 4; ppi_assign_params(params, TPM_PPI_FN_GETRSP); input.pointer = params; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, ppi_callback, NULL, tpm_device_name, &handle); if (ACPI_FAILURE(status)) return -ENXIO; status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, ACPI_TYPE_PACKAGE); if (ACPI_FAILURE(status)) return -ENOMEM; /* * parameter output.pointer should be of package type, including * 3 integers. The first means function return code, the second means * most recent TPM operation request, and the last means response to * the most recent TPM operation request. Only if the first is 0, and * the second integer is not 0, the response makes sense. */ ret_obj = ((union acpi_object *)output.pointer)->package.elements; if (ret_obj->type != ACPI_TYPE_INTEGER) { status = -EINVAL; goto cleanup; } if (ret_obj->integer.value) { status = -EFAULT; goto cleanup; } ret_obj++; if (ret_obj->type != ACPI_TYPE_INTEGER) { status = -EINVAL; goto cleanup; } if (ret_obj->integer.value) { req = ret_obj->integer.value; ret_obj++; if (ret_obj->type != ACPI_TYPE_INTEGER) { status = -EINVAL; goto cleanup; } if (ret_obj->integer.value == 0) status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, "0: Success"); else if (ret_obj->integer.value == 0xFFFFFFF0) status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, "0xFFFFFFF0: User Abort"); else if (ret_obj->integer.value == 0xFFFFFFF1) status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, "0xFFFFFFF1: BIOS Failure"); else if (ret_obj->integer.value >= 1 && ret_obj->integer.value <= 0x00000FFF) status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", req, ret_obj->integer.value, "Corresponding TPM error"); else status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", req, ret_obj->integer.value, "Error"); } else { status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", ret_obj->integer.value, "No Recent Request"); } cleanup: kfree(output.pointer); return status; }
static ssize_t tpm_show_ppi_transition_action(struct device *dev, struct device_attribute *attr, char *buf) { char version[PPI_VERSION_LEN + 1]; acpi_handle handle; acpi_status status; struct acpi_object_list input; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object params[4]; u32 ret; char *info[] = { "None", "Shutdown", "Reboot", "OS Vendor-specific", "Error", }; input.count = 4; ppi_assign_params(params, TPM_PPI_FN_VERSION); input.pointer = params; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, ppi_callback, NULL, tpm_device_name, &handle); if (ACPI_FAILURE(status)) return -ENXIO; status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, ACPI_TYPE_STRING); if (ACPI_FAILURE(status)) return -ENOMEM; strlcpy(version, ((union acpi_object *)output.pointer)->string.pointer, PPI_VERSION_LEN + 1); /* * PPI spec defines params[3].type as empty package, but some platforms * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for * compatibility, define params[3].type as buffer, if PPI version < 1.2 */ if (strcmp(version, "1.2") == -1) { params[3].type = ACPI_TYPE_BUFFER; params[3].buffer.length = 0; params[3].buffer.pointer = NULL; } params[2].integer.value = TPM_PPI_FN_GETACT; kfree(output.pointer); output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, ACPI_TYPE_INTEGER); if (ACPI_FAILURE(status)) return -ENOMEM; ret = ((union acpi_object *)output.pointer)->integer.value; if (ret < ARRAY_SIZE(info) - 1) status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); else status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ARRAY_SIZE(info)-1]); kfree(output.pointer); return status; }
static ssize_t tpm_store_ppi_request(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { char version[PPI_VERSION_LEN + 1]; acpi_handle handle; acpi_status status; struct acpi_object_list input; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object params[4]; union acpi_object obj; u32 req; u64 ret; input.count = 4; ppi_assign_params(params, TPM_PPI_FN_VERSION); input.pointer = params; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, ppi_callback, NULL, tpm_device_name, &handle); if (ACPI_FAILURE(status)) return -ENXIO; status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, ACPI_TYPE_STRING); if (ACPI_FAILURE(status)) return -ENOMEM; strlcpy(version, ((union acpi_object *)output.pointer)->string.pointer, PPI_VERSION_LEN + 1); kfree(output.pointer); output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; /* * the function to submit TPM operation request to pre-os environment * is updated with function index from SUBREQ to SUBREQ2 since PPI * version 1.1 */ if (strcmp(version, "1.1") == -1) params[2].integer.value = TPM_PPI_FN_SUBREQ; else params[2].integer.value = TPM_PPI_FN_SUBREQ2; /* * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS * accept buffer/string/integer type, but some BIOS accept buffer/ * string/package type. For PPI version 1.0 and 1.1, use buffer type * for compatibility, and use package type since 1.2 according to spec. */ if (strcmp(version, "1.2") == -1) { params[3].type = ACPI_TYPE_BUFFER; params[3].buffer.length = sizeof(req); sscanf(buf, "%d", &req); params[3].buffer.pointer = (char *)&req; } else { params[3].package.count = 1; obj.type = ACPI_TYPE_INTEGER; sscanf(buf, "%llu", &obj.integer.value); params[3].package.elements = &obj; } status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, ACPI_TYPE_INTEGER); if (ACPI_FAILURE(status)) return -ENOMEM; ret = ((union acpi_object *)output.pointer)->integer.value; if (ret == 0) status = (acpi_status)count; else if (ret == 1) status = -EPERM; else status = -EFAULT; kfree(output.pointer); return status; }
/** * acpi_cppc_processor_probe - Search for per CPU _CPC objects. * @pr: Ptr to acpi_processor containing this CPUs logical Id. * * Return: 0 for success or negative value for err. */ int acpi_cppc_processor_probe(struct acpi_processor *pr) { struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *out_obj, *cpc_obj; struct cpc_desc *cpc_ptr; struct cpc_reg *gas_t; struct device *cpu_dev; acpi_handle handle = pr->handle; unsigned int num_ent, i, cpc_rev; int pcc_subspace_id = -1; acpi_status status; int ret = -EFAULT; /* Parse the ACPI _CPC table for this cpu. */ status = acpi_evaluate_object_typed(handle, "_CPC", NULL, &output, ACPI_TYPE_PACKAGE); if (ACPI_FAILURE(status)) { ret = -ENODEV; goto out_buf_free; } out_obj = (union acpi_object *) output.pointer; cpc_ptr = kzalloc(sizeof(struct cpc_desc), GFP_KERNEL); if (!cpc_ptr) { ret = -ENOMEM; goto out_buf_free; } /* First entry is NumEntries. */ cpc_obj = &out_obj->package.elements[0]; if (cpc_obj->type == ACPI_TYPE_INTEGER) { num_ent = cpc_obj->integer.value; } else { pr_debug("Unexpected entry type(%d) for NumEntries\n", cpc_obj->type); goto out_free; } /* Only support CPPCv2. Bail otherwise. */ if (num_ent != CPPC_NUM_ENT) { pr_debug("Firmware exports %d entries. Expected: %d\n", num_ent, CPPC_NUM_ENT); goto out_free; } cpc_ptr->num_entries = num_ent; /* Second entry should be revision. */ cpc_obj = &out_obj->package.elements[1]; if (cpc_obj->type == ACPI_TYPE_INTEGER) { cpc_rev = cpc_obj->integer.value; } else { pr_debug("Unexpected entry type(%d) for Revision\n", cpc_obj->type); goto out_free; } if (cpc_rev != CPPC_REV) { pr_debug("Firmware exports revision:%d. Expected:%d\n", cpc_rev, CPPC_REV); goto out_free; } /* Iterate through remaining entries in _CPC */ for (i = 2; i < num_ent; i++) { cpc_obj = &out_obj->package.elements[i]; if (cpc_obj->type == ACPI_TYPE_INTEGER) { cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_INTEGER; cpc_ptr->cpc_regs[i-2].cpc_entry.int_value = cpc_obj->integer.value; } else if (cpc_obj->type == ACPI_TYPE_BUFFER) { gas_t = (struct cpc_reg *) cpc_obj->buffer.pointer; /* * The PCC Subspace index is encoded inside * the CPC table entries. The same PCC index * will be used for all the PCC entries, * so extract it only once. */ if (gas_t->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { if (pcc_subspace_id < 0) { pcc_subspace_id = gas_t->access_width; if (pcc_data_alloc(pcc_subspace_id)) goto out_free; } else if (pcc_subspace_id != gas_t->access_width) { pr_debug("Mismatched PCC ids.\n"); goto out_free; } } else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { if (gas_t->address) { void __iomem *addr; addr = ioremap(gas_t->address, gas_t->bit_width/8); if (!addr) goto out_free; cpc_ptr->cpc_regs[i-2].sys_mem_vaddr = addr; } } else { if (gas_t->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE || !cpc_ffh_supported()) { /* Support only PCC ,SYS MEM and FFH type regs */ pr_debug("Unsupported register type: %d\n", gas_t->space_id); goto out_free; } } cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_BUFFER; memcpy(&cpc_ptr->cpc_regs[i-2].cpc_entry.reg, gas_t, sizeof(*gas_t)); } else { pr_debug("Err in entry:%d in CPC table of CPU:%d \n", i, pr->id); goto out_free; } } per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id; /* Store CPU Logical ID */ cpc_ptr->cpu_id = pr->id; /* Parse PSD data for this CPU */ ret = acpi_get_psd(cpc_ptr, handle); if (ret) goto out_free; /* Register PCC channel once for all PCC subspace id. */ if (pcc_subspace_id >= 0 && !pcc_data[pcc_subspace_id]->pcc_channel_acquired) { ret = register_pcc_channel(pcc_subspace_id); if (ret) goto out_free; init_rwsem(&pcc_data[pcc_subspace_id]->pcc_lock); init_waitqueue_head(&pcc_data[pcc_subspace_id]->pcc_write_wait_q); } /* Everything looks okay */ pr_debug("Parsed CPC struct for CPU: %d\n", pr->id); /* Add per logical CPU nodes for reading its feedback counters. */ cpu_dev = get_cpu_device(pr->id); if (!cpu_dev) { ret = -EINVAL; goto out_free; } /* Plug PSD data into this CPUs CPC descriptor. */ per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr; ret = kobject_init_and_add(&cpc_ptr->kobj, &cppc_ktype, &cpu_dev->kobj, "acpi_cppc"); if (ret) { per_cpu(cpc_desc_ptr, pr->id) = NULL; goto out_free; } kfree(output.pointer); return 0; out_free: /* Free all the mapped sys mem areas for this CPU */ for (i = 2; i < cpc_ptr->num_entries; i++) { void __iomem *addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr; if (addr) iounmap(addr); } kfree(cpc_ptr); out_buf_free: kfree(output.pointer); return ret; }