Skip to content

Commit 0ac39d8

Browse files
bentheredonethatJassi Brar
authored andcommitted
mailbox: zynqmp: Enable Bufferless IPI usage on Versal-based SOC's
On Xilinx-AMD Versal and Versal-NET, there exist both inter-processor-interrupts with corresponding message buffers and without such buffers. Add a routine that, if the corresponding DT compatible string "xlnx,versal-ipi-mailbox" is used then a Versal-based SOC can use a mailbox Device Tree entry where both host and remote can use either of the buffered or bufferless interrupts. Signed-off-by: Ben Levinsky <[email protected]> Signed-off-by: Jassi Brar <[email protected]>
1 parent 41bcf30 commit 0ac39d8

File tree

1 file changed

+122
-7
lines changed

1 file changed

+122
-7
lines changed

drivers/mailbox/zynqmp-ipi-mailbox.c

Lines changed: 122 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@
5252
#define IPI_MB_CHNL_TX 0 /* IPI mailbox TX channel */
5353
#define IPI_MB_CHNL_RX 1 /* IPI mailbox RX channel */
5454

55+
/* IPI Message Buffer Information */
56+
#define RESP_OFFSET 0x20U
57+
#define DEST_OFFSET 0x40U
58+
#define IPI_BUF_SIZE 0x20U
59+
#define DST_BIT_POS 9U
60+
#define SRC_BITMASK GENMASK(11, 8)
61+
5562
/**
5663
* struct zynqmp_ipi_mchan - Description of a Xilinx ZynqMP IPI mailbox channel
5764
* @is_opened: indicate if the IPI channel is opened
@@ -169,9 +176,11 @@ static irqreturn_t zynqmp_ipi_interrupt(int irq, void *data)
169176
if (ret > 0 && ret & IPI_MB_STATUS_RECV_PENDING) {
170177
if (mchan->is_opened) {
171178
msg = mchan->rx_buf;
172-
msg->len = mchan->req_buf_size;
173-
memcpy_fromio(msg->data, mchan->req_buf,
174-
msg->len);
179+
if (msg) {
180+
msg->len = mchan->req_buf_size;
181+
memcpy_fromio(msg->data, mchan->req_buf,
182+
msg->len);
183+
}
175184
mbox_chan_received_data(chan, (void *)msg);
176185
status = IRQ_HANDLED;
177186
}
@@ -281,26 +290,26 @@ static int zynqmp_ipi_send_data(struct mbox_chan *chan, void *data)
281290

282291
if (mchan->chan_type == IPI_MB_CHNL_TX) {
283292
/* Send request message */
284-
if (msg && msg->len > mchan->req_buf_size) {
293+
if (msg && msg->len > mchan->req_buf_size && mchan->req_buf) {
285294
dev_err(dev, "channel %d message length %u > max %lu\n",
286295
mchan->chan_type, (unsigned int)msg->len,
287296
mchan->req_buf_size);
288297
return -EINVAL;
289298
}
290-
if (msg && msg->len)
299+
if (msg && msg->len && mchan->req_buf)
291300
memcpy_toio(mchan->req_buf, msg->data, msg->len);
292301
/* Kick IPI mailbox to send message */
293302
arg0 = SMC_IPI_MAILBOX_NOTIFY;
294303
zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res);
295304
} else {
296305
/* Send response message */
297-
if (msg && msg->len > mchan->resp_buf_size) {
306+
if (msg && msg->len > mchan->resp_buf_size && mchan->resp_buf) {
298307
dev_err(dev, "channel %d message length %u > max %lu\n",
299308
mchan->chan_type, (unsigned int)msg->len,
300309
mchan->resp_buf_size);
301310
return -EINVAL;
302311
}
303-
if (msg && msg->len)
312+
if (msg && msg->len && mchan->resp_buf)
304313
memcpy_toio(mchan->resp_buf, msg->data, msg->len);
305314
arg0 = SMC_IPI_MAILBOX_ACK;
306315
zynqmp_ipi_fw_call(ipi_mbox, arg0, IPI_SMC_ACK_EIRQ_MASK,
@@ -636,6 +645,109 @@ static int zynqmp_ipi_setup(struct zynqmp_ipi_mbox *ipi_mbox,
636645
return 0;
637646
}
638647

648+
/**
649+
* versal_ipi_setup - Set up IPIs to support mixed usage of
650+
* Buffered and Bufferless IPIs.
651+
*
652+
* @ipi_mbox: pointer to IPI mailbox private data structure
653+
* @node: IPI mailbox device node
654+
*
655+
* Return: 0 for success, negative value for failure
656+
*/
657+
static int versal_ipi_setup(struct zynqmp_ipi_mbox *ipi_mbox,
658+
struct device_node *node)
659+
{
660+
struct zynqmp_ipi_mchan *tx_mchan, *rx_mchan;
661+
struct resource host_res, remote_res;
662+
struct device_node *parent_node;
663+
int host_idx, remote_idx;
664+
struct device *mdev;
665+
666+
tx_mchan = &ipi_mbox->mchans[IPI_MB_CHNL_TX];
667+
rx_mchan = &ipi_mbox->mchans[IPI_MB_CHNL_RX];
668+
parent_node = of_get_parent(node);
669+
mdev = &ipi_mbox->dev;
670+
671+
host_idx = zynqmp_ipi_mbox_get_buf_res(parent_node, "msg", &host_res);
672+
remote_idx = zynqmp_ipi_mbox_get_buf_res(node, "msg", &remote_res);
673+
674+
/*
675+
* Only set up buffers if both sides claim to have msg buffers.
676+
* This is because each buffered IPI's corresponding msg buffers
677+
* are reserved for use by other buffered IPI's.
678+
*/
679+
if (!host_idx && !remote_idx) {
680+
u32 host_src, host_dst, remote_src, remote_dst;
681+
u32 buff_sz;
682+
683+
buff_sz = resource_size(&host_res);
684+
685+
host_src = host_res.start & SRC_BITMASK;
686+
remote_src = remote_res.start & SRC_BITMASK;
687+
688+
host_dst = (host_src >> DST_BIT_POS) * DEST_OFFSET;
689+
remote_dst = (remote_src >> DST_BIT_POS) * DEST_OFFSET;
690+
691+
/* Validate that IPI IDs is within IPI Message buffer space. */
692+
if (host_dst >= buff_sz || remote_dst >= buff_sz) {
693+
dev_err(mdev,
694+
"Invalid IPI Message buffer values: %x %x\n",
695+
host_dst, remote_dst);
696+
return -EINVAL;
697+
}
698+
699+
tx_mchan->req_buf = devm_ioremap(mdev,
700+
host_res.start | remote_dst,
701+
IPI_BUF_SIZE);
702+
if (!tx_mchan->req_buf) {
703+
dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
704+
return -ENOMEM;
705+
}
706+
707+
tx_mchan->resp_buf = devm_ioremap(mdev,
708+
(remote_res.start | host_dst) +
709+
RESP_OFFSET, IPI_BUF_SIZE);
710+
if (!tx_mchan->resp_buf) {
711+
dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
712+
return -ENOMEM;
713+
}
714+
715+
rx_mchan->req_buf = devm_ioremap(mdev,
716+
remote_res.start | host_dst,
717+
IPI_BUF_SIZE);
718+
if (!rx_mchan->req_buf) {
719+
dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
720+
return -ENOMEM;
721+
}
722+
723+
rx_mchan->resp_buf = devm_ioremap(mdev,
724+
(host_res.start | remote_dst) +
725+
RESP_OFFSET, IPI_BUF_SIZE);
726+
if (!rx_mchan->resp_buf) {
727+
dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
728+
return -ENOMEM;
729+
}
730+
731+
tx_mchan->resp_buf_size = IPI_BUF_SIZE;
732+
tx_mchan->req_buf_size = IPI_BUF_SIZE;
733+
tx_mchan->rx_buf = devm_kzalloc(mdev, IPI_BUF_SIZE +
734+
sizeof(struct zynqmp_ipi_message),
735+
GFP_KERNEL);
736+
if (!tx_mchan->rx_buf)
737+
return -ENOMEM;
738+
739+
rx_mchan->resp_buf_size = IPI_BUF_SIZE;
740+
rx_mchan->req_buf_size = IPI_BUF_SIZE;
741+
rx_mchan->rx_buf = devm_kzalloc(mdev, IPI_BUF_SIZE +
742+
sizeof(struct zynqmp_ipi_message),
743+
GFP_KERNEL);
744+
if (!rx_mchan->rx_buf)
745+
return -ENOMEM;
746+
}
747+
748+
return 0;
749+
}
750+
639751
/**
640752
* zynqmp_ipi_free_mboxes - Free IPI mailboxes devices
641753
*
@@ -743,6 +855,9 @@ static const struct of_device_id zynqmp_ipi_of_match[] = {
743855
{ .compatible = "xlnx,zynqmp-ipi-mailbox",
744856
.data = &zynqmp_ipi_setup,
745857
},
858+
{ .compatible = "xlnx,versal-ipi-mailbox",
859+
.data = &versal_ipi_setup,
860+
},
746861
{},
747862
};
748863
MODULE_DEVICE_TABLE(of, zynqmp_ipi_of_match);

0 commit comments

Comments
 (0)