Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iohub register race condition fix #227

Merged
merged 2 commits into from
Aug 27, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 64 additions & 44 deletions src/driver/amdxdna/amdxdna_mailbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,20 @@ struct mailbox {

};

#if defined(CONFIG_DEBUG_FS)
struct mailbox_res_record {
struct list_head re_entry;
struct xdna_mailbox_chann_res re_x2i;
struct xdna_mailbox_chann_res re_i2x;
int re_irq;
};
#endif /* CONFIG_DEBUG_FS */

struct mailbox_channel {
struct mailbox *mb;
#if defined(CONFIG_DEBUG_FS)
struct list_head chann_entry;
struct mailbox_res_record *record;
#endif
struct xdna_mailbox_chann_res res[CHAN_RES_NUM];
int msix_irq;
Expand Down Expand Up @@ -134,15 +144,6 @@ struct mailbox_msg {
struct mailbox_pkg pkg;
};

#if defined(CONFIG_DEBUG_FS)
struct mailbox_res_record {
struct list_head re_entry;
struct xdna_mailbox_chann_res re_x2i;
struct xdna_mailbox_chann_res re_i2x;
int re_irq;
};
#endif /* CONFIG_DEBUG_FS */

static void mailbox_reg_write(struct mailbox_channel *mb_chann, u32 mbox_reg, u32 data)
{
struct xdna_mailbox_res *mb_res = &mb_chann->mb->res;
Expand Down Expand Up @@ -390,7 +391,8 @@ static inline int mailbox_get_msg(struct mailbox_channel *mb_chann)
return -EINVAL;
}
mailbox_set_headptr(mb_chann, 0);
return 0;
ret = 0;
goto done;
}

if (unlikely(!header.total_size || !IS_ALIGNED(header.total_size, 4))) {
Expand All @@ -417,20 +419,66 @@ static inline int mailbox_get_msg(struct mailbox_channel *mb_chann)
trace_mbox_set_head(MAILBOX_NAME, mb_chann->msix_irq,
header.opcode, header.id);

done:
return ret;
}

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);

if (READ_ONCE(mb_chann->bad_state)) {
MB_ERR(mb_chann, "Channel in bad state, work aborted");
return;
}

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 == -ENOENT)
break;

/* Other error means device doesn't look good, disable irq. */
if (unlikely(ret)) {
MB_ERR(mb_chann, "Unexpected ret %d, disable irq", ret);
WRITE_ONCE(mb_chann->bad_state, true);
disable_irq(mb_chann->msix_irq);
break;
}
}
}

static irqreturn_t mailbox_irq_handler(int irq, void *p)
{
struct mailbox_channel *mb_chann = p;
u32 iohub;
int i;

trace_mbox_irq_handle(MAILBOX_NAME, irq);
/* Schedule a rx_work to call the callback functions */
queue_work(mb_chann->work_q, &mb_chann->rx_work);
/* Clear IOHUB register */
mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
/* Schedule a rx_work to call the callback functions */
queue_work(mb_chann->work_q, &mb_chann->rx_work);
for (i = 0; i < 4; i++) {
iohub = mailbox_reg_read(mb_chann, mb_chann->iohub_int_addr);
if (iohub)
goto race;
}

return IRQ_HANDLED;
race:
mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
queue_work(mb_chann->work_q, &mb_chann->rx_work);
iohub = mailbox_reg_read(mb_chann, mb_chann->iohub_int_addr);
if (unlikely(iohub))
MB_WARN_ONCE(mb_chann, "Clear and Set interrupt race again...");
return IRQ_HANDLED;
}

#ifdef AMDXDNA_DEVEL
Expand Down Expand Up @@ -560,37 +608,6 @@ static int mailbox_polld(void *data)
}
#endif

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);

if (READ_ONCE(mb_chann->bad_state)) {
MB_ERR(mb_chann, "Channel in bad state, work aborted");
return;
}

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 == -ENOENT)
break;

/* Other error means device doesn't look good, disable irq. */
if (unlikely(ret)) {
MB_ERR(mb_chann, "Unexpected ret %d, disable irq", ret);
WRITE_ONCE(mb_chann->bad_state, true);
disable_irq(mb_chann->msix_irq);
break;
}
}
}

int xdna_mailbox_send_msg(struct mailbox_channel *mb_chann,
const struct xdna_mailbox_msg *msg, u64 tx_timeout)
{
Expand Down Expand Up @@ -810,7 +827,7 @@ xdna_mailbox_create_channel(struct mailbox *mb,
#endif

INIT_WORK(&mb_chann->rx_work, mailbox_rx_worker);
mb_chann->work_q = create_singlethread_workqueue(MAILBOX_NAME);
mb_chann->work_q = alloc_ordered_workqueue(MAILBOX_NAME, 0);
if (!mb_chann->work_q) {
MB_ERR(mb_chann, "Create workqueue failed");
goto free_and_out;
Expand Down Expand Up @@ -842,6 +859,9 @@ xdna_mailbox_create_channel(struct mailbox *mb,
list_add(&mb_chann->chann_entry, &mb->chann_list);
mutex_unlock(&mb->mbox_lock);

#if defined(CONFIG_DEBUG_FS)
mb_chann->record = record;
#endif
MB_DBG(mb_chann, "Mailbox channel created (irq: %d)", mb_chann->msix_irq);
return mb_chann;

Expand Down