| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 
|---|
| 2 | /* | 
|---|
| 3 | *	Copyright (C) 2014 Linaro Ltd. | 
|---|
| 4 | *	Author:	Ashwin Chaugule <ashwin.chaugule@linaro.org> | 
|---|
| 5 | * | 
|---|
| 6 | *  PCC (Platform Communication Channel) is defined in the ACPI 5.0+ | 
|---|
| 7 | *  specification. It is a mailbox like mechanism to allow clients | 
|---|
| 8 | *  such as CPPC (Collaborative Processor Performance Control), RAS | 
|---|
| 9 | *  (Reliability, Availability and Serviceability) and MPST (Memory | 
|---|
| 10 | *  Node Power State Table) to talk to the platform (e.g. BMC) through | 
|---|
| 11 | *  shared memory regions as defined in the PCC table entries. The PCC | 
|---|
| 12 | *  specification supports a Doorbell mechanism for the PCC clients | 
|---|
| 13 | *  to notify the platform about new data. This Doorbell information | 
|---|
| 14 | *  is also specified in each PCC table entry. | 
|---|
| 15 | * | 
|---|
| 16 | *  Typical high level flow of operation is: | 
|---|
| 17 | * | 
|---|
| 18 | *  PCC Reads: | 
|---|
| 19 | *  * Client tries to acquire a channel lock. | 
|---|
| 20 | *  * After it is acquired it writes READ cmd in communication region cmd | 
|---|
| 21 | *		address. | 
|---|
| 22 | *  * Client issues mbox_send_message() which rings the PCC doorbell | 
|---|
| 23 | *		for its PCC channel. | 
|---|
| 24 | *  * If command completes, then client has control over channel and | 
|---|
| 25 | *		it can proceed with its reads. | 
|---|
| 26 | *  * Client releases lock. | 
|---|
| 27 | * | 
|---|
| 28 | *  PCC Writes: | 
|---|
| 29 | *  * Client tries to acquire channel lock. | 
|---|
| 30 | *  * Client writes to its communication region after it acquires a | 
|---|
| 31 | *		channel lock. | 
|---|
| 32 | *  * Client writes WRITE cmd in communication region cmd address. | 
|---|
| 33 | *  * Client issues mbox_send_message() which rings the PCC doorbell | 
|---|
| 34 | *		for its PCC channel. | 
|---|
| 35 | *  * If command completes, then writes have succeeded and it can release | 
|---|
| 36 | *		the channel lock. | 
|---|
| 37 | * | 
|---|
| 38 | *  There is a Nominal latency defined for each channel which indicates | 
|---|
| 39 | *  how long to wait until a command completes. If command is not complete | 
|---|
| 40 | *  the client needs to retry or assume failure. | 
|---|
| 41 | * | 
|---|
| 42 | *	For more details about PCC, please see the ACPI specification from | 
|---|
| 43 | *  http://www.uefi.org/ACPIv5.1 Section 14. | 
|---|
| 44 | * | 
|---|
| 45 | *  This file implements PCC as a Mailbox controller and allows for PCC | 
|---|
| 46 | *  clients to be implemented as its Mailbox Client Channels. | 
|---|
| 47 | */ | 
|---|
| 48 |  | 
|---|
| 49 | #include <linux/acpi.h> | 
|---|
| 50 | #include <linux/delay.h> | 
|---|
| 51 | #include <linux/io.h> | 
|---|
| 52 | #include <linux/init.h> | 
|---|
| 53 | #include <linux/interrupt.h> | 
|---|
| 54 | #include <linux/list.h> | 
|---|
| 55 | #include <linux/log2.h> | 
|---|
| 56 | #include <linux/platform_device.h> | 
|---|
| 57 | #include <linux/mailbox_controller.h> | 
|---|
| 58 | #include <linux/mailbox_client.h> | 
|---|
| 59 | #include <linux/io-64-nonatomic-lo-hi.h> | 
|---|
| 60 | #include <acpi/pcc.h> | 
|---|
| 61 |  | 
|---|
| 62 | #include "mailbox.h" | 
|---|
| 63 |  | 
|---|
| 64 | #define MBOX_IRQ_NAME		"pcc-mbox" | 
|---|
| 65 |  | 
|---|
| 66 | /** | 
|---|
| 67 | * struct pcc_chan_reg - PCC register bundle | 
|---|
| 68 | * | 
|---|
| 69 | * @vaddr: cached virtual address for this register | 
|---|
| 70 | * @gas: pointer to the generic address structure for this register | 
|---|
| 71 | * @preserve_mask: bitmask to preserve when writing to this register | 
|---|
| 72 | * @set_mask: bitmask to set when writing to this register | 
|---|
| 73 | * @status_mask: bitmask to determine and/or update the status for this register | 
|---|
| 74 | */ | 
|---|
| 75 | struct pcc_chan_reg { | 
|---|
| 76 | void __iomem *vaddr; | 
|---|
| 77 | struct acpi_generic_address *gas; | 
|---|
| 78 | u64 preserve_mask; | 
|---|
| 79 | u64 set_mask; | 
|---|
| 80 | u64 status_mask; | 
|---|
| 81 | }; | 
|---|
| 82 |  | 
|---|
| 83 | /** | 
|---|
| 84 | * struct pcc_chan_info - PCC channel specific information | 
|---|
| 85 | * | 
|---|
| 86 | * @chan: PCC channel information with Shared Memory Region info | 
|---|
| 87 | * @db: PCC register bundle for the doorbell register | 
|---|
| 88 | * @plat_irq_ack: PCC register bundle for the platform interrupt acknowledge | 
|---|
| 89 | *	register | 
|---|
| 90 | * @cmd_complete: PCC register bundle for the command complete check register | 
|---|
| 91 | * @cmd_update: PCC register bundle for the command complete update register | 
|---|
| 92 | * @error: PCC register bundle for the error status register | 
|---|
| 93 | * @plat_irq: platform interrupt | 
|---|
| 94 | * @type: PCC subspace type | 
|---|
| 95 | * @plat_irq_flags: platform interrupt flags | 
|---|
| 96 | * @chan_in_use: this flag is used just to check if the interrupt needs | 
|---|
| 97 | *		handling when it is shared. Since only one transfer can occur | 
|---|
| 98 | *		at a time and mailbox takes care of locking, this flag can be | 
|---|
| 99 | *		accessed without a lock. Note: the type only support the | 
|---|
| 100 | *		communication from OSPM to Platform, like type3, use it, and | 
|---|
| 101 | *		other types completely ignore it. | 
|---|
| 102 | */ | 
|---|
| 103 | struct pcc_chan_info { | 
|---|
| 104 | struct pcc_mbox_chan chan; | 
|---|
| 105 | struct pcc_chan_reg db; | 
|---|
| 106 | struct pcc_chan_reg plat_irq_ack; | 
|---|
| 107 | struct pcc_chan_reg cmd_complete; | 
|---|
| 108 | struct pcc_chan_reg cmd_update; | 
|---|
| 109 | struct pcc_chan_reg error; | 
|---|
| 110 | int plat_irq; | 
|---|
| 111 | u8 type; | 
|---|
| 112 | unsigned int plat_irq_flags; | 
|---|
| 113 | bool chan_in_use; | 
|---|
| 114 | }; | 
|---|
| 115 |  | 
|---|
| 116 | #define to_pcc_chan_info(c) container_of(c, struct pcc_chan_info, chan) | 
|---|
| 117 | static struct pcc_chan_info *chan_info; | 
|---|
| 118 | static int pcc_chan_count; | 
|---|
| 119 |  | 
|---|
| 120 | /* | 
|---|
| 121 | * PCC can be used with perf critical drivers such as CPPC | 
|---|
| 122 | * So it makes sense to locally cache the virtual address and | 
|---|
| 123 | * use it to read/write to PCC registers such as doorbell register | 
|---|
| 124 | * | 
|---|
| 125 | * The below read_register and write_registers are used to read and | 
|---|
| 126 | * write from perf critical registers such as PCC doorbell register | 
|---|
| 127 | */ | 
|---|
| 128 | static void read_register(void __iomem *vaddr, u64 *val, unsigned int bit_width) | 
|---|
| 129 | { | 
|---|
| 130 | switch (bit_width) { | 
|---|
| 131 | case 8: | 
|---|
| 132 | *val = readb(addr: vaddr); | 
|---|
| 133 | break; | 
|---|
| 134 | case 16: | 
|---|
| 135 | *val = readw(addr: vaddr); | 
|---|
| 136 | break; | 
|---|
| 137 | case 32: | 
|---|
| 138 | *val = readl(addr: vaddr); | 
|---|
| 139 | break; | 
|---|
| 140 | case 64: | 
|---|
| 141 | *val = readq(addr: vaddr); | 
|---|
| 142 | break; | 
|---|
| 143 | } | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | static void write_register(void __iomem *vaddr, u64 val, unsigned int bit_width) | 
|---|
| 147 | { | 
|---|
| 148 | switch (bit_width) { | 
|---|
| 149 | case 8: | 
|---|
| 150 | writeb(val, addr: vaddr); | 
|---|
| 151 | break; | 
|---|
| 152 | case 16: | 
|---|
| 153 | writew(val, addr: vaddr); | 
|---|
| 154 | break; | 
|---|
| 155 | case 32: | 
|---|
| 156 | writel(val, addr: vaddr); | 
|---|
| 157 | break; | 
|---|
| 158 | case 64: | 
|---|
| 159 | writeq(val, addr: vaddr); | 
|---|
| 160 | break; | 
|---|
| 161 | } | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|
| 164 | static int pcc_chan_reg_read(struct pcc_chan_reg *reg, u64 *val) | 
|---|
| 165 | { | 
|---|
| 166 | int ret = 0; | 
|---|
| 167 |  | 
|---|
| 168 | if (!reg->gas) { | 
|---|
| 169 | *val = 0; | 
|---|
| 170 | return 0; | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | if (reg->vaddr) | 
|---|
| 174 | read_register(vaddr: reg->vaddr, val, bit_width: reg->gas->bit_width); | 
|---|
| 175 | else | 
|---|
| 176 | ret = acpi_read(value: val, reg: reg->gas); | 
|---|
| 177 |  | 
|---|
| 178 | return ret; | 
|---|
| 179 | } | 
|---|
| 180 |  | 
|---|
| 181 | static int pcc_chan_reg_write(struct pcc_chan_reg *reg, u64 val) | 
|---|
| 182 | { | 
|---|
| 183 | int ret = 0; | 
|---|
| 184 |  | 
|---|
| 185 | if (!reg->gas) | 
|---|
| 186 | return 0; | 
|---|
| 187 |  | 
|---|
| 188 | if (reg->vaddr) | 
|---|
| 189 | write_register(vaddr: reg->vaddr, val, bit_width: reg->gas->bit_width); | 
|---|
| 190 | else | 
|---|
| 191 | ret = acpi_write(value: val, reg: reg->gas); | 
|---|
| 192 |  | 
|---|
| 193 | return ret; | 
|---|
| 194 | } | 
|---|
| 195 |  | 
|---|
| 196 | static int pcc_chan_reg_read_modify_write(struct pcc_chan_reg *reg) | 
|---|
| 197 | { | 
|---|
| 198 | int ret = 0; | 
|---|
| 199 | u64 val; | 
|---|
| 200 |  | 
|---|
| 201 | ret = pcc_chan_reg_read(reg, val: &val); | 
|---|
| 202 | if (ret) | 
|---|
| 203 | return ret; | 
|---|
| 204 |  | 
|---|
| 205 | val &= reg->preserve_mask; | 
|---|
| 206 | val |= reg->set_mask; | 
|---|
| 207 |  | 
|---|
| 208 | return pcc_chan_reg_write(reg, val); | 
|---|
| 209 | } | 
|---|
| 210 |  | 
|---|
| 211 | /** | 
|---|
| 212 | * pcc_map_interrupt - Map a PCC subspace GSI to a linux IRQ number | 
|---|
| 213 | * @interrupt: GSI number. | 
|---|
| 214 | * @flags: interrupt flags | 
|---|
| 215 | * | 
|---|
| 216 | * Returns: a valid linux IRQ number on success | 
|---|
| 217 | *		0 or -EINVAL on failure | 
|---|
| 218 | */ | 
|---|
| 219 | static int pcc_map_interrupt(u32 interrupt, u32 flags) | 
|---|
| 220 | { | 
|---|
| 221 | int trigger, polarity; | 
|---|
| 222 |  | 
|---|
| 223 | if (!interrupt) | 
|---|
| 224 | return 0; | 
|---|
| 225 |  | 
|---|
| 226 | trigger = (flags & ACPI_PCCT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE | 
|---|
| 227 | : ACPI_LEVEL_SENSITIVE; | 
|---|
| 228 |  | 
|---|
| 229 | polarity = (flags & ACPI_PCCT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW | 
|---|
| 230 | : ACPI_ACTIVE_HIGH; | 
|---|
| 231 |  | 
|---|
| 232 | return acpi_register_gsi(NULL, gsi: interrupt, triggering: trigger, polarity); | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|
| 235 | static bool pcc_chan_plat_irq_can_be_shared(struct pcc_chan_info *pchan) | 
|---|
| 236 | { | 
|---|
| 237 | return (pchan->plat_irq_flags & ACPI_PCCT_INTERRUPT_MODE) == | 
|---|
| 238 | ACPI_LEVEL_SENSITIVE; | 
|---|
| 239 | } | 
|---|
| 240 |  | 
|---|
| 241 | static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan) | 
|---|
| 242 | { | 
|---|
| 243 | u64 val; | 
|---|
| 244 | int ret; | 
|---|
| 245 |  | 
|---|
| 246 | if (!pchan->cmd_complete.gas) | 
|---|
| 247 | return true; | 
|---|
| 248 |  | 
|---|
| 249 | ret = pcc_chan_reg_read(reg: &pchan->cmd_complete, val: &val); | 
|---|
| 250 | if (ret) | 
|---|
| 251 | return false; | 
|---|
| 252 |  | 
|---|
| 253 | /* | 
|---|
| 254 | * Judge if the channel respond the interrupt based on the value of | 
|---|
| 255 | * command complete. | 
|---|
| 256 | */ | 
|---|
| 257 | val &= pchan->cmd_complete.status_mask; | 
|---|
| 258 |  | 
|---|
| 259 | /* | 
|---|
| 260 | * If this is PCC slave subspace channel, and the command complete | 
|---|
| 261 | * bit 0 indicates that Platform is sending a notification and OSPM | 
|---|
| 262 | * needs to respond this interrupt to process this command. | 
|---|
| 263 | */ | 
|---|
| 264 | if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) | 
|---|
| 265 | return !val; | 
|---|
| 266 |  | 
|---|
| 267 | return !!val; | 
|---|
| 268 | } | 
|---|
| 269 |  | 
|---|
| 270 | static int pcc_mbox_error_check_and_clear(struct pcc_chan_info *pchan) | 
|---|
| 271 | { | 
|---|
| 272 | u64 val; | 
|---|
| 273 | int ret; | 
|---|
| 274 |  | 
|---|
| 275 | ret = pcc_chan_reg_read(reg: &pchan->error, val: &val); | 
|---|
| 276 | if (ret) | 
|---|
| 277 | return ret; | 
|---|
| 278 |  | 
|---|
| 279 | val &= pchan->error.status_mask; | 
|---|
| 280 | if (val) { | 
|---|
| 281 | val &= ~pchan->error.status_mask; | 
|---|
| 282 | pcc_chan_reg_write(reg: &pchan->error, val); | 
|---|
| 283 | return -EIO; | 
|---|
| 284 | } | 
|---|
| 285 |  | 
|---|
| 286 | return 0; | 
|---|
| 287 | } | 
|---|
| 288 |  | 
|---|
| 289 | static void pcc_chan_acknowledge(struct pcc_chan_info *pchan) | 
|---|
| 290 | { | 
|---|
| 291 | struct acpi_pcct_ext_pcc_shared_memory __iomem *pcc_hdr; | 
|---|
| 292 |  | 
|---|
| 293 | if (pchan->type != ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) | 
|---|
| 294 | return; | 
|---|
| 295 |  | 
|---|
| 296 | pcc_chan_reg_read_modify_write(reg: &pchan->cmd_update); | 
|---|
| 297 |  | 
|---|
| 298 | pcc_hdr = pchan->chan.shmem; | 
|---|
| 299 |  | 
|---|
| 300 | /* | 
|---|
| 301 | * The PCC slave subspace channel needs to set the command | 
|---|
| 302 | * complete bit after processing message. If the PCC_ACK_FLAG | 
|---|
| 303 | * is set, it should also ring the doorbell. | 
|---|
| 304 | */ | 
|---|
| 305 | if (ioread32(&pcc_hdr->flags) & PCC_CMD_COMPLETION_NOTIFY) | 
|---|
| 306 | pcc_chan_reg_read_modify_write(reg: &pchan->db); | 
|---|
| 307 | } | 
|---|
| 308 |  | 
|---|
| 309 | static void *write_response(struct pcc_chan_info *pchan) | 
|---|
| 310 | { | 
|---|
| 311 | struct pcc_header ; | 
|---|
| 312 | void *buffer; | 
|---|
| 313 | int data_len; | 
|---|
| 314 |  | 
|---|
| 315 | memcpy_fromio(&pcc_header, pchan->chan.shmem, | 
|---|
| 316 | sizeof(pcc_header)); | 
|---|
| 317 | data_len = pcc_header.length - sizeof(u32) + sizeof(struct pcc_header); | 
|---|
| 318 |  | 
|---|
| 319 | buffer = pchan->chan.rx_alloc(pchan->chan.mchan->cl, data_len); | 
|---|
| 320 | if (buffer != NULL) | 
|---|
| 321 | memcpy_fromio(buffer, pchan->chan.shmem, data_len); | 
|---|
| 322 | return buffer; | 
|---|
| 323 | } | 
|---|
| 324 |  | 
|---|
| 325 | /** | 
|---|
| 326 | * pcc_mbox_irq - PCC mailbox interrupt handler | 
|---|
| 327 | * @irq:	interrupt number | 
|---|
| 328 | * @p: data/cookie passed from the caller to identify the channel | 
|---|
| 329 | * | 
|---|
| 330 | * Returns: IRQ_HANDLED if interrupt is handled or IRQ_NONE if not | 
|---|
| 331 | */ | 
|---|
| 332 | static irqreturn_t pcc_mbox_irq(int irq, void *p) | 
|---|
| 333 | { | 
|---|
| 334 | struct pcc_chan_info *pchan; | 
|---|
| 335 | struct mbox_chan *chan = p; | 
|---|
| 336 | struct pcc_header * = chan->active_req; | 
|---|
| 337 | void *handle = NULL; | 
|---|
| 338 |  | 
|---|
| 339 | pchan = chan->con_priv; | 
|---|
| 340 |  | 
|---|
| 341 | if (pcc_chan_reg_read_modify_write(reg: &pchan->plat_irq_ack)) | 
|---|
| 342 | return IRQ_NONE; | 
|---|
| 343 |  | 
|---|
| 344 | if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE && | 
|---|
| 345 | !pchan->chan_in_use) | 
|---|
| 346 | return IRQ_NONE; | 
|---|
| 347 |  | 
|---|
| 348 | if (!pcc_mbox_cmd_complete_check(pchan)) | 
|---|
| 349 | return IRQ_NONE; | 
|---|
| 350 |  | 
|---|
| 351 | if (pcc_mbox_error_check_and_clear(pchan)) | 
|---|
| 352 | return IRQ_NONE; | 
|---|
| 353 |  | 
|---|
| 354 | /* | 
|---|
| 355 | * Clear this flag after updating interrupt ack register and just | 
|---|
| 356 | * before mbox_chan_received_data() which might call pcc_send_data() | 
|---|
| 357 | * where the flag is set again to start new transfer. This is | 
|---|
| 358 | * required to avoid any possible race in updatation of this flag. | 
|---|
| 359 | */ | 
|---|
| 360 | pchan->chan_in_use = false; | 
|---|
| 361 |  | 
|---|
| 362 | if (pchan->chan.rx_alloc) | 
|---|
| 363 | handle = write_response(pchan); | 
|---|
| 364 |  | 
|---|
| 365 | if (chan->active_req) { | 
|---|
| 366 | pcc_header = chan->active_req; | 
|---|
| 367 | if (pcc_header->flags & PCC_CMD_COMPLETION_NOTIFY) | 
|---|
| 368 | mbox_chan_txdone(chan, r: 0); | 
|---|
| 369 | } | 
|---|
| 370 |  | 
|---|
| 371 | mbox_chan_received_data(chan, data: handle); | 
|---|
| 372 |  | 
|---|
| 373 | pcc_chan_acknowledge(pchan); | 
|---|
| 374 |  | 
|---|
| 375 | return IRQ_HANDLED; | 
|---|
| 376 | } | 
|---|
| 377 |  | 
|---|
| 378 | /** | 
|---|
| 379 | * pcc_mbox_request_channel - PCC clients call this function to | 
|---|
| 380 | *		request a pointer to their PCC subspace, from which they | 
|---|
| 381 | *		can get the details of communicating with the remote. | 
|---|
| 382 | * @cl: Pointer to Mailbox client, so we know where to bind the | 
|---|
| 383 | *		Channel. | 
|---|
| 384 | * @subspace_id: The PCC Subspace index as parsed in the PCC client | 
|---|
| 385 | *		ACPI package. This is used to lookup the array of PCC | 
|---|
| 386 | *		subspaces as parsed by the PCC Mailbox controller. | 
|---|
| 387 | * | 
|---|
| 388 | * Return: Pointer to the PCC Mailbox Channel if successful or ERR_PTR. | 
|---|
| 389 | */ | 
|---|
| 390 | struct pcc_mbox_chan * | 
|---|
| 391 | pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) | 
|---|
| 392 | { | 
|---|
| 393 | struct pcc_mbox_chan *pcc_mchan; | 
|---|
| 394 | struct pcc_chan_info *pchan; | 
|---|
| 395 | struct mbox_chan *chan; | 
|---|
| 396 | int rc; | 
|---|
| 397 |  | 
|---|
| 398 | if (subspace_id < 0 || subspace_id >= pcc_chan_count) | 
|---|
| 399 | return ERR_PTR(error: -ENOENT); | 
|---|
| 400 |  | 
|---|
| 401 | pchan = chan_info + subspace_id; | 
|---|
| 402 | chan = pchan->chan.mchan; | 
|---|
| 403 | if (IS_ERR(ptr: chan) || chan->cl) { | 
|---|
| 404 | pr_err( "Channel not found for idx: %d\n", subspace_id); | 
|---|
| 405 | return ERR_PTR(error: -EBUSY); | 
|---|
| 406 | } | 
|---|
| 407 |  | 
|---|
| 408 | rc = mbox_bind_client(chan, cl); | 
|---|
| 409 | if (rc) | 
|---|
| 410 | return ERR_PTR(error: rc); | 
|---|
| 411 |  | 
|---|
| 412 | pcc_mchan = &pchan->chan; | 
|---|
| 413 | pcc_mchan->shmem = acpi_os_ioremap(phys: pcc_mchan->shmem_base_addr, | 
|---|
| 414 | size: pcc_mchan->shmem_size); | 
|---|
| 415 | if (!pcc_mchan->shmem) | 
|---|
| 416 | goto err; | 
|---|
| 417 |  | 
|---|
| 418 | pcc_mchan->manage_writes = false; | 
|---|
| 419 |  | 
|---|
| 420 | /* This indicates that the channel is ready to accept messages. | 
|---|
| 421 | * This needs to happen after the channel has registered | 
|---|
| 422 | * its callback. There is no access point to do that in | 
|---|
| 423 | * the mailbox API. That implies that the mailbox client must | 
|---|
| 424 | * have set the allocate callback function prior to | 
|---|
| 425 | * sending any messages. | 
|---|
| 426 | */ | 
|---|
| 427 | if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) | 
|---|
| 428 | pcc_chan_reg_read_modify_write(reg: &pchan->cmd_update); | 
|---|
| 429 |  | 
|---|
| 430 | return pcc_mchan; | 
|---|
| 431 |  | 
|---|
| 432 | err: | 
|---|
| 433 | mbox_free_channel(chan); | 
|---|
| 434 | return ERR_PTR(error: -ENXIO); | 
|---|
| 435 | } | 
|---|
| 436 | EXPORT_SYMBOL_GPL(pcc_mbox_request_channel); | 
|---|
| 437 |  | 
|---|
| 438 | /** | 
|---|
| 439 | * pcc_mbox_free_channel - Clients call this to free their Channel. | 
|---|
| 440 | * | 
|---|
| 441 | * @pchan: Pointer to the PCC mailbox channel as returned by | 
|---|
| 442 | *	   pcc_mbox_request_channel() | 
|---|
| 443 | */ | 
|---|
| 444 | void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan) | 
|---|
| 445 | { | 
|---|
| 446 | struct mbox_chan *chan = pchan->mchan; | 
|---|
| 447 | struct pcc_chan_info *pchan_info; | 
|---|
| 448 | struct pcc_mbox_chan *pcc_mbox_chan; | 
|---|
| 449 |  | 
|---|
| 450 | if (!chan || !chan->cl) | 
|---|
| 451 | return; | 
|---|
| 452 | pchan_info = chan->con_priv; | 
|---|
| 453 | pcc_mbox_chan = &pchan_info->chan; | 
|---|
| 454 | if (pcc_mbox_chan->shmem) { | 
|---|
| 455 | iounmap(addr: pcc_mbox_chan->shmem); | 
|---|
| 456 | pcc_mbox_chan->shmem = NULL; | 
|---|
| 457 | } | 
|---|
| 458 |  | 
|---|
| 459 | mbox_free_channel(chan); | 
|---|
| 460 | } | 
|---|
| 461 | EXPORT_SYMBOL_GPL(pcc_mbox_free_channel); | 
|---|
| 462 |  | 
|---|
| 463 | static int pcc_write_to_buffer(struct mbox_chan *chan, void *data) | 
|---|
| 464 | { | 
|---|
| 465 | struct pcc_chan_info *pchan = chan->con_priv; | 
|---|
| 466 | struct pcc_mbox_chan *pcc_mbox_chan = &pchan->chan; | 
|---|
| 467 | struct pcc_header * = data; | 
|---|
| 468 |  | 
|---|
| 469 | if (!pchan->chan.manage_writes) | 
|---|
| 470 | return 0; | 
|---|
| 471 |  | 
|---|
| 472 | /* The PCC header length includes the command field | 
|---|
| 473 | * but not the other values from the header. | 
|---|
| 474 | */ | 
|---|
| 475 | int len = pcc_header->length - sizeof(u32) + sizeof(struct pcc_header); | 
|---|
| 476 | u64 val; | 
|---|
| 477 |  | 
|---|
| 478 | pcc_chan_reg_read(reg: &pchan->cmd_complete, val: &val); | 
|---|
| 479 | if (!val) { | 
|---|
| 480 | pr_info( "%s pchan->cmd_complete not set", __func__); | 
|---|
| 481 | return -1; | 
|---|
| 482 | } | 
|---|
| 483 | memcpy_toio(pcc_mbox_chan->shmem,  data, len); | 
|---|
| 484 | return 0; | 
|---|
| 485 | } | 
|---|
| 486 |  | 
|---|
| 487 |  | 
|---|
| 488 | /** | 
|---|
| 489 | * pcc_send_data - Called from Mailbox Controller code. If | 
|---|
| 490 | *		pchan->chan.rx_alloc is set, then the command complete | 
|---|
| 491 | *		flag is checked and the data is written to the shared | 
|---|
| 492 | *		buffer io memory. | 
|---|
| 493 | * | 
|---|
| 494 | *		If pchan->chan.rx_alloc is not set, then it is used | 
|---|
| 495 | *		here only to ring the channel doorbell. The PCC client | 
|---|
| 496 | *		specific read/write is done in the client driver in | 
|---|
| 497 | *		order to maintain atomicity over PCC channel once | 
|---|
| 498 | *		OS has control over it. See above for flow of operations. | 
|---|
| 499 | * @chan: Pointer to Mailbox channel over which to send data. | 
|---|
| 500 | * @data: Client specific data written over channel. Used here | 
|---|
| 501 | *		only for debug after PCC transaction completes. | 
|---|
| 502 | * | 
|---|
| 503 | * Return: Err if something failed else 0 for success. | 
|---|
| 504 | */ | 
|---|
| 505 | static int pcc_send_data(struct mbox_chan *chan, void *data) | 
|---|
| 506 | { | 
|---|
| 507 | int ret; | 
|---|
| 508 | struct pcc_chan_info *pchan = chan->con_priv; | 
|---|
| 509 |  | 
|---|
| 510 | ret = pcc_write_to_buffer(chan, data); | 
|---|
| 511 | if (ret) | 
|---|
| 512 | return ret; | 
|---|
| 513 |  | 
|---|
| 514 | ret = pcc_chan_reg_read_modify_write(reg: &pchan->cmd_update); | 
|---|
| 515 | if (ret) | 
|---|
| 516 | return ret; | 
|---|
| 517 |  | 
|---|
| 518 | ret = pcc_chan_reg_read_modify_write(reg: &pchan->db); | 
|---|
| 519 |  | 
|---|
| 520 | if (!ret && pchan->plat_irq > 0) | 
|---|
| 521 | pchan->chan_in_use = true; | 
|---|
| 522 |  | 
|---|
| 523 | return ret; | 
|---|
| 524 | } | 
|---|
| 525 |  | 
|---|
| 526 |  | 
|---|
| 527 | static bool pcc_last_tx_done(struct mbox_chan *chan) | 
|---|
| 528 | { | 
|---|
| 529 | struct pcc_chan_info *pchan = chan->con_priv; | 
|---|
| 530 | u64 val; | 
|---|
| 531 |  | 
|---|
| 532 | pcc_chan_reg_read(reg: &pchan->cmd_complete, val: &val); | 
|---|
| 533 | if (!val) | 
|---|
| 534 | return false; | 
|---|
| 535 | else | 
|---|
| 536 | return true; | 
|---|
| 537 | } | 
|---|
| 538 |  | 
|---|
| 539 |  | 
|---|
| 540 |  | 
|---|
| 541 | /** | 
|---|
| 542 | * pcc_startup - Called from Mailbox Controller code. Used here | 
|---|
| 543 | *		to request the interrupt. | 
|---|
| 544 | * @chan: Pointer to Mailbox channel to startup. | 
|---|
| 545 | * | 
|---|
| 546 | * Return: Err if something failed else 0 for success. | 
|---|
| 547 | */ | 
|---|
| 548 | static int pcc_startup(struct mbox_chan *chan) | 
|---|
| 549 | { | 
|---|
| 550 | struct pcc_chan_info *pchan = chan->con_priv; | 
|---|
| 551 | unsigned long irqflags; | 
|---|
| 552 | int rc; | 
|---|
| 553 |  | 
|---|
| 554 | if (pchan->plat_irq > 0) { | 
|---|
| 555 | irqflags = pcc_chan_plat_irq_can_be_shared(pchan) ? | 
|---|
| 556 | IRQF_SHARED | IRQF_ONESHOT : 0; | 
|---|
| 557 | rc = devm_request_irq(dev: chan->mbox->dev, irq: pchan->plat_irq, handler: pcc_mbox_irq, | 
|---|
| 558 | irqflags, MBOX_IRQ_NAME, dev_id: chan); | 
|---|
| 559 | if (unlikely(rc)) { | 
|---|
| 560 | dev_err(chan->mbox->dev, "failed to register PCC interrupt %d\n", | 
|---|
| 561 | pchan->plat_irq); | 
|---|
| 562 | return rc; | 
|---|
| 563 | } | 
|---|
| 564 | } | 
|---|
| 565 |  | 
|---|
| 566 | return 0; | 
|---|
| 567 | } | 
|---|
| 568 |  | 
|---|
| 569 | /** | 
|---|
| 570 | * pcc_shutdown - Called from Mailbox Controller code. Used here | 
|---|
| 571 | *		to free the interrupt. | 
|---|
| 572 | * @chan: Pointer to Mailbox channel to shutdown. | 
|---|
| 573 | */ | 
|---|
| 574 | static void pcc_shutdown(struct mbox_chan *chan) | 
|---|
| 575 | { | 
|---|
| 576 | struct pcc_chan_info *pchan = chan->con_priv; | 
|---|
| 577 |  | 
|---|
| 578 | if (pchan->plat_irq > 0) | 
|---|
| 579 | devm_free_irq(dev: chan->mbox->dev, irq: pchan->plat_irq, dev_id: chan); | 
|---|
| 580 | } | 
|---|
| 581 |  | 
|---|
| 582 | static const struct mbox_chan_ops pcc_chan_ops = { | 
|---|
| 583 | .send_data = pcc_send_data, | 
|---|
| 584 | .startup = pcc_startup, | 
|---|
| 585 | .shutdown = pcc_shutdown, | 
|---|
| 586 | .last_tx_done = pcc_last_tx_done, | 
|---|
| 587 | }; | 
|---|
| 588 |  | 
|---|
| 589 | /** | 
|---|
| 590 | * parse_pcc_subspace - Count PCC subspaces defined | 
|---|
| 591 | * @header: Pointer to the ACPI subtable header under the PCCT. | 
|---|
| 592 | * @end: End of subtable entry. | 
|---|
| 593 | * | 
|---|
| 594 | * Return: If we find a PCC subspace entry of a valid type, return 0. | 
|---|
| 595 | *	Otherwise, return -EINVAL. | 
|---|
| 596 | * | 
|---|
| 597 | * This gets called for each entry in the PCC table. | 
|---|
| 598 | */ | 
|---|
| 599 | static int parse_pcc_subspace(union acpi_subtable_headers *, | 
|---|
| 600 | const unsigned long end) | 
|---|
| 601 | { | 
|---|
| 602 | struct acpi_pcct_subspace *ss = (struct acpi_pcct_subspace *) header; | 
|---|
| 603 |  | 
|---|
| 604 | if (ss->header.type < ACPI_PCCT_TYPE_RESERVED) | 
|---|
| 605 | return 0; | 
|---|
| 606 |  | 
|---|
| 607 | return -EINVAL; | 
|---|
| 608 | } | 
|---|
| 609 |  | 
|---|
| 610 | static int | 
|---|
| 611 | pcc_chan_reg_init(struct pcc_chan_reg *reg, struct acpi_generic_address *gas, | 
|---|
| 612 | u64 preserve_mask, u64 set_mask, u64 status_mask, char *name) | 
|---|
| 613 | { | 
|---|
| 614 | if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { | 
|---|
| 615 | if (!(gas->bit_width >= 8 && gas->bit_width <= 64 && | 
|---|
| 616 | is_power_of_2(n: gas->bit_width))) { | 
|---|
| 617 | pr_err( "Error: Cannot access register of %u bit width", | 
|---|
| 618 | gas->bit_width); | 
|---|
| 619 | return -EFAULT; | 
|---|
| 620 | } | 
|---|
| 621 |  | 
|---|
| 622 | reg->vaddr = acpi_os_ioremap(phys: gas->address, size: gas->bit_width / 8); | 
|---|
| 623 | if (!reg->vaddr) { | 
|---|
| 624 | pr_err( "Failed to ioremap PCC %s register\n", name); | 
|---|
| 625 | return -ENOMEM; | 
|---|
| 626 | } | 
|---|
| 627 | } | 
|---|
| 628 | reg->gas = gas; | 
|---|
| 629 | reg->preserve_mask = preserve_mask; | 
|---|
| 630 | reg->set_mask = set_mask; | 
|---|
| 631 | reg->status_mask = status_mask; | 
|---|
| 632 | return 0; | 
|---|
| 633 | } | 
|---|
| 634 |  | 
|---|
| 635 | /** | 
|---|
| 636 | * pcc_parse_subspace_irq - Parse the PCC IRQ and PCC ACK register | 
|---|
| 637 | * | 
|---|
| 638 | * @pchan: Pointer to the PCC channel info structure. | 
|---|
| 639 | * @pcct_entry: Pointer to the ACPI subtable header. | 
|---|
| 640 | * | 
|---|
| 641 | * Return: 0 for Success, else errno. | 
|---|
| 642 | * | 
|---|
| 643 | * There should be one entry per PCC channel. This gets called for each | 
|---|
| 644 | * entry in the PCC table. This uses PCCY Type1 structure for all applicable | 
|---|
| 645 | * types(Type 1-4) to fetch irq | 
|---|
| 646 | */ | 
|---|
| 647 | static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan, | 
|---|
| 648 | struct acpi_subtable_header *pcct_entry) | 
|---|
| 649 | { | 
|---|
| 650 | int ret = 0; | 
|---|
| 651 | struct acpi_pcct_hw_reduced *pcct_ss; | 
|---|
| 652 |  | 
|---|
| 653 | if (pcct_entry->type < ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE || | 
|---|
| 654 | pcct_entry->type > ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) | 
|---|
| 655 | return 0; | 
|---|
| 656 |  | 
|---|
| 657 | pcct_ss = (struct acpi_pcct_hw_reduced *)pcct_entry; | 
|---|
| 658 | pchan->plat_irq = pcc_map_interrupt(interrupt: pcct_ss->platform_interrupt, | 
|---|
| 659 | flags: (u32)pcct_ss->flags); | 
|---|
| 660 | if (pchan->plat_irq <= 0) { | 
|---|
| 661 | pr_err( "PCC GSI %d not registered\n", | 
|---|
| 662 | pcct_ss->platform_interrupt); | 
|---|
| 663 | return -EINVAL; | 
|---|
| 664 | } | 
|---|
| 665 | pchan->plat_irq_flags = pcct_ss->flags; | 
|---|
| 666 |  | 
|---|
| 667 | if (pcct_ss->header.type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) { | 
|---|
| 668 | struct acpi_pcct_hw_reduced_type2 *pcct2_ss = (void *)pcct_ss; | 
|---|
| 669 |  | 
|---|
| 670 | ret = pcc_chan_reg_init(reg: &pchan->plat_irq_ack, | 
|---|
| 671 | gas: &pcct2_ss->platform_ack_register, | 
|---|
| 672 | preserve_mask: pcct2_ss->ack_preserve_mask, | 
|---|
| 673 | set_mask: pcct2_ss->ack_write_mask, status_mask: 0, | 
|---|
| 674 | name: "PLAT IRQ ACK"); | 
|---|
| 675 |  | 
|---|
| 676 | } else if (pcct_ss->header.type == ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE || | 
|---|
| 677 | pcct_ss->header.type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) { | 
|---|
| 678 | struct acpi_pcct_ext_pcc_master *pcct_ext = (void *)pcct_ss; | 
|---|
| 679 |  | 
|---|
| 680 | ret = pcc_chan_reg_init(reg: &pchan->plat_irq_ack, | 
|---|
| 681 | gas: &pcct_ext->platform_ack_register, | 
|---|
| 682 | preserve_mask: pcct_ext->ack_preserve_mask, | 
|---|
| 683 | set_mask: pcct_ext->ack_set_mask, status_mask: 0, | 
|---|
| 684 | name: "PLAT IRQ ACK"); | 
|---|
| 685 | } | 
|---|
| 686 |  | 
|---|
| 687 | if (pcc_chan_plat_irq_can_be_shared(pchan) && | 
|---|
| 688 | !pchan->plat_irq_ack.gas) { | 
|---|
| 689 | pr_err( "PCC subspace has level IRQ with no ACK register\n"); | 
|---|
| 690 | return -EINVAL; | 
|---|
| 691 | } | 
|---|
| 692 |  | 
|---|
| 693 | return ret; | 
|---|
| 694 | } | 
|---|
| 695 |  | 
|---|
| 696 | /** | 
|---|
| 697 | * pcc_parse_subspace_db_reg - Parse the PCC doorbell register | 
|---|
| 698 | * | 
|---|
| 699 | * @pchan: Pointer to the PCC channel info structure. | 
|---|
| 700 | * @pcct_entry: Pointer to the ACPI subtable header. | 
|---|
| 701 | * | 
|---|
| 702 | * Return: 0 for Success, else errno. | 
|---|
| 703 | */ | 
|---|
| 704 | static int pcc_parse_subspace_db_reg(struct pcc_chan_info *pchan, | 
|---|
| 705 | struct acpi_subtable_header *pcct_entry) | 
|---|
| 706 | { | 
|---|
| 707 | int ret = 0; | 
|---|
| 708 |  | 
|---|
| 709 | if (pcct_entry->type <= ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) { | 
|---|
| 710 | struct acpi_pcct_subspace *pcct_ss; | 
|---|
| 711 |  | 
|---|
| 712 | pcct_ss = (struct acpi_pcct_subspace *)pcct_entry; | 
|---|
| 713 |  | 
|---|
| 714 | ret = pcc_chan_reg_init(reg: &pchan->db, | 
|---|
| 715 | gas: &pcct_ss->doorbell_register, | 
|---|
| 716 | preserve_mask: pcct_ss->preserve_mask, | 
|---|
| 717 | set_mask: pcct_ss->write_mask, status_mask: 0,	name: "Doorbell"); | 
|---|
| 718 |  | 
|---|
| 719 | } else { | 
|---|
| 720 | struct acpi_pcct_ext_pcc_master *pcct_ext; | 
|---|
| 721 |  | 
|---|
| 722 | pcct_ext = (struct acpi_pcct_ext_pcc_master *)pcct_entry; | 
|---|
| 723 |  | 
|---|
| 724 | ret = pcc_chan_reg_init(reg: &pchan->db, | 
|---|
| 725 | gas: &pcct_ext->doorbell_register, | 
|---|
| 726 | preserve_mask: pcct_ext->preserve_mask, | 
|---|
| 727 | set_mask: pcct_ext->write_mask, status_mask: 0, name: "Doorbell"); | 
|---|
| 728 | if (ret) | 
|---|
| 729 | return ret; | 
|---|
| 730 |  | 
|---|
| 731 | ret = pcc_chan_reg_init(reg: &pchan->cmd_complete, | 
|---|
| 732 | gas: &pcct_ext->cmd_complete_register, | 
|---|
| 733 | preserve_mask: 0, set_mask: 0, status_mask: pcct_ext->cmd_complete_mask, | 
|---|
| 734 | name: "Command Complete Check"); | 
|---|
| 735 | if (ret) | 
|---|
| 736 | return ret; | 
|---|
| 737 |  | 
|---|
| 738 | ret = pcc_chan_reg_init(reg: &pchan->cmd_update, | 
|---|
| 739 | gas: &pcct_ext->cmd_update_register, | 
|---|
| 740 | preserve_mask: pcct_ext->cmd_update_preserve_mask, | 
|---|
| 741 | set_mask: pcct_ext->cmd_update_set_mask, status_mask: 0, | 
|---|
| 742 | name: "Command Complete Update"); | 
|---|
| 743 | if (ret) | 
|---|
| 744 | return ret; | 
|---|
| 745 |  | 
|---|
| 746 | ret = pcc_chan_reg_init(reg: &pchan->error, | 
|---|
| 747 | gas: &pcct_ext->error_status_register, | 
|---|
| 748 | preserve_mask: 0, set_mask: 0, status_mask: pcct_ext->error_status_mask, | 
|---|
| 749 | name: "Error Status"); | 
|---|
| 750 | } | 
|---|
| 751 | return ret; | 
|---|
| 752 | } | 
|---|
| 753 |  | 
|---|
| 754 | /** | 
|---|
| 755 | * pcc_parse_subspace_shmem - Parse the PCC Shared Memory Region information | 
|---|
| 756 | * | 
|---|
| 757 | * @pchan: Pointer to the PCC channel info structure. | 
|---|
| 758 | * @pcct_entry: Pointer to the ACPI subtable header. | 
|---|
| 759 | * | 
|---|
| 760 | */ | 
|---|
| 761 | static void pcc_parse_subspace_shmem(struct pcc_chan_info *pchan, | 
|---|
| 762 | struct acpi_subtable_header *pcct_entry) | 
|---|
| 763 | { | 
|---|
| 764 | if (pcct_entry->type <= ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) { | 
|---|
| 765 | struct acpi_pcct_subspace *pcct_ss = | 
|---|
| 766 | (struct acpi_pcct_subspace *)pcct_entry; | 
|---|
| 767 |  | 
|---|
| 768 | pchan->chan.shmem_base_addr = pcct_ss->base_address; | 
|---|
| 769 | pchan->chan.shmem_size = pcct_ss->length; | 
|---|
| 770 | pchan->chan.latency = pcct_ss->latency; | 
|---|
| 771 | pchan->chan.max_access_rate = pcct_ss->max_access_rate; | 
|---|
| 772 | pchan->chan.min_turnaround_time = pcct_ss->min_turnaround_time; | 
|---|
| 773 | } else { | 
|---|
| 774 | struct acpi_pcct_ext_pcc_master *pcct_ext = | 
|---|
| 775 | (struct acpi_pcct_ext_pcc_master *)pcct_entry; | 
|---|
| 776 |  | 
|---|
| 777 | pchan->chan.shmem_base_addr = pcct_ext->base_address; | 
|---|
| 778 | pchan->chan.shmem_size = pcct_ext->length; | 
|---|
| 779 | pchan->chan.latency = pcct_ext->latency; | 
|---|
| 780 | pchan->chan.max_access_rate = pcct_ext->max_access_rate; | 
|---|
| 781 | pchan->chan.min_turnaround_time = pcct_ext->min_turnaround_time; | 
|---|
| 782 | } | 
|---|
| 783 | } | 
|---|
| 784 |  | 
|---|
| 785 | /** | 
|---|
| 786 | * acpi_pcc_probe - Parse the ACPI tree for the PCCT. | 
|---|
| 787 | * | 
|---|
| 788 | * Return: 0 for Success, else errno. | 
|---|
| 789 | */ | 
|---|
| 790 | static int __init acpi_pcc_probe(void) | 
|---|
| 791 | { | 
|---|
| 792 | int count, i, rc = 0; | 
|---|
| 793 | acpi_status status; | 
|---|
| 794 | struct acpi_table_header *pcct_tbl; | 
|---|
| 795 | struct acpi_subtable_proc proc[ACPI_PCCT_TYPE_RESERVED]; | 
|---|
| 796 |  | 
|---|
| 797 | status = acpi_get_table(ACPI_SIG_PCCT, instance: 0, out_table: &pcct_tbl); | 
|---|
| 798 | if (ACPI_FAILURE(status) || !pcct_tbl) | 
|---|
| 799 | return -ENODEV; | 
|---|
| 800 |  | 
|---|
| 801 | /* Set up the subtable handlers */ | 
|---|
| 802 | for (i = ACPI_PCCT_TYPE_GENERIC_SUBSPACE; | 
|---|
| 803 | i < ACPI_PCCT_TYPE_RESERVED; i++) { | 
|---|
| 804 | proc[i].id = i; | 
|---|
| 805 | proc[i].count = 0; | 
|---|
| 806 | proc[i].handler = parse_pcc_subspace; | 
|---|
| 807 | } | 
|---|
| 808 |  | 
|---|
| 809 | count = acpi_table_parse_entries_array(ACPI_SIG_PCCT, | 
|---|
| 810 | table_size: sizeof(struct acpi_table_pcct), proc, | 
|---|
| 811 | proc_num: ACPI_PCCT_TYPE_RESERVED, MAX_PCC_SUBSPACES); | 
|---|
| 812 | if (count <= 0 || count > MAX_PCC_SUBSPACES) { | 
|---|
| 813 | if (count < 0) | 
|---|
| 814 | pr_warn( "Error parsing PCC subspaces from PCCT\n"); | 
|---|
| 815 | else | 
|---|
| 816 | pr_warn( "Invalid PCCT: %d PCC subspaces\n", count); | 
|---|
| 817 |  | 
|---|
| 818 | rc = -EINVAL; | 
|---|
| 819 | } else { | 
|---|
| 820 | pcc_chan_count = count; | 
|---|
| 821 | } | 
|---|
| 822 |  | 
|---|
| 823 | acpi_put_table(table: pcct_tbl); | 
|---|
| 824 |  | 
|---|
| 825 | return rc; | 
|---|
| 826 | } | 
|---|
| 827 |  | 
|---|
| 828 | /** | 
|---|
| 829 | * pcc_mbox_probe - Called when we find a match for the | 
|---|
| 830 | *	PCCT platform device. This is purely used to represent | 
|---|
| 831 | *	the PCCT as a virtual device for registering with the | 
|---|
| 832 | *	generic Mailbox framework. | 
|---|
| 833 | * | 
|---|
| 834 | * @pdev: Pointer to platform device returned when a match | 
|---|
| 835 | *	is found. | 
|---|
| 836 | * | 
|---|
| 837 | *	Return: 0 for Success, else errno. | 
|---|
| 838 | */ | 
|---|
| 839 | static int pcc_mbox_probe(struct platform_device *pdev) | 
|---|
| 840 | { | 
|---|
| 841 | struct device *dev = &pdev->dev; | 
|---|
| 842 | struct mbox_controller *pcc_mbox_ctrl; | 
|---|
| 843 | struct mbox_chan *pcc_mbox_channels; | 
|---|
| 844 | struct acpi_table_header *pcct_tbl; | 
|---|
| 845 | struct acpi_subtable_header *pcct_entry; | 
|---|
| 846 | struct acpi_table_pcct *acpi_pcct_tbl; | 
|---|
| 847 | acpi_status status = AE_OK; | 
|---|
| 848 | int i, rc, count = pcc_chan_count; | 
|---|
| 849 |  | 
|---|
| 850 | /* Search for PCCT */ | 
|---|
| 851 | status = acpi_get_table(ACPI_SIG_PCCT, instance: 0, out_table: &pcct_tbl); | 
|---|
| 852 |  | 
|---|
| 853 | if (ACPI_FAILURE(status) || !pcct_tbl) | 
|---|
| 854 | return -ENODEV; | 
|---|
| 855 |  | 
|---|
| 856 | pcc_mbox_channels = devm_kcalloc(dev, n: count, size: sizeof(*pcc_mbox_channels), | 
|---|
| 857 | GFP_KERNEL); | 
|---|
| 858 | if (!pcc_mbox_channels) { | 
|---|
| 859 | rc = -ENOMEM; | 
|---|
| 860 | goto err; | 
|---|
| 861 | } | 
|---|
| 862 |  | 
|---|
| 863 | chan_info = devm_kcalloc(dev, n: count, size: sizeof(*chan_info), GFP_KERNEL); | 
|---|
| 864 | if (!chan_info) { | 
|---|
| 865 | rc = -ENOMEM; | 
|---|
| 866 | goto err; | 
|---|
| 867 | } | 
|---|
| 868 |  | 
|---|
| 869 | pcc_mbox_ctrl = devm_kzalloc(dev, size: sizeof(*pcc_mbox_ctrl), GFP_KERNEL); | 
|---|
| 870 | if (!pcc_mbox_ctrl) { | 
|---|
| 871 | rc = -ENOMEM; | 
|---|
| 872 | goto err; | 
|---|
| 873 | } | 
|---|
| 874 |  | 
|---|
| 875 | /* Point to the first PCC subspace entry */ | 
|---|
| 876 | pcct_entry = (struct acpi_subtable_header *) ( | 
|---|
| 877 | (unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct)); | 
|---|
| 878 |  | 
|---|
| 879 | acpi_pcct_tbl = (struct acpi_table_pcct *) pcct_tbl; | 
|---|
| 880 | if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL) | 
|---|
| 881 | pcc_mbox_ctrl->txdone_irq = true; | 
|---|
| 882 |  | 
|---|
| 883 | for (i = 0; i < count; i++) { | 
|---|
| 884 | struct pcc_chan_info *pchan = chan_info + i; | 
|---|
| 885 |  | 
|---|
| 886 | pcc_mbox_channels[i].con_priv = pchan; | 
|---|
| 887 | pchan->chan.mchan = &pcc_mbox_channels[i]; | 
|---|
| 888 |  | 
|---|
| 889 | if (pcct_entry->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE && | 
|---|
| 890 | !pcc_mbox_ctrl->txdone_irq) { | 
|---|
| 891 | pr_err( "Platform Interrupt flag must be set to 1"); | 
|---|
| 892 | rc = -EINVAL; | 
|---|
| 893 | goto err; | 
|---|
| 894 | } | 
|---|
| 895 |  | 
|---|
| 896 | if (pcc_mbox_ctrl->txdone_irq) { | 
|---|
| 897 | rc = pcc_parse_subspace_irq(pchan, pcct_entry); | 
|---|
| 898 | if (rc < 0) | 
|---|
| 899 | goto err; | 
|---|
| 900 | } | 
|---|
| 901 | rc = pcc_parse_subspace_db_reg(pchan, pcct_entry); | 
|---|
| 902 | if (rc < 0) | 
|---|
| 903 | goto err; | 
|---|
| 904 |  | 
|---|
| 905 | pcc_parse_subspace_shmem(pchan, pcct_entry); | 
|---|
| 906 |  | 
|---|
| 907 | pchan->type = pcct_entry->type; | 
|---|
| 908 | pcct_entry = (struct acpi_subtable_header *) | 
|---|
| 909 | ((unsigned long) pcct_entry + pcct_entry->length); | 
|---|
| 910 | } | 
|---|
| 911 |  | 
|---|
| 912 | pcc_mbox_ctrl->num_chans = count; | 
|---|
| 913 |  | 
|---|
| 914 | pr_info( "Detected %d PCC Subspaces\n", pcc_mbox_ctrl->num_chans); | 
|---|
| 915 |  | 
|---|
| 916 | pcc_mbox_ctrl->chans = pcc_mbox_channels; | 
|---|
| 917 | pcc_mbox_ctrl->ops = &pcc_chan_ops; | 
|---|
| 918 | pcc_mbox_ctrl->dev = dev; | 
|---|
| 919 |  | 
|---|
| 920 | pr_info( "Registering PCC driver as Mailbox controller\n"); | 
|---|
| 921 | rc = mbox_controller_register(mbox: pcc_mbox_ctrl); | 
|---|
| 922 | if (rc) | 
|---|
| 923 | pr_err( "Err registering PCC as Mailbox controller: %d\n", rc); | 
|---|
| 924 | else | 
|---|
| 925 | return 0; | 
|---|
| 926 | err: | 
|---|
| 927 | acpi_put_table(table: pcct_tbl); | 
|---|
| 928 | return rc; | 
|---|
| 929 | } | 
|---|
| 930 |  | 
|---|
| 931 | static struct platform_driver pcc_mbox_driver = { | 
|---|
| 932 | .probe = pcc_mbox_probe, | 
|---|
| 933 | .driver = { | 
|---|
| 934 | .name = "PCCT", | 
|---|
| 935 | }, | 
|---|
| 936 | }; | 
|---|
| 937 |  | 
|---|
| 938 | static int __init pcc_init(void) | 
|---|
| 939 | { | 
|---|
| 940 | int ret; | 
|---|
| 941 | struct platform_device *pcc_pdev; | 
|---|
| 942 |  | 
|---|
| 943 | if (acpi_disabled) | 
|---|
| 944 | return -ENODEV; | 
|---|
| 945 |  | 
|---|
| 946 | /* Check if PCC support is available. */ | 
|---|
| 947 | ret = acpi_pcc_probe(); | 
|---|
| 948 |  | 
|---|
| 949 | if (ret) { | 
|---|
| 950 | pr_debug( "ACPI PCC probe failed.\n"); | 
|---|
| 951 | return -ENODEV; | 
|---|
| 952 | } | 
|---|
| 953 |  | 
|---|
| 954 | pcc_pdev = platform_create_bundle(&pcc_mbox_driver, | 
|---|
| 955 | pcc_mbox_probe, NULL, 0, NULL, 0); | 
|---|
| 956 |  | 
|---|
| 957 | if (IS_ERR(ptr: pcc_pdev)) { | 
|---|
| 958 | pr_debug( "Err creating PCC platform bundle\n"); | 
|---|
| 959 | pcc_chan_count = 0; | 
|---|
| 960 | return PTR_ERR(ptr: pcc_pdev); | 
|---|
| 961 | } | 
|---|
| 962 |  | 
|---|
| 963 | return 0; | 
|---|
| 964 | } | 
|---|
| 965 |  | 
|---|
| 966 | /* | 
|---|
| 967 | * Make PCC init postcore so that users of this mailbox | 
|---|
| 968 | * such as the ACPI Processor driver have it available | 
|---|
| 969 | * at their init. | 
|---|
| 970 | */ | 
|---|
| 971 | postcore_initcall(pcc_init); | 
|---|
| 972 |  | 
|---|