mailbox-mchp-ipc-sbi.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Microchip Inter-Processor communication (IPC) driver
  4. *
  5. * Copyright (c) 2021 - 2024 Microchip Technology Inc. All rights reserved.
  6. *
  7. * Author: Valentina Fernandez <valentina.fernandezalanis@microchip.com>
  8. *
  9. */
  10. #include <linux/io.h>
  11. #include <linux/err.h>
  12. #include <linux/smp.h>
  13. #include <linux/init.h>
  14. #include <linux/module.h>
  15. #include <linux/kernel.h>
  16. #include <linux/of_device.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/dma-mapping.h>
  19. #include <linux/platform_device.h>
  20. #include <linux/mailbox/mchp-ipc.h>
  21. #include <asm/sbi.h>
  22. #include <asm/vendorid_list.h>
  23. #define IRQ_STATUS_BITS 12
  24. #define NUM_CHANS_PER_CLUSTER 5
  25. #define IPC_DMA_BIT_MASK 32
  26. #define SBI_EXT_MICROCHIP_TECHNOLOGY (SBI_EXT_VENDOR_START | \
  27. MICROCHIP_VENDOR_ID)
  28. enum {
  29. SBI_EXT_IPC_PROBE = 0x100,
  30. SBI_EXT_IPC_CH_INIT,
  31. SBI_EXT_IPC_SEND,
  32. SBI_EXT_IPC_RECEIVE,
  33. SBI_EXT_IPC_STATUS,
  34. };
  35. enum ipc_hw {
  36. MIV_IHC,
  37. };
  38. /**
  39. * struct mchp_ipc_mbox_info - IPC probe message format
  40. *
  41. * @hw_type: IPC implementation available in the hardware
  42. * @num_channels: number of IPC channels available in the hardware
  43. *
  44. * Used to retrieve information on the IPC implementation
  45. * using the SBI_EXT_IPC_PROBE SBI function id.
  46. */
  47. struct mchp_ipc_mbox_info {
  48. enum ipc_hw hw_type;
  49. u8 num_channels;
  50. };
  51. /**
  52. * struct mchp_ipc_init - IPC channel init message format
  53. *
  54. * @max_msg_size: maxmimum message size in bytes of a given channel
  55. *
  56. * struct used by the SBI_EXT_IPC_CH_INIT SBI function id to get
  57. * the max message size in bytes of the initialized channel.
  58. */
  59. struct mchp_ipc_init {
  60. u16 max_msg_size;
  61. };
  62. /**
  63. * struct mchp_ipc_status - IPC status message format
  64. *
  65. * @status: interrupt status for all channels associated to a cluster
  66. * @cluster: specifies the cluster instance that originated an irq
  67. *
  68. * struct used by the SBI_EXT_IPC_STATUS SBI function id to get
  69. * the message present and message clear interrupt status for all the
  70. * channels associated to a cluster.
  71. */
  72. struct mchp_ipc_status {
  73. u32 status;
  74. u8 cluster;
  75. };
  76. /**
  77. * struct mchp_ipc_sbi_msg - IPC SBI payload message
  78. *
  79. * @buf_addr: physical address where the received data should be copied to
  80. * @size: maximum size(in bytes) that can be stored in the buffer pointed to by `buf`
  81. * @irq_type: mask representing the irq types that triggered an irq
  82. *
  83. * struct used by the SBI_EXT_IPC_SEND/SBI_EXT_IPC_RECEIVE SBI function
  84. * ids to send/receive a message from an associated processor using
  85. * the IPC.
  86. */
  87. struct mchp_ipc_sbi_msg {
  88. u64 buf_addr;
  89. u16 size;
  90. u8 irq_type;
  91. };
  92. struct mchp_ipc_cluster_cfg {
  93. void *buf_base;
  94. phys_addr_t buf_base_addr;
  95. int irq;
  96. };
  97. struct mchp_ipc_sbi_mbox {
  98. struct device *dev;
  99. struct mbox_chan *chans;
  100. struct mchp_ipc_cluster_cfg *cluster_cfg;
  101. void *buf_base;
  102. unsigned long buf_base_addr;
  103. struct mbox_controller controller;
  104. enum ipc_hw hw_type;
  105. };
  106. static int mchp_ipc_sbi_chan_send(u32 command, u32 channel, unsigned long address)
  107. {
  108. struct sbiret ret;
  109. ret = sbi_ecall(SBI_EXT_MICROCHIP_TECHNOLOGY, command, channel,
  110. address, 0, 0, 0, 0);
  111. if (ret.error)
  112. return sbi_err_map_linux_errno(ret.error);
  113. else
  114. return ret.value;
  115. }
  116. static int mchp_ipc_sbi_send(u32 command, unsigned long address)
  117. {
  118. struct sbiret ret;
  119. ret = sbi_ecall(SBI_EXT_MICROCHIP_TECHNOLOGY, command, address,
  120. 0, 0, 0, 0, 0);
  121. if (ret.error)
  122. return sbi_err_map_linux_errno(ret.error);
  123. else
  124. return ret.value;
  125. }
  126. static struct mchp_ipc_sbi_mbox *to_mchp_ipc_mbox(struct mbox_controller *mbox)
  127. {
  128. return container_of(mbox, struct mchp_ipc_sbi_mbox, controller);
  129. }
  130. static inline void mchp_ipc_prepare_receive_req(struct mbox_chan *chan)
  131. {
  132. struct mchp_ipc_sbi_chan *chan_info = (struct mchp_ipc_sbi_chan *)chan->con_priv;
  133. struct mchp_ipc_sbi_msg request;
  134. request.buf_addr = chan_info->msg_buf_rx_addr;
  135. request.size = chan_info->max_msg_size;
  136. memcpy(chan_info->buf_base_rx, &request, sizeof(struct mchp_ipc_sbi_msg));
  137. }
  138. static inline void mchp_ipc_process_received_data(struct mbox_chan *chan,
  139. struct mchp_ipc_msg *ipc_msg)
  140. {
  141. struct mchp_ipc_sbi_chan *chan_info = (struct mchp_ipc_sbi_chan *)chan->con_priv;
  142. struct mchp_ipc_sbi_msg sbi_msg;
  143. memcpy(&sbi_msg, chan_info->buf_base_rx, sizeof(struct mchp_ipc_sbi_msg));
  144. ipc_msg->buf = (u32 *)chan_info->msg_buf_rx;
  145. ipc_msg->size = sbi_msg.size;
  146. }
  147. static irqreturn_t mchp_ipc_cluster_aggr_isr(int irq, void *data)
  148. {
  149. struct mbox_chan *chan;
  150. struct mchp_ipc_sbi_chan *chan_info;
  151. struct mchp_ipc_sbi_mbox *ipc = (struct mchp_ipc_sbi_mbox *)data;
  152. struct mchp_ipc_msg ipc_msg;
  153. struct mchp_ipc_status status_msg;
  154. int ret;
  155. u32 i, chan_index, chan_id;
  156. bool found = false;
  157. /* Find out the hart that originated the irq */
  158. for_each_online_cpu(i) {
  159. if (irq == ipc->cluster_cfg[i].irq) {
  160. found = true;
  161. break;
  162. }
  163. }
  164. if (unlikely(!found))
  165. return IRQ_NONE;
  166. status_msg.cluster = cpuid_to_hartid_map(i);
  167. memcpy(ipc->cluster_cfg[i].buf_base, &status_msg, sizeof(struct mchp_ipc_status));
  168. ret = mchp_ipc_sbi_send(SBI_EXT_IPC_STATUS, ipc->cluster_cfg[i].buf_base_addr);
  169. if (ret < 0) {
  170. dev_err_ratelimited(ipc->dev, "could not get IHC irq status ret=%d\n", ret);
  171. return IRQ_HANDLED;
  172. }
  173. memcpy(&status_msg, ipc->cluster_cfg[i].buf_base, sizeof(struct mchp_ipc_status));
  174. /*
  175. * Iterate over each bit set in the IHC interrupt status register (IRQ_STATUS) to identify
  176. * the channel(s) that have a message to be processed/acknowledged.
  177. * The bits are organized in alternating format, where each pair of bits represents
  178. * the status of the message present and message clear interrupts for each cluster/hart
  179. * (from hart 0 to hart 5). Each cluster can have up to 5 fixed channels associated.
  180. */
  181. for_each_set_bit(i, (unsigned long *)&status_msg.status, IRQ_STATUS_BITS) {
  182. /* Find out the destination hart that triggered the interrupt */
  183. chan_index = i / 2;
  184. /*
  185. * The IP has no loopback channels, so we need to decrement the index when
  186. * the target hart has a greater index than our own
  187. */
  188. if (chan_index >= status_msg.cluster)
  189. chan_index--;
  190. /*
  191. * Calculate the channel id given the hart and channel index. Channel IDs
  192. * are unique across all clusters of an IPC, and iterate contiguously
  193. * across all clusters.
  194. */
  195. chan_id = status_msg.cluster * (NUM_CHANS_PER_CLUSTER + chan_index);
  196. chan = &ipc->chans[chan_id];
  197. chan_info = (struct mchp_ipc_sbi_chan *)chan->con_priv;
  198. if (i % 2 == 0) {
  199. mchp_ipc_prepare_receive_req(chan);
  200. ret = mchp_ipc_sbi_chan_send(SBI_EXT_IPC_RECEIVE, chan_id,
  201. chan_info->buf_base_rx_addr);
  202. if (ret < 0)
  203. continue;
  204. mchp_ipc_process_received_data(chan, &ipc_msg);
  205. mbox_chan_received_data(&ipc->chans[chan_id], (void *)&ipc_msg);
  206. } else {
  207. ret = mchp_ipc_sbi_chan_send(SBI_EXT_IPC_RECEIVE, chan_id,
  208. chan_info->buf_base_rx_addr);
  209. mbox_chan_txdone(&ipc->chans[chan_id], ret);
  210. }
  211. }
  212. return IRQ_HANDLED;
  213. }
  214. static int mchp_ipc_send_data(struct mbox_chan *chan, void *data)
  215. {
  216. struct mchp_ipc_sbi_chan *chan_info = (struct mchp_ipc_sbi_chan *)chan->con_priv;
  217. const struct mchp_ipc_msg *msg = data;
  218. struct mchp_ipc_sbi_msg sbi_payload;
  219. memcpy(chan_info->msg_buf_tx, msg->buf, msg->size);
  220. sbi_payload.buf_addr = chan_info->msg_buf_tx_addr;
  221. sbi_payload.size = msg->size;
  222. memcpy(chan_info->buf_base_tx, &sbi_payload, sizeof(sbi_payload));
  223. return mchp_ipc_sbi_chan_send(SBI_EXT_IPC_SEND, chan_info->id, chan_info->buf_base_tx_addr);
  224. }
  225. static int mchp_ipc_startup(struct mbox_chan *chan)
  226. {
  227. struct mchp_ipc_sbi_chan *chan_info = (struct mchp_ipc_sbi_chan *)chan->con_priv;
  228. struct mchp_ipc_sbi_mbox *ipc = to_mchp_ipc_mbox(chan->mbox);
  229. struct mchp_ipc_init ch_init_msg;
  230. int ret;
  231. /*
  232. * The TX base buffer is used to transmit two types of messages:
  233. * - struct mchp_ipc_init to initialize the channel
  234. * - struct mchp_ipc_sbi_msg to transmit user data/payload
  235. * Ensure the TX buffer size is large enough to accommodate either message type.
  236. */
  237. size_t max_size = max(sizeof(struct mchp_ipc_init), sizeof(struct mchp_ipc_sbi_msg));
  238. chan_info->buf_base_tx = kmalloc(max_size, GFP_KERNEL);
  239. if (!chan_info->buf_base_tx) {
  240. ret = -ENOMEM;
  241. goto fail;
  242. }
  243. chan_info->buf_base_tx_addr = __pa(chan_info->buf_base_tx);
  244. chan_info->buf_base_rx = kmalloc(max_size, GFP_KERNEL);
  245. if (!chan_info->buf_base_rx) {
  246. ret = -ENOMEM;
  247. goto fail_free_buf_base_tx;
  248. }
  249. chan_info->buf_base_rx_addr = __pa(chan_info->buf_base_rx);
  250. ret = mchp_ipc_sbi_chan_send(SBI_EXT_IPC_CH_INIT, chan_info->id,
  251. chan_info->buf_base_tx_addr);
  252. if (ret < 0) {
  253. dev_err(ipc->dev, "channel %u init failed\n", chan_info->id);
  254. goto fail_free_buf_base_rx;
  255. }
  256. memcpy(&ch_init_msg, chan_info->buf_base_tx, sizeof(struct mchp_ipc_init));
  257. chan_info->max_msg_size = ch_init_msg.max_msg_size;
  258. chan_info->msg_buf_tx = kmalloc(chan_info->max_msg_size, GFP_KERNEL);
  259. if (!chan_info->msg_buf_tx) {
  260. ret = -ENOMEM;
  261. goto fail_free_buf_base_rx;
  262. }
  263. chan_info->msg_buf_tx_addr = __pa(chan_info->msg_buf_tx);
  264. chan_info->msg_buf_rx = kmalloc(chan_info->max_msg_size, GFP_KERNEL);
  265. if (!chan_info->msg_buf_rx) {
  266. ret = -ENOMEM;
  267. goto fail_free_buf_msg_tx;
  268. }
  269. chan_info->msg_buf_rx_addr = __pa(chan_info->msg_buf_rx);
  270. switch (ipc->hw_type) {
  271. case MIV_IHC:
  272. return 0;
  273. default:
  274. goto fail_free_buf_msg_rx;
  275. }
  276. fail_free_buf_msg_rx:
  277. kfree(chan_info->msg_buf_rx);
  278. fail_free_buf_msg_tx:
  279. kfree(chan_info->msg_buf_tx);
  280. fail_free_buf_base_rx:
  281. kfree(chan_info->buf_base_rx);
  282. fail_free_buf_base_tx:
  283. kfree(chan_info->buf_base_tx);
  284. fail:
  285. return ret;
  286. }
  287. static void mchp_ipc_shutdown(struct mbox_chan *chan)
  288. {
  289. struct mchp_ipc_sbi_chan *chan_info = (struct mchp_ipc_sbi_chan *)chan->con_priv;
  290. kfree(chan_info->buf_base_tx);
  291. kfree(chan_info->buf_base_rx);
  292. kfree(chan_info->msg_buf_tx);
  293. kfree(chan_info->msg_buf_rx);
  294. }
  295. static const struct mbox_chan_ops mchp_ipc_ops = {
  296. .startup = mchp_ipc_startup,
  297. .send_data = mchp_ipc_send_data,
  298. .shutdown = mchp_ipc_shutdown,
  299. };
  300. static struct mbox_chan *mchp_ipc_mbox_xlate(struct mbox_controller *controller,
  301. const struct of_phandle_args *spec)
  302. {
  303. struct mchp_ipc_sbi_mbox *ipc = to_mchp_ipc_mbox(controller);
  304. unsigned int chan_id = spec->args[0];
  305. if (chan_id >= ipc->controller.num_chans) {
  306. dev_err(ipc->dev, "invalid channel id %d\n", chan_id);
  307. return ERR_PTR(-EINVAL);
  308. }
  309. return &ipc->chans[chan_id];
  310. }
  311. static int mchp_ipc_get_cluster_aggr_irq(struct mchp_ipc_sbi_mbox *ipc)
  312. {
  313. struct platform_device *pdev = to_platform_device(ipc->dev);
  314. char *irq_name;
  315. int cpuid, ret;
  316. unsigned long hartid;
  317. bool irq_found = false;
  318. for_each_online_cpu(cpuid) {
  319. hartid = cpuid_to_hartid_map(cpuid);
  320. irq_name = devm_kasprintf(ipc->dev, GFP_KERNEL, "hart-%lu", hartid);
  321. ret = platform_get_irq_byname_optional(pdev, irq_name);
  322. if (ret <= 0)
  323. continue;
  324. ipc->cluster_cfg[cpuid].irq = ret;
  325. ret = devm_request_irq(ipc->dev, ipc->cluster_cfg[cpuid].irq,
  326. mchp_ipc_cluster_aggr_isr, IRQF_SHARED,
  327. "miv-ihc-irq", ipc);
  328. if (ret)
  329. return ret;
  330. ipc->cluster_cfg[cpuid].buf_base = devm_kmalloc(ipc->dev,
  331. sizeof(struct mchp_ipc_status),
  332. GFP_KERNEL);
  333. if (!ipc->cluster_cfg[cpuid].buf_base)
  334. return -ENOMEM;
  335. ipc->cluster_cfg[cpuid].buf_base_addr = __pa(ipc->cluster_cfg[cpuid].buf_base);
  336. irq_found = true;
  337. }
  338. return irq_found;
  339. }
  340. static int mchp_ipc_probe(struct platform_device *pdev)
  341. {
  342. struct device *dev = &pdev->dev;
  343. struct mchp_ipc_mbox_info ipc_info;
  344. struct mchp_ipc_sbi_mbox *ipc;
  345. struct mchp_ipc_sbi_chan *priv;
  346. bool irq_avail = false;
  347. int ret;
  348. u32 chan_id;
  349. ret = sbi_probe_extension(SBI_EXT_MICROCHIP_TECHNOLOGY);
  350. if (ret <= 0)
  351. return dev_err_probe(dev, -ENODEV, "Microchip SBI extension not detected\n");
  352. ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
  353. if (!ipc)
  354. return -ENOMEM;
  355. platform_set_drvdata(pdev, ipc);
  356. ipc->buf_base = devm_kmalloc(dev, sizeof(struct mchp_ipc_mbox_info), GFP_KERNEL);
  357. if (!ipc->buf_base)
  358. return -ENOMEM;
  359. ipc->buf_base_addr = __pa(ipc->buf_base);
  360. ret = mchp_ipc_sbi_send(SBI_EXT_IPC_PROBE, ipc->buf_base_addr);
  361. if (ret < 0)
  362. return dev_err_probe(dev, ret, "could not probe IPC SBI service\n");
  363. memcpy(&ipc_info, ipc->buf_base, sizeof(struct mchp_ipc_mbox_info));
  364. ipc->controller.num_chans = ipc_info.num_channels;
  365. ipc->hw_type = ipc_info.hw_type;
  366. ipc->chans = devm_kcalloc(dev, ipc->controller.num_chans, sizeof(*ipc->chans), GFP_KERNEL);
  367. if (!ipc->chans)
  368. return -ENOMEM;
  369. ipc->dev = dev;
  370. ipc->controller.txdone_irq = true;
  371. ipc->controller.dev = ipc->dev;
  372. ipc->controller.ops = &mchp_ipc_ops;
  373. ipc->controller.chans = ipc->chans;
  374. ipc->controller.of_xlate = mchp_ipc_mbox_xlate;
  375. for (chan_id = 0; chan_id < ipc->controller.num_chans; chan_id++) {
  376. priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
  377. if (!priv)
  378. return -ENOMEM;
  379. ipc->chans[chan_id].con_priv = priv;
  380. priv->id = chan_id;
  381. }
  382. if (ipc->hw_type == MIV_IHC) {
  383. ipc->cluster_cfg = devm_kcalloc(dev, num_online_cpus(),
  384. sizeof(struct mchp_ipc_cluster_cfg),
  385. GFP_KERNEL);
  386. if (!ipc->cluster_cfg)
  387. return -ENOMEM;
  388. if (mchp_ipc_get_cluster_aggr_irq(ipc))
  389. irq_avail = true;
  390. }
  391. if (!irq_avail)
  392. return dev_err_probe(dev, -ENODEV, "missing interrupt property\n");
  393. ret = devm_mbox_controller_register(dev, &ipc->controller);
  394. if (ret)
  395. return dev_err_probe(dev, ret,
  396. "Inter-Processor communication (IPC) registration failed\n");
  397. return 0;
  398. }
  399. static const struct of_device_id mchp_ipc_of_match[] = {
  400. {.compatible = "microchip,sbi-ipc", },
  401. {}
  402. };
  403. MODULE_DEVICE_TABLE(of, mchp_ipc_of_match);
  404. static struct platform_driver mchp_ipc_driver = {
  405. .driver = {
  406. .name = "microchip_ipc",
  407. .of_match_table = mchp_ipc_of_match,
  408. },
  409. .probe = mchp_ipc_probe,
  410. };
  411. module_platform_driver(mchp_ipc_driver);
  412. MODULE_LICENSE("GPL");
  413. MODULE_AUTHOR("Valentina Fernandez <valentina.fernandezalanis@microchip.com>");
  414. MODULE_DESCRIPTION("Microchip Inter-Processor Communication (IPC) driver");