static int pcc_mbox_probe()

in pcc.c [627:716]


static int pcc_mbox_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct mbox_controller *pcc_mbox_ctrl;
	struct mbox_chan *pcc_mbox_channels;
	struct acpi_table_header *pcct_tbl;
	struct acpi_subtable_header *pcct_entry;
	struct acpi_table_pcct *acpi_pcct_tbl;
	acpi_status status = AE_OK;
	int i, rc, count = pcc_chan_count;

	/* Search for PCCT */
	status = acpi_get_table(ACPI_SIG_PCCT, 0, &pcct_tbl);

	if (ACPI_FAILURE(status) || !pcct_tbl)
		return -ENODEV;

	pcc_mbox_channels = devm_kcalloc(dev, count, sizeof(*pcc_mbox_channels),
					 GFP_KERNEL);
	if (!pcc_mbox_channels) {
		rc = -ENOMEM;
		goto err;
	}

	chan_info = devm_kcalloc(dev, count, sizeof(*chan_info), GFP_KERNEL);
	if (!chan_info) {
		rc = -ENOMEM;
		goto err;
	}

	pcc_mbox_ctrl = devm_kmalloc(dev, sizeof(*pcc_mbox_ctrl), GFP_KERNEL);
	if (!pcc_mbox_ctrl) {
		rc = -ENOMEM;
		goto err;
	}

	/* Point to the first PCC subspace entry */
	pcct_entry = (struct acpi_subtable_header *) (
		(unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct));

	acpi_pcct_tbl = (struct acpi_table_pcct *) pcct_tbl;
	if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL)
		pcc_mbox_ctrl->txdone_irq = true;

	for (i = 0; i < count; i++) {
		struct pcc_chan_info *pchan = chan_info + i;

		pcc_mbox_channels[i].con_priv = pchan;
		pchan->chan.mchan = &pcc_mbox_channels[i];

		if (pcct_entry->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE &&
		    !pcc_mbox_ctrl->txdone_irq) {
			pr_err("Plaform Interrupt flag must be set to 1");
			rc = -EINVAL;
			goto err;
		}

		if (pcc_mbox_ctrl->txdone_irq) {
			rc = pcc_parse_subspace_irq(pchan, pcct_entry);
			if (rc < 0)
				goto err;
		}
		rc = pcc_parse_subspace_db_reg(pchan, pcct_entry);
		if (rc < 0)
			goto err;

		pcc_parse_subspace_shmem(pchan, pcct_entry);

		pcct_entry = (struct acpi_subtable_header *)
			((unsigned long) pcct_entry + pcct_entry->length);
	}

	pcc_mbox_ctrl->num_chans = count;

	pr_info("Detected %d PCC Subspaces\n", pcc_mbox_ctrl->num_chans);

	pcc_mbox_ctrl->chans = pcc_mbox_channels;
	pcc_mbox_ctrl->ops = &pcc_chan_ops;
	pcc_mbox_ctrl->dev = dev;

	pr_info("Registering PCC driver as Mailbox controller\n");
	rc = mbox_controller_register(pcc_mbox_ctrl);
	if (rc)
		pr_err("Err registering PCC as Mailbox controller: %d\n", rc);
	else
		return 0;
err:
	acpi_put_table(pcct_tbl);
	return rc;
}