|
@@ -47,6 +47,171 @@
|
|
|
|
|
|
static int debug_acpi;
|
|
|
|
|
|
+static acpi_status
|
|
|
+decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ union acpi_object *fields = record->package.elements;
|
|
|
+ u32 revision = fields[1].integer.value;
|
|
|
+
|
|
|
+ switch (revision) {
|
|
|
+ case 1:
|
|
|
+ if (record->package.count != 6)
|
|
|
+ return AE_ERROR;
|
|
|
+ for (i = 2; i < 6; i++)
|
|
|
+ if (fields[i].type != ACPI_TYPE_INTEGER)
|
|
|
+ return AE_ERROR;
|
|
|
+ hpx->t0 = &hpx->type0_data;
|
|
|
+ hpx->t0->revision = revision;
|
|
|
+ hpx->t0->cache_line_size = fields[2].integer.value;
|
|
|
+ hpx->t0->latency_timer = fields[3].integer.value;
|
|
|
+ hpx->t0->enable_serr = fields[4].integer.value;
|
|
|
+ hpx->t0->enable_perr = fields[5].integer.value;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING
|
|
|
+ "%s: Type 0 Revision %d record not supported\n",
|
|
|
+ __FUNCTION__, revision);
|
|
|
+ return AE_ERROR;
|
|
|
+ }
|
|
|
+ return AE_OK;
|
|
|
+}
|
|
|
+
|
|
|
+static acpi_status
|
|
|
+decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ union acpi_object *fields = record->package.elements;
|
|
|
+ u32 revision = fields[1].integer.value;
|
|
|
+
|
|
|
+ switch (revision) {
|
|
|
+ case 1:
|
|
|
+ if (record->package.count != 5)
|
|
|
+ return AE_ERROR;
|
|
|
+ for (i = 2; i < 5; i++)
|
|
|
+ if (fields[i].type != ACPI_TYPE_INTEGER)
|
|
|
+ return AE_ERROR;
|
|
|
+ hpx->t1 = &hpx->type1_data;
|
|
|
+ hpx->t1->revision = revision;
|
|
|
+ hpx->t1->max_mem_read = fields[2].integer.value;
|
|
|
+ hpx->t1->avg_max_split = fields[3].integer.value;
|
|
|
+ hpx->t1->tot_max_split = fields[4].integer.value;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING
|
|
|
+ "%s: Type 1 Revision %d record not supported\n",
|
|
|
+ __FUNCTION__, revision);
|
|
|
+ return AE_ERROR;
|
|
|
+ }
|
|
|
+ return AE_OK;
|
|
|
+}
|
|
|
+
|
|
|
+static acpi_status
|
|
|
+decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ union acpi_object *fields = record->package.elements;
|
|
|
+ u32 revision = fields[1].integer.value;
|
|
|
+
|
|
|
+ switch (revision) {
|
|
|
+ case 1:
|
|
|
+ if (record->package.count != 18)
|
|
|
+ return AE_ERROR;
|
|
|
+ for (i = 2; i < 18; i++)
|
|
|
+ if (fields[i].type != ACPI_TYPE_INTEGER)
|
|
|
+ return AE_ERROR;
|
|
|
+ hpx->t2 = &hpx->type2_data;
|
|
|
+ hpx->t2->revision = revision;
|
|
|
+ hpx->t2->unc_err_mask_and = fields[2].integer.value;
|
|
|
+ hpx->t2->unc_err_mask_or = fields[3].integer.value;
|
|
|
+ hpx->t2->unc_err_sever_and = fields[4].integer.value;
|
|
|
+ hpx->t2->unc_err_sever_or = fields[5].integer.value;
|
|
|
+ hpx->t2->cor_err_mask_and = fields[6].integer.value;
|
|
|
+ hpx->t2->cor_err_mask_or = fields[7].integer.value;
|
|
|
+ hpx->t2->adv_err_cap_and = fields[8].integer.value;
|
|
|
+ hpx->t2->adv_err_cap_or = fields[9].integer.value;
|
|
|
+ hpx->t2->pci_exp_devctl_and = fields[10].integer.value;
|
|
|
+ hpx->t2->pci_exp_devctl_or = fields[11].integer.value;
|
|
|
+ hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value;
|
|
|
+ hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value;
|
|
|
+ hpx->t2->sec_unc_err_sever_and = fields[14].integer.value;
|
|
|
+ hpx->t2->sec_unc_err_sever_or = fields[15].integer.value;
|
|
|
+ hpx->t2->sec_unc_err_mask_and = fields[16].integer.value;
|
|
|
+ hpx->t2->sec_unc_err_mask_or = fields[17].integer.value;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING
|
|
|
+ "%s: Type 2 Revision %d record not supported\n",
|
|
|
+ __FUNCTION__, revision);
|
|
|
+ return AE_ERROR;
|
|
|
+ }
|
|
|
+ return AE_OK;
|
|
|
+}
|
|
|
+
|
|
|
+static acpi_status
|
|
|
+acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
|
|
|
+{
|
|
|
+ acpi_status status;
|
|
|
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
|
|
+ union acpi_object *package, *record, *fields;
|
|
|
+ u32 type;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /* Clear the return buffer with zeros */
|
|
|
+ memset(hpx, 0, sizeof(struct hotplug_params));
|
|
|
+
|
|
|
+ status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer);
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
+ return status;
|
|
|
+
|
|
|
+ package = (union acpi_object *)buffer.pointer;
|
|
|
+ if (package->type != ACPI_TYPE_PACKAGE) {
|
|
|
+ status = AE_ERROR;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < package->package.count; i++) {
|
|
|
+ record = &package->package.elements[i];
|
|
|
+ if (record->type != ACPI_TYPE_PACKAGE) {
|
|
|
+ status = AE_ERROR;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ fields = record->package.elements;
|
|
|
+ if (fields[0].type != ACPI_TYPE_INTEGER ||
|
|
|
+ fields[1].type != ACPI_TYPE_INTEGER) {
|
|
|
+ status = AE_ERROR;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ type = fields[0].integer.value;
|
|
|
+ switch (type) {
|
|
|
+ case 0:
|
|
|
+ status = decode_type0_hpx_record(record, hpx);
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
+ goto exit;
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ status = decode_type1_hpx_record(record, hpx);
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
+ goto exit;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ status = decode_type2_hpx_record(record, hpx);
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
+ goto exit;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printk(KERN_ERR "%s: Type %d record not supported\n",
|
|
|
+ __FUNCTION__, type);
|
|
|
+ status = AE_ERROR;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ exit:
|
|
|
+ kfree(buffer.pointer);
|
|
|
+ return status;
|
|
|
+}
|
|
|
|
|
|
static acpi_status
|
|
|
acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
|
|
@@ -60,6 +225,9 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
|
|
|
|
|
|
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
|
|
|
|
|
|
+ /* Clear the return buffer with zeros */
|
|
|
+ memset(hpp, 0, sizeof(struct hotplug_params));
|
|
|
+
|
|
|
/* get _hpp */
|
|
|
status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf);
|
|
|
switch (status) {
|
|
@@ -108,15 +276,16 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- hpp->cache_line_size = nui[0];
|
|
|
- hpp->latency_timer = nui[1];
|
|
|
- hpp->enable_serr = nui[2];
|
|
|
- hpp->enable_perr = nui[3];
|
|
|
+ hpp->t0 = &hpp->type0_data;
|
|
|
+ hpp->t0->cache_line_size = nui[0];
|
|
|
+ hpp->t0->latency_timer = nui[1];
|
|
|
+ hpp->t0->enable_serr = nui[2];
|
|
|
+ hpp->t0->enable_perr = nui[3];
|
|
|
|
|
|
- pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size);
|
|
|
- pr_debug(" _HPP: latency timer =0x%x\n", hpp->latency_timer);
|
|
|
- pr_debug(" _HPP: enable SERR =0x%x\n", hpp->enable_serr);
|
|
|
- pr_debug(" _HPP: enable PERR =0x%x\n", hpp->enable_perr);
|
|
|
+ pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->t0->cache_line_size);
|
|
|
+ pr_debug(" _HPP: latency timer =0x%x\n", hpp->t0->latency_timer);
|
|
|
+ pr_debug(" _HPP: enable SERR =0x%x\n", hpp->t0->enable_serr);
|
|
|
+ pr_debug(" _HPP: enable PERR =0x%x\n", hpp->t0->enable_perr);
|
|
|
|
|
|
free_and_return:
|
|
|
kfree(string.pointer);
|
|
@@ -188,6 +357,9 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
|
|
|
* this pci dev. If we don't find any _HPP, use hardcoded defaults
|
|
|
*/
|
|
|
while (handle) {
|
|
|
+ status = acpi_run_hpx(handle, hpp);
|
|
|
+ if (ACPI_SUCCESS(status))
|
|
|
+ break;
|
|
|
status = acpi_run_hpp(handle, hpp);
|
|
|
if (ACPI_SUCCESS(status))
|
|
|
break;
|