Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F162573858
D58141.id181653.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
37 KB
Referenced Files
None
Subscribers
None
D58141.id181653.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D58141: aq(4): add Atlantic 2 (AQC113) device support
Attached
Detach File
Event Timeline
Log In to Comment