| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
| |
Prevent infinite loop in uvideo_vs_negotiation() when a USB camera reports
step=0 in its continuous frame interval descriptor.
Cast fbuf_size calculation to uint64_t to avoid int overflow for large
width/height/bpp combinations.
Reported by: emaste
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The fixed 128 KiB secondary buffer cap dates from stereo-sized streams.
High channel-count or high sample-width OSS streams can consume most of
that budget in one graph quantum, leaving too little room for capture
catch-up or playback headroom.
Keep 128 KiB as the low-rate floor, but derive the effective soft-ring
cap from the channel byte rate, clamped to 4 MiB. Use that per-channel
cap when resizing the soft buffer and when clamping
SNDCTL_DSP_SETFRAGMENT requests.
Also clamp SNDCTL_DSP_LOW_WATER to the current soft-buffer size so an
impossible readiness threshold cannot make poll/select wait forever.
MFC after: 3 weeks
Reviewed by: christos
Differential Revision: https://reviews.freebsd.org/D58064
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Some UAC2 devices expose a single Clock Source entity that is shared
between their playback and capture interfaces (it appears in both the
output and input clock bitmaps). On such a device uaudio(4) programs
the sample rate for both directions when a stream starts. If playback
runs at a 44.1 kHz-family rate while the idle capture channel is left
at its 48 kHz-family default, the capture
SET_CUR(UA20_CS_SAM_FREQ_CONTROL) is issued after the playback one and
overwrites the rate on the shared clock. The device then runs at
~48 kHz while the playback stream carries 44.1 kHz data. Consuming
samples faster than they arrive, the device repeatedly runs out of
data, loses sync with the playback stream, and re-locks onto it
(audible dropouts, front-panel play/idle flicker). The 48 kHz family
is unaffected because both directions then agree on the rate.
Fix it in three parts:
- Add a shared-clock guard: before issuing SET_CUR to a clock id, if
that clock is shared between playback and capture and the other
direction is already streaming at a different rate, skip it. The
first active stream owns the clock; a later one follows it.
- When the recording channel is auto-started only as a source of jitter
information for asynchronous playback, align its nominal rate to the
playback rate before starting it, so it neither reprograms the shared
clock to a conflicting rate nor produces mismatched frame sizes.
- Always submit the explicit-feedback SYNC transfer so
dev.pcm.%d.feedback_rate stays live as a diagnostic even when a
capture stream is present.
Reproduced on an OKTO RESEARCH DAC8 STEREO (0x152a:0x88c5), whose
vestigial capture interface never streams; the same device plays the
44.1 kHz family correctly under Linux's snd-usb-audio.
As a side effect, this patch also fixes the sample rate bug mentioned in
the BUGS section of sound(4)'s man page, where a device needs to have
the same sample rate set for both playback and recording in order to
work properly.
PR: 295933
Assisted-By: Claude Opus 4.8 (claude-opus-4-8)
Signed-off-by: giacomo <delleceste@gmail.com>
MFC after: 2 weeks
Reviewed by: christos
Pull-Request: https://github.com/freebsd/freebsd-src/pull/2323
|
| |
|
|
| |
Reported by: vishwin
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
| |
detach() stopped streaming and called uvideo_vs_close() before
destroy_dev(), so a concurrent close() could race the teardown and call
uvideo_vs_close() a second time (double usbd_transfer_unsetup), and
mtx_destroy() could race a close still holding sc_mtx. sc_streaming
was also read without the lock in both paths.
Reorder detach() to call destroy_dev() first so all in-flight cdev
methods drain before any teardown. Read sc_streaming under sc_mtx in
both detach() and the last-close safety net.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The driver shared a single streaming state and buffer pool across all
open file descriptors, so a second client (e.g. another browser tab)
could disrupt the first: its cleanup STREAMOFF would tear down the
active stream, and stale buffers prevented re-acquisition.
Add per-fd state via devfs cdevpriv tracking whether this fd started
streaming. STREAMOFF and close from a non-streaming fd are no-ops.
STREAMOFF from the streaming fd stops the stream and frees the buffers
so that a new fd can re-acquire the camera. DQBUF returns EPIPE
immediately when buffers are freed instead of waiting for a timeout.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Frame interval data is read from device-supplied frame descriptors whose
bLength may be shorter than the number of intervals declared by
bFrameIntervalType. The continuous branch of uvideo_enum_fivals() read
three intervals unconditionally, and the discrete branch checked the
pointer but not the four bytes that UGETDW() reads, so a short or
malformed descriptor could read past bLength and leak adjacent kernel
memory to userspace. uvideo_vs_parse_desc_frame_max_rate() had the same
class of off-by-up-to-three-bytes read.
Compute the available bytes from bLength and validate before each read.
Reported by: emaste
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
qbuf(), dqbuf() and read() manipulated sc_mmap_q / sc_mmap_cur /
sc_frames_ready without sc_mtx, racing with the USB transfer callbacks
(producer) that run under the mutex. This could corrupt the queue or
trigger use-after-free.
Take sc_mtx around qbuf(), use mtx_sleep() and protect the queue
operations in dqbuf(), and use mtx_sleep() with a snapshot of sc_fsize
in read().
Also reject S_FMT and S_PARM with EBUSY while streaming: both
re-negotiate the probe/commit controls with the device, which disrupts
the active USB transfers (a second client opening the device would
otherwise freeze the first one's stream).
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
dwMaxVideoFrameSize comes from the USB probe/commit response and is not
validated. reqbufs() computed buf_size_total with signed int arithmetic
and no bound, so a bogus value could wrap the product to a small size
and yield a too-small buffer with a huge sc_mmap_buffer_size, causing
out-of-bounds writes from the USB transfer callbacks.
Bound the frame size against sc_max_fbuf_size and use overflow-checked
size_t arithmetic for the total and per-buffer offsets.
Reported by: emaste
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Allocate the mmap buffer via phys_pager_allocate() and map it into
kernel space with vm_map_find()/vm_map_wire(), instead of a custom
cdev_pager backed by contigmalloc. phys_pager_allocate() is required
over a bare vm_object_allocate(OBJT_PHYS) to initialise un_pager.phys.ops,
otherwise phys_pager_getpages() NULL-derefs during vm_map_wire().
Reviewed by: markj
Reported by: markj
Differential Revision: https://reviews.freebsd.org/D58394
|
| |
|
|
|
|
|
|
|
|
|
| |
Although the driver does not issue the extra receive-mode commands
accepting the feature is harmless and some devices, notably Apple's
Virtualization.framework, offer their control-queue features as a
group and refuse FEATURES_OK unless the whole set is acknowledged.
Signed-off-by: Faraz Vahedi <kfv@kfv.io>
Reviewed by: adrian
Pull Request: https://github.com/freebsd/freebsd-src/pull/2322
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When the device sets VIRTIO_NET_S_ANNOUNCE in the config status
field, for example after a VM migrates to a new host, announce
the interface's presence on the network so peers and switches
learn the new attachment point, then acknowledge the request
with the VIRTIO_NET_CTRL_ANNOUNCE_ACK control command, as per
VirtIO v1.3, 5.1.6.5.4.
The announcement raises iflladdr_event: the stack sends gratuitous
ARPs and unsolicited neighbor advertisements for the interface's
addresses, and stacked interfaces such as vlan(4) propagate the
event and announce theirs as well. The event handlers may sleep,
so the work is deferred from the config change interrupt to a task
on taskqueue_thread; that context also allows the acknowledgement
to be skipped safely if the interface was stopped in the meantime,
in which case the device keeps the bit set and the request is
re-delivered with the next config change interrupt.
Signed-off-by: Faraz Vahedi <kfv@kfv.io>
Reviewed by: adrian
Pull Request: https://github.com/freebsd/freebsd-src/pull/2322
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A device is permitted to reject an otherwise valid subset of its
offered features by refusing to accept FEATURES_OK (VirtIO v1.3,
2.2.2). Apple's Virtualization.framework does this in practice;
it treats the offered CSUM/TSO offloads as all-or-nothing, while
vtnet's default request contains only part of that group because
of hw.vtnet.lro_disable that would drop the guest TSO bits, thus
negotiation fails and the device does not attach.
If FEATURES_OK is rejected, retry the negotiation once with every
offload-related feature stripped. Changing the feature set after
a failed FEATURES_OK requires re-initialising from device reset
(VirtIO v1.3, 3.1.1), so the retry goes through virtio_reinit().
A NIC without offloads is preferable to no NIC at all. Devices
that accept the initial feature set are unaffected, while those
that also reject the reduced set continue to fail attachment as
before.
Signed-off-by: Faraz Vahedi <kfv@kfv.io>
Reviewed by: adrian
Pull Request: https://github.com/freebsd/freebsd-src/pull/2322
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Annotate validation failures in the PMC syscall handlers (allocate,
attach, read/write) with EXTERROR(), so pmc(3) callers see which
precondition failed, not a bare errno.
Register HWPMC_MOD in exterr_cat.h and the generated filenames.h.
Signed-off-by: Andre Silva <andasilv@amd.com>
Reviewed by: Ali Mashtizadeh <ali@mashtizadeh.com>, mhorne
Sponsored by: AMD
Pull Request: https://github.com/freebsd/freebsd-src/pull/2180
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Replace bare EINVAL in AMD/IBS allocation and config-validation with
EXTERROR(), so a failed pmc(3) allocation names the check and value.
Register HWPMC_AMD in exterr_cat.h and the generated filenames.h.
Signed-off-by: Andre Silva <andasilv@amd.com>
Reviewed by: Ali Mashtizadeh <ali@mashtizadeh.com>, mhorne
Sponsored by: AMD
Pull Request: https://github.com/freebsd/freebsd-src/pull/2180
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This fixes an issue with the Solo2 (and likely some of the Nitrokey
family) where hangs would occur with OpenSSH- it issues a CANCEL prior
to closing the device unconditionally, and without draining the read
endpoint we end up seeing the response to that CANCEL the next time
OpenSSH tries to connect. This throws the entire command/response
sequence out of whack.
This call used to break Yubikeys in some situations, but the fix that
landed in 28d85db46b48 ("xhci: Do not drop and add bits in xhci") seems
to have addressed that- presumably we sometimes end up stopping the
command and desyncing at the controller level. This probably implies
that we need a SYNCWRITE HID quirk, but that requires a little more work
in usbhid_sync_xfer() and this doesn't seem to cause any problems in
normal usage.
Reviewed by: aokblast, wulf
Differential Revision: https://reviews.freebsd.org/D58199
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The uvideo driver freed the mmap buffer (contigmalloc'd) in several
paths (VIDIOC_STREAMOFF, last close, detach) without coordinating
with the lifetime of existing user-space mmap mappings. This could
lead to use-after-free when user-space continued to access the
mapped memory after the backing pages had been freed.
Fix this by switching from the simple d_mmap callback to d_mmap_single
with custom cdev_pager_ops, and by attaching the contig buffer to a
single shared vm_object created at REQBUFS time:
- uvideo_reqbufs() allocates a uvideo_mmap_state (independent of the
softc) and a shared vm_object via cdev_pager_allocate() that spans
the whole buffer; the softc holds one reference to it.
- uvideo_cdev_mmap_single() simply hands out additional references to
that shared object; the requested offset selects which buffer is
mapped. The VM system tracks mapping lifetime through the object
reference count, so no per-mapping bookkeeping is needed.
- uvideo_pg_ctor/uvideo_pg_dtor validate the mapping and free the
contig buffer together with the state when the last reference
(softc's own or a user mapping) is dropped.
- uvideo_pg_fault installs a fictitious page for the backing physical
address, following the canonical device-pager pattern: update the
passed-in page in place when it is already fictitious, otherwise
allocate a fake page and vm_page_replace() the busy placeholder,
so that dev_pager_dealloc() does not deadlock.
- uvideo_vs_free_frame() drops the softc's reference instead of
contigfree()'ing directly; if mappings still exist the buffer stays
alive until the last uvideo_pg_dtor().
- VIDIOC_STREAMOFF no longer frees the buffer (per V4L2 spec).
- Last close always releases the buffer (deferred if mappings exist).
- The mmap_state outlives the softc, so the pager dtor can safely
free the buffer even after device detach.
Reported by: 章鱼哥 (@aipyapp) (www.aipyaipy.com)
Reported by: Chris Jarrett-Davies of the OpenAI Codex Security Team
|
| |
|
|
|
|
|
|
|
| |
Sponsored by: Klara, Inc.
Sponsored by: NetApp, Inc.
MFC after: 1 week
Fixes: 6d0001d44490 ("nvme: add support for DIOCGIDENT")
Reviewed by: bnovkov, imp
Differential Revision: https://reviews.freebsd.org/D58357
|
| |
|
|
|
|
|
| |
No functional change.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58311
|
| |
|
|
|
| |
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58310
|
| |
|
|
|
|
|
|
|
| |
When a FireWire bus resets, all devices negotiate who is the new boss.
when we detect the root node can't be cycle master,
we send a PHY config packet that forces a reelection.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58309
|
| |
|
|
|
|
|
| |
Removes a TODO that predates the existing drain call.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58308
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Implemented crom_crc_valid() helper to validate IEEE 1394 config ROM CRC-16
checksums.
Skipped root header CRC validation since csrhdr.crc_len cover the entire
ROM body which is not fully read at header parse time. Per-directory
CRC checks below catch corruption where it needed.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58307
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A bunch of drivers weren't properly converted. I mistakenly
put a call to ieee80211_output_seqno_assign() wherever the
crypto header was added, which isn't exactly correct.
There are plenty of drivers which don't share enough of their
raw and normal transmit path code for that to hold true.
So after some manual review, it looks like I've captured the
places (outside of iwn(4) which I committed earlier) where
I missed ieee80211_output_seqno_assign() calls.
* For bwi(4) and bwn(4) I refactored it out into a place that is
common enough and happens in the same lock hold window,
so it's serialised.
* For the rest, it's just plain missing from the raw path.
Locally tested:
* ural(4)
* ral(4)
* bwi(4)
Differential Revision: https://reviews.freebsd.org/D58098
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
FRED support as defined starting from the SDM rev. 90, requires a new
'events' entry point to receive user and kernel mode exceptions and
interrupts notifications from the hardware. A minimal asm trampoline is
enough, rest can be implemented in C due to the clean FRED organization
of the event reporting.
The syscall entry is handled by a microptimized assembly path, directly
calling into the amd64_syscall() handler, instead of the generic events
entry point.
Tested by: emaste
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D55829
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Import the device quirk system from OpenBSD to handle UVC devices
that need special handling. This includes:
- UVIDEO_FLAG_ISIGHT_STREAM_HEADER: non-standard streaming header
- UVIDEO_FLAG_REATTACH: needs reattach after firmware upload
- UVIDEO_FLAG_VENDOR_CLASS: incorrectly reports as vendor class
- UVIDEO_FLAG_NOATTACH: device not supported
- UVIDEO_FLAG_FORMAT_INDEX_IN_BMHINT: format index in bmHint
Add quirks table with known devices and lookup function.
Add iSight stream header decoder for Apple iSight cameras.
Obtained from: OpenBSD
|
| |
|
|
|
|
| |
Some UVC devices (e.g. Logitech C920) expose more than 8 Processing
Unit descriptors, causing "too many PU descriptors found!" errors.
Increase both limits from 8 to 32 to accommodate such devices.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A process-mode PMC's runcount tracks how many CPUs currently have it
loaded in hardware. It is decremented only by the context-switch-out
and process-exit reclaim paths, both of which the scheduler invokes
only for processes flagged P_HWPMC. Detaching a target that still has
the PMC live in hardware dropped the target and cleared P_HWPMC without
taking the PMC off the hardware or dropping the runcount reference, so
the reference leaked. A subsequent release then spun in
pmc_wait_for_pmc_idle() forever waiting for the runcount to reach zero:
on an INVARIANTS kernel this panics ("waiting too long for pmc to be
free"), otherwise it is an unkillable loop holding the hwpmc lock. Any
process able to allocate a PMC can trigger this by attaching a counting
PMC to itself and detaching it before releasing.
Take the PMC off the hardware and drop the runcount reference as part
of detaching, before P_HWPMC is cleared: reclaim it from the detaching
thread's own CPU directly, and, when the detach removes the PMC's last
target, wait for any references held by the target's other threads to
drain while P_HWPMC is still set (they can no longer reload it).
Reviewed by: adrian
MFC after: 2 weeks
Assisted-by: Claude Code (Fable 5)
Differential Revision: https://reviews.freebsd.org/D58342
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The accumulated count of a process-mode counting PMC is kept in a
64-bit software counter and seeded into the hardware counter at every
context switch in. Hardware counters are narrower than that - each
PMC class discovers and records its own counter width, e.g. 48 bits
on current x86 (queried from CPUID on Intel, architectural on AMD) -
so once the accumulated count approaches the end of the hardware
counter range, the counter wraps during a time slice and the value
read back at switch out is smaller than the value seeded. The
increment was computed assuming a full 64-bit counter: on INVARIANTS
kernels a long enough counting run panics with "negative increment"
the moment the accumulated count first crosses the hardware counter
range, and on other kernels the totals silently lose a full counter
range per wrap.
Compute the increment modulo the per-class hardware counter width
instead, in both places that accumulate switch-out deltas.
Reviewed by: adrian
MFC after: 2 weeks
Assisted-by: Claude Code (Fable 5)
Differential Revision: https://reviews.freebsd.org/D58340
|
| |
|
|
|
|
|
|
|
|
|
| |
bus_{read,write}_8 are macro wrappers around the corresponding bus_space
functions in sys/bus.h, so implementing bus_{read,write}_8 won't work.
Implement the underlying bus_space function instead.
Reviewed by: jrtc27, rlibby
Fixes: 9313f6b01485
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D58301
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
re(4) has unconditionally disabled ASPM L0s/L1 and CLKREQ at attach
for years; on laptops this costs 200mW+ (requested by adrian@ in the PR).
Make it a tunable following the existing hw.re.* pattern:
* default 1 keeps today's behavior;
* 0 preserves the firmware-configured ASPM state at attach and
skips the watchdog re-assert from the previous revision.
Documented in re.4.
* Verified on RTL8168H (XID 0x541): with hw.re.aspm_disable=0,
attach no longer logs "ASPM disabled" and pciconf -lcb shows
the firmware Link Control state preserved -- including Clock PM,
which the unconditional code previously cleared.
* Default (1) is behaviorally identical to the current driver.
* Note the tunable also stops the driver clearing CLKREQ, a small power
win even where firmware leaves L0s/L1 off.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58280
PR: kern/166724
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Distinguish the two failure classes from the PR in a single log line
(ring indices, ISR/IMR, TXCFG, interrupt mode): lost interrupt vs
genuine DMA stall.
Bail out instead of re-initializing when the controller reads back
all-ones (fallen off the bus; reinit cannot help).
Re-assert the driver's existing ASPM-disabled policy before reinit,
since firmware/power transitions re-arming L0s/L1 is a documented
stall trigger.
Diagnostics-only on the recovered path; no fast-path change.
* Field diagnostics running on an RTL8168H production fleet; the log
format distinguishes lost-doorbell / DMA-stall / dead-controller
without a debug build.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58279
PR: kern/166724
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A Tx completion that raises a status bit between the ISR ack at the top
of re_intr_msi() and the IMR re-enable at the bottom is never re-signalled:
these controllers do not re-assert MSI for an already-set status bit
(this is why hw.re.msi_disable is a known workaround in the PR).
Re-read ISR before re-enabling; if a Tx bit is pending, ack just that bit,
reap the ring and restart the queue. Rx bits are deliberately left set so
they re-arm the interrupt normally and Rx moderation state is untouched.
Also flush the posted IMR write. Mirrors what the INTx path already
achieves via the loop in re_intr().
* MSI interrupt mode on RTL8168H under load; "missed Tx interrupts"
watchdog recoveries no longer occur.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58278
PR: kern/166724
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
On PCIe parts a TxPoll request can be lost when packets are queued
in quick succession, leaving owned descriptors with no transfer in
progress until the watchdog fires. re_txeof() runs from the interrupt
handlers, re_tick() and re_watchdog(), so re-writing TXSTART whenever
the ring is still non-empty turns a potential 5-second stall into at
most one tick.
One register write on a path that already took an interrupt;
fast path untouched.
* Sustained bidirectional load on RTL8168H; no Tx stalls, no throughput
regression at 941 Mbps line rate.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58277
PR: kern/166724
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The STOPREQ command written by re_stop() is not defined for
RTL8168G and later; issuing it can wedge the MAC.
Replace it on those parts with the vendor-documented sequence:
* settle delay
* bounded poll for Tx queue empty
* clear TE/RE
* then bounded poll of the MCU command register (0xD3) FIFO-empty bits.
Also reset the controller before the Rx/Tx buffer free: a controller that
has not quiesced keeps DMAing stale, still-owned descriptors pointing at
freed mbufs (use-after-free under INVARIANTS, cross-NIC mbuf corruption
reported in the PR).
Adds the RL_MCU_* register definitions.
All waits are bounded; error paths only.
* iperf3 --bidir at line rate against RTL8168H (XID 0x541);
previously wedged the controller until power cycle, with the
quiesce the reset path recovers.
* Deployed in production on an RTL8168H fleet since 2026-07-01.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58276
PR: kern/166724
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Four Atlantic 2 register-access corrections found in bring-up.
B0 aggregate octet counters: the B0 firmware statistics interface reports
only aggregate rx/tx good octets, not the per-cast breakdown A0 and
Atlantic 1 provide, so every octet sysctl read a permanent zero while
frame counters advanced. Populate the aggregate octet fields from the B0
buffer; aq_update_hw_stats() accumulates them directly when the per-cast
octets are absent.
Drop the duplicate attach-time MCP reboot: aq_hw_mpi_create() already
reboots the A2 firmware to read its version and caps, then aq_hw_reset()
immediately rebooted it again -- a full MCP restart plus several
transaction-id-bracketed window reads, adding attach latency and a
duplicate banner. Give aq_hw_reset() a reboot flag and pass reboot=false
for A2 at attach; the load-bearing down/stop reboot (which resyncs A2 RX
DMA across ifconfig down/up) keeps reboot=true.
Skip Atlantic 1 register accesses on Atlantic 2: gate out the 0x7040
Atlantic 1 TPO write (which A2 lacks; already a no-op via the unset TPO2
feature, but Linux hw_atl2 omits it), and guard the
aq_hw_mpi_read_stats() direct reads of reg_rx_dma_stat_counter7 (dpc) and
the LRO counter (cprc) with !ATLANTIC2 -- those are Atlantic 1 codegen
offsets that on Atlantic 2 land on unrelated registers and can report
bogus input-drop / LRO counts.
HW-validated on AQC107 <-> AQC113C: A1 stats unchanged, A2 IQDROPS stays
0, attach consumes one MCP reboot instead of two, bidirectional iperf3
clean.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58143
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Wire up the Atlantic 2 receive datapath: the action-resolver table (ART),
multiqueue RSS, QoS, and interrupt moderation.
RX action-resolver table: Atlantic 2 replaces Atlantic 1's discrete RX
filter registers with an ART -- hardware computes a per-packet
classification tag, then walks {tag, mask, action} rows to drop, assign a
queue, or assign a TC. aq_hw_art_filter_set() installs one row under the
ART semaphore; aq_hw_init_rx_path() enables the resolver, tags L2
unicast/broadcast, installs the unicast/all-multicast and VLAN drop rows,
and assigns every 802.1p priority to TC 0 (mirroring the Atlantic 1
user-priority map, since our RX side is a single 8-ring group in TC 0).
Tag every enabled VLAN filter in the per-filter resolver-tag field -- a
register the BSD ports never write -- because the VLAN drop row matches
resolver tag 0, so without it all tagged receive was dead under VLAN
filtering. Promiscuous mode disables the drop rows rather than toggling
the Atlantic 1 promiscuous bits; all ART callers surface a semaphore
timeout consistently. The Atlantic 1 RX_TCP_RSS_HASH and TPO2
programming is gated to Atlantic 1.
Multiqueue RSS and QoS: fill Atlantic 2's own per-TC redirection table
(AQ2_RPF_RSS_REDIR), skipping the Atlantic 1 table and its write-enable
handshake. Program Atlantic 2's smaller packet-buffer sizes, its wider
data-TC credit/weight fields, and its ring-to-TC map, using
aq_hw_active_tcs() for the TC loops.
RSS hash types: the Atlantic 2 resolver has per-protocol hash-type enables
in REDIR2, so build the mask from aq_rss_hashconfig() instead of
hardcoding every protocol -- UDP 4-tuple hashing now follows the kernel
policy (off by default) with no L3L4 flow-filter workaround, and
aq_hw_udp_rss_enable() is skipped on Atlantic 2. The kernel-to-hardware
hash-type mapping is a small static lookup table rather than a nine-branch
chain, since the two bit spaces do not share a simple shift.
Tx interrupt moderation: Atlantic 2's per-ring Tx moderation control
register lives at a different address, but its field layout matches the
value the driver already builds, so write that value straight to it; Rx
moderation is shared.
HW-validated on AQC107 <-> AQC113C: TCP RSS spreads across 7/8 RX queues
under 16 parallel flows, rx_err=0.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58142
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add support for the Marvell Atlantic 2 (AQC113/114/115/116) controllers,
a new chip generation that is not register-compatible with the Atlantic 1
parts aq(4) supports today. Adapted from the OpenBSD/NetBSD if_aq driver.
Register and device definitions (aq2_hw.h): the firmware handshake
(MIF_BOOT / MCP_HOST_REQ_INT / MIF_HOST_FINISHED), the 0x12000/0x13000
firmware interface windows, and the action-resolver table (ART) that
replaces Atlantic 1's discrete RX filters, plus the Atlantic 2 PCI device
ids and the aq_is_atlantic2() helper. Reserve a chip-feature bit
(AQ_HW_CHIP_ATLANTIC2) and add the aq_hw fields the firmware fills at boot
(ART base index, statistics interface version A0/B0). The per-VLAN-filter
resolver-tag field comes from the Linux driver; the BSD sources never
write it.
Firmware operations (aq_fwa2.c): Atlantic 2 talks to the management CPU
through the 0x12000/0x13000 register windows plus the boot handshake,
rather than Atlantic 1's mailbox in shared RAM. Implement that as a third
aq_firmware_ops vtable (reset, set_mode, get_mode, get_mac_addr,
get_stats); aq_fwa2_reboot() boots the firmware, selects the A2 ops, and
reads the version and ART base index, failing fast on the
crash-init / boot-failed bits. fwa2_set_mode advertises full duplex only
(the media model exposes no half-duplex types) and writes and acks the
link options before raising ACTIVE mode, so a forced media change does not
begin negotiation with a stale rate mask. enum aq_fw_link_speed gains
aq_fw_10M, which Atlantic 2 supports and Atlantic 1 does not.
Probe and attach: list the device ids with their media types and link
speeds (all copper; AQC113* up to 10G, AQC116C to 1G), populate
hw->device_id, and tag the generation with AQ_HW_CHIP_ATLANTIC2 so
IS_CHIP_FEATURE() recognises it uniformly. Branch firmware bring-up and
reset on the generation: aq_hw_init_ucp() and aq_hw_reset() reboot the MCP
instead of the Atlantic 1 RBL/FLB reset -- without a real datapath reset
every stop/init cycle reprograms the rings on a live, desynced RX DMA
engine and the receive path stays dead. aq_hw_init() programs the
Atlantic 2 launch-time clock ratio in place of the Atlantic 1
MRRS / TX-DMA request-limit clamp. Add an AQ_LINK_10M capability bit
(Atlantic 2 links at 10M, Atlantic 1 cannot), offer 10baseT media, and map
IFM_10_T to aq_fw_10M.
With every supported media type now present, replace the per-speed switch
statements in aq_media.c with a single {link bit, fw rate, IFM_* subtype,
Mbit/s} table -- one source of truth for the supported link speeds.
With this an Atlantic 2 card probes, brings up its firmware, reads its
MAC, and negotiates link; the RX action-resolver datapath comes next.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58141
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Non-functional cleanup, with two diagnostic corrections.
Dead code: delete leftover commented-out AQ_DBG_ENTER/EXIT/PRINT calls
(aq_hw.c, aq_fw2x.c, aq_irq.c, aq_main.c), a commented-out aq_nic_cfg
local, the stale old-signature parameter blocks between the ring-init
declarations and their bodies (aq_ring.c), a trailing note on a live
statement, and the unused DumpHex() vendor debug helper (no callers; its
body only compiled under AQ_CFG_DEBUG_LVL > 3).
Register-write macros: parenthesize AQ_WRITE_REG_BIT's msk/shift/value
arguments so a compound argument cannot mis-bind, give AQ_HW_FLUSH() an
explicit hw parameter instead of capturing it from caller scope, and drop
the duplicate lowercase aq_hw_write_reg[_bit] aliases (converting the 43
call sites to the uppercase spelling) so there is a single form.
Diagnostics: the aq_log* family expanded through the base log macro, which
ignored its level and printed unconditionally, while the error traces
gated on a debug level that defaulted below LOG_ERR and so were suppressed
-- backwards. Gate the base log macro the way the trace one does and
default the level to lvl_error, so the once-per-event firmware reset /
capability errors are visible by default while the verbose info/dump
output stays opt-in.
Naming: rename identifiers carried verbatim from the vendor import that do
not match style -- names mixing an ALL-CAPS macro-style prefix with a
lowercase tail, and a trailing underscore the vendor used as a
"file-local" marker in place of static.
- dbg_level_ / dbg_categories_ -> aq_dbg_level / aq_dbg_categories: these
are real globals (the log/trace macros reference them from every
translation unit), so the trailing underscore was never a stand-in for
static; give them the aq_ namespace so the driver stops exporting
generically-named global symbols.
- log_base_ / trace_base_ -> aq_log_base / aq_trace_base: the internal
macros behind the aq_log*/trace* families.
- bootExitCode / flbStatus -> boot_exit_code / flb_status (aq_fw.c);
flb_status now matches the identically-purposed variable already spelled
that way in the sibling FLB-reset path.
Cosmetic: terminate the ring/HW-init, MSI-X admin-handler, and
media-change error messages with a newline so they are not garbled into
adjacent dmesg output, and label the per-queue rx_bytes sysctl "RX Octets"
(it was copy-pasted "TX Octets").
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58140
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Firmware-statistics accounting and interrupt-routing fixes.
Stats delta underflow: guard the MAC statistics delta accumulation
against counter wrap or a firmware counter reset, so a snapshot smaller
than the previous one does not underflow into a huge spurious delta.
Skip stats on a failed read: aq_update_hw_stats() ignored
aq_hw_mpi_read_stats()'s return and committed the on-stack mbox into
last_stats unconditionally. On a failed read that snapshot is garbage or
zero and poisons the delta baseline (a zeroed snapshot wipes last_stats,
so the next good read double-counts). Check the return and skip the
accumulation and the last_stats commit on failure.
Mailbox/stats separation: struct aq_hw_stats served both as the raw fw1x
MCP mailbox layout and as the driver's canonical stats snapshot, so any
field added to it would silently shift the fw1x mailbox read. Give the
fw1x mailbox its own raw layout in struct aq_hw_fw_mbox and let
aq_hw_stats become purely driver-owned; with the coupling gone, add
first-class aggregate octet fields (brc/btc) that Atlantic 2 B0 firmware
can populate directly. No A1 behavior change. The raw block is a named
struct (aq_fw1x_mbox_stats) with a _Static_assert tying its size to
aq_hw_stats' matching prefix, so the fw1x memcpy cannot silently misalign
if either field list drifts. Also drop the unused FW1X_MPI_STATE_ADR /
FW1X_MPI_CONTROL_ADR macros and the redundant fw1x_get_stats() dpc
assignment that the caller immediately overwrites.
Per-speed interrupt moderation: aq_hw_interrupt_moderation_set()
hardcoded speed_index = 0, so every link speed got the 10G timer pair and
the other rows were dead. Record the negotiated rate and index the
tables by ffs(speed) - 1, reordering the rows to match the
enum aq_fw_link_speed bit positions so the index cannot drift from the
enum. Rename the two per-speed timer tables (AQ_HW_NIC_timers_table_
{rx,tx}_ -> aq_itr_timers_{rx,tx}), function-local static arrays whose
SCREAMING_CASE vendor names read like macros.
Hardware error interrupts: route both hardware error causes (interrupt
map register 0) to the admin vector so they are actually delivered.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58139
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Correct several attach/detach/reset paths that either swallowed failures
or acted on undefined state.
MSI-X attach-failure double-free: aq_if_msix_intr_assign() freed the
per-RX-ring interrupts in its failure path and then returned an error, so
iflib's IFDI_DETACH freed the same irq structures again --
bus_teardown_intr() on a dangling tag and bus_release_resource() on an
already-released IRQ, panicking a box that should have simply failed to
attach. Let iflib own the teardown; drop the failure-path loop and the
now-dead index bookkeeping.
Detach loop bound: aq_if_detach() freed the per-ring interrupts looping
to isc_nrxqsets while indexing rx_rings[], which is sized by
rx_rings_count; index by rx_rings_count to match every other RX-ring
loop.
AQ_HW_WAIT_FOR final poll: the macro derived its result from the loop
counter rather than the condition, so a condition that became true on the
last iteration reported ETIMEDOUT. Worst for the acquire-on-read
firmware RAM semaphore, which was acquired in hardware but reported as a
timeout. Return based on the last evaluation of the condition.
RBL MAC reset SPI cleanup: mac_soft_reset_rbl() fired the global reset
without first tearing down the SPI/flash interface, so a flash burst in
flight left the SPI bus wedged, the RBL could not re-read flash, and the
reset returned EBUSY -- fatal at attach ("MAC reset failed: 16"). Set
bit 4 of the SPI control register (0x53c) before the global reset, as the
sibling FLB path and the Linux driver do.
Reset failure propagation: aq_hw_reset() discarded fw_ops->reset()'s
return, so a failed attach-time fw2x capability read left fw_caps == 0
permanently and stats silently froze. Propagate the error so the reset
fails and is retried.
aq_hw_init failure propagation: aq_hw_init() discarded
aq_hw_init_tx_path()/aq_hw_init_rx_path() returns and reported success,
bringing the interface up half-initialized; capture both and goto
err_exit (mainly the Atlantic 2 RX action-resolver path, which returns
EBUSY on ART semaphore timeout).
Link-state outputs: aq_hw_get_link_state() left *link_speed and *fc_neg
unwritten on early-return paths, and the caller acts on them
uninitialized, so a transient firmware get_mode() failure could fabricate
a phantom link-up at a garbage speed and program a garbage RX-pause bit.
Initialize both to safe link-down values before calling get_mode().
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58138
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Align RX steering with the kernel RSS framework and factor out the
active-traffic-class count.
RSS key and indirection table: on an options RSS kernel the stack owns a
canonical hash key and a hash-to-bucket indirection table binding each
bucket to a CPU. aq programmed a random arc4rand() key and a plain
i % rss_qs table, so the hash it stamped in iri_flowid and the queue it
steered a flow to did not match the CPU the stack chose -- defeating RSS
affinity. Under #ifdef RSS take the key from rss_getkey() and each entry
from rss_get_indirection_to_bucket(), as e1000/ixgbe/ixl do; the non-RSS
build keeps the random key and round-robin table.
RSS hash-type policy: drop the private hw.aq.enable_rss_udp knob (RDTUN,
default on) and add aq_rss_hashconfig(), which under options RSS returns
rss_gethashconfig() and otherwise the same UDP-off default. UDP 4-tuple
hashing scatters a fragmented datagram's pieces across queues because
only the first fragment carries the L4 ports, so it is now off by default
and re-enabled the standard way, via net.inet.rss.udp_4tuple, matching
ix/ixl/mlx5. On Atlantic 1 the UDP-off action stays the existing L3L4
flow-filter workaround; only its policy source changes.
TX traffic-class helper: factor the active-TC count (one per active
8-ring group, capped at HW_ATL_B0_TCS_MAX) out of aq_hw_qos_set() into
aq_hw_active_tcs(), so there is a single definition of the policy; the
Atlantic 2 RSS redirection table reuses it.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58137
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
aq_isc_rxd_pkt_get() returned EBADMSG when a receive descriptor's
MAC/receive-error bit (rx_stat bit 0) was set. iflib treats any error
from isc_rxd_pkt_get() as a fatal ring fault and answers with
IFC_DO_RESET -- a full interface reinitialization. A per-frame receive
error is not a ring fault: on a marginal link or cable the Atlantic
delivers errored frames continuously, so each one triggered another
reset and the interface reset-stormed itself into carrying no traffic
instead of merely dropping the bad frames.
The Atlantic delivers errored frames to the host by design (Linux drops
them in software via buff->is_error), and iflib offers no per-frame
error return that isn't a reset. Follow the vmxnet3 model: on a receive
error zero the fragment lengths and return success. iflib then discards
the packet (assemble_segments() excludes zero-length fragments) while
still recycling the descriptors through the refill path -- no reset.
Also drop frames flagged with an RX-DMA fault (rdm_err), not just the
MAC-error bit; and keep iri_len non-zero on that drop path, since iflib
asserts iri_len != 0.
The genuinely structural errors -- more segments than isc_rx_nsegments,
or a pkt_len inconsistent with the descriptor count -- still return
EBADMSG, since those indicate a confused ring where a reset is the right
recovery.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58136
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Advertise the offloads the hardware already performs, correct the TX
descriptor's L3 family selection, and correct the VLAN and multicast
receive-filter paths.
Offloads: advertise IFCAP_HWCSUM_IPV6 (adding CSUM_IP6_TCP/UDP/TSO to
isc_tx_csum_flags) and IFCAP_VLAN_HWTSO, and enable the RX outer
(S-VLAN) tag parse mode in aq_hw_offload_set().
TX descriptor L3 family: aq_setup_offloads() derived tx_desc_cmd_ipv4
from CSUM_IP|CSUM_TSO, but CSUM_TSO is (CSUM_IP_TSO|CSUM_IP6_TSO) and
tcp_output() sets both bits without regard to address family, so an
IPv6 TSO frame matched on CSUM_IP_TSO and went out with the IPv4
header-checksum command set on a frame that carries no IPv4 header.
The checksum flags cannot distinguish the family; key the bit off
IPI_TX_IPV4 instead, which iflib derives from the parsed ethertype,
as the IPI_TX_INTR test below it already does. Plain IPv6 checksum
offload was unaffected, as CSUM_IP6_TCP alone never matched the mask.
RX VLAN tag stripping: ring init hardwired hardware tag stripping off
while the RX path still set M_VLANTAG and the writeback tag for every
tagged frame, so a tagged frame arrived with the tag in line while the
mbuf claimed it stripped and ether_demux() parsed four bytes short of
the payload. Program per-ring stripping from IFCAP_VLAN_HWTAGGING and
set M_VLANTAG only under the same capability, so the two states stay
coherent.
VLAN filter and promiscuous edge cases: filter only when 1..16 VLANs are
registered -- with none (or more than the 16 the table holds) fall back
to VLAN-promiscuous and pass all tags, rather than dropping every tagged
frame against an empty filter table; and keep VLAN-promiscuous set
whenever the interface is IFF_PROMISC, so adding or removing a VLAN under
promisc does not clear it and start dropping tagged frames.
Multicast reconcile: ifdi_multi_set is declarative, but aq_if_multi_set()
only added -- shrinking the list left accept-all-multicast latched or
stale exact slots enabled, defeating hardware multicast filtering until
a reinit. Clear the exact slots before reprogramming the current list,
and always drive accept-all-multicast from the current state so a shrink
clears it.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58145
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
dpaa2_ni_init() only enabled the DPNI object; it never pushed the
promiscuous/allmulti state or the multicast filter table to the MC
firmware. The SIOCSIFFLAGS handler ignores flag changes that arrive
while the interface is down, yet still latches them into sc->if_flags,
so a promiscuous mode request made before the first up was silently
lost and could never be applied afterwards: the up path runs
dpaa2_ni_init(), which did not read the flags, and every later
SIOCSIFFLAGS compares against the already-latched value and sees no
change.
This is exactly what happens when if_bridge adds a dpni member while
the dpni is still down, e.g. rc.conf's
create_args_bridge0="... addm dpni0"
running at bridge clone time, before ifconfig_dpni0="up" is processed.
bridge_ioctl_add() puts the member into promiscuous mode at addm time;
the request never reaches the firmware, so the DPNI continues to
hardware-filter unicast destined to other MACs. ifconfig still
reports PROMISC (a stack-level flag), which makes the failure
invisible: the host stays reachable only via the DPNI's own MAC
address (e.g. with net.link.bridge.inherit_mac=1), while bridged
epair/vnet jail traffic is silently dropped on RX.
Reapply both pieces of administrative state after enabling the DPNI,
as other NIC drivers do in their init path. This also restores
multicast memberships joined while the interface was down.
PR: 292006
Reported by: jhibbits
Signed-off-by: Nick Price <nick@spun.io>
Reviewed by: jhibbits
Differential Revision: https://reviews.freebsd.org/D58330
|
| |
|
|
|
|
|
|
| |
SPL is a no-op on amd64. Real locking is already handled by fc_mtx and
per-driver mutexes.
Reviewed by: imp
Differential Revision: https://reviews.freebsd.org/D58210
|
| |
|
|
|
|
|
| |
Migrated fwdv to use per-unit-directory child device
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58204
|
| |
|
|
|
|
|
| |
Migrated fwisound to use per-unit-directory child device
Differential Revision: https://reviews.freebsd.org/D58203
Reviewed by: adrian
|