| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
| |
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)
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
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)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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_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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
| |
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D57656
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- 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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
| |
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
|
| | |
|
| |
|
|
|
|
|
|
| |
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
|
| |
|
|
| |
No need for a bespoke #define.
|
| |
|
|
|
|
|
| |
And remove some unused definitions.
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D54152
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
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_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.
|
| | |
|
| |
|
|
|
|
| |
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.
|
| |
|
|
| |
pause() has 2 different definition in unistd.h and sys/systm.h
|
|
|
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
|