Page MenuHomeFreeBSD

D58141.id181653.diff
No OneTemporary

D58141.id181653.diff

diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -858,6 +858,7 @@
dev/aq/aq_fw.c optional aq
dev/aq/aq_fw1x.c optional aq
dev/aq/aq_fw2x.c optional aq
+dev/aq/aq2_fw.c optional aq
dev/aq/aq_dbg.c optional aq
#
dev/ata/ata_if.m optional ata | atacore
diff --git a/sys/dev/aq/aq2_fw.c b/sys/dev/aq/aq2_fw.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/aq/aq2_fw.c
@@ -0,0 +1,448 @@
+/*-
+ * Atlantic 2 (AQC113/114/115/116) firmware operations for aq(4).
+ *
+ * Adapted from the OpenBSD/NetBSD if_aq driver:
+ *
+ * Copyright (c) 2021 Jonathan Matthew <jonathan@d14n.org>
+ * Copyright (c) 2021 Mike Larkin <mlarkin@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/endian.h>
+#include <net/ethernet.h>
+
+#include "aq_common.h"
+#include "aq_hw.h"
+#include "aq_hw_llh.h"
+#include "aq2_hw.h"
+#include "aq_fw.h"
+
+static int aq2_fw_reset(struct aq_hw *hw);
+static int aq2_fw_set_mode(struct aq_hw *hw, enum aq_hw_fw_mpi_state mode,
+ enum aq_fw_link_speed speed);
+static int aq2_fw_get_mode(struct aq_hw *hw, enum aq_hw_fw_mpi_state *mode,
+ enum aq_fw_link_speed *speed, enum aq_fw_link_fc *fc);
+static int aq2_fw_get_mac_addr(struct aq_hw *hw, uint8_t *mac);
+static int aq2_fw_get_stats(struct aq_hw *hw, struct aq_hw_stats *stats);
+
+/* Coherent OUT-window read, bracketed by the transaction id. */
+static int
+aq2_fw_interface_buffer_read(struct aq_hw *hw, uint32_t reg0, uint32_t *data0,
+ uint32_t size0)
+{
+ uint32_t tid0, tid1, reg, *data, size;
+ int timo;
+
+ for (timo = 1000; timo > 0; timo--) {
+ tid0 = AQ_READ_REG(hw, AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_REG);
+ if (((tid0 & AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_A) >>
+ AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_A_S) !=
+ ((tid0 & AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_B) >>
+ AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_B_S)) {
+ DELAY(10);
+ continue;
+ }
+
+ /* size0 is a 4-byte multiple: full register-width reads. */
+ for (reg = reg0, data = data0, size = size0;
+ size >= 4; reg += 4, data++, size -= 4)
+ *data = AQ_READ_REG(hw, reg);
+
+ tid1 = AQ_READ_REG(hw, AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_REG);
+ if (tid0 == tid1)
+ break;
+ }
+ if (timo == 0) {
+ device_printf(hw->dev, "A2 interface buffer read timeout\n");
+ return (ETIMEDOUT);
+ }
+ return (0);
+}
+
+/* Boot the A2 firmware and select the A2 firmware ops. */
+int
+aq2_fw_reboot(struct aq_hw *hw)
+{
+ uint32_t v, filter_caps[3];
+ int timo, err;
+ const char *iface;
+
+ hw->fw_ops = &aq2_fw_ops;
+
+ AQ_WRITE_REG(hw, AQ2_MCP_HOST_REQ_INT_CLR_REG, 1);
+ AQ_WRITE_REG(hw, AQ2_MIF_BOOT_REG, 1); /* reboot request */
+ for (timo = 20000; timo > 0; timo--) {
+ v = AQ_READ_REG(hw, AQ2_MIF_BOOT_REG);
+ if ((v & AQ2_MIF_BOOT_BOOT_STARTED) && v != 0xffffffff)
+ break;
+ DELAY(10);
+ }
+ if (timo <= 0) {
+ device_printf(hw->dev, "A2 firmware reboot timeout\n");
+ return (ETIMEDOUT);
+ }
+
+ for (timo = 200000; timo > 0; timo--) {
+ v = AQ_READ_REG(hw, AQ2_MIF_BOOT_REG);
+ if (v & AQ2_MIF_BOOT_COMPLETE)
+ break;
+ v = AQ_READ_REG(hw, AQ2_MCP_HOST_REQ_INT_REG);
+ if (v & AQ2_MCP_HOST_REQ_INT_READY)
+ break;
+ DELAY(10);
+ }
+ if (timo <= 0) {
+ device_printf(hw->dev, "A2 firmware restart timeout\n");
+ return (ETIMEDOUT);
+ }
+
+ v = AQ_READ_REG(hw, AQ2_MIF_BOOT_REG);
+ if (v & AQ2_MIF_BOOT_FAILED) {
+ device_printf(hw->dev, "A2 firmware restart failed\n");
+ return (EIO);
+ }
+ v = AQ_READ_REG(hw, AQ2_MCP_HOST_REQ_INT_REG);
+ if (v & AQ2_MCP_HOST_REQ_INT_READY) {
+ device_printf(hw->dev, "A2 firmware required but not present\n");
+ return (ENXIO);
+ }
+
+ /* Repack into fw_version's major.minor.build layout. */
+ err = aq2_fw_interface_buffer_read(hw,
+ AQ2_FW_INTERFACE_OUT_VERSION_BUNDLE_REG, &v, sizeof(v));
+ if (err != 0)
+ return (err);
+ hw->fw_version.raw =
+ (((v & AQ2_FW_INTERFACE_OUT_VERSION_MAJOR) >>
+ AQ2_FW_INTERFACE_OUT_VERSION_MAJOR_S) << 24) |
+ (((v & AQ2_FW_INTERFACE_OUT_VERSION_MINOR) >>
+ AQ2_FW_INTERFACE_OUT_VERSION_MINOR_S) << 16) |
+ ((v & AQ2_FW_INTERFACE_OUT_VERSION_BUILD) >>
+ AQ2_FW_INTERFACE_OUT_VERSION_BUILD_S);
+
+ err = aq2_fw_interface_buffer_read(hw,
+ AQ2_FW_INTERFACE_OUT_VERSION_IFACE_REG, &v, sizeof(v));
+ if (err != 0)
+ return (err);
+ hw->aq2_iface = v & AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER;
+ switch (hw->aq2_iface) {
+ case AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_A0:
+ iface = "A0";
+ break;
+ case AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_B0:
+ iface = "B0";
+ break;
+ default:
+ iface = "unknown";
+ break;
+ }
+ device_printf(hw->dev, "Atlantic 2 %s, firmware %u.%u.%u\n", iface,
+ hw->fw_version.major_version, hw->fw_version.minor_version,
+ hw->fw_version.build_number);
+
+ /* Base row added to every action-resolver-table index. */
+ err = aq2_fw_interface_buffer_read(hw,
+ AQ2_FW_INTERFACE_OUT_FILTER_CAPS_REG, filter_caps,
+ sizeof(filter_caps));
+ if (err != 0)
+ return (err);
+ hw->art_filter_base_index = ((filter_caps[2] &
+ AQ2_FW_INTERFACE_OUT_FILTER_CAPS3_RESOLVER_BASE_INDEX) >>
+ AQ2_FW_INTERFACE_OUT_FILTER_CAPS3_RESOLVER_BASE_INDEX_SHIFT) * 8;
+
+ return (0);
+}
+
+/* Commit an IN-window write; wait for the MCP ack. */
+static int
+aq2_fw_wait_shared_ack(struct aq_hw *hw)
+{
+ AQ_WRITE_REG(hw, AQ2_MIF_HOST_FINISHED_STATUS_WRITE_REG,
+ AQ2_MIF_HOST_FINISHED_STATUS_ACK);
+ return (AQ_HW_WAIT_FOR((AQ_READ_REG(hw,
+ AQ2_MIF_HOST_FINISHED_STATUS_READ_REG) &
+ AQ2_MIF_HOST_FINISHED_STATUS_ACK) == 0, 100, 1000));
+}
+
+static int
+aq2_fw_reset(struct aq_hw *hw)
+{
+ uint32_t v;
+ int err;
+
+ AQ_WRITE_REG_BIT(hw, AQ2_FW_INTERFACE_IN_LINK_CONTROL_REG,
+ AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE, 0,
+ AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_ACTIVE);
+
+ AQ_WRITE_REG(hw, AQ2_FW_INTERFACE_IN_MTU_REG,
+ HW_ATL_B0_MTU_JUMBO + sizeof(struct ether_header));
+
+ v = AQ_READ_REG(hw, AQ2_FW_INTERFACE_IN_REQUEST_POLICY_REG);
+ v |= AQ2_FW_INTERFACE_IN_REQUEST_POLICY_MCAST_QUEUE_OR_TC;
+ v &= ~AQ2_FW_INTERFACE_IN_REQUEST_POLICY_MCAST_RX_QUEUE_TC_INDEX;
+ v |= AQ2_FW_INTERFACE_IN_REQUEST_POLICY_MCAST_ACCEPT;
+ v |= AQ2_FW_INTERFACE_IN_REQUEST_POLICY_BCAST_QUEUE_OR_TC;
+ v &= ~AQ2_FW_INTERFACE_IN_REQUEST_POLICY_BCAST_RX_QUEUE_TC_INDEX;
+ v |= AQ2_FW_INTERFACE_IN_REQUEST_POLICY_BCAST_ACCEPT;
+ v |= AQ2_FW_INTERFACE_IN_REQUEST_POLICY_PROMISC_QUEUE_OR_TC;
+ v &= ~AQ2_FW_INTERFACE_IN_REQUEST_POLICY_PROMISC_RX_QUEUE_TX_INDEX;
+ AQ_WRITE_REG(hw, AQ2_FW_INTERFACE_IN_REQUEST_POLICY_REG, v);
+
+ err = aq2_fw_wait_shared_ack(hw);
+ if (err != 0)
+ device_printf(hw->dev, "A2 firmware reset timed out\n");
+ return (err);
+}
+
+static int
+aq2_fw_get_mac_addr(struct aq_hw *hw, uint8_t *mac)
+{
+ uint32_t mac_addr[2];
+
+ mac_addr[0] = AQ_READ_REG(hw, AQ2_FW_INTERFACE_IN_MAC_ADDRESS_REG);
+ mac_addr[1] = AQ_READ_REG(hw, AQ2_FW_INTERFACE_IN_MAC_ADDRESS_REG + 4);
+
+ if (mac_addr[0] == 0 && mac_addr[1] == 0) {
+ device_printf(hw->dev, "A2 mac address not found\n");
+ return (ENXIO);
+ }
+
+ mac_addr[0] = htole32(mac_addr[0]);
+ mac_addr[1] = htole32(mac_addr[1]);
+ memcpy(mac, (uint8_t *)mac_addr, ETHER_ADDR_LEN);
+ return (0);
+}
+
+static int
+aq2_fw_set_mode(struct aq_hw *hw, enum aq_hw_fw_mpi_state mode,
+ enum aq_fw_link_speed speed)
+{
+ uint32_t v;
+ int err;
+
+ v = AQ_READ_REG(hw, AQ2_FW_INTERFACE_IN_LINK_OPTIONS_REG);
+ v &= ~(AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10G |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_N5G |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_5G |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_N2G5 |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_2G5 |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_1G |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_100M |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10M |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_1G_HD |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_100M_HD |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10M_HD);
+ v &= ~AQ2_FW_INTERFACE_IN_LINK_OPTIONS_LINK_UP;
+
+ if (mode == MPI_INIT) {
+ if (speed & aq_fw_10G)
+ v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10G;
+ if (speed & aq_fw_5G)
+ v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_N5G |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_5G;
+ if (speed & aq_fw_2G5)
+ v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_N2G5 |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_2G5;
+ if (speed & aq_fw_1G)
+ v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_1G;
+ if (speed & aq_fw_100M)
+ v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_100M;
+ if (speed & aq_fw_10M)
+ v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10M;
+
+ v &= ~(AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_TX |
+ AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_RX);
+ if (hw->fc.fc_tx)
+ v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_TX;
+ if (hw->fc.fc_rx)
+ v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_RX;
+
+ v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_LINK_UP;
+ } else {
+ AQ_WRITE_REG_BIT(hw, AQ2_FW_INTERFACE_IN_LINK_CONTROL_REG,
+ AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE, 0,
+ AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_SHUTDOWN);
+ }
+
+ /* Options acked before ACTIVE so bring-up negotiates the new mask. */
+ AQ_WRITE_REG(hw, AQ2_FW_INTERFACE_IN_LINK_OPTIONS_REG, v);
+ if (mode == MPI_INIT) {
+ err = aq2_fw_wait_shared_ack(hw);
+ if (err != 0)
+ return (err);
+ AQ_WRITE_REG_BIT(hw, AQ2_FW_INTERFACE_IN_LINK_CONTROL_REG,
+ AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE, 0,
+ AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_ACTIVE);
+ }
+ return (aq2_fw_wait_shared_ack(hw));
+}
+
+static int
+aq2_fw_get_mode(struct aq_hw *hw, enum aq_hw_fw_mpi_state *modep,
+ enum aq_fw_link_speed *speedp, enum aq_fw_link_fc *fcp)
+{
+ uint32_t v;
+ enum aq_fw_link_speed speed;
+ enum aq_fw_link_fc fc = aq_fw_fc_none;
+
+ if (modep != NULL)
+ *modep = MPI_INIT;
+
+ v = AQ_READ_REG(hw, AQ2_FW_INTERFACE_OUT_LINK_STATUS_REG);
+ switch ((v & AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE) >>
+ AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_S) {
+ case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_10G:
+ speed = aq_fw_10G;
+ break;
+ case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_5G:
+ speed = aq_fw_5G;
+ break;
+ case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_2G5:
+ speed = aq_fw_2G5;
+ break;
+ case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_1G:
+ speed = aq_fw_1G;
+ break;
+ case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_100M:
+ speed = aq_fw_100M;
+ break;
+ case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_10M:
+ speed = aq_fw_10M;
+ break;
+ default:
+ speed = aq_fw_none;
+ break;
+ }
+ if (speedp != NULL)
+ *speedp = speed;
+
+ if (v & AQ2_FW_INTERFACE_OUT_LINK_STATUS_PAUSE_TX)
+ fc |= aq_fw_fc_ENABLE_TX;
+ if (v & AQ2_FW_INTERFACE_OUT_LINK_STATUS_PAUSE_RX)
+ fc |= aq_fw_fc_ENABLE_RX;
+ if (fcp != NULL)
+ *fcp = fc;
+
+ return (0);
+}
+
+/* A2 firmware stats; layout depends on interface version. */
+struct aq2_fw_statistics_a0 {
+ uint32_t link_up;
+ uint32_t link_down;
+ uint64_t tx_unicast_octets;
+ uint64_t tx_multicast_octets;
+ uint64_t tx_broadcast_octets;
+ uint64_t rx_unicast_octets;
+ uint64_t rx_multicast_octets;
+ uint64_t rx_broadcast_octets;
+ uint32_t tx_unicast_frames;
+ uint32_t tx_multicast_frames;
+ uint32_t tx_broadcast_frames;
+ uint32_t tx_errors;
+ uint32_t rx_unicast_frames;
+ uint32_t rx_multicast_frames;
+ uint32_t rx_broadcast_frames;
+ uint32_t rx_dropped_frames;
+ uint32_t rx_errors;
+ uint32_t tx_good_frames;
+ uint32_t rx_good_frames;
+ uint32_t reserved1;
+ uint32_t main_loop_cycles;
+ uint32_t reserved2;
+};
+
+struct aq2_fw_statistics_b0 {
+ uint64_t rx_good_octets;
+ uint64_t rx_pause_frames;
+ uint64_t rx_good_frames;
+ uint64_t rx_errors;
+ uint64_t rx_unicast_frames;
+ uint64_t rx_multicast_frames;
+ uint64_t rx_broadcast_frames;
+ uint64_t tx_good_octets;
+ uint64_t tx_pause_frames;
+ uint64_t tx_good_frames;
+ uint64_t tx_errors;
+ uint64_t tx_unicast_frames;
+ uint64_t tx_multicast_frames;
+ uint64_t tx_broadcast_frames;
+ uint32_t main_loop_cycles;
+} __packed;
+
+union aq2_fw_statistics {
+ struct aq2_fw_statistics_a0 a0;
+ struct aq2_fw_statistics_b0 b0;
+};
+
+static int
+aq2_fw_get_stats(struct aq_hw *hw, struct aq_hw_stats *stats)
+{
+ union aq2_fw_statistics u;
+ int err;
+
+ memset(stats, 0, sizeof(*stats));
+
+ err = aq2_fw_interface_buffer_read(hw, AQ2_FW_INTERFACE_OUT_STATS_REG,
+ (uint32_t *)&u, sizeof(u));
+ if (err != 0)
+ return (err);
+
+ if (hw->aq2_iface == AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_A0) {
+ stats->uprc = u.a0.rx_unicast_frames;
+ stats->mprc = u.a0.rx_multicast_frames;
+ stats->bprc = u.a0.rx_broadcast_frames;
+ stats->erpr = u.a0.rx_errors;
+ stats->ubrc = u.a0.rx_unicast_octets;
+ stats->mbrc = u.a0.rx_multicast_octets;
+ stats->bbrc = u.a0.rx_broadcast_octets;
+ stats->prc = u.a0.rx_good_frames;
+ stats->uptc = u.a0.tx_unicast_frames;
+ stats->mptc = u.a0.tx_multicast_frames;
+ stats->bptc = u.a0.tx_broadcast_frames;
+ stats->erpt = u.a0.tx_errors;
+ stats->ubtc = u.a0.tx_unicast_octets;
+ stats->mbtc = u.a0.tx_multicast_octets;
+ stats->bbtc = u.a0.tx_broadcast_octets;
+ stats->ptc = u.a0.tx_good_frames;
+ } else if (hw->aq2_iface == AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_B0) {
+ /* B0 reports aggregate octets only; per-cast stays zero. */
+ stats->uprc = u.b0.rx_unicast_frames;
+ stats->mprc = u.b0.rx_multicast_frames;
+ stats->bprc = u.b0.rx_broadcast_frames;
+ stats->erpr = u.b0.rx_errors;
+ stats->prc = u.b0.rx_good_frames;
+ stats->uptc = u.b0.tx_unicast_frames;
+ stats->mptc = u.b0.tx_multicast_frames;
+ stats->bptc = u.b0.tx_broadcast_frames;
+ stats->erpt = u.b0.tx_errors;
+ stats->ptc = u.b0.tx_good_frames;
+ }
+
+ return (0);
+}
+
+const struct aq_firmware_ops aq2_fw_ops = {
+ .reset = aq2_fw_reset,
+ .set_mode = aq2_fw_set_mode,
+ .get_mode = aq2_fw_get_mode,
+ .get_mac_addr = aq2_fw_get_mac_addr,
+ .get_stats = aq2_fw_get_stats,
+ .led_control = NULL,
+};
diff --git a/sys/dev/aq/aq2_hw.h b/sys/dev/aq/aq2_hw.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/aq/aq2_hw.h
@@ -0,0 +1,276 @@
+/*-
+ * Atlantic 2 (AQC113/114/115/116) register definitions for aq(4).
+ *
+ * Register layout and field definitions adapted from the OpenBSD/NetBSD
+ * if_aq driver:
+ *
+ * Copyright (c) 2021 Jonathan Matthew <jonathan@d14n.org>
+ * Copyright (c) 2021 Mike Larkin <mlarkin@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef AQ2_HW_H
+#define AQ2_HW_H
+
+/* Atlantic 2 PCI device IDs (Aquantia/Marvell). */
+#define AQ_DEVICE_ID_AQC113 0x04C0
+#define AQ_DEVICE_ID_AQC113C 0x14C0
+#define AQ_DEVICE_ID_AQC113CA 0x34C0
+#define AQ_DEVICE_ID_AQC113CS 0x94C0
+#define AQ_DEVICE_ID_AQC114CS 0x93C0
+#define AQ_DEVICE_ID_AQC115C 0x12C0
+#define AQ_DEVICE_ID_AQC116C 0x11C0
+
+static __inline bool
+aq_is_atlantic2(uint16_t device_id)
+{
+ switch (device_id) {
+ case AQ_DEVICE_ID_AQC113:
+ case AQ_DEVICE_ID_AQC113C:
+ case AQ_DEVICE_ID_AQC113CA:
+ case AQ_DEVICE_ID_AQC113CS:
+ case AQ_DEVICE_ID_AQC114CS:
+ case AQ_DEVICE_ID_AQC115C:
+ case AQ_DEVICE_ID_AQC116C:
+ return (true);
+ default:
+ return (false);
+ }
+}
+
+/* Atlantic 2 host packet-buffer sizes (Atlantic 1 uses 160/320). */
+#define AQ2_HW_TXBUF_MAX 128
+#define AQ2_HW_RXBUF_MAX 192
+
+/* A2 firmware handshake registers (host <-> MCP). */
+#define AQ2_MIF_HOST_FINISHED_STATUS_WRITE_REG 0x0e00
+#define AQ2_MIF_HOST_FINISHED_STATUS_READ_REG 0x0e04
+#define AQ2_MIF_HOST_FINISHED_STATUS_ACK (1 << 0)
+
+#define AQ2_MCP_HOST_REQ_INT_REG 0x0f00
+#define AQ2_MCP_HOST_REQ_INT_READY (1 << 0)
+#define AQ2_MCP_HOST_REQ_INT_SET_REG 0x0f04
+#define AQ2_MCP_HOST_REQ_INT_CLR_REG 0x0f08
+
+#define AQ2_MIF_BOOT_REG 0x3040
+#define AQ2_MIF_BOOT_HOST_DATA_LOADED (1 << 16)
+#define AQ2_MIF_BOOT_BOOT_STARTED (1 << 24)
+#define AQ2_MIF_BOOT_CRASH_INIT (1 << 27)
+#define AQ2_MIF_BOOT_BOOT_CODE_FAILED (1 << 28)
+#define AQ2_MIF_BOOT_FW_INIT_FAILED (1 << 29)
+#define AQ2_MIF_BOOT_FW_INIT_COMP_SUCCESS (1U << 31)
+#define AQ2_MIF_BOOT_FAILED \
+ (AQ2_MIF_BOOT_CRASH_INIT | AQ2_MIF_BOOT_BOOT_CODE_FAILED | \
+ AQ2_MIF_BOOT_FW_INIT_FAILED)
+#define AQ2_MIF_BOOT_COMPLETE \
+ (AQ2_MIF_BOOT_FAILED | AQ2_MIF_BOOT_FW_INIT_COMP_SUCCESS)
+
+/* The ART semaphore is global CPU semaphore index 3. */
+#define AQ2_ART_SEM_INDEX 3
+
+/* Action Resolver Table (replaces Atlantic 1's discrete RPF filters). */
+#define AQ2_ART_ACTION_ACT_SHIFT 8
+#define AQ2_ART_ACTION_RSS 0x0080
+#define AQ2_ART_ACTION_INDEX_SHIFT 2
+#define AQ2_ART_ACTION_ENABLE 0x0001
+#define AQ2_ART_ACTION(act, rss, idx, en) \
+ (((act) << AQ2_ART_ACTION_ACT_SHIFT) | \
+ ((rss) ? AQ2_ART_ACTION_RSS : 0) | \
+ ((idx) << AQ2_ART_ACTION_INDEX_SHIFT) | \
+ ((en) ? AQ2_ART_ACTION_ENABLE : 0))
+#define AQ2_ART_ACTION_DROP AQ2_ART_ACTION(0, 0, 0, 1)
+#define AQ2_ART_ACTION_DISABLE AQ2_ART_ACTION(0, 0, 0, 0)
+#define AQ2_ART_ACTION_ASSIGN_QUEUE(q) AQ2_ART_ACTION(1, 0, (q), 1)
+#define AQ2_ART_ACTION_ASSIGN_TC(tc) AQ2_ART_ACTION(1, 1, (tc), 1)
+
+#define AQ2_RPF_TAG_PCP_MASK 0xe0000000
+#define AQ2_RPF_TAG_PCP_SHIFT 29
+#define AQ2_RPF_TAG_FLEX_MASK 0x18000000
+#define AQ2_RPF_TAG_UNKNOWN_MASK 0x07000000
+#define AQ2_RPF_TAG_L4_MASK 0x00e00000
+#define AQ2_RPF_TAG_L3_V6_MASK 0x001c0000
+#define AQ2_RPF_TAG_L3_V4_MASK 0x00038000
+#define AQ2_RPF_TAG_UNTAG_MASK 0x00004000
+#define AQ2_RPF_TAG_VLAN_MASK 0x00003c00
+#define AQ2_RPF_TAG_ET_MASK 0x00000380
+#define AQ2_RPF_TAG_ALLMC_MASK 0x00000040
+#define AQ2_RPF_TAG_UC_MASK 0x0000002f
+
+/* Logical ART row indices (before adding sc_art_filter_base_index). */
+#define AQ2_RPF_INDEX_L2_PROMISC_OFF 0
+#define AQ2_RPF_INDEX_VLAN_PROMISC_OFF 1
+#define AQ2_RPF_INDEX_L3L4_USER 8
+#define AQ2_RPF_INDEX_ET_PCP_USER 24
+#define AQ2_RPF_INDEX_VLAN_USER 40
+#define AQ2_RPF_INDEX_PCP_TO_TC 56
+
+#define AQ2_RPF_L2BC_TAG_REG 0x50f0
+#define AQ2_RPF_L2BC_TAG_MASK 0x0000003f
+
+#define AQ2_RPF_NEW_CTRL_REG 0x5104
+#define AQ2_RPF_NEW_CTRL_ENABLE (1 << 11)
+
+#define AQ2_RPF_REDIR2_REG 0x54c8
+#define AQ2_RPF_REDIR2_INDEX (1 << 12)
+#define AQ2_RPF_REDIR2_HASHTYPE 0x000001FF
+#define AQ2_RPF_REDIR2_HASHTYPE_NONE 0
+#define AQ2_RPF_REDIR2_HASHTYPE_ALL 0x000001FF
+
+#define AQ2_RX_Q_TC_MAP_REG(i) (0x5900 + (i) * 4)
+#define AQ2_TX_Q_TC_MAP_REG(i) (0x799c + (i) * 4)
+
+#define AQ2_RPF_RSS_REDIR_MAX 64
+#define AQ2_RPF_RSS_REDIR_REG(tc, i) \
+ (0x6200 + (0x100 * ((tc) >> 2)) + (i) * 4)
+
+#define AQ2_RPF_REC_TAB_ENABLE_REG 0x6ff0
+#define AQ2_RPF_REC_TAB_ENABLE_MASK 0x0000ffff
+
+#define AQ2_LAUNCHTIME_CTRL_REG 0x7a1c
+#define AQ2_LAUNCHTIME_CTRL_RATIO 0x0000ff00
+#define AQ2_LAUNCHTIME_CTRL_RATIO_SPEED_QUARTER 4
+#define AQ2_LAUNCHTIME_CTRL_RATIO_SPEED_HALF 2
+#define AQ2_LAUNCHTIME_CTRL_RATIO_SPEED_FULL 1
+
+#define AQ2_HW_FPGA_VERSION_REG 0x00f4
+
+#define AQ2_TX_INTR_MODERATION_CTL_REG(i) (0x7c28 + (i) * 0x40)
+#define AQ2_TX_INTR_MODERATION_CTL_EN (1 << 1)
+#define AQ2_TX_INTR_MODERATION_CTL_MIN 0x0000ff00
+#define AQ2_TX_INTR_MODERATION_CTL_MAX 0x01ff0000
+
+/* Firmware interface IN window (host -> MCP). */
+#define AQ2_FW_INTERFACE_IN_MTU_REG 0x12000
+#define AQ2_FW_INTERFACE_IN_MAC_ADDRESS_REG 0x12008
+
+#define AQ2_FW_INTERFACE_IN_LINK_CONTROL_REG 0x12010
+#define AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE 0x0000000f
+#define AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_INVALID 0
+#define AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_ACTIVE 1
+#define AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_SLEEP_PROXY 2
+#define AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_LOWPOWER 3
+#define AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_SHUTDOWN 4
+
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_REG 0x12018
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_DOWNSHIFT (1 << 27)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_TX (1 << 25)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_RX (1 << 24)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_EEE_10G (1 << 20)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_EEE_5G (1 << 19)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_EEE_2G5 (1 << 18)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_EEE_1G (1 << 17)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_EEE_100M (1 << 16)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10G (1 << 15)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_N5G (1 << 14)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_5G (1 << 13)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_N2G5 (1 << 12)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_2G5 (1 << 11)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_1G (1 << 10)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_100M (1 << 9)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10M (1 << 8)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_1G_HD (1 << 7)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_100M_HD (1 << 6)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10M_HD (1 << 5)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_LINK_RENEGOTIATE (1 << 1)
+#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_LINK_UP (1 << 0)
+
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_REG 0x12a58
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_MCAST_QUEUE_OR_TC 0x00800000
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_MCAST_RX_QUEUE_TC_INDEX 0x007c0000
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_MCAST_ACCEPT 0x00010000
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_BCAST_QUEUE_OR_TC 0x00008000
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_BCAST_RX_QUEUE_TC_INDEX 0x00007c00
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_BCAST_ACCEPT 0x00000100
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_PROMISC_QUEUE_OR_TC 0x00000080
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_PROMISC_RX_QUEUE_TX_INDEX 0x0000007c
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_PROMISC_MCAST 0x00000002
+#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_PROMISC_ALL 0x00000001
+
+/* Firmware interface OUT window (MCP -> host). */
+#define AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_REG 0x13000
+#define AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_B 0xffff0000
+#define AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_B_S 16
+#define AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_A 0x0000ffff
+#define AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_A_S 0
+
+#define AQ2_FW_INTERFACE_OUT_VERSION_BUNDLE_REG 0x13004
+#define AQ2_FW_INTERFACE_OUT_VERSION_MAC_REG 0x13008
+
+#define AQ2_FW_INTERFACE_OUT_VERSION_PHY_REG 0x1300c
+#define AQ2_FW_INTERFACE_OUT_VERSION_BUILD 0xffff0000
+#define AQ2_FW_INTERFACE_OUT_VERSION_BUILD_S 16
+#define AQ2_FW_INTERFACE_OUT_VERSION_MINOR 0x0000ff00
+#define AQ2_FW_INTERFACE_OUT_VERSION_MINOR_S 8
+#define AQ2_FW_INTERFACE_OUT_VERSION_MAJOR 0x000000ff
+#define AQ2_FW_INTERFACE_OUT_VERSION_MAJOR_S 0
+
+#define AQ2_FW_INTERFACE_OUT_VERSION_IFACE_REG 0x13010
+#define AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER 0x0000000f
+#define AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_A0 0
+#define AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_B0 1
+
+#define AQ2_FW_INTERFACE_OUT_STATS_REG 0x13700
+
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_REG 0x13014
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_DUPLEX (1 << 11)
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_EEE (1 << 10)
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_PAUSE_RX (1 << 9)
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_PAUSE_TX (1 << 8)
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE 0x000000f0
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_S 4
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_10G 6
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_5G 5
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_2G5 4
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_1G 3
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_100M 2
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_10M 1
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_INVALID 0
+#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_STATE 0x0000000f
+
+#define AQ2_FW_INTERFACE_OUT_FILTER_CAPS_REG 0x13774
+#define AQ2_FW_INTERFACE_OUT_FILTER_CAPS3_RESOLVER_BASE_INDEX 0x00ff0000
+#define AQ2_FW_INTERFACE_OUT_FILTER_CAPS3_RESOLVER_BASE_INDEX_SHIFT 16
+
+#define AQ2_RPF_ACT_ART_REQ_TAG_REG(i) (0x14000 + (i) * 0x10)
+#define AQ2_RPF_ACT_ART_REQ_MASK_REG(i) (0x14004 + (i) * 0x10)
+#define AQ2_RPF_ACT_ART_REQ_ACTION_REG(i) (0x14008 + (i) * 0x10)
+
+/*
+ * L2 unicast filter MSW register (shared with Atlantic 1). Atlantic 2 sets
+ * the TAG field so unicast frames are classified into the resolver table.
+ */
+#define AQ2_RPF_VLAN_FLR_TAG_REG(i) (0x5290 + (i) * 4)
+#define AQ2_RPF_VLAN_FLR_TAG 0x0000F000
+#define AQ2_RPF_VLAN_FLR_TAG_SHIFT 12
+
+#define RPF_L2UC_MSW_REG(i) (0x5114 + (i) * 8)
+#define RPF_L2UC_MSW_TAG 0x03c00000
+#define RPF_L2UC_MSW_TAG_SHIFT 22
+
+/*
+ * Tx packet-scheduler data-TC credit/weight (shared register, but the
+ * Atlantic 2 fields are wider than Atlantic 1's), and the Tx buffer control
+ * register whose randomized ring->TC map Atlantic 2 enables.
+ */
+#define TPS_DATA_TCT_REG(i) (0x7110 + (i) * 4)
+#define TPS2_DATA_TCT_CREDIT_MAX 0xffff0000
+#define TPS2_DATA_TCT_CREDIT_MAX_SHIFT 16
+#define TPS2_DATA_TCT_WEIGHT 0x00007fff
+#define TPS2_DATA_TCT_WEIGHT_SHIFT 0
+
+#define TPB_TX_BUF_REG 0x7900
+#define TPB_TX_BUF_TC_Q_RAND_MAP_EN (1 << 9)
+#define TPB_TX_BUF_TC_Q_RAND_MAP_EN_SHIFT 9
+
+#endif /* AQ2_HW_H */
diff --git a/sys/dev/aq/aq_device.h b/sys/dev/aq/aq_device.h
--- a/sys/dev/aq/aq_device.h
+++ b/sys/dev/aq/aq_device.h
@@ -44,14 +44,15 @@
};
#define AQ_LINK_UNKNOWN 0x00000000
-#define AQ_LINK_100M 0x00000001
-#define AQ_LINK_1G 0x00000002
-#define AQ_LINK_2G5 0x00000004
-#define AQ_LINK_5G 0x00000008
-#define AQ_LINK_10G 0x00000010
+#define AQ_LINK_10M 0x00000001
+#define AQ_LINK_100M 0x00000002
+#define AQ_LINK_1G 0x00000004
+#define AQ_LINK_2G5 0x00000008
+#define AQ_LINK_5G 0x00000010
+#define AQ_LINK_10G 0x00000020
#define AQ_LINK_ALL (AQ_LINK_100M | AQ_LINK_1G | AQ_LINK_2G5 | AQ_LINK_5G | \
- AQ_LINK_10G )
+ AQ_LINK_10G)
struct aq_stats {
uint64_t prc;
diff --git a/sys/dev/aq/aq_fw.h b/sys/dev/aq/aq_fw.h
--- a/sys/dev/aq/aq_fw.h
+++ b/sys/dev/aq/aq_fw.h
@@ -39,11 +39,12 @@
enum aq_fw_link_speed
{
aq_fw_none = 0,
- aq_fw_100M = (1 << 0),
- aq_fw_1G = (1 << 1),
- aq_fw_2G5 = (1 << 2),
- aq_fw_5G = (1 << 3),
- aq_fw_10G = (1 << 4),
+ aq_fw_10M = (1 << 0), /* Atlantic 2 only */
+ aq_fw_100M = (1 << 1),
+ aq_fw_1G = (1 << 2),
+ aq_fw_2G5 = (1 << 3),
+ aq_fw_5G = (1 << 4),
+ aq_fw_10G = (1 << 5),
};
enum aq_fw_link_fc
@@ -55,7 +56,7 @@
};
#define aq_fw_speed_auto \
- (aq_fw_100M | aq_fw_1G | aq_fw_2G5 | aq_fw_5G | aq_fw_10G)
+ (aq_fw_10M | aq_fw_100M | aq_fw_1G | aq_fw_2G5 | aq_fw_5G | aq_fw_10G)
struct aq_firmware_ops
{
@@ -70,10 +71,13 @@
int (*led_control)(struct aq_hw* hw, uint32_t mode);
};
+/* aq_fw1x/aq_fw2x: Atlantic 1 firmware ABIs; aq2_fw: Atlantic 2 (AQC11x). */
extern const struct aq_firmware_ops aq_fw1x_ops;
extern const struct aq_firmware_ops aq_fw2x_ops;
+extern const struct aq_firmware_ops aq2_fw_ops;
int aq_fw_reset(struct aq_hw* hw);
int aq_fw_ops_init(struct aq_hw* hw);
+int aq2_fw_reboot(struct aq_hw* hw);
#endif // AQ_FW_H
diff --git a/sys/dev/aq/aq_hw.h b/sys/dev/aq/aq_hw.h
--- a/sys/dev/aq/aq_hw.h
+++ b/sys/dev/aq/aq_hw.h
@@ -201,6 +201,12 @@
u_long flags;
uint32_t tx_rings_count;
+
+ /* Atlantic 2: base row added to every action-resolver-table index. */
+ uint32_t art_filter_base_index;
+
+ /* Atlantic 2: firmware statistics interface version (A0/B0). */
+ uint32_t aq2_iface;
};
#define AQ_HW_MAC 0U
@@ -254,6 +260,7 @@
#define AQ_HW_CHIP_REVISION_A0 0x01000000U
#define AQ_HW_CHIP_REVISION_B0 0x02000000U
#define AQ_HW_CHIP_REVISION_B1 0x04000000U
+#define AQ_HW_CHIP_ATLANTIC2 0x08000000U
#define IS_CHIP_FEATURE(HW, _F_) (AQ_HW_CHIP_##_F_ & \
(HW)->chip_features)
diff --git a/sys/dev/aq/aq_hw.c b/sys/dev/aq/aq_hw.c
--- a/sys/dev/aq/aq_hw.c
+++ b/sys/dev/aq/aq_hw.c
@@ -39,6 +39,7 @@
#include <machine/cpu.h>
#include "aq_hw.h"
+#include "aq2_hw.h"
#include "aq_dbg.h"
#include "aq_hw_llh.h"
#include "aq_fw.h"
@@ -151,6 +152,10 @@
hw->fw_version.raw = 0;
+ /* Atlantic 2 uses a different reset/firmware handshake. */
+ if (IS_CHIP_FEATURE(hw, ATLANTIC2))
+ return (aq2_fw_reboot(hw));
+
err = aq_fw_reset(hw);
if (err != 0) {
device_printf(hw->dev, "aq_hw_init_ucp(): F/W reset failed, err %d\n", err);
@@ -280,6 +285,9 @@
case aq_fw_100M:
*link_speed = 100U;
break;
+ case aq_fw_10M:
+ *link_speed = 10U;
+ break;
default:
*link_speed = 0U;
break;
@@ -361,7 +369,11 @@
AQ_DBG_ENTER();
- err = aq_fw_reset(hw);
+ /* A2 resets by rebooting the MCP; A1 uses the RBL/FLB reset. */
+ if (IS_CHIP_FEATURE(hw, ATLANTIC2))
+ err = aq2_fw_reboot(hw);
+ else
+ err = aq_fw_reset(hw);
if (err != 0)
goto err_exit;
@@ -634,15 +646,32 @@
AQ_DBG_ENTER();
- /* Force limit MRRS on RDM/TDM to 2K */
- val = AQ_READ_REG(hw, AQ_HW_PCI_REG_CONTROL_6_ADR);
- AQ_WRITE_REG(hw, AQ_HW_PCI_REG_CONTROL_6_ADR, (val & ~0x707) | 0x404);
-
- /* TX DMA total request limit. B0 hardware is not capable to
- * handle more than (8K-MRRS) incoming DMA data.
- * Value 24 in 256byte units
- */
- AQ_WRITE_REG(hw, AQ_HW_TX_DMA_TOTAL_REQ_LIMIT_ADR, 24);
+ /* Atlantic 1 only: clamp MRRS and TX DMA total request limit. */
+ if (!IS_CHIP_FEATURE(hw, ATLANTIC2)) {
+ /* Force limit MRRS on RDM/TDM to 2K */
+ val = AQ_READ_REG(hw, AQ_HW_PCI_REG_CONTROL_6_ADR);
+ AQ_WRITE_REG(hw, AQ_HW_PCI_REG_CONTROL_6_ADR,
+ (val & ~0x707) | 0x404);
+
+ /* TX DMA total request limit. B0 hardware is not capable to
+ * handle more than (8K-MRRS) incoming DMA data.
+ * Value 24 in 256byte units
+ */
+ AQ_WRITE_REG(hw, AQ_HW_TX_DMA_TOTAL_REQ_LIMIT_ADR, 24);
+ } else {
+ /* Atlantic 2: launch-time clock ratio per FPGA version. */
+ uint32_t fpgaver = AQ_READ_REG(hw, AQ2_HW_FPGA_VERSION_REG);
+ uint32_t ratio;
+
+ if (fpgaver < 0x01000000U)
+ ratio = AQ2_LAUNCHTIME_CTRL_RATIO_SPEED_FULL;
+ else if (fpgaver >= 0x01008502U)
+ ratio = AQ2_LAUNCHTIME_CTRL_RATIO_SPEED_HALF;
+ else
+ ratio = AQ2_LAUNCHTIME_CTRL_RATIO_SPEED_QUARTER;
+ AQ_WRITE_REG_BIT(hw, AQ2_LAUNCHTIME_CTRL_REG,
+ AQ2_LAUNCHTIME_CTRL_RATIO, 8, ratio);
+ }
err = aq_hw_init_tx_path(hw);
if (err != 0)
diff --git a/sys/dev/aq/aq_main.c b/sys/dev/aq/aq_main.c
--- a/sys/dev/aq/aq_main.c
+++ b/sys/dev/aq/aq_main.c
@@ -69,6 +69,7 @@
#include "aq_device.h"
#include "aq_fw.h"
#include "aq_hw.h"
+#include "aq2_hw.h"
#include "aq_hw_llh.h"
#include "aq_ring.h"
#include "aq_dbg.h"
@@ -136,6 +137,22 @@
PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC112S,
"Aquantia AQtion 2.5Gbit Network Adapter"),
+ /* Atlantic 2 (Marvell AQtion) */
+ PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC113,
+ "Marvell AQtion 10Gbit Network Adapter"),
+ PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC113C,
+ "Marvell AQtion 10Gbit Network Adapter"),
+ PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC113CA,
+ "Marvell AQtion 10Gbit Network Adapter"),
+ PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC113CS,
+ "Marvell AQtion 10Gbit Network Adapter"),
+ PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC114CS,
+ "Marvell AQtion 5Gbit Network Adapter"),
+ PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC115C,
+ "Marvell AQtion 2.5Gbit Network Adapter"),
+ PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC116C,
+ "Marvell AQtion 1Gbit Network Adapter"),
+
PVID_END
};
@@ -344,6 +361,9 @@
softc->hw.hw_tag = softc->mmio_tag;
softc->hw.hw_handle = softc->mmio_handle;
softc->hw.dev = softc->dev;
+ softc->hw.device_id = pci_get_device(softc->dev);
+ if (aq_is_atlantic2(softc->hw.device_id))
+ softc->hw.chip_features |= AQ_HW_CHIP_ATLANTIC2;
hw = &softc->hw;
hw->link_rate = aq_fw_speed_auto;
hw->itr = -1;
@@ -1183,6 +1203,33 @@
softc->link_speeds = AQ_LINK_ALL & ~(AQ_LINK_10G | AQ_LINK_5G);
break;
+ case AQ_DEVICE_ID_AQC113:
+ case AQ_DEVICE_ID_AQC113C:
+ case AQ_DEVICE_ID_AQC113CA:
+ case AQ_DEVICE_ID_AQC113CS:
+ softc->media_type = AQ_MEDIA_TYPE_TP;
+ softc->link_speeds = AQ_LINK_10M | AQ_LINK_ALL;
+ break;
+
+ case AQ_DEVICE_ID_AQC114CS:
+ softc->media_type = AQ_MEDIA_TYPE_TP;
+ softc->link_speeds = AQ_LINK_10M |
+ (AQ_LINK_ALL & ~AQ_LINK_10G);
+ break;
+
+ case AQ_DEVICE_ID_AQC115C:
+ softc->media_type = AQ_MEDIA_TYPE_TP;
+ softc->link_speeds = AQ_LINK_10M |
+ (AQ_LINK_ALL & ~(AQ_LINK_10G | AQ_LINK_5G));
+ break;
+
+ case AQ_DEVICE_ID_AQC116C:
+ softc->media_type = AQ_MEDIA_TYPE_TP;
+ softc->link_speeds =
+ AQ_LINK_10M |
+ (AQ_LINK_ALL & ~(AQ_LINK_10G | AQ_LINK_5G | AQ_LINK_2G5));
+ break;
+
default:
return (ENXIO);
}
diff --git a/sys/dev/aq/aq_media.c b/sys/dev/aq/aq_media.c
--- a/sys/dev/aq/aq_media.c
+++ b/sys/dev/aq/aq_media.c
@@ -50,13 +50,27 @@
#include "aq_fw.h"
#include "aq_dbg.h"
-#define AQ_HW_SUPPORT_SPEED(softc, s) ((softc)->link_speeds & s)
+/* Single source of truth for the supported link speeds. */
+static const struct aq_media_map {
+ uint32_t link_bit; /* AQ_LINK_* capability bit */
+ enum aq_fw_link_speed fw_rate; /* aq_fw_* rate */
+ int ifm; /* IFM_* media subtype */
+ uint32_t mbps; /* link speed, Mbit/s */
+} aq_media_types[] = {
+ { AQ_LINK_10M, aq_fw_10M, IFM_10_T, 10 },
+ { AQ_LINK_100M, aq_fw_100M, IFM_100_TX, 100 },
+ { AQ_LINK_1G, aq_fw_1G, IFM_1000_T, 1000 },
+ { AQ_LINK_2G5, aq_fw_2G5, IFM_2500_T, 2500 },
+ { AQ_LINK_5G, aq_fw_5G, IFM_5000_T, 5000 },
+ { AQ_LINK_10G, aq_fw_10G, IFM_10G_T, 10000 },
+};
void
aq_mediastatus_update(struct aq_dev *aq_dev, uint32_t link_speed,
const struct aq_hw_fc_info *fc_neg)
{
struct aq_hw *hw = &aq_dev->hw;
+ u_int i;
aq_dev->media_active = 0;
if (fc_neg->fc_rx)
@@ -64,27 +78,11 @@
if (fc_neg->fc_tx)
aq_dev->media_active |= IFM_ETH_TXPAUSE;
- switch(link_speed) {
- case 100:
- aq_dev->media_active |= IFM_100_TX | IFM_FDX;
- break;
- case 1000:
- aq_dev->media_active |= IFM_1000_T | IFM_FDX;
- break;
- case 2500:
- aq_dev->media_active |= IFM_2500_T | IFM_FDX;
- break;
- case 5000:
- aq_dev->media_active |= IFM_5000_T | IFM_FDX;
- break;
- case 10000:
- aq_dev->media_active |= IFM_10G_T | IFM_FDX;
- break;
- case 0:
- default:
- aq_dev->media_active |= IFM_NONE;
- break;
- }
+ for (i = 0; i < nitems(aq_media_types); i++)
+ if (link_speed == aq_media_types[i].mbps)
+ break;
+ aq_dev->media_active |= i < nitems(aq_media_types) ?
+ (aq_media_types[i].ifm | IFM_FDX) : IFM_NONE;
if (hw->link_rate == aq_fw_speed_auto)
aq_dev->media_active |= IFM_AUTO;
@@ -114,6 +112,7 @@
struct ifmedia *ifm = iflib_get_media(aq_dev->ctx);
int user_media = IFM_SUBTYPE(ifm->ifm_media);
uint64_t media_rate;
+ u_int i;
AQ_DBG_ENTERA("media 0x%x", user_media);
@@ -136,34 +135,18 @@
iflib_link_state_change(aq_dev->ctx, LINK_STATE_DOWN, 0);
break;
- case IFM_100_TX:
- hw->link_rate = aq_fw_100M;
- media_rate = 100 * 1000;
- break;
-
- case IFM_1000_T:
- hw->link_rate = aq_fw_1G;
- media_rate = 1000 * 1000;
- break;
-
- case IFM_2500_T:
- hw->link_rate = aq_fw_2G5;
- media_rate = 2500 * 1000;
- break;
-
- case IFM_5000_T:
- hw->link_rate = aq_fw_5G;
- media_rate = 5000 * 1000;
- break;
-
- case IFM_10G_T:
- hw->link_rate = aq_fw_10G;
- media_rate = 10000 * 1000;
+ default:
+ for (i = 0; i < nitems(aq_media_types); i++)
+ if (user_media == aq_media_types[i].ifm)
+ break;
+ if (i == nitems(aq_media_types)) {
+ device_printf(hw->dev, "unknown media: 0x%X\n",
+ user_media);
+ return (0);
+ }
+ hw->link_rate = aq_media_types[i].fw_rate;
+ media_rate = (uint64_t)aq_media_types[i].mbps * 1000;
break;
-
- default: // should never happen
- device_printf(hw->dev, "unknown media: 0x%X\n", user_media);
- return (0);
}
hw->fc.fc_rx = (ifm->ifm_media & IFM_ETH_RXPAUSE) ? 1 : 0;
hw->fc.fc_tx = (ifm->ifm_media & IFM_ETH_TXPAUSE) ? 1 : 0;
@@ -197,6 +180,8 @@
void
aq_initmedia(struct aq_dev *aq_dev)
{
+ u_int i;
+
AQ_DBG_ENTER();
// ifconfig eth0 none
@@ -205,16 +190,9 @@
ifmedia_add(aq_dev->media, IFM_ETHER | IFM_AUTO, 0, NULL);
aq_add_media_types(aq_dev, IFM_AUTO);
- if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_100M))
- aq_add_media_types(aq_dev, IFM_100_TX);
- if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_1G))
- aq_add_media_types(aq_dev, IFM_1000_T);
- if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_2G5))
- aq_add_media_types(aq_dev, IFM_2500_T);
- if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_5G))
- aq_add_media_types(aq_dev, IFM_5000_T);
- if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_10G))
- aq_add_media_types(aq_dev, IFM_10G_T);
+ for (i = 0; i < nitems(aq_media_types); i++)
+ if (aq_dev->link_speeds & aq_media_types[i].link_bit)
+ aq_add_media_types(aq_dev, aq_media_types[i].ifm);
// link is initially autoselect
ifmedia_set(aq_dev->media,
diff --git a/sys/modules/aq/Makefile b/sys/modules/aq/Makefile
--- a/sys/modules/aq/Makefile
+++ b/sys/modules/aq/Makefile
@@ -3,7 +3,7 @@
KMOD = if_aq
SRCS = aq_main.c aq_media.c aq_irq.c
SRCS += aq_ring.c aq_hw.c aq_hw_llh.c
-SRCS += aq_fw.c aq_fw1x.c aq_fw2x.c aq_dbg.c
+SRCS += aq_fw.c aq_fw1x.c aq_fw2x.c aq2_fw.c aq_dbg.c
SRCS += device_if.h bus_if.h pci_if.h
SRCS += ifdi_if.h opt_inet.h opt_inet6.h opt_platform.h opt_rss.h
SRCS += miibus_if.h

File Metadata

Mime Type
text/plain
Expires
Wed, Jul 15, 4:45 PM (2 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35072280
Default Alt Text
D58141.id181653.diff (37 KB)

Event Timeline