はじめに
AMD XDNA Driver for Linux を覗いてみる (その3)
今回は、mailbox 関連を見ていきます。
amdxdna_mailbox.c
amdxdna_mailbox.c で、Host と XDAN 間の mailbox を実装しています。
memcpy(&record->re_x2i, x2i, sizeof(*x2i)); memcpy(&record->re_i2x, i2x, sizeof(*i2x));
re_x2i と re_i2x で双方向のメッセージ通信をやっていますね。
INIT_WORK(&mb_chann->rx_work, mailbox_rx_worker); mb_chann->work_q = create_singlethread_workqueue(mb->name);
受信側は、mailbox_rx_worker にて行っています。
static void mailbox_rx_worker(struct work_struct *rx_work) { struct mailbox_channel *mb_chann; int ret; mb_chann = container_of(rx_work, struct mailbox_channel, rx_work); while (1) { /* * If return is 0, keep consuming next message, until there is * no messages or an error happened. */ ret = mailbox_get_msg(mb_chann); if (ret) break; } }
下記のmailbox_get_msgを呼び出しているだけですね。
static inline int mailbox_get_msg(struct mailbox_channel *mb_chann) { struct xdna_msg_header header; u32 ringbuf_size; u32 head, tail; u32 start_addr; u64 read_addr; u32 msg_size; u32 val;
tail = mailbox_get_tailptr(mb_chann, CHAN_RES_I2X);
head = mb_chann->i2x_head;
ringbuf_size = mailbox_get_ringbuf_size(mb_chann, CHAN_RES_I2X);
start_addr = mb_chann->res[CHAN_RES_I2X].rb_start_addr;
/* ringbuf empty */
if ((head & (ringbuf_size - 1)) == (tail & (ringbuf_size - 1)))
return -ENOENT;
if (head == ringbuf_size)
head = 0;
/* Peek size of the message or TOMBSTONE */
read_addr = mb_chann->mb->res.ringbuf_base + start_addr + head;
val = ioread32((void *)read_addr);
/* The first word could be total size or TOMBSTONE */
if (val == TOMBSTONE) {
mailbox_set_headptr(mb_chann, 0);
return 0;
}
msg_size = val;
memcpy_fromio(&header, (void *)read_addr, sizeof(header));
if (msg_size + sizeof(header) > tail - head) {
WARN_ONCE(1, "Invalid message size %d, tail %d, head %d\n",
msg_size, tail, head);
return -EINVAL;
}
read_addr += sizeof(header);
if (header.id < ASYNC_MSG_START_ID)
mailbox_get_resp(mb_chann, &header, (u32 *)read_addr);
else
mailbox_get_async_msg(mb_chann, &header, (u32 *)read_addr);
mailbox_set_headptr(mb_chann, head + sizeof(header) + msg_size);
/* After update head, it can equal to ringbuf_size. This is expected. */
trace_mbox_set_head(mb_chann->mb->name, mb_chann->msix_irq,
header.opcode, header.id);
return 0;
}
割り込みハンドラ[mailbox_irq_handler](https://github.com/amd/xdna-driver/blob/main/src/driver/amdxdna/amdxdna_mailbox.c#L378-L388)を登録しています。
/* Everything look good. Time to enable irq handler */
ret = request_irq(mb_irq, mailbox_irq_handler, 0, mb->name, mb_chann);
mailbox_riq_hanlder では、色々とやらずに、上記の create_singlethread_workqueue で生成した、mb_chann->work_q をスケジュールしていますね。 work_q (mailbox_rx_worker)の中で行います。
static irqreturn_t mailbox_irq_handler(int irq, void p) { struct mailbox_channel mb_chann = p;
trace_mbox_irq_handle(mb_chann->mb->name, irq);
/* Schedule a rx_work to call the callback functions */
queue_work(mb_chann->work_q, &mb_chann->rx_work);
mailbox_clear_msix_intr(mb_chann);
return IRQ_HANDLED;
}
# おわりに 今回は、mailbox 関連をみてみました。