Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mailbox: add Microchip IPC support

Add a mailbox controller driver for the Microchip Inter-processor
Communication (IPC), which is used to send and receive data between
processors.

The driver uses the RISC-V Supervisor Binary Interface (SBI) to
communicate with software running in machine mode (M-mode) to access
the IPC hardware block.

Additional details on the Microchip vendor extension and the IPC
function IDs described in the driver can be found in the following
documentation:

https://github.com/linux4microchip/microchip-sbi-ecall-extension

This SBI interface in this driver is compatible with the Mi-V Inter-hart
Communication (IHC) IP.

Transmitting and receiving data through the mailbox framework is done
through struct mchp_ipc_msg.

Signed-off-by: Valentina Fernandez <valentina.fernandezalanis@microchip.com>
Signed-off-by: Jassi Brar <jassisinghbrar@gmail.com>

authored by

Valentina Fernandez and committed by
Jassi Brar
e4b1d67e af33bd58

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