diff options
-rw-r--r-- | drivers/mailbox/pcc.c | 81 |
1 files changed, 38 insertions, 43 deletions
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 3ef7f036ceea..fc3c237daef2 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c | |||
@@ -373,33 +373,24 @@ static const struct mbox_chan_ops pcc_chan_ops = { | |||
373 | }; | 373 | }; |
374 | 374 | ||
375 | /** | 375 | /** |
376 | * parse_pcc_subspace - Parse the PCC table and verify PCC subspace | 376 | * parse_pcc_subspaces -- Count PCC subspaces defined |
377 | * entries. There should be one entry per PCC client. | ||
378 | * @header: Pointer to the ACPI subtable header under the PCCT. | 377 | * @header: Pointer to the ACPI subtable header under the PCCT. |
379 | * @end: End of subtable entry. | 378 | * @end: End of subtable entry. |
380 | * | 379 | * |
381 | * Return: 0 for Success, else errno. | 380 | * Return: If we find a PCC subspace entry of a valid type, return 0. |
381 | * Otherwise, return -EINVAL. | ||
382 | * | 382 | * |
383 | * This gets called for each entry in the PCC table. | 383 | * This gets called for each entry in the PCC table. |
384 | */ | 384 | */ |
385 | static int parse_pcc_subspace(struct acpi_subtable_header *header, | 385 | static int parse_pcc_subspace(struct acpi_subtable_header *header, |
386 | const unsigned long end) | 386 | const unsigned long end) |
387 | { | 387 | { |
388 | struct acpi_pcct_hw_reduced *pcct_ss; | 388 | struct acpi_pcct_subspace *ss = (struct acpi_pcct_subspace *) header; |
389 | |||
390 | if (pcc_mbox_ctrl.num_chans <= MAX_PCC_SUBSPACES) { | ||
391 | pcct_ss = (struct acpi_pcct_hw_reduced *) header; | ||
392 | 389 | ||
393 | if ((pcct_ss->header.type != | 390 | if (ss->header.type < ACPI_PCCT_TYPE_RESERVED) |
394 | ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE) | 391 | return 0; |
395 | && (pcct_ss->header.type != | ||
396 | ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2)) { | ||
397 | pr_err("Incorrect PCC Subspace type detected\n"); | ||
398 | return -EINVAL; | ||
399 | } | ||
400 | } | ||
401 | 392 | ||
402 | return 0; | 393 | return -EINVAL; |
403 | } | 394 | } |
404 | 395 | ||
405 | /** | 396 | /** |
@@ -449,8 +440,8 @@ static int __init acpi_pcc_probe(void) | |||
449 | struct acpi_table_header *pcct_tbl; | 440 | struct acpi_table_header *pcct_tbl; |
450 | struct acpi_subtable_header *pcct_entry; | 441 | struct acpi_subtable_header *pcct_entry; |
451 | struct acpi_table_pcct *acpi_pcct_tbl; | 442 | struct acpi_table_pcct *acpi_pcct_tbl; |
443 | struct acpi_subtable_proc proc[ACPI_PCCT_TYPE_RESERVED]; | ||
452 | int count, i, rc; | 444 | int count, i, rc; |
453 | int sum = 0; | ||
454 | acpi_status status = AE_OK; | 445 | acpi_status status = AE_OK; |
455 | 446 | ||
456 | /* Search for PCCT */ | 447 | /* Search for PCCT */ |
@@ -459,43 +450,41 @@ static int __init acpi_pcc_probe(void) | |||
459 | if (ACPI_FAILURE(status) || !pcct_tbl) | 450 | if (ACPI_FAILURE(status) || !pcct_tbl) |
460 | return -ENODEV; | 451 | return -ENODEV; |
461 | 452 | ||
462 | count = acpi_table_parse_entries(ACPI_SIG_PCCT, | 453 | /* Set up the subtable handlers */ |
463 | sizeof(struct acpi_table_pcct), | 454 | for (i = ACPI_PCCT_TYPE_GENERIC_SUBSPACE; |
464 | ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE, | 455 | i < ACPI_PCCT_TYPE_RESERVED; i++) { |
465 | parse_pcc_subspace, MAX_PCC_SUBSPACES); | 456 | proc[i].id = i; |
466 | sum += (count > 0) ? count : 0; | 457 | proc[i].count = 0; |
467 | 458 | proc[i].handler = parse_pcc_subspace; | |
468 | count = acpi_table_parse_entries(ACPI_SIG_PCCT, | 459 | } |
469 | sizeof(struct acpi_table_pcct), | ||
470 | ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2, | ||
471 | parse_pcc_subspace, MAX_PCC_SUBSPACES); | ||
472 | sum += (count > 0) ? count : 0; | ||
473 | 460 | ||
474 | if (sum == 0 || sum >= MAX_PCC_SUBSPACES) { | 461 | count = acpi_table_parse_entries_array(ACPI_SIG_PCCT, |
475 | pr_err("Error parsing PCC subspaces from PCCT\n"); | 462 | sizeof(struct acpi_table_pcct), proc, |
463 | ACPI_PCCT_TYPE_RESERVED, MAX_PCC_SUBSPACES); | ||
464 | if (count == 0 || count > MAX_PCC_SUBSPACES) { | ||
465 | pr_warn("Invalid PCCT: %d PCC subspaces\n", count); | ||
476 | return -EINVAL; | 466 | return -EINVAL; |
477 | } | 467 | } |
478 | 468 | ||
479 | pcc_mbox_channels = kzalloc(sizeof(struct mbox_chan) * | 469 | pcc_mbox_channels = kzalloc(sizeof(struct mbox_chan) * count, GFP_KERNEL); |
480 | sum, GFP_KERNEL); | ||
481 | if (!pcc_mbox_channels) { | 470 | if (!pcc_mbox_channels) { |
482 | pr_err("Could not allocate space for PCC mbox channels\n"); | 471 | pr_err("Could not allocate space for PCC mbox channels\n"); |
483 | return -ENOMEM; | 472 | return -ENOMEM; |
484 | } | 473 | } |
485 | 474 | ||
486 | pcc_doorbell_vaddr = kcalloc(sum, sizeof(void *), GFP_KERNEL); | 475 | pcc_doorbell_vaddr = kcalloc(count, sizeof(void *), GFP_KERNEL); |
487 | if (!pcc_doorbell_vaddr) { | 476 | if (!pcc_doorbell_vaddr) { |
488 | rc = -ENOMEM; | 477 | rc = -ENOMEM; |
489 | goto err_free_mbox; | 478 | goto err_free_mbox; |
490 | } | 479 | } |
491 | 480 | ||
492 | pcc_doorbell_ack_vaddr = kcalloc(sum, sizeof(void *), GFP_KERNEL); | 481 | pcc_doorbell_ack_vaddr = kcalloc(count, sizeof(void *), GFP_KERNEL); |
493 | if (!pcc_doorbell_ack_vaddr) { | 482 | if (!pcc_doorbell_ack_vaddr) { |
494 | rc = -ENOMEM; | 483 | rc = -ENOMEM; |
495 | goto err_free_db_vaddr; | 484 | goto err_free_db_vaddr; |
496 | } | 485 | } |
497 | 486 | ||
498 | pcc_doorbell_irq = kcalloc(sum, sizeof(int), GFP_KERNEL); | 487 | pcc_doorbell_irq = kcalloc(count, sizeof(int), GFP_KERNEL); |
499 | if (!pcc_doorbell_irq) { | 488 | if (!pcc_doorbell_irq) { |
500 | rc = -ENOMEM; | 489 | rc = -ENOMEM; |
501 | goto err_free_db_ack_vaddr; | 490 | goto err_free_db_ack_vaddr; |
@@ -509,18 +498,24 @@ static int __init acpi_pcc_probe(void) | |||
509 | if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL) | 498 | if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL) |
510 | pcc_mbox_ctrl.txdone_irq = true; | 499 | pcc_mbox_ctrl.txdone_irq = true; |
511 | 500 | ||
512 | for (i = 0; i < sum; i++) { | 501 | for (i = 0; i < count; i++) { |
513 | struct acpi_generic_address *db_reg; | 502 | struct acpi_generic_address *db_reg; |
514 | struct acpi_pcct_hw_reduced *pcct_ss; | 503 | struct acpi_pcct_subspace *pcct_ss; |
515 | pcc_mbox_channels[i].con_priv = pcct_entry; | 504 | pcc_mbox_channels[i].con_priv = pcct_entry; |
516 | 505 | ||
517 | pcct_ss = (struct acpi_pcct_hw_reduced *) pcct_entry; | 506 | if (pcct_entry->type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE || |
507 | pcct_entry->type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) { | ||
508 | struct acpi_pcct_hw_reduced *pcct_hrss; | ||
509 | |||
510 | pcct_hrss = (struct acpi_pcct_hw_reduced *) pcct_entry; | ||
518 | 511 | ||
519 | if (pcc_mbox_ctrl.txdone_irq) { | 512 | if (pcc_mbox_ctrl.txdone_irq) { |
520 | rc = pcc_parse_subspace_irq(i, pcct_ss); | 513 | rc = pcc_parse_subspace_irq(i, pcct_hrss); |
521 | if (rc < 0) | 514 | if (rc < 0) |
522 | goto err; | 515 | goto err; |
516 | } | ||
523 | } | 517 | } |
518 | pcct_ss = (struct acpi_pcct_subspace *) pcct_entry; | ||
524 | 519 | ||
525 | /* If doorbell is in system memory cache the virt address */ | 520 | /* If doorbell is in system memory cache the virt address */ |
526 | db_reg = &pcct_ss->doorbell_register; | 521 | db_reg = &pcct_ss->doorbell_register; |
@@ -531,7 +526,7 @@ static int __init acpi_pcc_probe(void) | |||
531 | ((unsigned long) pcct_entry + pcct_entry->length); | 526 | ((unsigned long) pcct_entry + pcct_entry->length); |
532 | } | 527 | } |
533 | 528 | ||
534 | pcc_mbox_ctrl.num_chans = sum; | 529 | pcc_mbox_ctrl.num_chans = count; |
535 | 530 | ||
536 | pr_info("Detected %d PCC Subspaces\n", pcc_mbox_ctrl.num_chans); | 531 | pr_info("Detected %d PCC Subspaces\n", pcc_mbox_ctrl.num_chans); |
537 | 532 | ||