blob: 453a58fda3a49f38b0712c4cc8a7fe898386dd1e [file] [log] [blame]
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Ashwin Chaugule86c22f82014-11-12 19:59:38 -05002/*
3 * Copyright (C) 2014 Linaro Ltd.
4 * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
5 *
Ashwin Chaugule86c22f82014-11-12 19:59:38 -05006 * 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
Ashwin Chaugule33350e62015-01-27 16:03:57 -050014 * is also specified in each PCC table entry.
Ashwin Chaugule86c22f82014-11-12 19:59:38 -050015 *
Ashwin Chaugule33350e62015-01-27 16:03:57 -050016 * 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.
Tom Saeger9d2e8b92021-03-12 19:31:10 -070035 * * If command completes, then writes have succeeded and it can release
Ashwin Chaugule33350e62015-01-27 16:03:57 -050036 * 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
Ashwin Chaugule86c22f82014-11-12 19:59:38 -050043 * 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>
hotranaca314e2016-08-15 17:14:05 -070053#include <linux/interrupt.h>
Ashwin Chaugule86c22f82014-11-12 19:59:38 -050054#include <linux/list.h>
55#include <linux/platform_device.h>
56#include <linux/mailbox_controller.h>
57#include <linux/mailbox_client.h>
Prakash, Prashanth8b0f5782016-02-17 13:21:01 -070058#include <linux/io-64-nonatomic-lo-hi.h>
Hoan Tran6ca595a2016-11-14 11:19:02 -080059#include <acpi/pcc.h>
Ashwin Chaugule86c22f82014-11-12 19:59:38 -050060
61#include "mailbox.h"
62
hotranaca314e2016-08-15 17:14:05 -070063#define MBOX_IRQ_NAME "pcc-mbox"
Ashwin Chaugule86c22f82014-11-12 19:59:38 -050064
65static struct mbox_chan *pcc_mbox_channels;
66
Sudeep Holla80b2bdd2021-09-17 14:33:46 +010067/**
68 * struct pcc_chan_info - PCC channel specific information
69 *
Sudeep Holla0f2591e2021-09-17 14:33:49 +010070 * @chan: PCC channel information with Shared Memory Region info
Sudeep Holla80b2bdd2021-09-17 14:33:46 +010071 * @db_vaddr: cached virtual address for doorbell register
72 * @db_ack_vaddr: cached virtual address for doorbell ack register
73 * @db_irq: doorbell interrupt
74 */
75struct pcc_chan_info {
Sudeep Holla0f2591e2021-09-17 14:33:49 +010076 struct pcc_mbox_chan chan;
Sudeep Holla80b2bdd2021-09-17 14:33:46 +010077 void __iomem *db_vaddr;
78 void __iomem *db_ack_vaddr;
79 int db_irq;
80};
81
Sudeep Holla7b6da7f2021-09-17 14:33:50 +010082#define to_pcc_chan_info(c) container_of(c, struct pcc_chan_info, chan)
Sudeep Holla80b2bdd2021-09-17 14:33:46 +010083static struct pcc_chan_info *chan_info;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -050084static struct mbox_controller pcc_mbox_ctrl = {};
Ashwin Chaugule86c22f82014-11-12 19:59:38 -050085
Prakash, Prashanth8b0f5782016-02-17 13:21:01 -070086/*
87 * PCC can be used with perf critical drivers such as CPPC
88 * So it makes sense to locally cache the virtual address and
89 * use it to read/write to PCC registers such as doorbell register
90 *
91 * The below read_register and write_registers are used to read and
92 * write from perf critical registers such as PCC doorbell register
93 */
94static int read_register(void __iomem *vaddr, u64 *val, unsigned int bit_width)
95{
96 int ret_val = 0;
97
98 switch (bit_width) {
99 case 8:
100 *val = readb(vaddr);
101 break;
102 case 16:
103 *val = readw(vaddr);
104 break;
105 case 32:
106 *val = readl(vaddr);
107 break;
108 case 64:
109 *val = readq(vaddr);
110 break;
111 default:
112 pr_debug("Error: Cannot read register of %u bit width",
113 bit_width);
114 ret_val = -EFAULT;
115 break;
116 }
117 return ret_val;
118}
119
120static int write_register(void __iomem *vaddr, u64 val, unsigned int bit_width)
121{
122 int ret_val = 0;
123
124 switch (bit_width) {
125 case 8:
126 writeb(val, vaddr);
127 break;
128 case 16:
129 writew(val, vaddr);
130 break;
131 case 32:
132 writel(val, vaddr);
133 break;
134 case 64:
135 writeq(val, vaddr);
136 break;
137 default:
138 pr_debug("Error: Cannot write register of %u bit width",
139 bit_width);
140 ret_val = -EFAULT;
141 break;
142 }
143 return ret_val;
144}
145
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500146/**
hotranaca314e2016-08-15 17:14:05 -0700147 * pcc_map_interrupt - Map a PCC subspace GSI to a linux IRQ number
148 * @interrupt: GSI number.
149 * @flags: interrupt flags
150 *
151 * Returns: a valid linux IRQ number on success
152 * 0 or -EINVAL on failure
153 */
154static int pcc_map_interrupt(u32 interrupt, u32 flags)
155{
156 int trigger, polarity;
157
158 if (!interrupt)
159 return 0;
160
161 trigger = (flags & ACPI_PCCT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
162 : ACPI_LEVEL_SENSITIVE;
163
164 polarity = (flags & ACPI_PCCT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
165 : ACPI_ACTIVE_HIGH;
166
167 return acpi_register_gsi(NULL, interrupt, trigger, polarity);
168}
169
170/**
171 * pcc_mbox_irq - PCC mailbox interrupt handler
Sudeep Holla10dcc2d2021-09-17 14:33:44 +0100172 * @irq: interrupt number
173 * @p: data/cookie passed from the caller to identify the channel
174 *
175 * Returns: IRQ_HANDLED if interrupt is handled or IRQ_NONE if not
hotranaca314e2016-08-15 17:14:05 -0700176 */
177static irqreturn_t pcc_mbox_irq(int irq, void *p)
178{
179 struct acpi_generic_address *doorbell_ack;
180 struct acpi_pcct_hw_reduced *pcct_ss;
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100181 struct pcc_chan_info *pchan;
hotranaca314e2016-08-15 17:14:05 -0700182 struct mbox_chan *chan = p;
183 u64 doorbell_ack_preserve;
184 u64 doorbell_ack_write;
185 u64 doorbell_ack_val;
186 int ret;
187
188 pcct_ss = chan->con_priv;
189
190 mbox_chan_received_data(chan, NULL);
191
192 if (pcct_ss->header.type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) {
193 struct acpi_pcct_hw_reduced_type2 *pcct2_ss = chan->con_priv;
194 u32 id = chan - pcc_mbox_channels;
195
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100196 pchan = chan_info + id;
David E. Boxc7a1dfb2017-06-05 16:39:08 +0800197 doorbell_ack = &pcct2_ss->platform_ack_register;
hotranaca314e2016-08-15 17:14:05 -0700198 doorbell_ack_preserve = pcct2_ss->ack_preserve_mask;
199 doorbell_ack_write = pcct2_ss->ack_write_mask;
200
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100201 ret = read_register(pchan->db_ack_vaddr,
202 &doorbell_ack_val, doorbell_ack->bit_width);
hotranaca314e2016-08-15 17:14:05 -0700203 if (ret)
204 return IRQ_NONE;
205
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100206 ret = write_register(pchan->db_ack_vaddr,
hotranaca314e2016-08-15 17:14:05 -0700207 (doorbell_ack_val & doorbell_ack_preserve)
208 | doorbell_ack_write,
209 doorbell_ack->bit_width);
210 if (ret)
211 return IRQ_NONE;
212 }
213
214 return IRQ_HANDLED;
215}
216
217/**
218 * pcc_mbox_request_channel - PCC clients call this function to
219 * request a pointer to their PCC subspace, from which they
220 * can get the details of communicating with the remote.
221 * @cl: Pointer to Mailbox client, so we know where to bind the
222 * Channel.
223 * @subspace_id: The PCC Subspace index as parsed in the PCC client
224 * ACPI package. This is used to lookup the array of PCC
225 * subspaces as parsed by the PCC Mailbox controller.
226 *
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100227 * Return: Pointer to the PCC Mailbox Channel if successful or ERR_PTR.
hotranaca314e2016-08-15 17:14:05 -0700228 */
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100229struct pcc_mbox_chan *
230pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id)
hotranaca314e2016-08-15 17:14:05 -0700231{
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100232 struct pcc_chan_info *pchan;
hotranaca314e2016-08-15 17:14:05 -0700233 struct device *dev = pcc_mbox_ctrl.dev;
234 struct mbox_chan *chan;
235 unsigned long flags;
236
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100237 if (subspace_id < 0 || subspace_id >= pcc_mbox_ctrl.num_chans)
238 return ERR_PTR(-ENOENT);
hotranaca314e2016-08-15 17:14:05 -0700239
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100240 pchan = chan_info + subspace_id;
241 chan = pchan->chan.mchan;
hotranaca314e2016-08-15 17:14:05 -0700242 if (IS_ERR(chan) || chan->cl) {
243 dev_err(dev, "Channel not found for idx: %d\n", subspace_id);
244 return ERR_PTR(-EBUSY);
245 }
246
247 spin_lock_irqsave(&chan->lock, flags);
248 chan->msg_free = 0;
249 chan->msg_count = 0;
250 chan->active_req = NULL;
251 chan->cl = cl;
252 init_completion(&chan->tx_complete);
253
254 if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
Sudeep Holla33cd7122017-09-28 11:18:52 +0100255 chan->txdone_method = TXDONE_BY_ACK;
hotranaca314e2016-08-15 17:14:05 -0700256
Hoan Tran6ca595a2016-11-14 11:19:02 -0800257 spin_unlock_irqrestore(&chan->lock, flags);
258
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100259 if (pchan->db_irq > 0) {
hotranaca314e2016-08-15 17:14:05 -0700260 int rc;
261
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100262 rc = devm_request_irq(dev, pchan->db_irq, pcc_mbox_irq, 0,
263 MBOX_IRQ_NAME, chan);
hotranaca314e2016-08-15 17:14:05 -0700264 if (unlikely(rc)) {
265 dev_err(dev, "failed to register PCC interrupt %d\n",
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100266 pchan->db_irq);
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100267 pcc_mbox_free_channel(&pchan->chan);
268 return ERR_PTR(rc);
hotranaca314e2016-08-15 17:14:05 -0700269 }
270 }
271
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100272 return &pchan->chan;
hotranaca314e2016-08-15 17:14:05 -0700273}
274EXPORT_SYMBOL_GPL(pcc_mbox_request_channel);
275
276/**
277 * pcc_mbox_free_channel - Clients call this to free their Channel.
278 *
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100279 * @pchan: Pointer to the PCC mailbox channel as returned by
280 * pcc_mbox_request_channel()
hotranaca314e2016-08-15 17:14:05 -0700281 */
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100282void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan)
hotranaca314e2016-08-15 17:14:05 -0700283{
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100284 struct pcc_chan_info *pchan_info = to_pcc_chan_info(pchan);
285 struct mbox_chan *chan = pchan->mchan;
hotranaca314e2016-08-15 17:14:05 -0700286 unsigned long flags;
287
288 if (!chan || !chan->cl)
289 return;
290
Sudeep Holla7b6da7f2021-09-17 14:33:50 +0100291 if (pchan_info->db_irq > 0)
292 devm_free_irq(chan->mbox->dev, pchan_info->db_irq, chan);
Hoan Tran6ca595a2016-11-14 11:19:02 -0800293
hotranaca314e2016-08-15 17:14:05 -0700294 spin_lock_irqsave(&chan->lock, flags);
295 chan->cl = NULL;
296 chan->active_req = NULL;
Sudeep Holla33cd7122017-09-28 11:18:52 +0100297 if (chan->txdone_method == TXDONE_BY_ACK)
hotranaca314e2016-08-15 17:14:05 -0700298 chan->txdone_method = TXDONE_BY_POLL;
299
hotranaca314e2016-08-15 17:14:05 -0700300 spin_unlock_irqrestore(&chan->lock, flags);
301}
302EXPORT_SYMBOL_GPL(pcc_mbox_free_channel);
303
hotranaca314e2016-08-15 17:14:05 -0700304/**
Ashwin Chaugule33350e62015-01-27 16:03:57 -0500305 * pcc_send_data - Called from Mailbox Controller code. Used
306 * here only to ring the channel doorbell. The PCC client
307 * specific read/write is done in the client driver in
308 * order to maintain atomicity over PCC channel once
309 * OS has control over it. See above for flow of operations.
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500310 * @chan: Pointer to Mailbox channel over which to send data.
Ashwin Chaugule33350e62015-01-27 16:03:57 -0500311 * @data: Client specific data written over channel. Used here
312 * only for debug after PCC transaction completes.
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500313 *
314 * Return: Err if something failed else 0 for success.
315 */
316static int pcc_send_data(struct mbox_chan *chan, void *data)
317{
318 struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv;
Prakash, Prashanth8b0f5782016-02-17 13:21:01 -0700319 struct acpi_generic_address *doorbell;
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100320 struct pcc_chan_info *pchan;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500321 u64 doorbell_preserve;
322 u64 doorbell_val;
323 u64 doorbell_write;
Prakash, Prashanth8b0f5782016-02-17 13:21:01 -0700324 u32 id = chan - pcc_mbox_channels;
325 int ret = 0;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500326
Prakash, Prashanth8b0f5782016-02-17 13:21:01 -0700327 if (id >= pcc_mbox_ctrl.num_chans) {
328 pr_debug("pcc_send_data: Invalid mbox_chan passed\n");
329 return -ENOENT;
330 }
331
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100332 pchan = chan_info + id;
Prakash, Prashanth8b0f5782016-02-17 13:21:01 -0700333 doorbell = &pcct_ss->doorbell_register;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500334 doorbell_preserve = pcct_ss->preserve_mask;
335 doorbell_write = pcct_ss->write_mask;
336
Ashwin Chaugule33350e62015-01-27 16:03:57 -0500337 /* Sync notification from OS to Platform. */
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100338 if (pchan->db_vaddr) {
339 ret = read_register(pchan->db_vaddr, &doorbell_val,
340 doorbell->bit_width);
Prakash, Prashanth8b0f5782016-02-17 13:21:01 -0700341 if (ret)
342 return ret;
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100343 ret = write_register(pchan->db_vaddr,
344 (doorbell_val & doorbell_preserve)
345 | doorbell_write, doorbell->bit_width);
Prakash, Prashanth8b0f5782016-02-17 13:21:01 -0700346 } else {
347 ret = acpi_read(&doorbell_val, doorbell);
348 if (ret)
349 return ret;
350 ret = acpi_write((doorbell_val & doorbell_preserve) | doorbell_write,
351 doorbell);
352 }
353 return ret;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500354}
355
Andrew Bresticker05ae7972015-05-04 10:36:35 -0700356static const struct mbox_chan_ops pcc_chan_ops = {
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500357 .send_data = pcc_send_data,
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500358};
359
360/**
Sudeep Holla10dcc2d2021-09-17 14:33:44 +0100361 * parse_pcc_subspace - Count PCC subspaces defined
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500362 * @header: Pointer to the ACPI subtable header under the PCCT.
363 * @end: End of subtable entry.
364 *
Al Stone8f8027c2018-05-16 16:01:41 -0600365 * Return: If we find a PCC subspace entry of a valid type, return 0.
366 * Otherwise, return -EINVAL.
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500367 *
368 * This gets called for each entry in the PCC table.
369 */
Keith Busch60574d12019-03-11 14:55:57 -0600370static int parse_pcc_subspace(union acpi_subtable_headers *header,
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500371 const unsigned long end)
372{
Al Stone8f8027c2018-05-16 16:01:41 -0600373 struct acpi_pcct_subspace *ss = (struct acpi_pcct_subspace *) header;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500374
Al Stone8f8027c2018-05-16 16:01:41 -0600375 if (ss->header.type < ACPI_PCCT_TYPE_RESERVED)
376 return 0;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500377
Al Stone8f8027c2018-05-16 16:01:41 -0600378 return -EINVAL;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500379}
380
381/**
hotranaca314e2016-08-15 17:14:05 -0700382 * pcc_parse_subspace_irq - Parse the PCC IRQ and PCC ACK register
Sudeep Holla319bfb32021-09-17 14:33:47 +0100383 *
384 * @pchan: Pointer to the PCC channel info structure.
385 * @pcct_entry: Pointer to the ACPI subtable header.
hotranaca314e2016-08-15 17:14:05 -0700386 *
387 * Return: 0 for Success, else errno.
388 *
Sudeep Holla319bfb32021-09-17 14:33:47 +0100389 * There should be one entry per PCC channel. This gets called for each
390 * entry in the PCC table. This uses PCCY Type1 structure for all applicable
391 * types(Type 1-4) to fetch irq
hotranaca314e2016-08-15 17:14:05 -0700392 */
Sudeep Holla319bfb32021-09-17 14:33:47 +0100393static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan,
394 struct acpi_subtable_header *pcct_entry)
hotranaca314e2016-08-15 17:14:05 -0700395{
Sudeep Holla319bfb32021-09-17 14:33:47 +0100396 struct acpi_pcct_hw_reduced *pcct_ss;
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100397
Sudeep Holla319bfb32021-09-17 14:33:47 +0100398 if (pcct_entry->type < ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE ||
399 pcct_entry->type > ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE)
400 return 0;
401
402 pcct_ss = (struct acpi_pcct_hw_reduced *)pcct_entry;
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100403 pchan->db_irq = pcc_map_interrupt(pcct_ss->platform_interrupt,
404 (u32)pcct_ss->flags);
405 if (pchan->db_irq <= 0) {
hotranaca314e2016-08-15 17:14:05 -0700406 pr_err("PCC GSI %d not registered\n",
David E. Boxc7a1dfb2017-06-05 16:39:08 +0800407 pcct_ss->platform_interrupt);
hotranaca314e2016-08-15 17:14:05 -0700408 return -EINVAL;
409 }
410
Sudeep Holla319bfb32021-09-17 14:33:47 +0100411 if (pcct_ss->header.type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) {
hotranaca314e2016-08-15 17:14:05 -0700412 struct acpi_pcct_hw_reduced_type2 *pcct2_ss = (void *)pcct_ss;
413
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100414 pchan->db_ack_vaddr =
415 acpi_os_ioremap(pcct2_ss->platform_ack_register.address,
416 pcct2_ss->platform_ack_register.bit_width / 8);
417 if (!pchan->db_ack_vaddr) {
hotranaca314e2016-08-15 17:14:05 -0700418 pr_err("Failed to ioremap PCC ACK register\n");
419 return -ENOMEM;
420 }
421 }
422
423 return 0;
424}
425
426/**
Sudeep Holla4e3c96f2021-09-17 14:33:48 +0100427 * pcc_parse_subspace_db_reg - Parse the PCC doorbell register
428 *
429 * @pchan: Pointer to the PCC channel info structure.
430 * @pcct_entry: Pointer to the ACPI subtable header.
431 *
432 */
433static void pcc_parse_subspace_db_reg(struct pcc_chan_info *pchan,
434 struct acpi_subtable_header *pcct_entry)
435{
436 struct acpi_pcct_subspace *pcct_ss;
437 struct acpi_generic_address *db_reg;
438
439 pcct_ss = (struct acpi_pcct_subspace *)pcct_entry;
440
441 /* If doorbell is in system memory cache the virt address */
442 db_reg = &pcct_ss->doorbell_register;
443 if (db_reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
444 pchan->db_vaddr = acpi_os_ioremap(db_reg->address,
445 db_reg->bit_width / 8);
446}
447
448/**
Sudeep Holla0f2591e2021-09-17 14:33:49 +0100449 * pcc_parse_subspace_shmem - Parse the PCC Shared Memory Region information
450 *
451 * @pchan: Pointer to the PCC channel info structure.
452 * @pcct_entry: Pointer to the ACPI subtable header.
453 *
454 */
455static void pcc_parse_subspace_shmem(struct pcc_chan_info *pchan,
456 struct acpi_subtable_header *pcct_entry)
457{
458 struct acpi_pcct_subspace *pcct_ss;
459
460 pcct_ss = (struct acpi_pcct_subspace *)pcct_entry;
461
462 pchan->chan.shmem_base_addr = pcct_ss->base_address;
463 pchan->chan.shmem_size = pcct_ss->length;
464 pchan->chan.latency = pcct_ss->latency;
465 pchan->chan.max_access_rate = pcct_ss->max_access_rate;
466 pchan->chan.min_turnaround_time = pcct_ss->min_turnaround_time;
467}
468
469/**
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500470 * acpi_pcc_probe - Parse the ACPI tree for the PCCT.
471 *
472 * Return: 0 for Success, else errno.
473 */
474static int __init acpi_pcc_probe(void)
475{
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500476 struct acpi_table_header *pcct_tbl;
477 struct acpi_subtable_header *pcct_entry;
hotranaca314e2016-08-15 17:14:05 -0700478 struct acpi_table_pcct *acpi_pcct_tbl;
Al Stone8f8027c2018-05-16 16:01:41 -0600479 struct acpi_subtable_proc proc[ACPI_PCCT_TYPE_RESERVED];
hotranaca314e2016-08-15 17:14:05 -0700480 int count, i, rc;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500481 acpi_status status = AE_OK;
482
483 /* Search for PCCT */
Lv Zheng6b11d1d2016-12-14 15:04:39 +0800484 status = acpi_get_table(ACPI_SIG_PCCT, 0, &pcct_tbl);
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500485
Punit Agrawal66ed4ca2017-08-01 13:43:57 +0100486 if (ACPI_FAILURE(status) || !pcct_tbl)
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500487 return -ENODEV;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500488
Al Stone8f8027c2018-05-16 16:01:41 -0600489 /* Set up the subtable handlers */
490 for (i = ACPI_PCCT_TYPE_GENERIC_SUBSPACE;
491 i < ACPI_PCCT_TYPE_RESERVED; i++) {
492 proc[i].id = i;
493 proc[i].count = 0;
494 proc[i].handler = parse_pcc_subspace;
495 }
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500496
Al Stone8f8027c2018-05-16 16:01:41 -0600497 count = acpi_table_parse_entries_array(ACPI_SIG_PCCT,
498 sizeof(struct acpi_table_pcct), proc,
499 ACPI_PCCT_TYPE_RESERVED, MAX_PCC_SUBSPACES);
David Arcariafd0b1f2018-08-27 15:19:08 -0400500 if (count <= 0 || count > MAX_PCC_SUBSPACES) {
501 if (count < 0)
502 pr_warn("Error parsing PCC subspaces from PCCT\n");
503 else
504 pr_warn("Invalid PCCT: %d PCC subspaces\n", count);
Hanjun Guo425ab032020-07-22 17:40:40 +0800505
506 rc = -EINVAL;
507 goto err_put_pcct;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500508 }
509
Kees Cook6396bb22018-06-12 14:03:40 -0700510 pcc_mbox_channels = kcalloc(count, sizeof(struct mbox_chan),
511 GFP_KERNEL);
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500512 if (!pcc_mbox_channels) {
513 pr_err("Could not allocate space for PCC mbox channels\n");
Hanjun Guo425ab032020-07-22 17:40:40 +0800514 rc = -ENOMEM;
515 goto err_put_pcct;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500516 }
517
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100518 chan_info = kcalloc(count, sizeof(*chan_info), GFP_KERNEL);
519 if (!chan_info) {
hotranaca314e2016-08-15 17:14:05 -0700520 rc = -ENOMEM;
521 goto err_free_mbox;
522 }
523
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500524 /* Point to the first PCC subspace entry */
525 pcct_entry = (struct acpi_subtable_header *) (
526 (unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct));
527
hotranaca314e2016-08-15 17:14:05 -0700528 acpi_pcct_tbl = (struct acpi_table_pcct *) pcct_tbl;
529 if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL)
530 pcc_mbox_ctrl.txdone_irq = true;
531
Al Stone8f8027c2018-05-16 16:01:41 -0600532 for (i = 0; i < count; i++) {
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100533 struct pcc_chan_info *pchan = chan_info + i;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500534 pcc_mbox_channels[i].con_priv = pcct_entry;
Prakash, Prashanth8b0f5782016-02-17 13:21:01 -0700535
Sudeep Holla0f2591e2021-09-17 14:33:49 +0100536 pchan->chan.mchan = &pcc_mbox_channels[i];
537
Sudeep Holla319bfb32021-09-17 14:33:47 +0100538 if (pcc_mbox_ctrl.txdone_irq) {
539 rc = pcc_parse_subspace_irq(pchan, pcct_entry);
540 if (rc < 0)
541 goto err;
hotranaca314e2016-08-15 17:14:05 -0700542 }
Sudeep Holla4e3c96f2021-09-17 14:33:48 +0100543 pcc_parse_subspace_db_reg(pchan, pcct_entry);
hotranaca314e2016-08-15 17:14:05 -0700544
Sudeep Holla0f2591e2021-09-17 14:33:49 +0100545 pcc_parse_subspace_shmem(pchan, pcct_entry);
546
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500547 pcct_entry = (struct acpi_subtable_header *)
548 ((unsigned long) pcct_entry + pcct_entry->length);
549 }
550
Al Stone8f8027c2018-05-16 16:01:41 -0600551 pcc_mbox_ctrl.num_chans = count;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500552
553 pr_info("Detected %d PCC Subspaces\n", pcc_mbox_ctrl.num_chans);
554
555 return 0;
hotranaca314e2016-08-15 17:14:05 -0700556
557err:
Sudeep Holla80b2bdd2021-09-17 14:33:46 +0100558 kfree(chan_info);
hotranaca314e2016-08-15 17:14:05 -0700559err_free_mbox:
560 kfree(pcc_mbox_channels);
Hanjun Guo425ab032020-07-22 17:40:40 +0800561err_put_pcct:
562 acpi_put_table(pcct_tbl);
hotranaca314e2016-08-15 17:14:05 -0700563 return rc;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500564}
565
566/**
567 * pcc_mbox_probe - Called when we find a match for the
568 * PCCT platform device. This is purely used to represent
569 * the PCCT as a virtual device for registering with the
570 * generic Mailbox framework.
571 *
572 * @pdev: Pointer to platform device returned when a match
573 * is found.
574 *
575 * Return: 0 for Success, else errno.
576 */
577static int pcc_mbox_probe(struct platform_device *pdev)
578{
579 int ret = 0;
580
581 pcc_mbox_ctrl.chans = pcc_mbox_channels;
582 pcc_mbox_ctrl.ops = &pcc_chan_ops;
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500583 pcc_mbox_ctrl.dev = &pdev->dev;
584
585 pr_info("Registering PCC driver as Mailbox controller\n");
586 ret = mbox_controller_register(&pcc_mbox_ctrl);
587
588 if (ret) {
589 pr_err("Err registering PCC as Mailbox controller: %d\n", ret);
590 ret = -ENODEV;
591 }
592
593 return ret;
594}
595
Jason Yan00d99902020-04-03 11:52:08 +0800596static struct platform_driver pcc_mbox_driver = {
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500597 .probe = pcc_mbox_probe,
598 .driver = {
599 .name = "PCCT",
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500600 },
601};
602
603static int __init pcc_init(void)
604{
605 int ret;
606 struct platform_device *pcc_pdev;
607
608 if (acpi_disabled)
609 return -ENODEV;
610
611 /* Check if PCC support is available. */
612 ret = acpi_pcc_probe();
613
614 if (ret) {
Rafael J. Wysockiefd756d2015-02-05 00:40:08 +0100615 pr_debug("ACPI PCC probe failed.\n");
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500616 return -ENODEV;
617 }
618
619 pcc_pdev = platform_create_bundle(&pcc_mbox_driver,
620 pcc_mbox_probe, NULL, 0, NULL, 0);
621
Wei Yongjun356d5d22015-01-14 09:10:56 +0800622 if (IS_ERR(pcc_pdev)) {
Rafael J. Wysockiefd756d2015-02-05 00:40:08 +0100623 pr_debug("Err creating PCC platform bundle\n");
Wei Yongjun356d5d22015-01-14 09:10:56 +0800624 return PTR_ERR(pcc_pdev);
Ashwin Chaugule86c22f82014-11-12 19:59:38 -0500625 }
626
627 return 0;
628}
Ashwin Chauguled3c68f22015-08-05 09:40:24 -0400629
630/*
631 * Make PCC init postcore so that users of this mailbox
632 * such as the ACPI Processor driver have it available
633 * at their init.
634 */
635postcore_initcall(pcc_init);