| 1 | // SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 2 | /* | 
|---|
| 3 | * Author: Sudeep Holla <sudeep.holla@arm.com> | 
|---|
| 4 | * Copyright 2021 Arm Limited | 
|---|
| 5 | * | 
|---|
| 6 | * The PCC Address Space also referred as PCC Operation Region pertains to the | 
|---|
| 7 | * region of PCC subspace that succeeds the PCC signature. The PCC Operation | 
|---|
| 8 | * Region works in conjunction with the PCC Table(Platform Communications | 
|---|
| 9 | * Channel Table). PCC subspaces that are marked for use as PCC Operation | 
|---|
| 10 | * Regions must not be used as PCC subspaces for the standard ACPI features | 
|---|
| 11 | * such as CPPC, RASF, PDTT and MPST. These standard features must always use | 
|---|
| 12 | * the PCC Table instead. | 
|---|
| 13 | * | 
|---|
| 14 | * This driver sets up the PCC Address Space and installs an handler to enable | 
|---|
| 15 | * handling of PCC OpRegion in the firmware. | 
|---|
| 16 | * | 
|---|
| 17 | */ | 
|---|
| 18 | #include <linux/kernel.h> | 
|---|
| 19 | #include <linux/acpi.h> | 
|---|
| 20 | #include <linux/completion.h> | 
|---|
| 21 | #include <linux/idr.h> | 
|---|
| 22 | #include <linux/io.h> | 
|---|
| 23 |  | 
|---|
| 24 | #include <acpi/pcc.h> | 
|---|
| 25 |  | 
|---|
| 26 | /* | 
|---|
| 27 | * Arbitrary retries in case the remote processor is slow to respond | 
|---|
| 28 | * to PCC commands | 
|---|
| 29 | */ | 
|---|
| 30 | #define PCC_CMD_WAIT_RETRIES_NUM	500ULL | 
|---|
| 31 |  | 
|---|
| 32 | struct pcc_data { | 
|---|
| 33 | struct pcc_mbox_chan *pcc_chan; | 
|---|
| 34 | struct completion done; | 
|---|
| 35 | struct mbox_client cl; | 
|---|
| 36 | struct acpi_pcc_info ctx; | 
|---|
| 37 | }; | 
|---|
| 38 |  | 
|---|
| 39 | static struct acpi_pcc_info pcc_ctx; | 
|---|
| 40 |  | 
|---|
| 41 | static void pcc_rx_callback(struct mbox_client *cl, void *m) | 
|---|
| 42 | { | 
|---|
| 43 | struct pcc_data *data = container_of(cl, struct pcc_data, cl); | 
|---|
| 44 |  | 
|---|
| 45 | complete(&data->done); | 
|---|
| 46 | } | 
|---|
| 47 |  | 
|---|
| 48 | static acpi_status | 
|---|
| 49 | acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function, | 
|---|
| 50 | void *handler_context,  void **region_context) | 
|---|
| 51 | { | 
|---|
| 52 | struct pcc_data *data; | 
|---|
| 53 | struct acpi_pcc_info *ctx = handler_context; | 
|---|
| 54 | struct pcc_mbox_chan *pcc_chan; | 
|---|
| 55 | static acpi_status ret; | 
|---|
| 56 |  | 
|---|
| 57 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 
|---|
| 58 | if (!data) | 
|---|
| 59 | return AE_NO_MEMORY; | 
|---|
| 60 |  | 
|---|
| 61 | data->cl.rx_callback = pcc_rx_callback; | 
|---|
| 62 | data->cl.knows_txdone = true; | 
|---|
| 63 | data->ctx.length = ctx->length; | 
|---|
| 64 | data->ctx.subspace_id = ctx->subspace_id; | 
|---|
| 65 | data->ctx.internal_buffer = ctx->internal_buffer; | 
|---|
| 66 |  | 
|---|
| 67 | init_completion(x: &data->done); | 
|---|
| 68 | data->pcc_chan = pcc_mbox_request_channel(cl: &data->cl, subspace_id: ctx->subspace_id); | 
|---|
| 69 | if (IS_ERR(ptr: data->pcc_chan)) { | 
|---|
| 70 | pr_err( "Failed to find PCC channel for subspace %d\n", | 
|---|
| 71 | ctx->subspace_id); | 
|---|
| 72 | ret = AE_NOT_FOUND; | 
|---|
| 73 | goto err_free_data; | 
|---|
| 74 | } | 
|---|
| 75 |  | 
|---|
| 76 | pcc_chan = data->pcc_chan; | 
|---|
| 77 | if (!pcc_chan->mchan->mbox->txdone_irq) { | 
|---|
| 78 | pr_err( "This channel-%d does not support interrupt.\n", | 
|---|
| 79 | ctx->subspace_id); | 
|---|
| 80 | ret = AE_SUPPORT; | 
|---|
| 81 | goto err_free_channel; | 
|---|
| 82 | } | 
|---|
| 83 |  | 
|---|
| 84 | *region_context = data; | 
|---|
| 85 | return AE_OK; | 
|---|
| 86 |  | 
|---|
| 87 | err_free_channel: | 
|---|
| 88 | pcc_mbox_free_channel(chan: data->pcc_chan); | 
|---|
| 89 | err_free_data: | 
|---|
| 90 | kfree(objp: data); | 
|---|
| 91 |  | 
|---|
| 92 | return ret; | 
|---|
| 93 | } | 
|---|
| 94 |  | 
|---|
| 95 | static acpi_status | 
|---|
| 96 | acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr, | 
|---|
| 97 | u32 bits, acpi_integer *value, | 
|---|
| 98 | void *handler_context, void *region_context) | 
|---|
| 99 | { | 
|---|
| 100 | int ret; | 
|---|
| 101 | struct pcc_data *data = region_context; | 
|---|
| 102 | u64 usecs_lat; | 
|---|
| 103 |  | 
|---|
| 104 | reinit_completion(x: &data->done); | 
|---|
| 105 |  | 
|---|
| 106 | /* Write to Shared Memory */ | 
|---|
| 107 | memcpy_toio(data->pcc_chan->shmem, (void *)value, data->ctx.length); | 
|---|
| 108 |  | 
|---|
| 109 | ret = mbox_send_message(chan: data->pcc_chan->mchan, NULL); | 
|---|
| 110 | if (ret < 0) | 
|---|
| 111 | return AE_ERROR; | 
|---|
| 112 |  | 
|---|
| 113 | /* | 
|---|
| 114 | * pcc_chan->latency is just a Nominal value. In reality the remote | 
|---|
| 115 | * processor could be much slower to reply. So add an arbitrary | 
|---|
| 116 | * amount of wait on top of Nominal. | 
|---|
| 117 | */ | 
|---|
| 118 | usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency; | 
|---|
| 119 | ret = wait_for_completion_timeout(x: &data->done, | 
|---|
| 120 | timeout: usecs_to_jiffies(u: usecs_lat)); | 
|---|
| 121 | if (ret == 0) { | 
|---|
| 122 | pr_err( "PCC command executed timeout!\n"); | 
|---|
| 123 | return AE_TIME; | 
|---|
| 124 | } | 
|---|
| 125 |  | 
|---|
| 126 | mbox_chan_txdone(chan: data->pcc_chan->mchan, r: ret); | 
|---|
| 127 |  | 
|---|
| 128 | memcpy_fromio(value, data->pcc_chan->shmem, data->ctx.length); | 
|---|
| 129 |  | 
|---|
| 130 | return AE_OK; | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 | void __init acpi_init_pcc(void) | 
|---|
| 134 | { | 
|---|
| 135 | acpi_status status; | 
|---|
| 136 |  | 
|---|
| 137 | status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, | 
|---|
| 138 | ACPI_ADR_SPACE_PLATFORM_COMM, | 
|---|
| 139 | handler: &acpi_pcc_address_space_handler, | 
|---|
| 140 | setup: &acpi_pcc_address_space_setup, | 
|---|
| 141 | context: &pcc_ctx); | 
|---|
| 142 | if (ACPI_FAILURE(status)) | 
|---|
| 143 | pr_alert( "OperationRegion handler could not be installed\n"); | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|