aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/aq
Commit message (Collapse)AuthorAgeFilesLines
* aq(4): arm PHY thermal shutdown only where a sensor existsNick Price2026-08-162-4/+9
| | | | | | | | | | | | | aq_fw2x_thermal_arm() reached for a copper PHY register that the fibre parts do not implement, so arming failed on every init and printed a warning for a capability the hardware cannot have. Return ENOTSUP when the firmware does not advertise a temperature sensor, matching aq_fw2x_get_temp(), and warn only for a genuine failure. Signed-off-by: Nick Price <nprice@FreeBSD.org> Accepted-by: adrian Approved-by: adrian (cherry picked from commit 3c7f1aa3b831431193106f8610b2142131d774f5)
* aq(4): probe the D100 device IDNick Price2026-08-161-0/+2
| | | | | | | | | | | | | The D100 device ID was defined and handled by aq_hw_capabilities(), but had no entry in aq_vendor_info_array[], so the driver never probed it and the card was left unattached. Add the missing entry; the table lists the fibre variant last within each group, so it follows D109 rather than sorting numerically. Signed-off-by: Nick Price <nprice@FreeBSD.org> Accepted-by: adrian Approved-by: adrian (cherry picked from commit 4976b1d24abd6ff660e60041d1990b22c0bc2e5b)
* aq(4): report link transitions and previously silent failuresNick Price2026-08-097-23/+281
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A link flap left nothing in the log to work from. Both the link up and link down messages were gated on bootverbose while the message for a speed change that keeps carrier was not, so a default kernel was silent about a flap yet loud about a downshift -- the inverse of what an operator wants. The generic message from if_link_state_change() carries no speed, so gating the driver's own left the negotiated rate unrecorded. Report both transitions unconditionally. Say more than the rate. aq_hw_get_link_state() already negotiates flow control and throws it away, and Atlantic 2 reports duplex and EEE in the same link status word the rate comes from; decode them through a new get_link_info firmware op and name all of it on the up transition. EEE matters for a flap: low power idle transitions are a common source of marginal link trouble on multi-gigabit copper, and whether it was active is otherwise invisible. Give the down transition a cause. The PHY global fault code was only consulted from the thermal state machine, so an ordinary link loss reported nothing at all. Read the fault code, the firmware link state and the PHY temperature once per transition and append whatever is available. The firmware raises a fault one poll after it drops the link, so a thermal trip usually shows only its temperature here and aq_thermal_poll() names it on the following poll; the temperature alone is enough to separate a hot PHY from a cable event. Warn before the PHY trips rather than only after. The Atlantic 2 health monitor word carries a hot warning bit next to the ready and fault bits that nothing decoded. Report both edges of it from the thermal poll, so an adapter that is approaching its shutdown threshold says so while the link is still up. Expose the firmware's own link transition counters. The Atlantic 2 A0 statistics layout opens with link_up and link_down, which were read out of the firmware on every statistics poll and discarded. Publish them as dev.aq.N.fw_link_up and fw_link_down so a single flap can be told from a link that has been flapping all night. The B0 layout has no equivalent, so the op reports ENOTSUP there and the nodes are not created, matching how the temperature node is handled. Stop announcing a link state that was never read. The return value of aq_hw_get_link_state() was discarded, so a failed read would have been announced as link down. No firmware backend can fail that call today -- all three decode a register with no error path -- but the caller no longer depends on that, and it says so once if it ever starts failing. Report the hardware failures that were being discarded. The driver already reports the errors it keeps, so what stayed quiet was the set of calls whose result was never examined at all. None of these are expected to fail, which is precisely why a failure needs to say so: each one leaves the interface running but misconfigured in a way that presents as a network problem rather than a driver problem. aq_if_init() discarded aq_hw_start(), aq_hw_rss_hash_set(), aq_hw_rss_set() and aq_hw_udp_rss_enable(), so a datapath that never started or an indirection table that was never programmed showed up only as an interface that passes no traffic or delivers every flow to one queue. aq_mc_filter_apply() discarded aq_hw_mac_addr_set(), so a multicast address the stack believes is programmed could silently not be; report the address that failed and leave the filter slot for the next one instead of burning it. aq_update_vlan_filters() reported only the last of its three register writes. aq_if_stop() discarded both ring stop calls and the MAC reset, and a MAC that did not reset can still be mastering the bus. aq_if_detach() and aq_if_suspend() discarded aq_hw_deinit(). The interrupt moderation update on a link speed change was dropped as well; it runs only on a transition, so reporting it cannot become noisy. aq_if_attach_pre() discarded aq_hw_capabilities(), which is the only behavioral change here: it now fails the attach rather than continuing with an unset media type and an empty link speed mask, which would attach an interface that can never negotiate a link. It returns an error only for a device the probe table does not cover, so it is not reachable in practice. Document the resulting sysctls, along with the existing temperature and tracing nodes, which had no manual page coverage. Tested on an AQC113C (Atlantic 2 B0, firmware 1.5.38). Link up reports "speed=10000, full-duplex, flowcontrol none, EEE off", and "speed=1000" after a forced renegotiation, so the rate and duplex are read rather than assumed. A cable pull reports "link DOWN, F/W link state 0, temp 59 C" with the PHY fault clause correctly absent, which is what separates a cable event from a thermal trip. The B0 interface reports ENOTSUP for the link counters, so those two nodes are correctly not created. Traffic is unaffected: ten flows spread over all eight RX queues with no errors and no drops. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D58749 Signed-off-by: Nick Price <nprice@FreeBSD.org>
* aq(4): interface lifecycle and link-state fixesNick Price2026-08-023-8/+34
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | aq_if_init() programmed the address captured at attach, so an address set with "ifconfig ether" or by lagg(4) enslavement was never written to unicast filter slot 0: the interface transmitted with the new address but the MAC still filtered on the old one, so it received nothing. Copy the current if_getlladdr() the way the other iflib drivers do. The link state could latch UP forever. aq_if_stop() cleared linkup before calling aq_if_update_admin_status(), which suppressed the LINK_STATE_DOWN transition the "link was UP" branch would have made. Announce the down transition directly from aq_if_stop() instead, and do not poll the admin status there at all: the MAC has just been reset, so a stale link reading would re-announce the link as up. The admin task itself had to stop reporting a link on a stopped interface. iflib runs it while either IFF_DRV_RUNNING or IFF_DRV_OACTIVE is set, and iflib_stop() sets OACTIVE, so the task kept polling after the stop and re-announced LINK_STATE_UP behind the driver's back. Treat a non-running interface as having no link. A lagg(4) parent otherwise keeps hashing flows onto a port whose carrier is gone, because LAGG_PORTACTIVE tests if_link_state together with IFF_UP. Stop the rest of the task there as well: the PHY thermal poll and the initialization retry both end in iflib_request_reset(), and _task_fn_admin() acts on that with no test of its own, so either could re-initialize an interface the operator had just taken down. aq_if_update_admin_status() also only reacted to transitions in and out of zero speed, so an autoneg downshift that kept the link up left if_baudrate, ifmedia, RX pause and interrupt moderation programmed for the old speed. Track the announced speed and re-run that work when it changes. aq_if_suspend() resets the MAC and stops the rings, but iflib_device_suspend() only calls IFDI_SUSPEND and never stops the interface, leaving IFF_DRV_RUNNING set over a suspended device. Clear it. Signed-off-by: Nick Price <nick@spun.io> Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D58473
* aq(4): mailbox, flow-control and firmware error-handling fixesNick Price2026-08-026-34/+121
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fold the whole-driver-review correctness and hardening fixes for the firmware and hardware layers. Advance the firmware-mailbox address per word in aq_hw_fw_downld_dwords(): on B1 silicon each loop iteration waits for the mailbox address register to differ from the expected address, but it was set once and never moved, so after the first word every wait returned immediately and read stale data. Advance it four bytes per word. B0 is unaffected (it polls the busy bit). The same function also left err set to ETIMEDOUT after successfully force-recovering the RAM CPU semaphore; the transfer loop is guarded by "--cnt && !err", so it ran zero iterations and returned a timeout with an untouched buffer, making the recovery path dead code. aq_hw_get_mac_permanent() ignored the get_mac_addr() error and then examined a buffer the firmware op never wrote on failure. A fresh softc is zero, so the "invalid address" test fired, a random locally administered MAC was substituted, and err was overwritten with 0 -- a transient mailbox failure produced a card that attached with a different MAC every boot. Fail instead; the random-address fallback still covers a genuinely blank or multicast burned-in address. aq_fw1x_reset() discarded the same download's return value and then read transaction_id out of an uninitialized stack struct, so propagate that error too. Encode RX-only flow control as PAUSE|ASYM_PAUSE rather than PAUSE alone: firmware 2.x/3.x has no independent RX-only bit, so the old encoding advertised symmetric pause when RX-only was requested. The MPI_INIT path also never cleared the pause bits before OR-ing in the requested ones, so flow control could be enabled and never disabled; clear them first, as the Atlantic 2 and Linux implementations do. Reject single-vector MSI in aq_if_attach_post() the same way legacy INTx is rejected: ift_legacy_intr is NULL, so no driver filter would acknowledge the not-clear-on-read, auto-masked device interrupt status; every supported Atlantic device provides MSI-X. Propagate firmware and MDIO errors instead of discarding them. The fw2x MDIO primitive returned a data word with no way to report a controller timeout; give aq_fw2x_mdio_op() a status return and a data out-parameter, propagate it through phy_write/read/reset/thermal_arm, and stop advancing the thermal recovery state machine when a PHY reset fails. Use that error to end the PHY address scan early: aq_fw2x_init_phy_id() probed all 32 MDIO ports even when the controller itself was timing out, spending up to ten seconds under fw_mtx and the iflib context lock. aq_fw2x_reset() also drove the shared MIF mailbox without fw_mtx, unlike every other fw2x mailbox user, so it could interleave with the temperature sysctl and load the capability mask from the wrong window. aq_hw_mpi_set() can return ETIMEDOUT when the Atlantic 2 shared firmware buffer is not acknowledged; aq_hw_init() now aborts through its error path rather than enabling rings with an unaccepted link state, and aq_if_init() logs the later link-speed error. Retry a failed initialization instead of leaving the link down. ifdi_init has no return value, so iflib marks the interface running once aq_if_init() returns; a propagated firmware-ack failure would otherwise leave it running with no initialized hardware and no recovery. Record the failure and retry from the admin task via iflib_request_reset(), paced by the once-per-second timer, giving up after a bounded number of attempts. Ring and queue start failures are deliberately left to the existing diagnostic, since they leave the remaining queues usable. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D58437
* aq(4): clean up diagnostics and remove dead codeNick Price2026-08-025-104/+53
| | | | | | | | | | | | | | | | | | | | | | | | | Non-functional cleanup, no change in behavior. device_printf() already prefixes each line with the device name, so the inline "atlantic:" token in the status and error messages produced a doubled prefix and diverged from the trace macros; remove it so all output carries one uniform "aqN:" prefix. Compile the RX/TX descriptor tracers only when AQ_CFG_DEBUG_LVL > 2 and make them no-op macros otherwise, so the default build no longer pays a cross-TU call plus argument evaluation per descriptor. Drop enum aq_dev_state, struct aq_rx_filters, and struct aq_vlan_tag, which have no remaining references now that VLAN state lives in a bitstr_t. Replace the four identical aq_sysctl_print_{tx,rx}_{head,tail} handlers, each carrying a dead write path on a read-only oid, with one aq_sysctl_print_ring_ptr that selects the accessor from arg2. Reduce the thermal and PHY-recovery comments to single terse lines that keep the load-bearing register numbers and the A1-vs-A2 recovery difference. Signed-off-by: Nick Price <nick@spun.io> Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D58436
* aq(4): PHY thermal-shutdown handling and correctness fixesNick Price2026-08-029-9/+380
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fold the thermal-protection work and the correctness fixes that landed alongside it. Report and auto-recover from PHY thermal shutdown. The Atlantic PHYs can autonomously shut down on over-temperature, latching global fault 0x8007 and dropping the link; Atlantic 2 ships this armed, Atlantic 1 disabled. Arm it on Atlantic 1 at interface init (1E.C478.A via the MAC's MDIO controller), and recover from a trip automatically: the admin-status poll detects the fault, logs the shutdown limit and measured temperature, and holds the link down until the PHY cools, then restores it -- Atlantic 1 needs a PHY reset (1E.2681.0) with the MAC firmware running plus a full re-init, Atlantic 2 recovers on the re-init alone. New firmware ops get_phy_fault, phy_reset, thermal_arm, and get_thermal_limit back the state machine in aq_if_update_admin_status(). Make that Atlantic 1 thermal MDIO path address-correct and fail-safe. The direct-MDIO helpers hardcoded the Clause-45 port address to 0, but it is strap-selectable: on a board whose PHY answers elsewhere every thermal op targeted nothing, so arming silently no-oped and the post-trip reset never cleared the latch. Discover the address by scanning ports 0..31 for a PMA/PMD identifier and form it as (phy_id << 5) | mmd, marking it valid only when a PHY actually answers. aq_fw2x_phy_read also returned 0 on a semaphore timeout, indistinguishable from a real 1E.C478 == 0, so thermal_arm could zero live provisioning bits; give the read an error return and gate thermal_arm and get_thermal_limit on it. Bound the multicast filter slot index. aq_mc_filter_apply() programmed slot count + 1 and bailed only at count == AQ_HW_MAC_MAX (33), one address too late, so a 33rd entry raced in between the if_llmaddr_count() snapshot and the if_foreach_llmaddr() walk drove an out-of-bounds MMIO write to slot 33. Fire the guard at AQ_HW_MAC_MAX - 1, and also reject index >= AQ_HW_MAC_MAX in aq_hw_mac_addr_set() where the slot becomes an RPF register offset. Correctness and safety fixes: initialize the sysctl context in attach_pre so the iflib fail-path detach cannot sysctl_ctx_free() an uninitialized list (a page fault when MSI/MSI-X is denied); range-check the Atlantic 2 action-resolver table index, taken verbatim from a firmware-supplied base, before writing the ART registers; and accumulate statistics deltas as unsigned, since AQ_SDELTA discarded a forward delta of 2^31 or more at 10G across a stretched admin poll. Signed-off-by: Nick Price <nick@spun.io> Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D58435
* aq(4): observability controls and sysctl/header hygieneNick Price2026-08-0212-85/+305
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fold the driver's observability and infrastructure work. Make aq_device.h self-contained: it declares struct aq_dev in terms of iflib, bitstring, socket, and ethernet types but included none of the headers that define them, compiling only because every includer happened to pull those first. Include what it uses. No functional change. Make the debug controls per-instance. The debug and debug_categories sysctls were registered per device but pointed at file-scope globals, so writing dev.aq.1.debug also changed dev.aq.0.debug and a card could not be traced in isolation. Move the level and category mask into struct aq_dev, reach them through the aq_dev back-pointer in struct aq_hw (wired up in attach_pre before the first firmware trace and guarded against a NULL deref), emit through device_printf() so each line carries its unit, and seed initial values from per-unit device hints so attach can be traced. Expose the PHY die temperature as dev.aq.N.temperature through a new firmware get_temp op: Atlantic 1 v2 reads it through the mailbox MPI control/state toggle, Atlantic 2 from the phy_health_monitor block in the OUT window (located at 0x13620 and confirmed by its ready bit). Atlantic 1 v1 has no sensor and exposes no node. Because this is the first firmware accessor iflib does not serialise, add a per-instance mutex in struct aq_hw and take it across the v2 read-modify-write in set_mode(), get_stats(), get_mode(), and get_temp(); the v1 and Atlantic 2 paths do not need it and say so. Trace the Atlantic 2 firmware path, which previously emitted nothing at any debug level (aq2_fw.c did not even include aq_dbg.h): the boot handshake, reset policy, MAC address, and link mode set/read, using the existing dbg_init and dbg_fw categories, with the per-poll mode read at detail level. Scope the driver sysctls to a context freed at detach. They were registered on the device newbus context, which newbus tears down only after DEVICE_DETACH returns, yet iflib frees the rings and softc inside DEVICE_DETACH -- a sysctl read racing detach could touch freed memory. Give the driver its own sysctl_ctx_list and free it at the start of aq_if_detach, draining in-flight readers first. Signed-off-by: Nick Price <nick@spun.io> Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D58434
* aq(4): correct Atlantic 2 register accessNick Price2026-07-194-18/+31
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* aq(4): program the Atlantic 2 multiqueue datapathNick Price2026-07-194-28/+210
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* aq(4): add Atlantic 2 (AQC113) device supportNick Price2026-07-198-84/+879
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* aq(4): remove dead code and tidy macros, diagnostics, and namingNick Price2026-07-1912-211/+136
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* aq(4): harden the interrupt and MAC-statistics pathsNick Price2026-07-194-44/+90
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* aq(4): harden the attach, detach, and reset error pathsNick Price2026-07-194-13/+30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* aq(4): honor the kernel RSS policy and add a TX traffic-class helperNick Price2026-07-193-15/+36
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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(4): drop errored RX frames instead of resetting the interfaceNick Price2026-07-191-5/+21
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* aq(4): expand and correct offloads, fix VLAN/multicast filteringNick Price2026-07-196-19/+62
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* aq(4): naming and exposureNick Price2026-06-205-65/+63
| | | | | Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57656
* aq(4): add a runtime dev.aq.N.debug trace controlNick Price2026-06-203-9/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The trace_* family (trace/trace_error/trace_warn/trace_detail, used in the F/W and init/config paths) was gated behind the compile-time AQ_CFG_DEBUG_LVL, which is 0, so the dbg_level_/dbg_categories_ runtime variables were dead and tracing could only be enabled by recompiling. Decouple trace_base_ from AQ_CFG_DEBUG_LVL so it is always compiled and gated purely at runtime on dbg_level_/dbg_categories_, make those two variables writable (no longer const, default level 0 = off), and expose them as dev.aq.N.debug (verbosity) and dev.aq.N.debug_categories (subsystem mask) sysctls. The datapath-heavy AQ_DBG_ENTER/PRINT/DUMP macros and the trace_aq_*_descr descriptor dumps stay behind AQ_CFG_DEBUG_LVL (still 0), so the per-packet paths are untouched -- trace_* is only used off the datapath. The two variables are global (the trace macros reference them directly), so the per-device sysctls share one backing store, which is fine for a debug knob. Validated on AQC107: dev.aq.0.debug defaults to 0 with no trace output; setting it to 6 emits the F/W init/reset/capabilities traces on the next F/W operation; setting it back to 0 silences them; traffic unaffected at line rate, rx_err=0. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57440
* aq(4): take F/W statistics off the iflib core lock (kick-and-read)Nick Price2026-06-201-54/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The once-per-second statistics refresh ran the whole F/W-mailbox transaction under iflib's CTX (sx) lock: fw2x_get_stats toggled the MPI STATISTICS control bit and busy-polled the state register for the acknowledgement (up to ~25 ms) before downloading the counters, so a slow F/W response blocked datapath reconfigure / ioctls for the duration. The per-cast and error counters have no direct-register source -- the reference Linux atlantic driver and our port both read them out of the F/W mailbox, and the MSM registers the chip exposes are never used for the periodic counters. So rather than poll, adopt the kick-and-read shape the iflib peer with the same constraint uses (vmxnet3): consume the snapshot the F/W produced for the *previous* request, then toggle the bit to request the next one -- no wait. The F/W finished that previous refresh ~1 s ago, so the download needs no poll, and the toggle write stays serialized against set_mode by the CTX lock exactly as before. This removes the 25 ms poll (and the toggle_mpi_ctrl_and_wait_ helper) from under the lock; only the fast 16-dword download remains. Cost: the counters lag one 1 s cycle, invisible for monitoring, and a torn read is already rejected by aq_update_hw_stats' monotonic-delta check. Validated on AQC107: a fixed 500 MiB RX transfer advances good_octets_rcvd by 549.6 MB -- 500 MiB plus the ~4.8% Ethernet framing overhead -- with rx_err=0 and traffic at line rate. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57439
* aq(4): modernize and de-Linuxify the vendor driverNick Price2026-06-2016-451/+328
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Dead-code removal, device_printf(9) logging, style(9) de-Linuxification, const F/W-ops tables, and readability cleanups. No change for valid traffic. Dead code and logging: - Remove the sub-gigabit TSO-masking block in the link-state ISR: it cleared IFCAP_TSO from the static isc_capabilities record (read only at attach / SIOCSIFCAP, never on the datapath), so it never gated TSO and only corrupted the validation mask. The Atlantic has no sub-gigabit TSO erratum. - Tidy the RX buffer-size handling: drop the dead switch(MCLBYTES) in aq_if_rx_queues_alloc, rename rx_max_frame_size -> rx_buf_size, and bound the per-fragment length from the wb.pkt_len writeback (EBADMSG on underflow or a final fragment longer than the RX buffer). - Drop every __FreeBSD__/__FreeBSD_version branch (FreeBSD 14.0 baseline); the pre-13 arms used pre-opaque-if_t APIs since removed and one never built. - Route all log messages through device_printf(9) (MAC via %6D), adding a device_t to struct aq_hw; drop the dead AQ_XXX_UNIMPLEMENTED_FUNCTION and aq_log_error macros and the per-ring init console spam. - Minor: comma -> semicolon in aq_if_attach_pre; (uint64_t) -> (uint32_t) TX high-word cast; MODULE_VERSION(atlantic, 1); remove unused/duplicate #includes. style(9) and types: - Remove all typedef'd struct/enum/union types (aq_dev_t, the speed/fc/ debug enums, the volatile RX/TX descriptor types, the firmware-file types) in favor of bare tags; for the DMA descriptors the volatile qualifier moves to the pointer/use sites. Drop the _s/_e tag suffixes and the "#define aq_hw_s aq_hw" alias. Rename the OOP-style *self parameter to hw. Replace usec_delay/msec_delay/ARRAY_SIZE/LOWORD with FreeBSD equivalents (BIT kept). __attribute__((__packed__)) -> __packed. F/W-ops vtable: - Rename the leftover hal parameter to hw; make aq_fw1x_ops/aq_fw2x_ops const (read-only data); drop the always-true "fw_ops &&" and always-present dispatch guards (only led_control, absent in F/W 1.x, keeps its NULL check). Readability: - aq_isc_rxd_pkt_get: fold the four identical RX-error blocks into one rx_err: label. aq_isc_rxd_available: hoist the shared descriptor advance out of the EOP test and drop the redundant continue. aq_hw_offload_set: drop the dead "int err = 0". Fix a stale "10 ms" comment on a 50 ms DELAY and the redundant literal parentheses. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57438
* aq(4): enable jumbo frames, software LRO, and suspend/resumeNick Price2026-06-202-20/+31
| | | | | | | | | | | | | | | | | | | | | | | | - Configure the RX buffer size from the interface MTU and enable jumbo frames up to 9000 bytes, replacing the fixed standard-frame setup. - Advertise IFCAP_LRO so iflib coalesces received TCP segments with its software tcp_lro(9), like every other in-tree iflib driver (ix/igc/em/vmxnet3); aq does no hardware LRO. iflib builds the per-RX-queue LRO context unconditionally, so the capability bit is all that is required; enabled by default via isc_capenable, toggle at runtime with ifconfig. - Add suspend/shutdown/resume handlers, replacing the unimplemented- function placeholders. aq_if_shutdown/aq_if_suspend stop the interface and deinitialize the hardware; aq_if_resume re-resets the F/W, re-reads the mailbox address and re-selects fw_ops via aq_hw_mpi_create() before iflib re-inits, because the runtime init path (aq_hw_init) reuses the cached mailbox/fw_ops and a D3 power cycle can clear them. iflib calls IFDI_RESUME unconditionally, so this also covers resuming while the interface was administratively down. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57437
* aq(4): RX/TX and HW-path correctness and hardeningNick Pricenull2026-06-208-56/+138
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Independent correctness fixes, plus robustness against a non-responding device, malformed descriptor writeback, and torn MMIO reads, and the move to the FreeBSD bus_space(9) register abstraction. Correctness: - aq_hw_ver_match returned true if any of major/minor/build was >= expected; compare lexicographically so e.g. 2.0.1 is correctly seen as older than 2.1.0. - The VLAN hardware-filter iteration used the vlan tag directly as the bitstring index; use vlan_tag + 1 so the active-VLAN bookkeeping lines up with the table. - aq_initmedia only registered IFM_AUTO in full-duplex/pause variants, so a bare "ifconfig aq0 media autoselect" matched no entry and returned ENXIO. Add the bare IFM_ETHER|IFM_AUTO entry, matching ix/em/igc/ixv. - Convert the per-ring diagnostic counters to counter(9): per-CPU, tear-free, no atomics on the increment path, fixing a data race and a 32-bit torn read against the locklessly-read sysctls. Drop three counters that were never populated (jumbo_pkts, tx_drops, tx_queue_full). Hardening and modernization: - Implement aq_hw_err_from_flags (previously a stub returning 0 that left ~24 call sites as no-ops): detect a non-responding device in the register read path (all-ones, confirmed against reg 0x10) and latch a sticky AQ_HW_FLAG_ERR_UNPLUG -> ENXIO; aq_if_init clears it so a transient detection cannot permanently wedge the device. - Bound the RX fragment loop in aq_isc_rxd_pkt_get (EBADMSG once i reaches isc_rx_nsegments) so a malformed never-EOP stream cannot write past the fragment array. - Bound the TX completion count in aq_isc_txd_credits_update against the raw HW head pointer (reject head >= tx_size) so a glitched head cannot make iflib free still-in-flight TX mbufs. - Remove the dead hardware-RSC branch in aq_isc_rxd_available; it followed wb.next_desp, a raw device value used as an index, but RSC is never enabled so rsc_cnt is always 0. Advance sequentially like the other in-tree iflib drivers; this drops the last raw-hardware-pointer dereference in the RX path. - Flush MMIO after interrupt-status acks (AQ_HW_FLUSH) so the write lands before the vector is re-armed under auto-mask-clear; retry the high word in read64_ against a torn lo/hi pair; document the non-atomic IMR read-modify-write in itr_irq_map_en_{rx,tx}_set. - Replace the raw-pointer MMIO (the Linux readl/writel idiom) with bus_space(9): store the BAR tag and handle in struct aq_hw and route AQ_READ_REG/AQ_WRITE_REG through bus_space_read_4/write_4. No functional change on amd64. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57436
* aq(4): adopt native FreeBSD errno conventionNick Price2026-06-206-101/+91
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Convert the driver's internal error-handling chain from the Linux negative-errno convention to FreeBSD positive errno everywhere. - All `return (-EXXX)` become `return (EXXX)`, `int err = -EXXX` loses the sign, and `if (err < 0)` checks become `if (err != 0)` across aq_fw.c, aq_fw1x.c, aq_fw2x.c and aq_hw.c. - mac_soft_reset_flb_ returns ETIMEDOUT/0 instead of a bool so it matches its RBL sibling. - The ETIME and EOK aliases in aq_common.h are removed; all sites use ETIMEDOUT and 0 directly, and the `rc = -rc` sign flips in aq_if_attach_pre are dropped. Turn AQ_HW_WAIT_FOR into a statement expression evaluating to 0 on success or ETIMEDOUT on timeout, assigned explicitly at all seven call sites, instead of silently assigning ETIMEDOUT to a variable named err in the caller scope. A statement expression rather than an inline function because every call must re-evaluate its condition each iteration -- one even assigns hw->mbox_addr as a side effect. Fix two correctness bugs surfaced by the conversion: - fw1x_get_stats gated its stats copy with `if (err >= 0)`, correct under negative errno but accepting every positive errno after the flip. Change to `if (err == 0)`. - fw2x_reset returned 0 regardless of capability-download failure, silently leaving fw_caps = 0. Return the real err. Harden aq_if_attach_pre: bit_alloc(4096, M_AQ, M_NOWAIT) was unchecked, so under OOM a later `ifconfig vlanN create` would NULL-deref the bitstring; check for NULL and fail with ENOMEM. The fail label's hardcoded `return (ENXIO)` becomes `return (rc)` so each error path reports its real errno. Remove the dead error checks in aq_hw_offload_set: the `if (err != 0) goto err_exit` blocks after the void tpo_/rpo_/tdm_ register-write helpers were unreachable (err is never set), and the real error capture is the aq_hw_err_from_flags call at the function tail. Drop the now-orphaned err_exit label. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57435
* aq(4): interrupt model and queue-count correctnessNick Pricenull2026-06-204-24/+54
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Rework the MSI-X and queue-count handling to use the standard iflib interrupt model and to keep every ring serviced. - Cap isc_n{tx,rx}qsets_max at the RSS indirection-table size (HW_ATL_RSS_INDIRECTION_QUEUES_MAX, 8) instead of HW_ATL_B0_RINGS_MAX. RSS only steers RX traffic to eight rings, so on hosts with more CPUs the surplus TX rings never make progress: iflib flowid-steers TCP flows across every TX ring, and a flow landing on a surplus ring has its segments queued but never transmitted, hanging the connection. - Add a TX-specific ifdi_tx_queue_intr_enable that reads tx_rings[txqid]->msix. It was wired to the RX handler, which indexes rx_rings[] with the qid; safe only while tx_rings_count == rx_rings_count, otherwise the lookup walks past rx_rings[] and feeds a garbage msix value into the IRQ mask register. - Fix three MSI-X / admin-IRQ bugs: the TX softirq was attached to rx_rings[i]->irq (overwriting the RX handle and leaving the TX handle uninitialized); the admin-IRQ failure path dereferenced rx_rings[rx_rings_count], one past the end; and aq_linkstat_isr cleared the admin interrupt by writing the raw vector number instead of BIT(vector). - Allocate one IFLIB_INTR_RXTX vector per RX/TX queue pair like every other in-tree iflib driver (em/ix/igc, vmxnet3) instead of an IFLIB_INTR_RX vector per RX ring plus a hand-wrapped IFLIB_INTR_TX softirq per TX ring. iflib's iflib_fast_intr_rxtx() then services TX completions on the shared vector through isc_txd_credits_update(). Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57434
* aq(4): Fix RSS indirection table OOB write and queue distributionNick Price2026-06-203-3/+14
| | | | | | | | | | | Two related fixes to `aq(4)`'s RSS indirection table handling: 1. Fix an out-of-bounds stack write in `aq_hw_rss_set()`. RSS table entries are 3 bits (8 queues max), but with more than 8 RX rings `rss_table[]` holds larger values; the 32-bit write then spills one `uint16_t` past `bitary[]` and corrupts the stack, so the NIC never links or the kernel panics. Mask each value to 3 bits and pack 16 bits at a time to keep the write in bounds. 2. Build the indirection table in `aq_if_attach_post()` with a modulo over `min(rx_rings_count, HW_ATL_RSS_INDIRECTION_QUEUES_MAX)` instead of `i & (rx_rings_count - 1)`, which assumed a power-of-two ring count. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57240
* aq(4): style(9) cleanupEd Maste2026-01-1211-67/+106
|
* aq(4): Style, whitespace and misc cleanupEd Maste2026-01-0518-3335/+3592
| | | | | | | | The compiled objects do not change other than a few diagnostic messages that include __LINE__. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D54304
* aq(4): Use standard ETHER_ADDR_LEN definitionEd Maste2025-12-194-5/+4
| | | | No need for a bespoke #define.
* aq(4): Use sys, not userland, headersEd Maste2025-12-116-12/+5
| | | | | | | And remove some unused definitions. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D54152
* aq(4): Fix VLAN tag testEd Maste2025-11-301-1/+1
| | | | | | | | | | | | | Previously emitted a compiler warning "warning: bitwise comparison always evaluates to false." Looking at the OpenBSD driver (which is based on this code) it looks like the VLAN flag should be set if either of these bits is. In the OpenBSD driver these are AQ_RXDESC_TYPE_VLAN and AQ_RXDESC_TYPE_VLAN2 rather than a magic number 0x60. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D53836
* aq(4): Remove unimplemented functionsEd Maste2025-11-301-4/+0
| | | | | | | aq_if_priv_ioctl and aq_if_debug have prototypes but are not yet implemented. Just remove the commented-out DEVMETHODs and the unused prototypes, to clear a build-time warning; the DEVMETHODs and prototypes can be readded if / when they are implemented.
* aq(4): Remove unused DRIVER_MODULE devclassJohn Baldwin2025-11-301-0/+4
|
* aq(4): Port to IfAPIOlivier Cochard2025-11-303-16/+16
| | | | | | Direct access to struct ifnet members is not possible in FreeBSD 15; accessors must be used. These exist in all supported FreeBSD versions, so we do not need to make this conditional.
* aq(4): Remove #include of user header <unistd.h>Rozhuk Ivan2025-11-301-1/+0
| | | | pause() has 2 different definition in unistd.h and sys/systm.h
* sys: Import snapshot of Aquantia ACQ107 vendor driverEd Maste2025-11-3018-0/+12109
Obtained from https://github.com/Aquantia/aqtion-freebsd commit c61d27b1d94af72c642deefa0595884481ea7377. This is not using a vendor branch. The formerly-upstream repo is abandoned and I do not believe it will receive updates. This initial import serves as a snapshot of the vendor code, but from here we will iterate on it in the tree as our own code. Bug fixes, code cleanup, and build infrastructure will follow. NetBSD and OpenBSD have derivatives of this driver (with additional hardware support). We can look to changes in those drivers, and the Linux driver, to add support here. Reviewed by: adrian Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D53813