pnt_se05x_get_data() compared the object size with the buffer even when ReadSize had failed and left it unset.
Signed-off-by: Royyan Zahir <royzah@gmail.com>
Add an optional maxrequest callback at the end of sdio_dev_s. A zero
or unset callback adds no host-specific limit; nonzero values are byte
limits that apply to all request buffers.
Combine the host limit with MMCSD_MULTIBLOCK_LIMIT when splitting
block reads and writes. Reject a host limit smaller than one block and
oversized raw multi-block commands before starting the transfer.
Cancel receive setup after a failed CMD23, attempt CMD12 after failed
open-ended multi-block reads, and propagate stop-command failures.
Keep these generic MMC/SD changes separate from the STM32H7 driver.
Assisted-by: Codex:GPT-6
Signed-off-by: msli-dev <747640013@qq.com>
struct pl031_lowerhalf_s always had a struct lower_setalarm_s field,
but rtc.h defines that type only with CONFIG_RTC_ALARM, so the driver
did not compile without alarms. No configuration enabled RTC_PL031, so
nothing caught it. The field is used only by the alarm code; give it
the same condition.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
The INA226 driver was character mode only, and stayed that way after
everything around it moved, because the sensor framework had no type it
could publish: there was nothing for volts or amps until now.
Add the framework version beside it, in the shape the tree uses for a
part with both. The old driver is untouched and still builds by
default; the new one replaces it when SENSORS_INA226_UORB is set.
The part publishes three topics, voltage, current and power, from a
single reading that they all share the timestamp of. Reading once per
topic would put three transfers on the bus for one sample and, worse,
would leave the three values describing three different instants, which
is the wrong property for a power measurement: the product of a voltage
and a current measured at different moments is not the power at either.
The power is computed here rather than read from the part, because the
part's own power register needs its calibration register given a
current scale first, and multiplying two values already in hand does
not.
One worker feeds all three, so it starts when the first topic is
subscribed and stops when the last goes away, and the part is left
powered down until then rather than converting into a void.
Each topic keeps the interval it asked for and the worker runs at the
shortest of them, since one reading serves all three. Neither is taken
at face value: asking faster than the part converts returns the same
reading twice, and a period shorter than a clock tick rounds down to no
delay at all, which would leave the worker re-queueing itself with the
bus never idle. Both floors are applied and the caller is told what it
will actually get, which is what the interface is for.
The shunt is rejected if it is zero or negative, which would otherwise
divide by zero on the first reading.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Implement the MTD write callback when CONFIG_MTD_BYTE_WRITE is enabled,
allowing unaligned byte writes without changing existing block operations.
Reject ranges outside the physical device and return zero for valid empty
writes without SPI traffic.
Use the initialized SPI device ID, hold the bus lock across the request,
and issue write-enable for each transfer. With CONFIG_RAMTRON_CHUNKING,
split writes at the write-buffer boundaries of chunk-limited parts.
Document the optional callback and its bounds and chunk behavior.
Verified with mocked-SPI host tests, driver compilation with byte writes
and chunking enabled/disabled, and a Conductor STM32H743BI hardware test
covering single-byte and unaligned writes, surrounding-byte preservation,
invalid ranges, and restoration of the original FRAM contents. Hardware
coverage is limited to the installed 32 KiB part.
Assisted-by: Codex:GPT-6
Signed-off-by: jsanchez-2g <jsanchez@2g-eng.com>
This commit adds 4-byte address mode support to the Winbond W25 SPI
NOR flash driver (drivers/mtd/w25.c):
- Detect W25_JEDEC_CAPACITY_256MBIT (0x19) and W25_JEDEC_CAPACITY_512MBIT (0x20).
- Send W25_EN4B (0xB7) command to enter 4-byte address mode on initialization
when chip capacity >= 256Mbit.
- Expand w25_dev_s nsectors to uint32_t to support chips > 128Mbit.
- Add w25_sendaddr() helper supporting both 3-byte and 4-byte addressing
for sector erase, byte read, page write, and byte write.
- Verified on hardware with Winbond W25Q256JV (256Mbit / 32MB):
both raw MTD block access at >20MB (>16MB boundary) and SmartFS
mounting and file reading are verified working.
Assisted-by: gemini-3.8-flash
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
netdev_lower_carrier_XXX can't be called before netdev is registered
Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
ctucanfd_sock_recv() did not compile with CONFIG_CAN_CTUCANFD_SOCKET:
* the rwcnt bounds check used an undeclared 'frame' instead of
'rxframe';
* the !CONFIG_NET_CAN_EXTID paths used 'continue' outside a loop.
Both error paths now free the allocated RX packet and return NULL,
so a dropped frame no longer leaks the netpkt. Also add the blank
lines after declarations that nxstyle requires in this file.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: raiden00pl <raiden00@railab.me>
Every other driver subdirectory adds bare file names to CSRCS and points
VPATH and DEPPATH at itself, so drivers/lcd/st7365p.c is built as
drivers/st7365p.o. segger/Make.defs instead put the path in CSRCS, so its
objects were built as drivers/segger/serial_rtt.o and friends.
The generated rules in drivers/Make.dep name their target with the basename
of the source -- mkdeps calls basename() and prefixes --obj-path -- so they
read "serial_rtt.o: segger/serial_rtt.c ... nuttx/config.h". No such file
was ever built. The dependency rule and the compile rule named different
targets, and nothing under drivers/segger was ever recompiled when a header
or the configuration changed.
The result is a stale object silently linked against fresh ones. Enabling
CONFIG_TTY_SIGINT, for instance, adds a pid_t to struct uart_dev_s, which
moves every field after it. serial.c is rebuilt and reads dev->ops from its
new offset; serial_rtt.o is not, and its statically initialised device still
has ops four bytes lower. uart_open() then branches through whatever
follows it, and the board hard faults in uart_attach() before the console
has emitted a byte -- a symptom with no visible connection to its cause.
Use the same convention as the other subdirectories.
Tested on a Pimoroni Pico Plus 2 W with the RTT console
(pimoroni-pico-plus-2-w:nsh with CONFIG_SERIAL_RTT_CONSOLE). On master,
touching nuttx/serial/serial.h or enabling CONFIG_TTY_SIGINT does not
recompile segger/serial_rtt.c, and the incrementally built image prints
nothing on RTT. With this change, serial_rtt.c is recompiled in both
cases, and the same incremental build boots to NSH over RTT.
drivers/mtd/Make.defs has the same shape for its downloaded dhara and nvblk
sources and is left alone: it adds both nvblk.c and mtd/nvblk/src/nvblk.c,
whose basenames collide, so it needs more than a change of convention.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Every BATIOC_* case in the gauge upper half calls dev->ops->X() after
checking only that the *argument* pointer is non-NULL. The operations
themselves are optional -- max1704x.c implements four of the eight, and
the in-tree fake gauge leaves chipid and operate NULL -- so asking a gauge
for something it does not provide calls through a NULL pointer.
On ARM that is not a null dereference but a branch to address 0, which has
the Thumb bit clear: the core takes a usage fault with CFSR bit 17,
INVSTATE, escalated to a hard fault. From userspace it looks like the
program stopped mid-run for no reason, and on a board whose assert path
delays before resetting it looks like a hang.
Guard all eight. A missing method is now ENOTTY, which is what the default
case already returns for an unrecognised command and what a caller can
sensibly probe for.
Tested on sim:nsh with the fake gauge and a local test app. Before the
change, ioctl(BATIOC_CHIPID) kills the simulator with SIGSEGV. After the
change, BATIOC_CHIPID and BATIOC_OPERATE return ENOTTY and
BATIOC_VOLTAGE still returns the voltage. nucleo-f412zg:nsh with
BATTERY_GAUGE, MAX1704X, BQ27426 and BATTERY_FAKE_GAUGE builds.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Whitespace only. Add a blank line after the declarations in the BATIOC_*
cases, and indent two case labels like the others. The errors are older
than the next commit, but checkpatch checks the whole file.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
telnet_putchar() dropped every CR from the user buffer. RFC 854
requires a CR to be followed by LF or NUL, so send it and add a NUL
if the next character is not LF.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: raiden00pl <raiden00@railab.me>
telnet_putchar() appended the carriage return after the line feed, so
every output line ended with LF CR. RFC 854 defines the telnet end of
line as CR LF.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: raiden00pl <raiden00@railab.me>
Indent the switch cases in telnet_ioctl() and factory_ioctl(), align a
closing brace and wrap a long comment line. No functional change.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: raiden00pl <raiden00@railab.me>
The check CI job runs nxstyle over the whole file once it is touched,
and mmcsd_ioctl()/mmcsd_iocmd() carried pre-existing violations: case
labels and their blocks were indented one level too shallow, and four
argument continuation lines exceeded 78 columns. Reindent the two
switch bodies and rewrap the long call sites (local buffer variables
for the CMD8/18/25 data pointers, operand-per-line for the CMD23
ternary). No functional change.
Signed-off-by: rikaken2004 <244897142+rikaken2004@users.noreply.github.com>
The non-DMA data paths discard the return value of SDIO_RECVSETUP in
mmcsd_readsingle() and mmcsd_readmultiple() and of SDIO_SENDSETUP in
mmcsd_writesingle(), mmcsd_writemultiple() and the CMD56 read/write
helpers, so when the lower half fails to set up the transfer the
driver still issues CMD17/18/24/25/56 and the failure only surfaces
later as an unrelated-looking transfer timeout. The DMA paths in the
same functions all check SDIO_DMARECVSETUP/SDIO_DMASENDSETUP, cancel
the transfer and propagate the error, so mirror that handling on the
non-DMA paths.
Signed-off-by: rikaken2004 <244897142+rikaken2004@users.noreply.github.com>
A stopped oscillator sets OS in the seconds register and leaves stale
time behind, which the driver returned as the time. Return -EAGAIN, as
it already does before it is enabled, so the clock starts unset instead
of wrong. Setting the time clears OS.
Signed-off-by: Royyan Zahir <royzah@gmail.com>
nxstyle reports fourteen errors in this file. The switch in
usbhost_hub_configdesc() puts its case labels level with the brace that
opens the switch rather than one step further in, and a declaration is
followed straight away by a statement.
CI checks every file a patch touches rather than only the lines it
changes, so these have to go before anything else in this file can be
altered.
Whitespace, three comments rewrapped to stay inside the line limit
after the extra indent, and one blank line. No code changes: git diff
-w shows only the comments.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
struct usbhost_roothubport_s carries the number of the controller its port
belongs to, so a port can be named on a system with more than one.
Nothing set it.
Take the number from whoever brings the controller up rather than counting
registrations, which would agree with the name the driver reports only
while controllers are registered in the order they are named.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The driver refused CONFIG_USBHOST_HUB outright. Everything needed to
describe a device behind a hub is now in place, so implement the rest.
- xhci_device_init() took a root hub port and read the slot, the control
endpoint and the device out of it, all of which belong to the device.
It now takes the hub port and the control endpoint, and records the
device on the root port only when that is where it sits: once a hub is
plugged in, the device a root port names is the hub. xhci_address_set()
and xhci_device_deinit() likewise work on a device, and
xhci_disconnect() finds the device by the port going away.
- The hub asks for a port's control endpoint before it reports the
connection, so xhci_epalloc() has nothing to attach one to. It returns
an endpoint with no slot, and xhci_connect() gives it one when it
creates the device.
- A hub must be described to the controller as a hub before anything
behind it can be reached, and nothing knows it is one when its slot is
created. xhci_hub_update() corrects the slot context with a Configure
Endpoint command the first time something appears behind it.
- A hub reports each changed port without waiting for the last to be dealt
with, so the connect method queues them; holding one pointer meant the
second report overwrote the first. No more can be outstanding than the
controller has slots.
- Report the root port and slot counts from HCSPARAMS1, and the port count
from a hub's descriptor.
Tested on an EIC7700X board with a hub on one controller and a keyboard on
the other. Behind the hub, a 59 GB mass storage device mounts and reads a
file back, and a composite CDC device gives four ttyACM nodes.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
A controller reaches a device by the path to it and, for a slow device,
through the hub that translates for it. Neither was described, so a
device behind a hub was addressed as though it were on the root port.
The route string is that path: each hub between the device and the root
contributes a nibble holding the port the next thing down occupies, tier
nearest the root in the lowest nibble. Walking up from the device reaches
the deepest tier first, so shifting left by a nibble each time leaves them
in the order the field wants. The walk stops after five, which is what
the field holds and what USB allows, and a port above fifteen is clamped.
Slot context dword 2 names the transaction translator carrying a low or
full speed device behind a high speed hub. It reports the hub by slot,
where EHCI reports it by USB address, and it names the nearest high speed
ancestor rather than the immediate parent, since a full speed hub below a
high speed one is itself carried by the translator above it. The think
time comes from the hub descriptor by way of the hub class driver, in the
same units.
xhci_epalloc() carried a copy of sam_ehci.c's block, writing
epinfo->hubaddr and epinfo->hubport, which is how EHCI describes a split
transaction in its queue head. This driver never read either field, and
xHCI wants the information in the slot context. Both fields and the code
setting them are removed.
Multi-TT is not set, for the reason given in the previous commit.
No functional change: hubs cannot be enabled yet, and a device on a root
port has neither hubs above it nor a translator.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Some host controllers must be told about the hubs in a topology, not only
about the device at the end of it. xHCI is one: a hub's slot context
carries a hub flag, its downstream port count and the think time of its
transaction translator, and the controller routes to anything behind that
hub using them.
The hub class driver already reads both values from the hub descriptor and
keeps them privately. Publish them on the hub's own hub port, beside the
speed and function address that already describe the device attached
there. A driver setting up a device behind a hub finds them on that
device's parent.
They are written before the hub activates any downstream port, so they are
in place before there is anything behind it, and a port with no hub
reports zero ports because the hub class clears each child before use.
Nothing is required to read them.
Fields rather than a driver method: a method would need a null check at
the call site and would define an order it must be called in. Both are
inside CONFIG_USBHOST_HUB, as struct usbhost_hubport_s's parent pointer
already is.
Multi-TT is not included; it comes from the hub's interface protocol
rather than its descriptor, and driving a multi-TT hub as single-TT costs
bandwidth behind it but is correct.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The slot, the default control endpoint and the device context lived in
struct xhci_rhport_s, and anything needing a device reached it as
rhport->dev. That holds only while every device is plugged straight into
the controller; a hub puts several behind one root port, each with its own
slot and context.
Two keys replace it. An endpoint records the slot it was opened on, so
xhci_dev_from_ep() answers which device a transfer belongs to. A hub port
belongs to one device wherever it sits, so xhci_dev_from_hport() answers
which device is on a port when there is no endpoint to ask yet.
The functions converted here used both at once: xhci_ep0configure() issued
Evaluate Context for epinfo->slot while filling in rhport->dev's context,
and xhci_ctrl_xfer() reached the endpoint ring through the port and back.
xhci_slot_init() read the speed and control ring through the port, which
would fail quietly, since the slot context speed field has no valid zero
and a low speed device behind a high speed hub does not share its speed.
No functional change for a directly attached device: its port's slot and
its endpoint's slot are the same, and its hub port is the root port's own.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Suppress the peer notifications while a ring keeps delivering work, batch
the receive completions into one kick per burst and drop the redundant
txdone signal from the transmit path. Validate the peer controlled frame
lengths, accept descriptor chains on both lanes, keep every ring access on
the upper half's work thread so the interrupt context callbacks stay lock
free, and prefer the MAC from the configuration space, falling back to the
Kconfig address or a random one.
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
The CI style check runs nxstyle over every file a pull request touches,
so the files changed by the previous two commits have to comply even
where the problems were not introduced here. 504 errors in 25 files are
fixed: whitespace, blank lines, brace placement, switch/case indentation,
label indentation and comment blocks only, with no functional change.
Assisted-by: DeepSeek Harness:deepseek-flash
Signed-off-by: rongbaichuan <rongbaichuan1027@163.com>
nxsem_init(), nxsem_destroy(), nxmutex_init() and nxmutex_destroy()
always return OK, so checking the result only leaves dead code: the
compiler cannot remove it, because these are cross-translation-unit calls
and the nxrmutex_destroy() test is duplicated into every inlined call
site.
Apply the convention already established in commit a47a36bc5b (PR #7473)
to the two definitions which still test the value and to the 54 remaining
call sites. No signature or prototype is changed.
Testing: stm32f103-minimum:nsh builds with -Os without new warnings.
Assisted-by: DeepSeek Harness:deepseek-flash
Signed-off-by: rongbaichuan <rongbaichuan1027@163.com>
up_mdelay() is used in the reset sequence but nuttx/arch.h was not
included, causing an implicit-declaration build error.
Signed-off-by: raiden00pl <raiden00@railab.me>
Implement ioe_setpwm for the SX1509 by mapping the duty cycle to the
LED driver ON intensity of the pin.
Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
Add an ioe_setpwm operation (guarded by CONFIG_IOEXPANDER_PWM) for
expanders that can modulate their outputs, e.g. through a LED driver
engine.
Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
#20231 added a comment ahead of the sensor's power-on SW_RESET that
named esp32s3-specific things in otherwise generic driver code:
esptool/RTS-pin reset vocabulary, a literal path to
boards/xtensa/esp32s3/common/src/esp32s3_board_lsm6ds3trc.c, and the
espressif-arch esp_gpioirqenable() function.
None of that is specific to this driver's actual logic, which is
reached by any board wiring this sensor's INT1 through its own
config->attach() callback, whatever the arch. Reworded to describe
the reset/level-trigger requirement in those generic terms instead,
and dropped an ESP32S3-collar bring-up anecdote that does not belong
in driver documentation.
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
Assisted-by: Claude:claude-sonnet-5
A single failed burst read of FIFO_DATA_OUT was enough to take the board
down.
The drain path gave up on error, unlocked and returned, leaving the FIFO
above its watermark. INT1 is level triggered on exactly that condition,
so the line stayed asserted, the worker was re-entered the instant the
IRQ was re-enabled, failed again, and that hot loop starved every other
task until the board wedged -- console cut off mid-line, no crash dump.
Observed killing a board within seconds of the first failure.
Fix: if the read fails, empty the FIFO through Bypass and restore the
previous mode bits, which deasserts INT1. That costs one batch of
samples and acquisition resumes on the next watermark. Restoring the
saved bits rather than recomputing them preserves the FIFO-only ODR set
by fifo_configure().
Losing a batch is a far better outcome than losing the board.
The underlying cause of these timeouts on esp32s3 was light sleep cutting
the transfer in half; that is fixed separately in esp32s3_i2c.c. This
commit is the driver recovering gracefully from a failed read whatever
its cause, which it was not before.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
The worker declared its drain buffer as int16_t raw[FIFO_MAX_WORDS], and
FIFO_MAX_WORDS scales with CONFIG_SENSORS_LSM6DS3TRC_FIFO_WATERMARK.
At the Kconfig default watermark of 8 that is 192 bytes and nobody ever
noticed. At the watermark this collar uses, 250, it is 6000 bytes inside
an 8192-byte HPWORK stack -- 73% of it, before the call frame and the
whole I2C stack underneath. Any board raising the watermark walks into a
stack overflow in a shared work queue, which is about the worst place to
find one.
Allocated once at registration so the drain path stays allocation-free,
and the driver fails registration cleanly if it cannot get the memory.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
lsm6ds3trc_register() attached the INT1 handler without ever putting the
sensor into a known state, which made every reboot a coin toss.
The LSM6DS3TR-C has its own supply and its own reset. An MCU reset --
watchdog, RTS pin, esptool, a plain "reboot" -- does not reset it, so it
comes back still holding whatever the previous session configured: for
this driver, INT1_CTRL.INT1_FTH still set and a FIFO still over its
watermark, i.e. INT1 already asserted at registration time.
With the (correct) ONHIGH level trigger, arming an already-active line
storms immediately. The board then wedges during bring-up with no
console output and no crash dump -- it looked like a boot that stopped
right after Wi-Fi init and never reached NSH. That symptom cost a long
detour: it was blamed in turn on a stuck I2C bus, on corrupted NVS/Wi-Fi
calibration, and finally on a failing USB-serial adapter, because the one
thing that reliably cleared it was unplugging the board -- which is
simply the only way to power-cycle the *sensor*.
SW_RESET (CTRL3_C bit 0) clears INT1_CTRL and FIFO_CTRL back to 0, which
deasserts INT1. It self-clears in ~50 us; poll for it rather than
assume, and retry the write a few times, since the bus has been seen to
return -EIO on the very first transaction after a cold boot.
Carry on if the reset never takes. An unreset sensor risks the storm
this exists to prevent, but refusing to register leaves the application
with no /dev/uorb/sensor_accel0 at all, which is fatal to it -- a single
-EIO here took the whole collar down once. Losing the sensor to guard
against a maybe-storm is the wrong trade.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
esp_gpio_irq() registers per-pin GPIO interrupts through
gpio_isr_handler_add(), never through esp_setup_irq(), so
esp_get_handle() never finds them and up_disable_irq()/up_enable_irq()
silently no-op for any GPIO-derived irq number. Fall back to
esp_gpioirqdisable()/esp_gpioirqenable() (translating irq back to a
pin via ESP_IRQ2PIN()) when the normal interrupt-matrix lookup misses.
This surfaced through drivers/sensors/lsm6ds3trc_uorb.c: its ISR
schedules a worker to drain the sensor's FIFO over I2C and disables
its own IRQ until the worker re-enables it, so a level-triggered
source (e.g. a PM GPIO wake source left in level mode) doesn't
refire continuously and starve every task, HPWORK included, before
the worker ever gets to run. That disable/enable only works now that
up_disable_irq()/up_enable_irq() actually do something for GPIO irqs.
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
Assisted-by: Claude:claude-sonnet-5
Implements the device end of virtio-net, so a peer running the stock
virtio-net driver sees this side as a network card, and registers a netdev
lowerhalf.
Ring layout follows the peer's numbering: vq[0] is its RX queue, which we fill
to transmit, and vq[1] its TX queue, which we harvest. No features are
negotiated, so every frame carries the zeroed legacy virtio_net_hdr.
Peer buffers are reached by raw 64-bit address through an arch-provided
translation window -- the AM67 RAT, identity mapping elsewhere -- splitting
copies that straddle it.
Also gives DRIVERS_VHOST a prompt; it was promptless and so unselectable
without a driver forcing it.
Verified on t3-gem-o1 against an unmodified Linux virtio_net: eth0 registers,
ifup brings it to RUNNING, and the peer pings it 5/5 at 0.27 ms and 60/60 with
0% loss.
Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
vhost_get_vq_buffers() converts descriptor addresses through the shared-memory
I/O region, which truncates silently when the CPU cannot address all of the
peer's memory -- a 32-bit remote core against a 64-bit host, where
metal_phys_addr_t is 32-bit and Linux posts buffers above 4 GB.
Returns the raw 64-bit address and length instead, so class drivers can
translate through platform window hardware. Completion is unchanged.
Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
ptp_clock_dummy_getcrosststamp() stored the seconds of the monotonic
clock in the nanoseconds field of the monoraw member, so the
monotonic time of the cross timestamp was wrong. Store the nanoseconds.
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Assisted-by: Claude:claude-sonnet-5
xhci_enumerate() reports failure by marking the hub port disconnected,
which is what makes xhci_wait() return and the attempt repeat. The root
port is still connected, so the two disagree again immediately and the
attempt repeats for as long as the device stays plugged in. A device that
fails every time is retried forever: 1055 attempts in 90 seconds on an
EIC7700X board, enough console traffic to make the board unusable.
Count consecutive failures per root port and stop at
CONFIG_USBHOST_XHCI_ENUM_RETRIES, leaving the port as it is so xhci_wait()
blocks until something physically changes. A new connection clears the
count, as does a successful enumeration, so a device needing a second
attempt still gets one. The default of three rides out a slow device or a
marginal reset.
The same board now makes three attempts, reports that it has given up and
falls silent, while a keyboard on the other port enumerates throughout.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
A device slot is a finite controller resource: HCSPARAMS1 reports how many
exist and Enable Slot fails with No Slots Available once they are gone.
Two paths took one and returned without giving it back.
xhci_device_init() enables a slot before initialising the transfer ring,
the slot context and the device address, and each of those returned
directly on failure. It also treated a slot number larger than the
controller supports as success, since Enable Slot itself had succeeded.
xhci_enumerate() is the larger leak: the device is addressed by the time
usbhost_enumerate() runs, so a device whose descriptor cannot be read, or
that no class driver claims, leaves the slot held. That path clears
hport->connected so the port is retried, taking another slot each time.
Release the slot on both paths with xhci_device_deinit(), which issues
Disable Slot, clears the DCBAA entry and resets the context. The endpoint
ring is left allocated; xhci_ring_init() reuses an existing one.
Tested on an EIC7700X board with a device no class driver claims, so the
port retries indefinitely: previously the eighth attempt failed with
completion code 9 and the controller enumerated nothing further on either
port; now 1104 consecutive attempts produced no slot failure.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
xhci_ctrl_xfer() and xhci_transfer() release the controller lock before
xhci_transfer_wait(), so the lock does not cover the interval in which a
transfer is outstanding. Two threads issuing requests on the same
endpoint both reach xhci_ioc_setup(), and the second trips the
DEBUGASSERT(!epinfo->iocwait) that guards it, or overwrites the first
thread's completion state where assertions are compiled out.
A default control endpoint reaches this readily: every interface driver on
a composite device speaks through endpoint 0, so a two interface HID
keyboard runs two poll threads both issuing GET_REPORT.
Other host controller drivers hold the controller lock across the wait,
which here would serialise the whole controller and give up the per
endpoint rings xHCI provides. Add a mutex to struct xhci_epinfo_s and
hold that instead. It is taken before the controller lock on both paths,
so the order is endpoint then controller.
xhci_epfree() also freed the endpoint container without destroying iocsem.
Destroy both.
Reachable on any xHCI controller, independently of the preceding commits.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Submitting an asynchronous transfer refused any buffer needing a cache
line stand-in, and that test also refuses every buffer whose length is not
a whole number of cache lines, which an interrupt transfer's rarely is: a
HID keyboard reads eight bytes. Every submission returned -EFAULT before
a descriptor was written, and a class driver resubmitting from its
completion callback never sees a second chance.
The refusal existed because the copy out of a stand-in is done by the
blocked caller, and an asynchronous transfer has none. The work queue
thread handling the completion will do: a buffer given to DRVR_ASYNCH
comes from DRVR_ALLOC, so it is kernel memory reachable from any thread.
Use the same stand-in machinery as every other transfer and finish the DMA
in the completion, just before the callback. A cancelled transfer returns
its stand-in on cancellation.
The callback also moves outside the spinlock. It is class driver code
that queues work and takes its own locks, and it may now free a stand-in.
Whether a completion is synchronous is still decided under the lock, since
a posted waiter may be carrying a new transfer immediately.
The asynchronous setup now records the requested length, as the
synchronous setup does. The byte count handed to the callback is worked
out from it and the residue, and was previously whatever the endpoint held
from an earlier transfer.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
A root hub port whose enumeration failed is enumerated again, and the slot
the failed attempt used has been given back by then, so the port has no
device context behind it. xhci_epalloc() took that pointer and wrote the
new endpoint through it without looking, so the retry stored through NULL
and took the system down in answer to a device that had merely failed to
come up.
Check for the device, and free the endpoint that has no home rather than
leaking it.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The Interval field of an endpoint context is an exponent: the controller
services the endpoint every 2^Interval microframes. An endpoint
descriptor states its period differently depending on device speed, so the
number cannot be copied across, which is what this did. A low speed
keyboard asking to be polled every 10ms was programmed as 2^10
microframes, which the controller would not accept: Configure Endpoint
went unanswered and allocation failed with -EIO.
Low and full speed interrupt endpoints state a period in frames, so the
exponent is the highest bit of that period in microframes, clamped to the
range the specification allows. Other periodic endpoints already state an
exponent, one greater than the one wanted here. Control and bulk
endpoints are not periodic and the field means nothing to them.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The copy out of a stand-in was done in the completion handler, which runs
on a work queue, while the buffer it copies into may belong to a user
process whose addresses mean nothing there. Reading a block device
directly from a user program faulted. The caller is blocked until the
transfer finishes, so the copy belongs there.
An asynchronous transfer has no blocked caller to come back to, so a
buffer that would need a stand-in is refused for that path. Its callers
are class drivers using kernel memory, which do not need one. The
refusal is lifted once the completion path can do the copy itself.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Report each device as it comes up, and report it going away.
The announcement is made at the end of the port enable rather than at
connect, because the PORTSC speed field means nothing until the port has
been reset: a USB2 port reports its reset default, full speed, until then,
so every device would be announced at 12Mbps regardless of what it
negotiates a moment later.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>