usb/msc: wait for interrupt instead of polling a flag

This should make usb/msc a whole lot more efficient by pausing the
worker goroutine and waiting for an interrupt to unpause it instead of
waiting in a loop and sleeping for 0.1ms each cycle.

In other words, this should make it both faster (no unnecessary delay
due to the time.Sleep) and more efficient (no polling).
This commit is contained in:
Ayke van Laethem
2025-08-27 09:39:28 +02:00
parent fb2755d18f
commit 88db2c3594
2 changed files with 26 additions and 26 deletions
+6 -6
View File
@@ -1,12 +1,12 @@
package msc package msc
import ( import (
"internal/task"
"machine" "machine"
"machine/usb" "machine/usb"
"machine/usb/descriptor" "machine/usb/descriptor"
"machine/usb/msc/csw" "machine/usb/msc/csw"
"machine/usb/msc/scsi" "machine/usb/msc/scsi"
"time"
) )
type mscState uint8 type mscState uint8
@@ -28,7 +28,7 @@ var MSC *msc
type msc struct { type msc struct {
buf []byte // Buffer for incoming/outgoing data buf []byte // Buffer for incoming/outgoing data
blockCache []byte // Buffer for block read/write data blockCache []byte // Buffer for block read/write data
taskQueued bool // Flag to indicate if the buffer has a task queued taskWaiter task.Waiter // Waiter for events outside interrupt context
rxStalled bool // Flag to indicate if the RX endpoint is stalled rxStalled bool // Flag to indicate if the RX endpoint is stalled
txStalled bool // Flag to indicate if the TX endpoint is stalled txStalled bool // Flag to indicate if the TX endpoint is stalled
maxPacketSize uint32 // Maximum packet size for the IN endpoint maxPacketSize uint32 // Maximum packet size for the IN endpoint
@@ -120,7 +120,9 @@ func newMSC(dev machine.BlockDevice) *msc {
func (m *msc) processTasks() { func (m *msc) processTasks() {
// Process tasks that cannot be done in an interrupt context // Process tasks that cannot be done in an interrupt context
for { for {
if m.taskQueued { // Wait for the next task to arrive.
m.taskWaiter.Wait()
cmd := m.cbw.SCSICmd() cmd := m.cbw.SCSICmd()
switch cmd.CmdType() { switch cmd.CmdType() {
case scsi.CmdWrite: case scsi.CmdWrite:
@@ -131,11 +133,9 @@ func (m *msc) processTasks() {
// Acknowledge the received data from the host // Acknowledge the received data from the host
m.queuedBytes = 0 m.queuedBytes = 0
m.taskQueued = false m.taskWaiter.Done()
machine.AckUsbOutTransfer(usb.MSC_ENDPOINT_OUT) machine.AckUsbOutTransfer(usb.MSC_ENDPOINT_OUT)
} }
time.Sleep(100 * time.Microsecond)
}
} }
func (m *msc) ready() bool { func (m *msc) ready() bool {
+4 -4
View File
@@ -251,7 +251,7 @@ func (m *msc) scsiQueueTask(cmdType scsi.CmdType, b []byte) bool {
} }
// Save the incoming data in our buffer for processing outside of interrupt context. // Save the incoming data in our buffer for processing outside of interrupt context.
if m.taskQueued { if m.taskWaiter.Working() {
// If we already have a full task queue we can't accept this data // If we already have a full task queue we can't accept this data
m.sendScsiError(csw.StatusFailed, scsi.SenseAbortedCommand, scsi.SenseCodeMsgReject) m.sendScsiError(csw.StatusFailed, scsi.SenseAbortedCommand, scsi.SenseCodeMsgReject)
return true return true
@@ -268,14 +268,14 @@ func (m *msc) scsiQueueTask(cmdType scsi.CmdType, b []byte) bool {
case scsi.CmdWrite: case scsi.CmdWrite:
// If we're writing data wait until we have a full write block of data that can be processed. // If we're writing data wait until we have a full write block of data that can be processed.
if m.queuedBytes == uint32(cap(m.blockCache)) || (m.sentBytes+m.queuedBytes >= m.transferBytes) { if m.queuedBytes == uint32(cap(m.blockCache)) || (m.sentBytes+m.queuedBytes >= m.transferBytes) {
m.taskQueued = true m.taskWaiter.Resume()
} }
case scsi.CmdUnmap: case scsi.CmdUnmap:
m.taskQueued = true m.taskWaiter.Resume()
} }
// Don't acknowledge the incoming data until we can process it. // Don't acknowledge the incoming data until we can process it.
return !m.taskQueued return !m.taskWaiter.Working()
} }
func (m *msc) sendScsiError(status csw.Status, key scsi.Sense, code scsi.SenseCode) { func (m *msc) sendScsiError(status csw.Status, key scsi.Sense, code scsi.SenseCode) {