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.