diff options
-rw-r--r-- | drivers/mailbox/pcc.c | 122 |
1 files changed, 37 insertions, 85 deletions
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 977c814cdf6f..7e91d68a3ac3 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c | |||
@@ -20,10 +20,35 @@ | |||
20 | * shared memory regions as defined in the PCC table entries. The PCC | 20 | * shared memory regions as defined in the PCC table entries. The PCC |
21 | * specification supports a Doorbell mechanism for the PCC clients | 21 | * specification supports a Doorbell mechanism for the PCC clients |
22 | * to notify the platform about new data. This Doorbell information | 22 | * to notify the platform about new data. This Doorbell information |
23 | * is also specified in each PCC table entry. See pcc_send_data() | 23 | * is also specified in each PCC table entry. |
24 | * and pcc_tx_done() for basic mode of operation. | ||
25 | * | 24 | * |
26 | * For more details about PCC, please see the ACPI specification from | 25 | * Typical high level flow of operation is: |
26 | * | ||
27 | * PCC Reads: | ||
28 | * * Client tries to acquire a channel lock. | ||
29 | * * After it is acquired it writes READ cmd in communication region cmd | ||
30 | * address. | ||
31 | * * Client issues mbox_send_message() which rings the PCC doorbell | ||
32 | * for its PCC channel. | ||
33 | * * If command completes, then client has control over channel and | ||
34 | * it can proceed with its reads. | ||
35 | * * Client releases lock. | ||
36 | * | ||
37 | * PCC Writes: | ||
38 | * * Client tries to acquire channel lock. | ||
39 | * * Client writes to its communication region after it acquires a | ||
40 | * channel lock. | ||
41 | * * Client writes WRITE cmd in communication region cmd address. | ||
42 | * * Client issues mbox_send_message() which rings the PCC doorbell | ||
43 | * for its PCC channel. | ||
44 | * * If command completes, then writes have succeded and it can release | ||
45 | * the channel lock. | ||
46 | * | ||
47 | * There is a Nominal latency defined for each channel which indicates | ||
48 | * how long to wait until a command completes. If command is not complete | ||
49 | * the client needs to retry or assume failure. | ||
50 | * | ||
51 | * For more details about PCC, please see the ACPI specification from | ||
27 | * http://www.uefi.org/ACPIv5.1 Section 14. | 52 | * http://www.uefi.org/ACPIv5.1 Section 14. |
28 | * | 53 | * |
29 | * This file implements PCC as a Mailbox controller and allows for PCC | 54 | * This file implements PCC as a Mailbox controller and allows for PCC |
@@ -42,8 +67,6 @@ | |||
42 | #include "mailbox.h" | 67 | #include "mailbox.h" |
43 | 68 | ||
44 | #define MAX_PCC_SUBSPACES 256 | 69 | #define MAX_PCC_SUBSPACES 256 |
45 | #define PCCS_SS_SIG_MAGIC 0x50434300 | ||
46 | #define PCC_CMD_COMPLETE 0x1 | ||
47 | 70 | ||
48 | static struct mbox_chan *pcc_mbox_channels; | 71 | static struct mbox_chan *pcc_mbox_channels; |
49 | 72 | ||
@@ -71,23 +94,6 @@ static struct mbox_chan *get_pcc_channel(int id) | |||
71 | } | 94 | } |
72 | 95 | ||
73 | /** | 96 | /** |
74 | * get_subspace_id - Given a Mailbox channel, find out the | ||
75 | * PCC subspace id. | ||
76 | * @chan: Pointer to Mailbox Channel from which we want | ||
77 | * the index. | ||
78 | * Return: Errno if not found, else positive index number. | ||
79 | */ | ||
80 | static int get_subspace_id(struct mbox_chan *chan) | ||
81 | { | ||
82 | unsigned int id = chan - pcc_mbox_channels; | ||
83 | |||
84 | if (id < 0 || id > pcc_mbox_ctrl.num_chans) | ||
85 | return -ENOENT; | ||
86 | |||
87 | return id; | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * pcc_mbox_request_channel - PCC clients call this function to | 97 | * pcc_mbox_request_channel - PCC clients call this function to |
92 | * request a pointer to their PCC subspace, from which they | 98 | * request a pointer to their PCC subspace, from which they |
93 | * can get the details of communicating with the remote. | 99 | * can get the details of communicating with the remote. |
@@ -117,7 +123,7 @@ struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl, | |||
117 | chan = get_pcc_channel(subspace_id); | 123 | chan = get_pcc_channel(subspace_id); |
118 | 124 | ||
119 | if (!chan || chan->cl) { | 125 | if (!chan || chan->cl) { |
120 | dev_err(dev, "%s: PCC mailbox not free\n", __func__); | 126 | dev_err(dev, "Channel not found for idx: %d\n", subspace_id); |
121 | return ERR_PTR(-EBUSY); | 127 | return ERR_PTR(-EBUSY); |
122 | } | 128 | } |
123 | 129 | ||
@@ -161,81 +167,30 @@ void pcc_mbox_free_channel(struct mbox_chan *chan) | |||
161 | EXPORT_SYMBOL_GPL(pcc_mbox_free_channel); | 167 | EXPORT_SYMBOL_GPL(pcc_mbox_free_channel); |
162 | 168 | ||
163 | /** | 169 | /** |
164 | * pcc_tx_done - Callback from Mailbox controller code to | 170 | * pcc_send_data - Called from Mailbox Controller code. Used |
165 | * check if PCC message transmission completed. | 171 | * here only to ring the channel doorbell. The PCC client |
166 | * @chan: Pointer to Mailbox channel on which previous | 172 | * specific read/write is done in the client driver in |
167 | * transmission occurred. | 173 | * order to maintain atomicity over PCC channel once |
168 | * | 174 | * OS has control over it. See above for flow of operations. |
169 | * Return: TRUE if succeeded. | ||
170 | */ | ||
171 | static bool pcc_tx_done(struct mbox_chan *chan) | ||
172 | { | ||
173 | struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv; | ||
174 | struct acpi_pcct_shared_memory *generic_comm_base = | ||
175 | (struct acpi_pcct_shared_memory *) pcct_ss->base_address; | ||
176 | u16 cmd_delay = pcct_ss->latency; | ||
177 | unsigned int retries = 0; | ||
178 | |||
179 | /* Try a few times while waiting for platform to consume */ | ||
180 | while (!(readw_relaxed(&generic_comm_base->status) | ||
181 | & PCC_CMD_COMPLETE)) { | ||
182 | |||
183 | if (retries++ < 5) | ||
184 | udelay(cmd_delay); | ||
185 | else { | ||
186 | /* | ||
187 | * If the remote is dead, this will cause the Mbox | ||
188 | * controller to timeout after mbox client.tx_tout | ||
189 | * msecs. | ||
190 | */ | ||
191 | pr_err("PCC platform did not respond.\n"); | ||
192 | return false; | ||
193 | } | ||
194 | } | ||
195 | return true; | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * pcc_send_data - Called from Mailbox Controller code to finally | ||
200 | * transmit data over channel. | ||
201 | * @chan: Pointer to Mailbox channel over which to send data. | 175 | * @chan: Pointer to Mailbox channel over which to send data. |
202 | * @data: Actual data to be written over channel. | 176 | * @data: Client specific data written over channel. Used here |
177 | * only for debug after PCC transaction completes. | ||
203 | * | 178 | * |
204 | * Return: Err if something failed else 0 for success. | 179 | * Return: Err if something failed else 0 for success. |
205 | */ | 180 | */ |
206 | static int pcc_send_data(struct mbox_chan *chan, void *data) | 181 | static int pcc_send_data(struct mbox_chan *chan, void *data) |
207 | { | 182 | { |
208 | struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv; | 183 | struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv; |
209 | struct acpi_pcct_shared_memory *generic_comm_base = | ||
210 | (struct acpi_pcct_shared_memory *) pcct_ss->base_address; | ||
211 | struct acpi_generic_address doorbell; | 184 | struct acpi_generic_address doorbell; |
212 | u64 doorbell_preserve; | 185 | u64 doorbell_preserve; |
213 | u64 doorbell_val; | 186 | u64 doorbell_val; |
214 | u64 doorbell_write; | 187 | u64 doorbell_write; |
215 | u16 cmd = *(u16 *) data; | ||
216 | u16 ss_idx = -1; | ||
217 | |||
218 | ss_idx = get_subspace_id(chan); | ||
219 | |||
220 | if (ss_idx < 0) { | ||
221 | pr_err("Invalid Subspace ID from PCC client\n"); | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | 188 | ||
225 | doorbell = pcct_ss->doorbell_register; | 189 | doorbell = pcct_ss->doorbell_register; |
226 | doorbell_preserve = pcct_ss->preserve_mask; | 190 | doorbell_preserve = pcct_ss->preserve_mask; |
227 | doorbell_write = pcct_ss->write_mask; | 191 | doorbell_write = pcct_ss->write_mask; |
228 | 192 | ||
229 | /* Write to the shared comm region. */ | 193 | /* Sync notification from OS to Platform. */ |
230 | writew(cmd, &generic_comm_base->command); | ||
231 | |||
232 | /* Write Subspace MAGIC value so platform can identify destination. */ | ||
233 | writel((PCCS_SS_SIG_MAGIC | ss_idx), &generic_comm_base->signature); | ||
234 | |||
235 | /* Flip CMD COMPLETE bit */ | ||
236 | writew(0, &generic_comm_base->status); | ||
237 | |||
238 | /* Sync notification from OSPM to Platform. */ | ||
239 | acpi_read(&doorbell_val, &doorbell); | 194 | acpi_read(&doorbell_val, &doorbell); |
240 | acpi_write((doorbell_val & doorbell_preserve) | doorbell_write, | 195 | acpi_write((doorbell_val & doorbell_preserve) | doorbell_write, |
241 | &doorbell); | 196 | &doorbell); |
@@ -245,7 +200,6 @@ static int pcc_send_data(struct mbox_chan *chan, void *data) | |||
245 | 200 | ||
246 | static struct mbox_chan_ops pcc_chan_ops = { | 201 | static struct mbox_chan_ops pcc_chan_ops = { |
247 | .send_data = pcc_send_data, | 202 | .send_data = pcc_send_data, |
248 | .last_tx_done = pcc_tx_done, | ||
249 | }; | 203 | }; |
250 | 204 | ||
251 | /** | 205 | /** |
@@ -351,8 +305,6 @@ static int pcc_mbox_probe(struct platform_device *pdev) | |||
351 | 305 | ||
352 | pcc_mbox_ctrl.chans = pcc_mbox_channels; | 306 | pcc_mbox_ctrl.chans = pcc_mbox_channels; |
353 | pcc_mbox_ctrl.ops = &pcc_chan_ops; | 307 | pcc_mbox_ctrl.ops = &pcc_chan_ops; |
354 | pcc_mbox_ctrl.txdone_poll = true; | ||
355 | pcc_mbox_ctrl.txpoll_period = 10; | ||
356 | pcc_mbox_ctrl.dev = &pdev->dev; | 308 | pcc_mbox_ctrl.dev = &pdev->dev; |
357 | 309 | ||
358 | pr_info("Registering PCC driver as Mailbox controller\n"); | 310 | pr_info("Registering PCC driver as Mailbox controller\n"); |