Skip to content

Commit

Permalink
rtio: Add pollable queue of iodevs
Browse files Browse the repository at this point in the history
In some instances IO devices are better off being polled for work
completion or moving state machines forward. Shifting the responsibility
of device polling to the context avoids duplicating this possible need
in each iodev. In addition it allows for submit to be simply a queue
push while poll is where real work is done if needed avoiding a possible
deep call stack where submitting results in more submits and interrupts.

Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
  • Loading branch information
teburd committed Sep 13, 2023
1 parent f541a08 commit 4def8ce
Showing 1 changed file with 73 additions and 1 deletion.
74 changes: 73 additions & 1 deletion include/zephyr/rtio/rtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,9 @@ struct rtio {

/* Completion queue */
struct rtio_mpsc cq;

/* iodev poll queue head */
struct rtio_mpsc iodev_poll_q;
};

/** The memory partition associated with all RTIO context information */
Expand Down Expand Up @@ -424,6 +427,24 @@ struct rtio_iodev_api {
* @param iodev_sqe Submission queue entry
*/
void (*submit)(struct rtio_iodev_sqe *iodev_sqe);

/**
* @brief Poll the iodev
*
* Upon submit, if blocking incremental work is needed the iodev
* may request from the RTIO context to be polled when the next poll
* iteration occurs.
*
* This may be used for short blocking work or polling hardware for
* completion in the future. Using poll ensures the call stack remains
* relatively shallow while also batching the blocking work to some other
* call context as submit may be called in high priority ISR context.
*
* @param iodev IODev to poll
* @retval true Poll again, more polling required.
* @retval false Do not poll again, polling complete.
*/
bool (*poll)(struct rtio_iodev *iodev);
};

/**
Expand All @@ -433,7 +454,10 @@ struct rtio_iodev {
/* Function pointer table */
const struct rtio_iodev_api *api;

/* Queue of RTIO contexts with requests */
/* Queue member of iodevs awaiting polling */
struct rtio_mpsc_node iodev_poll_q;

/* Queue of submissions for this iodev */
struct rtio_mpsc iodev_sq;

/* Data associated with this iodev */
Expand Down Expand Up @@ -1438,6 +1462,54 @@ static inline int z_impl_rtio_submit(struct rtio *r, uint32_t wait_count)
return res;
}

/**
* @brief Add the iodev to the poll queue
*
* At any point if an iodev wishes to be polled to move work forward it may
* add an iodev to the poll queue. Polling may be used to check on hardware
* registers for work completion when interrupts are unwanted *or* in the case
* where the iodev represents a state machine and poll may be used to push the
* state machine forward avoiding deeply nested calls.
*
* @note This should only be called by the iodev when it wishes to be polled.
*
* @param r RTIO context
* @param iodev RTIO iodev to be polled
*/
static inline void rtio_poll_q_push(struct rtio *r, struct rtio_iodev *iodev)
{
rtio_mpsc_push(&r->iodev_poll_q, &iodev->iodev_poll_q);
}

/**
* @brief Attempt to poll the next iodev in the queue
*
* When iodevs are enqueued to be polled, rtio_poll will pop the next awaiting
* iodev and call its poll function. This function may automatically re-add
* the iodev to the queue if its not yet done.
*
* @param r RTIO context to poll on
* @retval iodev Pointer to the iodev that was polled
* @retval NULL If no iodev was polled
*/
static inline struct rtio_iodev *rtio_poll_one(struct rtio *r)
{
struct rtio_mpsc_node *next = rtio_mpsc_pop(&r->iodev_poll_q);

if (next == NULL) {
return NULL;
}

struct rtio_iodev *iodev = CONTAINER_OF(next, struct rtio_iodev, iodev_poll_q);
bool poll_again = iodev->api->poll(iodev);

if (poll_again) {
rtio_poll_q_push(r, iodev);
}

return iodev;
}

/**
* @}
*/
Expand Down

0 comments on commit 4def8ce

Please sign in to comment.