Skip to content

Commit 5378bdf

Browse files
Adam YoungJassi Brar
authored andcommitted
mailbox/pcc: support mailbox management of the shared buffer
Define a new, optional, callback that allows the driver to specify how the return data buffer is allocated. If that callback is set, mailbox/pcc.c is now responsible for reading from and writing to the PCC shared buffer. This also allows for proper checks of the Commnand complete flag between the PCC sender and receiver. For Type 4 channels, initialize the command complete flag prior to accepting messages. Since the mailbox does not know what memory allocation scheme to use for response messages, the client now has an optional callback that allows it to allocate the buffer for a response message. When an outbound message is written to the buffer, the mailbox checks for the flag indicating the client wants an tx complete notification via IRQ. Upon receipt of the interrupt It will pair it with the outgoing message. The expected use is to free the kernel memory buffer for the previous outgoing message. Signed-off-by: Adam Young <[email protected]> Signed-off-by: Jassi Brar <[email protected]>
1 parent 75f1fbc commit 5378bdf

File tree

2 files changed

+127
-4
lines changed

2 files changed

+127
-4
lines changed

drivers/mailbox/pcc.c

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,22 @@ static void pcc_chan_acknowledge(struct pcc_chan_info *pchan)
306306
pcc_chan_reg_read_modify_write(&pchan->db);
307307
}
308308

309+
static void *write_response(struct pcc_chan_info *pchan)
310+
{
311+
struct pcc_header 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+
309325
/**
310326
* pcc_mbox_irq - PCC mailbox interrupt handler
311327
* @irq: interrupt number
@@ -317,6 +333,8 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
317333
{
318334
struct pcc_chan_info *pchan;
319335
struct mbox_chan *chan = p;
336+
struct pcc_header *pcc_header = chan->active_req;
337+
void *handle = NULL;
320338

321339
pchan = chan->con_priv;
322340

@@ -340,7 +358,17 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
340358
* required to avoid any possible race in updatation of this flag.
341359
*/
342360
pchan->chan_in_use = false;
343-
mbox_chan_received_data(chan, NULL);
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, 0);
369+
}
370+
371+
mbox_chan_received_data(chan, handle);
344372

345373
pcc_chan_acknowledge(pchan);
346374

@@ -384,9 +412,24 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id)
384412
pcc_mchan = &pchan->chan;
385413
pcc_mchan->shmem = acpi_os_ioremap(pcc_mchan->shmem_base_addr,
386414
pcc_mchan->shmem_size);
387-
if (pcc_mchan->shmem)
388-
return pcc_mchan;
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(&pchan->cmd_update);
429+
430+
return pcc_mchan;
389431

432+
err:
390433
mbox_free_channel(chan);
391434
return ERR_PTR(-ENXIO);
392435
}
@@ -417,8 +460,38 @@ void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan)
417460
}
418461
EXPORT_SYMBOL_GPL(pcc_mbox_free_channel);
419462

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 *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(&pchan->cmd_complete, &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+
420488
/**
421-
* pcc_send_data - Called from Mailbox Controller code. Used
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
422495
* here only to ring the channel doorbell. The PCC client
423496
* specific read/write is done in the client driver in
424497
* order to maintain atomicity over PCC channel once
@@ -434,17 +507,37 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
434507
int ret;
435508
struct pcc_chan_info *pchan = chan->con_priv;
436509

510+
ret = pcc_write_to_buffer(chan, data);
511+
if (ret)
512+
return ret;
513+
437514
ret = pcc_chan_reg_read_modify_write(&pchan->cmd_update);
438515
if (ret)
439516
return ret;
440517

441518
ret = pcc_chan_reg_read_modify_write(&pchan->db);
519+
442520
if (!ret && pchan->plat_irq > 0)
443521
pchan->chan_in_use = true;
444522

445523
return ret;
446524
}
447525

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(&pchan->cmd_complete, &val);
533+
if (!val)
534+
return false;
535+
else
536+
return true;
537+
}
538+
539+
540+
448541
/**
449542
* pcc_startup - Called from Mailbox Controller code. Used here
450543
* to request the interrupt.
@@ -490,6 +583,7 @@ static const struct mbox_chan_ops pcc_chan_ops = {
490583
.send_data = pcc_send_data,
491584
.startup = pcc_startup,
492585
.shutdown = pcc_shutdown,
586+
.last_tx_done = pcc_last_tx_done,
493587
};
494588

495589
/**

include/acpi/pcc.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,35 @@ struct pcc_mbox_chan {
1717
u32 latency;
1818
u32 max_access_rate;
1919
u16 min_turnaround_time;
20+
21+
/* Set to true to indicate that the mailbox should manage
22+
* writing the dat to the shared buffer. This differs from
23+
* the case where the drivesr are writing to the buffer and
24+
* using send_data only to ring the doorbell. If this flag
25+
* is set, then the void * data parameter of send_data must
26+
* point to a kernel-memory buffer formatted in accordance with
27+
* the PCC specification.
28+
*
29+
* The active buffer management will include reading the
30+
* notify_on_completion flag, and will then
31+
* call mbox_chan_txdone when the acknowledgment interrupt is
32+
* received.
33+
*/
34+
bool manage_writes;
35+
36+
/* Optional callback that allows the driver
37+
* to allocate the memory used for receiving
38+
* messages. The return value is the location
39+
* inside the buffer where the mailbox should write the data.
40+
*/
41+
void *(*rx_alloc)(struct mbox_client *cl, int size);
42+
};
43+
44+
struct pcc_header {
45+
u32 signature;
46+
u32 flags;
47+
u32 length;
48+
u32 command;
2049
};
2150

2251
/* Generic Communications Channel Shared Memory Region */

0 commit comments

Comments
 (0)