[PATCH] acpi_pcihp: Add support for _HPX
[linux-2.6.git] / drivers / pci / hotplug / acpi_pcihp.c
index afac5c3..51cb9f8 100644 (file)
 
 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;