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 RISC-V SBI message proxy (MPXY) based mailbox driver

Add a mailbox controller driver for the new SBI message proxy extension
which is part of the SBI v3.0 specification.

Acked-by: Jassi Brar <jassisinghbrar@gmail.com>
Co-developed-by: Rahul Pathak <rpathak@ventanamicro.com>
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Link: https://lore.kernel.org/r/20250818040920.272664-8-apatel@ventanamicro.com
Signed-off-by: Paul Walmsley <pjw@kernel.org>

authored by

Anup Patel and committed by
Paul Walmsley
bf3022a4 6f01c24f

+1007
+11
drivers/mailbox/Kconfig
··· 369 369 processor and coprocessor that handles various power management task 370 370 and more. 371 371 372 + config RISCV_SBI_MPXY_MBOX 373 + tristate "RISC-V SBI Message Proxy (MPXY) Mailbox" 374 + depends on RISCV_SBI 375 + default RISCV 376 + help 377 + Mailbox driver implementation for RISC-V SBI Message Proxy (MPXY) 378 + extension. This mailbox driver is used to send messages to the 379 + remote processor through the SBI implementation (M-mode firmware 380 + or HS-mode hypervisor). Say Y here if you want to have this support. 381 + If unsure say N. 382 + 372 383 endif
+2
drivers/mailbox/Makefile
··· 78 78 obj-$(CONFIG_CIX_MBOX) += cix-mailbox.o 79 79 80 80 obj-$(CONFIG_BCM74110_MAILBOX) += bcm74110-mailbox.o 81 + 82 + obj-$(CONFIG_RISCV_SBI_MPXY_MBOX) += riscv-sbi-mpxy-mbox.o
+994
drivers/mailbox/riscv-sbi-mpxy-mbox.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * RISC-V SBI Message Proxy (MPXY) mailbox controller driver 4 + * 5 + * Copyright (C) 2025 Ventana Micro Systems Inc. 6 + */ 7 + 8 + #include <linux/cpu.h> 9 + #include <linux/errno.h> 10 + #include <linux/init.h> 11 + #include <linux/mailbox_controller.h> 12 + #include <linux/mailbox/riscv-rpmi-message.h> 13 + #include <linux/minmax.h> 14 + #include <linux/mm.h> 15 + #include <linux/module.h> 16 + #include <linux/msi.h> 17 + #include <linux/of_irq.h> 18 + #include <linux/percpu.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/smp.h> 21 + #include <linux/string.h> 22 + #include <linux/types.h> 23 + #include <asm/byteorder.h> 24 + #include <asm/sbi.h> 25 + 26 + /* ====== SBI MPXY extension data structures ====== */ 27 + 28 + /* SBI MPXY MSI related channel attributes */ 29 + struct sbi_mpxy_msi_info { 30 + /* Lower 32-bits of the MSI target address */ 31 + u32 msi_addr_lo; 32 + /* Upper 32-bits of the MSI target address */ 33 + u32 msi_addr_hi; 34 + /* MSI data value */ 35 + u32 msi_data; 36 + }; 37 + 38 + /* 39 + * SBI MPXY standard channel attributes. 40 + * 41 + * NOTE: The sequence of attribute fields are as-per the 42 + * defined sequence in the attribute table in spec (or 43 + * as-per the enum sbi_mpxy_attribute_id). 44 + */ 45 + struct sbi_mpxy_channel_attrs { 46 + /* Message protocol ID */ 47 + u32 msg_proto_id; 48 + /* Message protocol version */ 49 + u32 msg_proto_version; 50 + /* Message protocol maximum message length */ 51 + u32 msg_max_len; 52 + /* Message protocol message send timeout in microseconds */ 53 + u32 msg_send_timeout; 54 + /* Message protocol message completion timeout in microseconds */ 55 + u32 msg_completion_timeout; 56 + /* Bit array for channel capabilities */ 57 + u32 capability; 58 + /* SSE event ID */ 59 + u32 sse_event_id; 60 + /* MSI enable/disable control knob */ 61 + u32 msi_control; 62 + /* Channel MSI info */ 63 + struct sbi_mpxy_msi_info msi_info; 64 + /* Events state control */ 65 + u32 events_state_ctrl; 66 + }; 67 + 68 + /* 69 + * RPMI specific SBI MPXY channel attributes. 70 + * 71 + * NOTE: The sequence of attribute fields are as-per the 72 + * defined sequence in the attribute table in spec (or 73 + * as-per the enum sbi_mpxy_rpmi_attribute_id). 74 + */ 75 + struct sbi_mpxy_rpmi_channel_attrs { 76 + /* RPMI service group ID */ 77 + u32 servicegroup_id; 78 + /* RPMI service group version */ 79 + u32 servicegroup_version; 80 + /* RPMI implementation ID */ 81 + u32 impl_id; 82 + /* RPMI implementation version */ 83 + u32 impl_version; 84 + }; 85 + 86 + /* SBI MPXY channel IDs data in shared memory */ 87 + struct sbi_mpxy_channel_ids_data { 88 + /* Remaining number of channel ids */ 89 + __le32 remaining; 90 + /* Returned channel ids in current function call */ 91 + __le32 returned; 92 + /* Returned channel id array */ 93 + __le32 channel_array[]; 94 + }; 95 + 96 + /* SBI MPXY notification data in shared memory */ 97 + struct sbi_mpxy_notification_data { 98 + /* Remaining number of notification events */ 99 + __le32 remaining; 100 + /* Number of notification events returned */ 101 + __le32 returned; 102 + /* Number of notification events lost */ 103 + __le32 lost; 104 + /* Reserved for future use */ 105 + __le32 reserved; 106 + /* Returned channel id array */ 107 + u8 events_data[]; 108 + }; 109 + 110 + /* ====== MPXY data structures & helper routines ====== */ 111 + 112 + /* MPXY Per-CPU or local context */ 113 + struct mpxy_local { 114 + /* Shared memory base address */ 115 + void *shmem; 116 + /* Shared memory physical address */ 117 + phys_addr_t shmem_phys_addr; 118 + /* Flag representing whether shared memory is active or not */ 119 + bool shmem_active; 120 + }; 121 + 122 + static DEFINE_PER_CPU(struct mpxy_local, mpxy_local); 123 + static unsigned long mpxy_shmem_size; 124 + static bool mpxy_shmem_init_done; 125 + 126 + static int mpxy_get_channel_count(u32 *channel_count) 127 + { 128 + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); 129 + struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem; 130 + u32 remaining, returned; 131 + struct sbiret sret; 132 + 133 + if (!mpxy->shmem_active) 134 + return -ENODEV; 135 + if (!channel_count) 136 + return -EINVAL; 137 + 138 + get_cpu(); 139 + 140 + /* Get the remaining and returned fields to calculate total */ 141 + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS, 142 + 0, 0, 0, 0, 0, 0); 143 + if (sret.error) 144 + goto err_put_cpu; 145 + 146 + remaining = le32_to_cpu(sdata->remaining); 147 + returned = le32_to_cpu(sdata->returned); 148 + *channel_count = remaining + returned; 149 + 150 + err_put_cpu: 151 + put_cpu(); 152 + return sbi_err_map_linux_errno(sret.error); 153 + } 154 + 155 + static int mpxy_get_channel_ids(u32 channel_count, u32 *channel_ids) 156 + { 157 + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); 158 + struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem; 159 + u32 remaining, returned, count, start_index = 0; 160 + struct sbiret sret; 161 + 162 + if (!mpxy->shmem_active) 163 + return -ENODEV; 164 + if (!channel_count || !channel_ids) 165 + return -EINVAL; 166 + 167 + get_cpu(); 168 + 169 + do { 170 + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS, 171 + start_index, 0, 0, 0, 0, 0); 172 + if (sret.error) 173 + goto err_put_cpu; 174 + 175 + remaining = le32_to_cpu(sdata->remaining); 176 + returned = le32_to_cpu(sdata->returned); 177 + 178 + count = returned < (channel_count - start_index) ? 179 + returned : (channel_count - start_index); 180 + memcpy_from_le32(&channel_ids[start_index], sdata->channel_array, count); 181 + start_index += count; 182 + } while (remaining && start_index < channel_count); 183 + 184 + err_put_cpu: 185 + put_cpu(); 186 + return sbi_err_map_linux_errno(sret.error); 187 + } 188 + 189 + static int mpxy_read_attrs(u32 channel_id, u32 base_attrid, u32 attr_count, 190 + u32 *attrs_buf) 191 + { 192 + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); 193 + struct sbiret sret; 194 + 195 + if (!mpxy->shmem_active) 196 + return -ENODEV; 197 + if (!attr_count || !attrs_buf) 198 + return -EINVAL; 199 + 200 + get_cpu(); 201 + 202 + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_READ_ATTRS, 203 + channel_id, base_attrid, attr_count, 0, 0, 0); 204 + if (sret.error) 205 + goto err_put_cpu; 206 + 207 + memcpy_from_le32(attrs_buf, (__le32 *)mpxy->shmem, attr_count); 208 + 209 + err_put_cpu: 210 + put_cpu(); 211 + return sbi_err_map_linux_errno(sret.error); 212 + } 213 + 214 + static int mpxy_write_attrs(u32 channel_id, u32 base_attrid, u32 attr_count, 215 + u32 *attrs_buf) 216 + { 217 + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); 218 + struct sbiret sret; 219 + 220 + if (!mpxy->shmem_active) 221 + return -ENODEV; 222 + if (!attr_count || !attrs_buf) 223 + return -EINVAL; 224 + 225 + get_cpu(); 226 + 227 + memcpy_to_le32((__le32 *)mpxy->shmem, attrs_buf, attr_count); 228 + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_WRITE_ATTRS, 229 + channel_id, base_attrid, attr_count, 0, 0, 0); 230 + 231 + put_cpu(); 232 + return sbi_err_map_linux_errno(sret.error); 233 + } 234 + 235 + static int mpxy_send_message_with_resp(u32 channel_id, u32 msg_id, 236 + void *tx, unsigned long tx_len, 237 + void *rx, unsigned long max_rx_len, 238 + unsigned long *rx_len) 239 + { 240 + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); 241 + unsigned long rx_bytes; 242 + struct sbiret sret; 243 + 244 + if (!mpxy->shmem_active) 245 + return -ENODEV; 246 + if (!tx && tx_len) 247 + return -EINVAL; 248 + 249 + get_cpu(); 250 + 251 + /* Message protocols allowed to have no data in messages */ 252 + if (tx_len) 253 + memcpy(mpxy->shmem, tx, tx_len); 254 + 255 + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SEND_MSG_WITH_RESP, 256 + channel_id, msg_id, tx_len, 0, 0, 0); 257 + if (rx && !sret.error) { 258 + rx_bytes = sret.value; 259 + if (rx_bytes > max_rx_len) { 260 + put_cpu(); 261 + return -ENOSPC; 262 + } 263 + 264 + memcpy(rx, mpxy->shmem, rx_bytes); 265 + if (rx_len) 266 + *rx_len = rx_bytes; 267 + } 268 + 269 + put_cpu(); 270 + return sbi_err_map_linux_errno(sret.error); 271 + } 272 + 273 + static int mpxy_send_message_without_resp(u32 channel_id, u32 msg_id, 274 + void *tx, unsigned long tx_len) 275 + { 276 + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); 277 + struct sbiret sret; 278 + 279 + if (!mpxy->shmem_active) 280 + return -ENODEV; 281 + if (!tx && tx_len) 282 + return -EINVAL; 283 + 284 + get_cpu(); 285 + 286 + /* Message protocols allowed to have no data in messages */ 287 + if (tx_len) 288 + memcpy(mpxy->shmem, tx, tx_len); 289 + 290 + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SEND_MSG_WITHOUT_RESP, 291 + channel_id, msg_id, tx_len, 0, 0, 0); 292 + 293 + put_cpu(); 294 + return sbi_err_map_linux_errno(sret.error); 295 + } 296 + 297 + static int mpxy_get_notifications(u32 channel_id, 298 + struct sbi_mpxy_notification_data *notif_data, 299 + unsigned long *events_data_len) 300 + { 301 + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); 302 + struct sbiret sret; 303 + 304 + if (!mpxy->shmem_active) 305 + return -ENODEV; 306 + if (!notif_data || !events_data_len) 307 + return -EINVAL; 308 + 309 + get_cpu(); 310 + 311 + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS, 312 + channel_id, 0, 0, 0, 0, 0); 313 + if (sret.error) 314 + goto err_put_cpu; 315 + 316 + memcpy(notif_data, mpxy->shmem, sret.value + 16); 317 + *events_data_len = sret.value; 318 + 319 + err_put_cpu: 320 + put_cpu(); 321 + return sbi_err_map_linux_errno(sret.error); 322 + } 323 + 324 + static int mpxy_get_shmem_size(unsigned long *shmem_size) 325 + { 326 + struct sbiret sret; 327 + 328 + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_SHMEM_SIZE, 329 + 0, 0, 0, 0, 0, 0); 330 + if (sret.error) 331 + return sbi_err_map_linux_errno(sret.error); 332 + if (shmem_size) 333 + *shmem_size = sret.value; 334 + return 0; 335 + } 336 + 337 + static int mpxy_setup_shmem(unsigned int cpu) 338 + { 339 + struct page *shmem_page; 340 + struct mpxy_local *mpxy; 341 + struct sbiret sret; 342 + 343 + mpxy = per_cpu_ptr(&mpxy_local, cpu); 344 + if (mpxy->shmem_active) 345 + return 0; 346 + 347 + shmem_page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(mpxy_shmem_size)); 348 + if (!shmem_page) 349 + return -ENOMEM; 350 + 351 + /* 352 + * Linux setup of shmem is done in mpxy OVERWRITE mode. 353 + * flags[1:0] = 00b 354 + */ 355 + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SET_SHMEM, 356 + page_to_phys(shmem_page), 0, 0, 0, 0, 0); 357 + if (sret.error) { 358 + free_pages((unsigned long)page_to_virt(shmem_page), 359 + get_order(mpxy_shmem_size)); 360 + return sbi_err_map_linux_errno(sret.error); 361 + } 362 + 363 + mpxy->shmem = page_to_virt(shmem_page); 364 + mpxy->shmem_phys_addr = page_to_phys(shmem_page); 365 + mpxy->shmem_active = true; 366 + 367 + return 0; 368 + } 369 + 370 + /* ====== MPXY mailbox data structures ====== */ 371 + 372 + /* MPXY mailbox channel */ 373 + struct mpxy_mbox_channel { 374 + struct mpxy_mbox *mbox; 375 + u32 channel_id; 376 + struct sbi_mpxy_channel_attrs attrs; 377 + struct sbi_mpxy_rpmi_channel_attrs rpmi_attrs; 378 + struct sbi_mpxy_notification_data *notif; 379 + u32 max_xfer_len; 380 + bool have_events_state; 381 + u32 msi_index; 382 + u32 msi_irq; 383 + bool started; 384 + }; 385 + 386 + /* MPXY mailbox */ 387 + struct mpxy_mbox { 388 + struct device *dev; 389 + u32 channel_count; 390 + struct mpxy_mbox_channel *channels; 391 + u32 msi_count; 392 + struct mpxy_mbox_channel **msi_index_to_channel; 393 + struct mbox_controller controller; 394 + }; 395 + 396 + /* ====== MPXY RPMI processing ====== */ 397 + 398 + static void mpxy_mbox_send_rpmi_data(struct mpxy_mbox_channel *mchan, 399 + struct rpmi_mbox_message *msg) 400 + { 401 + msg->error = 0; 402 + switch (msg->type) { 403 + case RPMI_MBOX_MSG_TYPE_GET_ATTRIBUTE: 404 + switch (msg->attr.id) { 405 + case RPMI_MBOX_ATTR_SPEC_VERSION: 406 + msg->attr.value = mchan->attrs.msg_proto_version; 407 + break; 408 + case RPMI_MBOX_ATTR_MAX_MSG_DATA_SIZE: 409 + msg->attr.value = mchan->max_xfer_len; 410 + break; 411 + case RPMI_MBOX_ATTR_SERVICEGROUP_ID: 412 + msg->attr.value = mchan->rpmi_attrs.servicegroup_id; 413 + break; 414 + case RPMI_MBOX_ATTR_SERVICEGROUP_VERSION: 415 + msg->attr.value = mchan->rpmi_attrs.servicegroup_version; 416 + break; 417 + case RPMI_MBOX_ATTR_IMPL_ID: 418 + msg->attr.value = mchan->rpmi_attrs.impl_id; 419 + break; 420 + case RPMI_MBOX_ATTR_IMPL_VERSION: 421 + msg->attr.value = mchan->rpmi_attrs.impl_version; 422 + break; 423 + default: 424 + msg->error = -EOPNOTSUPP; 425 + break; 426 + } 427 + break; 428 + case RPMI_MBOX_MSG_TYPE_SET_ATTRIBUTE: 429 + /* None of the RPMI linux mailbox attributes are writeable */ 430 + msg->error = -EOPNOTSUPP; 431 + break; 432 + case RPMI_MBOX_MSG_TYPE_SEND_WITH_RESPONSE: 433 + if ((!msg->data.request && msg->data.request_len) || 434 + (msg->data.request && msg->data.request_len > mchan->max_xfer_len) || 435 + (!msg->data.response && msg->data.max_response_len)) { 436 + msg->error = -EINVAL; 437 + break; 438 + } 439 + if (!(mchan->attrs.capability & SBI_MPXY_CHAN_CAP_SEND_WITH_RESP)) { 440 + msg->error = -EIO; 441 + break; 442 + } 443 + msg->error = mpxy_send_message_with_resp(mchan->channel_id, 444 + msg->data.service_id, 445 + msg->data.request, 446 + msg->data.request_len, 447 + msg->data.response, 448 + msg->data.max_response_len, 449 + &msg->data.out_response_len); 450 + break; 451 + case RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE: 452 + if ((!msg->data.request && msg->data.request_len) || 453 + (msg->data.request && msg->data.request_len > mchan->max_xfer_len)) { 454 + msg->error = -EINVAL; 455 + break; 456 + } 457 + if (!(mchan->attrs.capability & SBI_MPXY_CHAN_CAP_SEND_WITHOUT_RESP)) { 458 + msg->error = -EIO; 459 + break; 460 + } 461 + msg->error = mpxy_send_message_without_resp(mchan->channel_id, 462 + msg->data.service_id, 463 + msg->data.request, 464 + msg->data.request_len); 465 + break; 466 + default: 467 + msg->error = -EOPNOTSUPP; 468 + break; 469 + } 470 + } 471 + 472 + static void mpxy_mbox_peek_rpmi_data(struct mbox_chan *chan, 473 + struct mpxy_mbox_channel *mchan, 474 + struct sbi_mpxy_notification_data *notif, 475 + unsigned long events_data_len) 476 + { 477 + struct rpmi_notification_event *event; 478 + struct rpmi_mbox_message msg; 479 + unsigned long pos = 0; 480 + 481 + while (pos < events_data_len && (events_data_len - pos) <= sizeof(*event)) { 482 + event = (struct rpmi_notification_event *)(notif->events_data + pos); 483 + 484 + msg.type = RPMI_MBOX_MSG_TYPE_NOTIFICATION_EVENT; 485 + msg.notif.event_datalen = le16_to_cpu(event->event_datalen); 486 + msg.notif.event_id = event->event_id; 487 + msg.notif.event_data = event->event_data; 488 + msg.error = 0; 489 + 490 + mbox_chan_received_data(chan, &msg); 491 + pos += sizeof(*event) + msg.notif.event_datalen; 492 + } 493 + } 494 + 495 + static int mpxy_mbox_read_rpmi_attrs(struct mpxy_mbox_channel *mchan) 496 + { 497 + return mpxy_read_attrs(mchan->channel_id, 498 + SBI_MPXY_ATTR_MSGPROTO_ATTR_START, 499 + sizeof(mchan->rpmi_attrs) / sizeof(u32), 500 + (u32 *)&mchan->rpmi_attrs); 501 + } 502 + 503 + /* ====== MPXY mailbox callbacks ====== */ 504 + 505 + static int mpxy_mbox_send_data(struct mbox_chan *chan, void *data) 506 + { 507 + struct mpxy_mbox_channel *mchan = chan->con_priv; 508 + 509 + if (mchan->attrs.msg_proto_id == SBI_MPXY_MSGPROTO_RPMI_ID) { 510 + mpxy_mbox_send_rpmi_data(mchan, data); 511 + return 0; 512 + } 513 + 514 + return -EOPNOTSUPP; 515 + } 516 + 517 + static bool mpxy_mbox_peek_data(struct mbox_chan *chan) 518 + { 519 + struct mpxy_mbox_channel *mchan = chan->con_priv; 520 + struct sbi_mpxy_notification_data *notif = mchan->notif; 521 + bool have_notifications = false; 522 + unsigned long data_len; 523 + int rc; 524 + 525 + if (!(mchan->attrs.capability & SBI_MPXY_CHAN_CAP_GET_NOTIFICATIONS)) 526 + return false; 527 + 528 + do { 529 + rc = mpxy_get_notifications(mchan->channel_id, notif, &data_len); 530 + if (rc || !data_len) 531 + break; 532 + 533 + if (mchan->attrs.msg_proto_id == SBI_MPXY_MSGPROTO_RPMI_ID) 534 + mpxy_mbox_peek_rpmi_data(chan, mchan, notif, data_len); 535 + 536 + have_notifications = true; 537 + } while (1); 538 + 539 + return have_notifications; 540 + } 541 + 542 + static irqreturn_t mpxy_mbox_irq_thread(int irq, void *dev_id) 543 + { 544 + mpxy_mbox_peek_data(dev_id); 545 + return IRQ_HANDLED; 546 + } 547 + 548 + static int mpxy_mbox_setup_msi(struct mbox_chan *chan, 549 + struct mpxy_mbox_channel *mchan) 550 + { 551 + struct device *dev = mchan->mbox->dev; 552 + int rc; 553 + 554 + /* Do nothing if MSI not supported */ 555 + if (mchan->msi_irq == U32_MAX) 556 + return 0; 557 + 558 + /* Fail if MSI already enabled */ 559 + if (mchan->attrs.msi_control) 560 + return -EALREADY; 561 + 562 + /* Request channel MSI handler */ 563 + rc = request_threaded_irq(mchan->msi_irq, NULL, mpxy_mbox_irq_thread, 564 + 0, dev_name(dev), chan); 565 + if (rc) { 566 + dev_err(dev, "failed to request MPXY channel 0x%x IRQ\n", 567 + mchan->channel_id); 568 + return rc; 569 + } 570 + 571 + /* Enable channel MSI control */ 572 + mchan->attrs.msi_control = 1; 573 + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_CONTROL, 574 + 1, &mchan->attrs.msi_control); 575 + if (rc) { 576 + dev_err(dev, "enable MSI control failed for MPXY channel 0x%x\n", 577 + mchan->channel_id); 578 + mchan->attrs.msi_control = 0; 579 + free_irq(mchan->msi_irq, chan); 580 + return rc; 581 + } 582 + 583 + return 0; 584 + } 585 + 586 + static void mpxy_mbox_cleanup_msi(struct mbox_chan *chan, 587 + struct mpxy_mbox_channel *mchan) 588 + { 589 + struct device *dev = mchan->mbox->dev; 590 + int rc; 591 + 592 + /* Do nothing if MSI not supported */ 593 + if (mchan->msi_irq == U32_MAX) 594 + return; 595 + 596 + /* Do nothing if MSI already disabled */ 597 + if (!mchan->attrs.msi_control) 598 + return; 599 + 600 + /* Disable channel MSI control */ 601 + mchan->attrs.msi_control = 0; 602 + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_CONTROL, 603 + 1, &mchan->attrs.msi_control); 604 + if (rc) { 605 + dev_err(dev, "disable MSI control failed for MPXY channel 0x%x\n", 606 + mchan->channel_id); 607 + } 608 + 609 + /* Free channel MSI handler */ 610 + free_irq(mchan->msi_irq, chan); 611 + } 612 + 613 + static int mpxy_mbox_setup_events(struct mpxy_mbox_channel *mchan) 614 + { 615 + struct device *dev = mchan->mbox->dev; 616 + int rc; 617 + 618 + /* Do nothing if events state not supported */ 619 + if (!mchan->have_events_state) 620 + return 0; 621 + 622 + /* Fail if events state already enabled */ 623 + if (mchan->attrs.events_state_ctrl) 624 + return -EALREADY; 625 + 626 + /* Enable channel events state */ 627 + mchan->attrs.events_state_ctrl = 1; 628 + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_EVENTS_STATE_CONTROL, 629 + 1, &mchan->attrs.events_state_ctrl); 630 + if (rc) { 631 + dev_err(dev, "enable events state failed for MPXY channel 0x%x\n", 632 + mchan->channel_id); 633 + mchan->attrs.events_state_ctrl = 0; 634 + return rc; 635 + } 636 + 637 + return 0; 638 + } 639 + 640 + static void mpxy_mbox_cleanup_events(struct mpxy_mbox_channel *mchan) 641 + { 642 + struct device *dev = mchan->mbox->dev; 643 + int rc; 644 + 645 + /* Do nothing if events state not supported */ 646 + if (!mchan->have_events_state) 647 + return; 648 + 649 + /* Do nothing if events state already disabled */ 650 + if (!mchan->attrs.events_state_ctrl) 651 + return; 652 + 653 + /* Disable channel events state */ 654 + mchan->attrs.events_state_ctrl = 0; 655 + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_EVENTS_STATE_CONTROL, 656 + 1, &mchan->attrs.events_state_ctrl); 657 + if (rc) 658 + dev_err(dev, "disable events state failed for MPXY channel 0x%x\n", 659 + mchan->channel_id); 660 + } 661 + 662 + static int mpxy_mbox_startup(struct mbox_chan *chan) 663 + { 664 + struct mpxy_mbox_channel *mchan = chan->con_priv; 665 + int rc; 666 + 667 + if (mchan->started) 668 + return -EALREADY; 669 + 670 + /* Setup channel MSI */ 671 + rc = mpxy_mbox_setup_msi(chan, mchan); 672 + if (rc) 673 + return rc; 674 + 675 + /* Setup channel notification events */ 676 + rc = mpxy_mbox_setup_events(mchan); 677 + if (rc) { 678 + mpxy_mbox_cleanup_msi(chan, mchan); 679 + return rc; 680 + } 681 + 682 + /* Mark the channel as started */ 683 + mchan->started = true; 684 + 685 + return 0; 686 + } 687 + 688 + static void mpxy_mbox_shutdown(struct mbox_chan *chan) 689 + { 690 + struct mpxy_mbox_channel *mchan = chan->con_priv; 691 + 692 + if (!mchan->started) 693 + return; 694 + 695 + /* Mark the channel as stopped */ 696 + mchan->started = false; 697 + 698 + /* Cleanup channel notification events */ 699 + mpxy_mbox_cleanup_events(mchan); 700 + 701 + /* Cleanup channel MSI */ 702 + mpxy_mbox_cleanup_msi(chan, mchan); 703 + } 704 + 705 + static const struct mbox_chan_ops mpxy_mbox_ops = { 706 + .send_data = mpxy_mbox_send_data, 707 + .peek_data = mpxy_mbox_peek_data, 708 + .startup = mpxy_mbox_startup, 709 + .shutdown = mpxy_mbox_shutdown, 710 + }; 711 + 712 + /* ====== MPXY platform driver ===== */ 713 + 714 + static void mpxy_mbox_msi_write(struct msi_desc *desc, struct msi_msg *msg) 715 + { 716 + struct device *dev = msi_desc_to_dev(desc); 717 + struct mpxy_mbox *mbox = dev_get_drvdata(dev); 718 + struct mpxy_mbox_channel *mchan; 719 + struct sbi_mpxy_msi_info *minfo; 720 + int rc; 721 + 722 + mchan = mbox->msi_index_to_channel[desc->msi_index]; 723 + if (!mchan) { 724 + dev_warn(dev, "MPXY channel not available for MSI index %d\n", 725 + desc->msi_index); 726 + return; 727 + } 728 + 729 + minfo = &mchan->attrs.msi_info; 730 + minfo->msi_addr_lo = msg->address_lo; 731 + minfo->msi_addr_hi = msg->address_hi; 732 + minfo->msi_data = msg->data; 733 + 734 + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_ADDR_LO, 735 + sizeof(*minfo) / sizeof(u32), (u32 *)minfo); 736 + if (rc) { 737 + dev_warn(dev, "failed to write MSI info for MPXY channel 0x%x\n", 738 + mchan->channel_id); 739 + } 740 + } 741 + 742 + static struct mbox_chan *mpxy_mbox_fw_xlate(struct mbox_controller *ctlr, 743 + const struct fwnode_reference_args *pa) 744 + { 745 + struct mpxy_mbox *mbox = container_of(ctlr, struct mpxy_mbox, controller); 746 + struct mpxy_mbox_channel *mchan; 747 + u32 i; 748 + 749 + if (pa->nargs != 2) 750 + return ERR_PTR(-EINVAL); 751 + 752 + for (i = 0; i < mbox->channel_count; i++) { 753 + mchan = &mbox->channels[i]; 754 + if (mchan->channel_id == pa->args[0] && 755 + mchan->attrs.msg_proto_id == pa->args[1]) 756 + return &mbox->controller.chans[i]; 757 + } 758 + 759 + return ERR_PTR(-ENOENT); 760 + } 761 + 762 + static int mpxy_mbox_populate_channels(struct mpxy_mbox *mbox) 763 + { 764 + u32 i, *channel_ids __free(kfree) = NULL; 765 + struct mpxy_mbox_channel *mchan; 766 + int rc; 767 + 768 + /* Find-out of number of channels */ 769 + rc = mpxy_get_channel_count(&mbox->channel_count); 770 + if (rc) 771 + return dev_err_probe(mbox->dev, rc, "failed to get number of MPXY channels\n"); 772 + if (!mbox->channel_count) 773 + return dev_err_probe(mbox->dev, -ENODEV, "no MPXY channels available\n"); 774 + 775 + /* Allocate and fetch all channel IDs */ 776 + channel_ids = kcalloc(mbox->channel_count, sizeof(*channel_ids), GFP_KERNEL); 777 + if (!channel_ids) 778 + return -ENOMEM; 779 + rc = mpxy_get_channel_ids(mbox->channel_count, channel_ids); 780 + if (rc) 781 + return dev_err_probe(mbox->dev, rc, "failed to get MPXY channel IDs\n"); 782 + 783 + /* Populate all channels */ 784 + mbox->channels = devm_kcalloc(mbox->dev, mbox->channel_count, 785 + sizeof(*mbox->channels), GFP_KERNEL); 786 + if (!mbox->channels) 787 + return -ENOMEM; 788 + for (i = 0; i < mbox->channel_count; i++) { 789 + mchan = &mbox->channels[i]; 790 + mchan->mbox = mbox; 791 + mchan->channel_id = channel_ids[i]; 792 + 793 + rc = mpxy_read_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSG_PROT_ID, 794 + sizeof(mchan->attrs) / sizeof(u32), 795 + (u32 *)&mchan->attrs); 796 + if (rc) { 797 + return dev_err_probe(mbox->dev, rc, 798 + "MPXY channel 0x%x read attrs failed\n", 799 + mchan->channel_id); 800 + } 801 + 802 + if (mchan->attrs.msg_proto_id == SBI_MPXY_MSGPROTO_RPMI_ID) { 803 + rc = mpxy_mbox_read_rpmi_attrs(mchan); 804 + if (rc) { 805 + return dev_err_probe(mbox->dev, rc, 806 + "MPXY channel 0x%x read RPMI attrs failed\n", 807 + mchan->channel_id); 808 + } 809 + } 810 + 811 + mchan->notif = devm_kzalloc(mbox->dev, mpxy_shmem_size, GFP_KERNEL); 812 + if (!mchan->notif) 813 + return -ENOMEM; 814 + 815 + mchan->max_xfer_len = min(mpxy_shmem_size, mchan->attrs.msg_max_len); 816 + 817 + if ((mchan->attrs.capability & SBI_MPXY_CHAN_CAP_GET_NOTIFICATIONS) && 818 + (mchan->attrs.capability & SBI_MPXY_CHAN_CAP_EVENTS_STATE)) 819 + mchan->have_events_state = true; 820 + 821 + if ((mchan->attrs.capability & SBI_MPXY_CHAN_CAP_GET_NOTIFICATIONS) && 822 + (mchan->attrs.capability & SBI_MPXY_CHAN_CAP_MSI)) 823 + mchan->msi_index = mbox->msi_count++; 824 + else 825 + mchan->msi_index = U32_MAX; 826 + mchan->msi_irq = U32_MAX; 827 + } 828 + 829 + return 0; 830 + } 831 + 832 + static int mpxy_mbox_probe(struct platform_device *pdev) 833 + { 834 + struct device *dev = &pdev->dev; 835 + struct mpxy_mbox_channel *mchan; 836 + struct mpxy_mbox *mbox; 837 + int msi_idx, rc; 838 + u32 i; 839 + 840 + /* 841 + * Initialize MPXY shared memory only once. This also ensures 842 + * that SBI MPXY mailbox is probed only once. 843 + */ 844 + if (mpxy_shmem_init_done) { 845 + dev_err(dev, "SBI MPXY mailbox already initialized\n"); 846 + return -EALREADY; 847 + } 848 + 849 + /* Probe for SBI MPXY extension */ 850 + if (sbi_spec_version < sbi_mk_version(1, 0) || 851 + sbi_probe_extension(SBI_EXT_MPXY) <= 0) { 852 + dev_info(dev, "SBI MPXY extension not available\n"); 853 + return -ENODEV; 854 + } 855 + 856 + /* Find-out shared memory size */ 857 + rc = mpxy_get_shmem_size(&mpxy_shmem_size); 858 + if (rc) 859 + return dev_err_probe(dev, rc, "failed to get MPXY shared memory size\n"); 860 + 861 + /* 862 + * Setup MPXY shared memory on each CPU 863 + * 864 + * Note: Don't cleanup MPXY shared memory upon CPU power-down 865 + * because the RPMI System MSI irqchip driver needs it to be 866 + * available when migrating IRQs in CPU power-down path. 867 + */ 868 + cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/sbi-mpxy-shmem", 869 + mpxy_setup_shmem, NULL); 870 + 871 + /* Mark as MPXY shared memory initialization done */ 872 + mpxy_shmem_init_done = true; 873 + 874 + /* Allocate mailbox instance */ 875 + mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); 876 + if (!mbox) 877 + return -ENOMEM; 878 + mbox->dev = dev; 879 + platform_set_drvdata(pdev, mbox); 880 + 881 + /* Populate mailbox channels */ 882 + rc = mpxy_mbox_populate_channels(mbox); 883 + if (rc) 884 + return rc; 885 + 886 + /* Initialize mailbox controller */ 887 + mbox->controller.txdone_irq = false; 888 + mbox->controller.txdone_poll = false; 889 + mbox->controller.ops = &mpxy_mbox_ops; 890 + mbox->controller.dev = dev; 891 + mbox->controller.num_chans = mbox->channel_count; 892 + mbox->controller.fw_xlate = mpxy_mbox_fw_xlate; 893 + mbox->controller.chans = devm_kcalloc(dev, mbox->channel_count, 894 + sizeof(*mbox->controller.chans), 895 + GFP_KERNEL); 896 + if (!mbox->controller.chans) 897 + return -ENOMEM; 898 + for (i = 0; i < mbox->channel_count; i++) 899 + mbox->controller.chans[i].con_priv = &mbox->channels[i]; 900 + 901 + /* Setup MSIs for mailbox (if required) */ 902 + if (mbox->msi_count) { 903 + /* 904 + * The device MSI domain for platform devices on RISC-V architecture 905 + * is only available after the MSI controller driver is probed so, 906 + * explicitly configure here. 907 + */ 908 + if (!dev_get_msi_domain(dev)) { 909 + /* 910 + * The device MSI domain for OF devices is only set at the 911 + * time of populating/creating OF device. If the device MSI 912 + * domain is discovered later after the OF device is created 913 + * then we need to set it explicitly before using any platform 914 + * MSI functions. 915 + */ 916 + if (dev_of_node(dev)) 917 + of_msi_configure(dev, dev_of_node(dev)); 918 + 919 + if (!dev_get_msi_domain(dev)) 920 + return -EPROBE_DEFER; 921 + } 922 + 923 + mbox->msi_index_to_channel = devm_kcalloc(dev, mbox->msi_count, 924 + sizeof(*mbox->msi_index_to_channel), 925 + GFP_KERNEL); 926 + if (!mbox->msi_index_to_channel) 927 + return -ENOMEM; 928 + 929 + for (msi_idx = 0; msi_idx < mbox->msi_count; msi_idx++) { 930 + for (i = 0; i < mbox->channel_count; i++) { 931 + mchan = &mbox->channels[i]; 932 + if (mchan->msi_index == msi_idx) { 933 + mbox->msi_index_to_channel[msi_idx] = mchan; 934 + break; 935 + } 936 + } 937 + } 938 + 939 + rc = platform_device_msi_init_and_alloc_irqs(dev, mbox->msi_count, 940 + mpxy_mbox_msi_write); 941 + if (rc) { 942 + return dev_err_probe(dev, rc, "Failed to allocate %d MSIs\n", 943 + mbox->msi_count); 944 + } 945 + 946 + for (i = 0; i < mbox->channel_count; i++) { 947 + mchan = &mbox->channels[i]; 948 + if (mchan->msi_index == U32_MAX) 949 + continue; 950 + mchan->msi_irq = msi_get_virq(dev, mchan->msi_index); 951 + } 952 + } 953 + 954 + /* Register mailbox controller */ 955 + rc = devm_mbox_controller_register(dev, &mbox->controller); 956 + if (rc) { 957 + dev_err_probe(dev, rc, "Registering SBI MPXY mailbox failed\n"); 958 + if (mbox->msi_count) 959 + platform_device_msi_free_irqs_all(dev); 960 + return rc; 961 + } 962 + 963 + dev_info(dev, "mailbox registered with %d channels\n", 964 + mbox->channel_count); 965 + return 0; 966 + } 967 + 968 + static void mpxy_mbox_remove(struct platform_device *pdev) 969 + { 970 + struct mpxy_mbox *mbox = platform_get_drvdata(pdev); 971 + 972 + if (mbox->msi_count) 973 + platform_device_msi_free_irqs_all(mbox->dev); 974 + } 975 + 976 + static const struct of_device_id mpxy_mbox_of_match[] = { 977 + { .compatible = "riscv,sbi-mpxy-mbox" }, 978 + {} 979 + }; 980 + MODULE_DEVICE_TABLE(of, mpxy_mbox_of_match); 981 + 982 + static struct platform_driver mpxy_mbox_driver = { 983 + .driver = { 984 + .name = "riscv-sbi-mpxy-mbox", 985 + .of_match_table = mpxy_mbox_of_match, 986 + }, 987 + .probe = mpxy_mbox_probe, 988 + .remove = mpxy_mbox_remove, 989 + }; 990 + module_platform_driver(mpxy_mbox_driver); 991 + 992 + MODULE_LICENSE("GPL"); 993 + MODULE_AUTHOR("Anup Patel <apatel@ventanamicro.com>"); 994 + MODULE_DESCRIPTION("RISC-V SBI MPXY mailbox controller driver");