usb_canbus: Rework USB message transmit prioritization

There is no need to heavily prioritize the sending of canbus packets
over USB.  A single check to flush the incoming canbus packets is
sufficient.

Also, be sure to wake up canserial_notify_tx() even if canhw_send()
blocks.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2023-04-15 12:54:32 -04:00
parent 28f11244c3
commit b17ae55f5b
1 changed files with 38 additions and 38 deletions

View File

@ -112,7 +112,7 @@ static struct usbcan_data {
uint8_t host_status; uint8_t host_status;
// Canbus data routed locally // Canbus data routed locally
uint8_t notify_local; uint8_t notify_local, usb_send_busy;
uint32_t assigned_id; uint32_t assigned_id;
// Data from physical canbus interface // Data from physical canbus interface
@ -166,20 +166,24 @@ send_frame(struct canbus_msg *msg)
} }
// Send any pending hw frames to host // Send any pending hw frames to host
static int static void
drain_hw_queue(void) drain_hw_queue(void)
{ {
uint32_t pull_pos = UsbCan.pull_pos; uint32_t pull_pos = UsbCan.pull_pos;
for (;;) { for (;;) {
uint32_t push_pos = readl(&UsbCan.push_pos); uint32_t push_pos = readl(&UsbCan.push_pos);
if (push_pos == pull_pos) if (push_pos == pull_pos) {
// No more data to send // No more data to send
return 0; UsbCan.usb_send_busy = 0;
return;
}
uint32_t pos = pull_pos % ARRAY_SIZE(UsbCan.queue); uint32_t pos = pull_pos % ARRAY_SIZE(UsbCan.queue);
int ret = send_frame(&UsbCan.queue[pos]); int ret = send_frame(&UsbCan.queue[pos]);
if (ret < 0) if (ret < 0) {
// USB is busy - retry later // USB is busy - retry later
return -1; UsbCan.usb_send_busy = 1;
return;
}
UsbCan.pull_pos = pull_pos = pull_pos + 1; UsbCan.pull_pos = pull_pos = pull_pos + 1;
} }
} }
@ -189,12 +193,11 @@ usbcan_task(void)
{ {
if (!sched_check_wake(&UsbCan.wake)) if (!sched_check_wake(&UsbCan.wake))
return; return;
for (;;) {
// Send any pending hw frames to host
int ret = drain_hw_queue();
if (ret < 0)
return;
// Send any pending hw frames to host
drain_hw_queue();
for (;;) {
// See if previous host frame needs to be transmitted // See if previous host frame needs to be transmitted
uint_fast8_t host_status = UsbCan.host_status; uint_fast8_t host_status = UsbCan.host_status;
if (host_status & (HS_TX_HW | HS_TX_LOCAL)) { if (host_status & (HS_TX_HW | HS_TX_LOCAL)) {
@ -209,53 +212,50 @@ usbcan_task(void)
UsbCan.host_status = host_status = host_status & ~HS_TX_LOCAL; UsbCan.host_status = host_status = host_status & ~HS_TX_LOCAL;
} }
if (host_status & HS_TX_HW) { if (host_status & HS_TX_HW) {
ret = canhw_send(&msg); int ret = canhw_send(&msg);
if (ret < 0) if (ret < 0)
return; break;
UsbCan.host_status = host_status = host_status & ~HS_TX_HW; UsbCan.host_status = host_status = host_status & ~HS_TX_HW;
} }
continue;
} }
// Send any previous echo frames // Send any previous echo frames
if (host_status) { if (host_status) {
ret = usb_send_bulk_in(&UsbCan.host_frame if (UsbCan.usb_send_busy)
, sizeof(UsbCan.host_frame)); // Don't send echo frame until other traffic is sent
return;
int ret = usb_send_bulk_in(&UsbCan.host_frame
, sizeof(UsbCan.host_frame));
if (ret < 0) if (ret < 0)
return; return;
UsbCan.host_status = 0; UsbCan.host_status = 0;
continue;
} }
// See if can read a new frame from host // Read next frame from host
ret = usb_read_bulk_out(&UsbCan.host_frame, USB_CDC_EP_BULK_OUT_SIZE); int ret = usb_read_bulk_out(&UsbCan.host_frame
if (ret > 0) { , USB_CDC_EP_BULK_OUT_SIZE);
uint32_t id = UsbCan.host_frame.can_id; if (ret <= 0)
UsbCan.host_status = HS_TX_ECHO | HS_TX_HW; // No frame available - no more work to be done
if (id == CANBUS_ID_ADMIN) break;
UsbCan.host_status = HS_TX_ECHO | HS_TX_HW | HS_TX_LOCAL; uint32_t id = UsbCan.host_frame.can_id;
else if (UsbCan.assigned_id && UsbCan.assigned_id == id) UsbCan.host_status = HS_TX_ECHO | HS_TX_HW;
UsbCan.host_status = HS_TX_ECHO | HS_TX_LOCAL; if (id == CANBUS_ID_ADMIN)
continue; UsbCan.host_status = HS_TX_ECHO | HS_TX_HW | HS_TX_LOCAL;
} else if (UsbCan.assigned_id && UsbCan.assigned_id == id)
UsbCan.host_status = HS_TX_ECHO | HS_TX_LOCAL;
// No more work to be done
if (UsbCan.notify_local) {
UsbCan.notify_local = 0;
canserial_notify_tx();
}
return;
} }
if (UsbCan.notify_local && !UsbCan.usb_send_busy)
canserial_notify_tx();
} }
DECL_TASK(usbcan_task); DECL_TASK(usbcan_task);
int int
canbus_send(struct canbus_msg *msg) canbus_send(struct canbus_msg *msg)
{ {
int ret = drain_hw_queue(); if (UsbCan.usb_send_busy)
if (ret < 0)
goto retry_later; goto retry_later;
ret = send_frame(msg); int ret = send_frame(msg);
if (ret < 0) if (ret < 0)
goto retry_later; goto retry_later;
UsbCan.notify_local = 0; UsbCan.notify_local = 0;