From: jmatthew Date: Mon, 24 Apr 2023 09:18:55 +0000 (+0000) Subject: Add initial support for Atlantic 2 hardware. Atlantic 2 has X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=b760e38cba0077df50da6ef9800468f32ec6f3ec;p=openbsd Add initial support for Atlantic 2 hardware. Atlantic 2 has much more complicated rx processing, and here we're doing the bare minimum to get packets moving. RSS is not implemented yet, vlans and multicast (among others) probably don't work yet either. tested by kettenis@ on an M2 Mac Mini, and by me on an AQC113 card provided by Brad ok dlg@ --- diff --git a/sys/dev/pci/if_aq_pci.c b/sys/dev/pci/if_aq_pci.c index 0702c275c9c..b79099c4fc0 100644 --- a/sys/dev/pci/if_aq_pci.c +++ b/sys/dev/pci/if_aq_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_aq_pci.c,v 1.19 2023/04/23 22:57:23 jmatthew Exp $ */ +/* $OpenBSD: if_aq_pci.c,v 1.20 2023/04/24 09:18:55 jmatthew Exp $ */ /* $NetBSD: if_aq.c,v 1.27 2021/06/16 00:21:18 riastradh Exp $ */ /* @@ -132,6 +132,7 @@ #define AQ_FW_SOFTRESET_RESET (1 << 15) #define AQ_FW_VERSION_REG 0x0018 #define AQ_HW_REVISION_REG 0x001c +#define AQ2_HW_FPGA_VERSION_REG 0x00f4 #define AQ_GLB_NVR_INTERFACE1_REG 0x0100 #define AQ_FW_MBOX_CMD_REG 0x0200 #define AQ_FW_MBOX_CMD_EXECUTE 0x00008000 @@ -140,6 +141,7 @@ #define AQ_FW_MBOX_VAL_REG 0x020C #define AQ_FW_GLB_CPU_SEM_REG(i) (0x03a0 + (i) * 4) #define AQ_FW_SEM_RAM_REG AQ_FW_GLB_CPU_SEM_REG(2) +#define AQ2_ART_SEM_REG AQ_FW_GLB_CPU_SEM_REG(3) #define AQ_FW_GLB_CTL2_REG 0x0404 #define AQ_GLB_GENERAL_PROVISIONING9_REG 0x0520 #define AQ_GLB_NVR_PROVISIONING2_REG 0x0534 @@ -213,6 +215,7 @@ #define RPF_L2UC_MSW_REG(i) (0x5114 + (i) * 8) #define RPF_L2UC_MSW_MACADDR_HI 0xFFFF #define RPF_L2UC_MSW_ACTION 0x70000 +#define RPF_L2UC_MSW_TAG 0x03c00000 #define RPF_L2UC_MSW_EN (1 << 31) #define AQ_HW_MAC_NUM 34 @@ -353,8 +356,10 @@ #define TPB_TX_BUF_REG 0x7900 #define TPB_TX_BUF_EN (1 << 0) #define TPB_TX_BUF_SCP_INS_EN (1 << 2) +#define TPB_TX_BUF_CLK_GATE_EN (1 << 5) #define TPB_TX_BUF_TC_MODE_EN (1 << 8) + /* TPB_TXB_BUFSIZE_REG[AQ_TRAFFICCLASS_NUM] 0x7910-7990 */ #define TPB_TXB_BUFSIZE_REG(i) (0x7910 + (i) * 0x10) #define TPB_TXB_BUFSIZE (0xFF) @@ -392,11 +397,198 @@ #define TX_INTR_MODERATION_CTL_MIN (0xFF << 8) #define TX_INTR_MODERATION_CTL_MAX (0x1FF << 16) +/* AQ2 registers */ + +#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 (1 << 31) + +/* AQ2 action resolver table */ +#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 + +/* index of aq2_filter_art_set() */ +#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 0x00000100 +#define AQ2_RPF_REDIR2_HASHTYPE_NONE 0 +#define AQ2_RPF_REDIR2_HASHTYPE_IP (1 << 0) +#define AQ2_RPF_REDIR2_HASHTYPE_TCP4 (1 << 1) +#define AQ2_RPF_REDIR2_HASHTYPE_UDP4 (1 << 2) +#define AQ2_RPF_REDIR2_HASHTYPE_IP6 (1 << 3) +#define AQ2_RPF_REDIR2_HASHTYPE_TCP6 (1 << 4) +#define AQ2_RPF_REDIR2_HASHTYPE_UDP6 (1 << 5) +#define AQ2_RPF_REDIR2_HASHTYPE_IP6EX (1 << 6) +#define AQ2_RPF_REDIR2_HASHTYPE_TCP6EX (1 << 7) +#define AQ2_RPF_REDIR2_HASHTYPE_UDP6EX (1 << 8) +#define AQ2_RPF_REDIR2_HASHTYPE_ALL 0x00000100 + +#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_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 + +#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_EXTERNAL_LOOPBACK (1 << 4) +#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_INTERNAL_LOOPBACK (1 << 3) +#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_MINIMAL_LINK_SPEED (1 << 2) +#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 + +#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_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) + #define __LOWEST_SET_BIT(__mask) (((((uint32_t)__mask) - 1) & ((uint32_t)__mask)) ^ ((uint32_t)__mask)) #define __SHIFTIN(__x, __mask) ((__x) * __LOWEST_SET_BIT(__mask)) #define AQ_READ_REG(sc, reg) \ bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) +#define AQ_READ_REGS(sc, reg, p, cnt) \ + bus_space_read_region_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (p), (cnt)); #define AQ_WRITE_REG(sc, reg, val) \ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) @@ -449,7 +641,11 @@ #define FEATURES_AQ1_REV_B1 0x04000000 #define FEATURES_AQ1_REV_B (FEATURES_AQ1_REV_B0|FEATURES_AQ1_REV_B1) #define FEATURES_AQ1 (FEATURES_AQ1_REV_A|FEATURES_AQ1_REV_B) +#define FEATURES_AQ2 0x10000000 +#define FEATURES_AQ2_IFACE_A0 0x20000000 +#define FEATURES_AQ2_IFACE_B0 0x40000000 #define HWTYPE_AQ1_P(sc) (((sc)->sc_features & FEATURES_AQ1) != 0) +#define HWTYPE_AQ2_P(sc) (((sc)->sc_features & FEATURES_AQ2) != 0) /* lock for firmware interface */ #define AQ_MPI_LOCK(sc) mtx_enter(&(sc)->sc_mpi_mutex); @@ -521,6 +717,7 @@ enum aq_hwtype { HWTYPE_AQ1, + HWTYPE_AQ2 }; enum aq_fw_bootloader_mode { @@ -538,11 +735,12 @@ enum aq_media_type { enum aq_link_speed { AQ_LINK_NONE = 0, - AQ_LINK_100M = (1 << 0), - AQ_LINK_1G = (1 << 1), - AQ_LINK_2G5 = (1 << 2), - AQ_LINK_5G = (1 << 3), - AQ_LINK_10G = (1 << 4) + AQ_LINK_10M = (1 << 0), + AQ_LINK_100M = (1 << 1), + AQ_LINK_1G = (1 << 2), + AQ_LINK_2G5 = (1 << 3), + AQ_LINK_5G = (1 << 4), + AQ_LINK_10G = (1 << 5) }; #define AQ_LINK_ALL (AQ_LINK_100M | AQ_LINK_1G | AQ_LINK_2G5 | \ @@ -776,6 +974,7 @@ struct aq_softc { int sc_rbl_enabled; int sc_fast_start_enabled; int sc_flash_present; + int sc_art_filter_base_index; uint32_t sc_fw_version; const struct aq_firmware_ops *sc_fw_ops; uint64_t sc_fw_caps; @@ -797,6 +996,13 @@ const struct pci_matchid aq_devices[] = { { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC109 }, { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC111 }, { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC112 }, + { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC113 }, + { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC113C }, + { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC113CA }, + { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC113CS }, + { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC114CS }, + { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC115C }, + { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC116C }, { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC100S }, { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC107S }, { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC108S }, @@ -864,6 +1070,30 @@ const struct aq_product { { PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_D109, HWTYPE_AQ1, AQ_MEDIA_TYPE_TP, AQ_LINK_100M | AQ_LINK_1G | AQ_LINK_2G5 }, + +{ PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC113, HWTYPE_AQ2, + AQ_MEDIA_TYPE_TP, AQ_LINK_ALL | AQ_LINK_10M +}, +{ PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC113C, HWTYPE_AQ2, + AQ_MEDIA_TYPE_TP, AQ_LINK_ALL | AQ_LINK_10M +}, +{ PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC113CA, HWTYPE_AQ2, + AQ_MEDIA_TYPE_TP, AQ_LINK_ALL | AQ_LINK_10M +}, +{ PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC113CS, HWTYPE_AQ2, + AQ_MEDIA_TYPE_TP, AQ_LINK_ALL | AQ_LINK_10M +}, +{ PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC114CS, HWTYPE_AQ2, + AQ_MEDIA_TYPE_TP, + AQ_LINK_10M | AQ_LINK_100M | AQ_LINK_1G | AQ_LINK_2G5 | AQ_LINK_5G +}, +{ PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC115C, HWTYPE_AQ2, + AQ_MEDIA_TYPE_TP, + AQ_LINK_10M | AQ_LINK_100M | AQ_LINK_1G | AQ_LINK_2G5 +}, +{ PCI_VENDOR_AQUANTIA, PCI_PRODUCT_AQUANTIA_AQC116C, HWTYPE_AQ2, + AQ_MEDIA_TYPE_TP, AQ_LINK_10M | AQ_LINK_100M | AQ_LINK_1G +}, }; int aq_match(struct device *, void *, void *); @@ -905,6 +1135,12 @@ int aq1_mac_soft_reset_rbl(struct aq_softc *, enum aq_fw_bootloader_mode *); int aq1_mac_soft_reset_flb(struct aq_softc *); int aq1_fw_downld_dwords(struct aq_softc *, uint32_t, uint32_t *, uint32_t); +int aq2_interface_buffer_read(struct aq_softc *, uint32_t, uint32_t *, + uint32_t); +int aq2_fw_reboot(struct aq_softc *); +int aq2_filter_art_set(struct aq_softc *, uint32_t, uint32_t, uint32_t, + uint32_t action); + void aq_refill(void *); int aq_rx_fill(struct aq_softc *, struct aq_rxring *); static inline unsigned int aq_rx_fill_slots(struct aq_softc *, @@ -931,6 +1167,14 @@ int aq_fw2x_set_mode(struct aq_softc *, enum aq_hw_fw_mpi_state, enum aq_link_speed, enum aq_link_fc, enum aq_link_eee); int aq_fw2x_get_stats(struct aq_softc *, struct aq_hw_stats_s *); +int aq2_fw_reset(struct aq_softc *); +int aq2_get_mac_addr(struct aq_softc *); +int aq2_fw_get_mode(struct aq_softc *, enum aq_hw_fw_mpi_state *, + enum aq_link_speed *, enum aq_link_fc *, enum aq_link_eee *); +int aq2_fw_set_mode(struct aq_softc *, enum aq_hw_fw_mpi_state, + enum aq_link_speed, enum aq_link_fc, enum aq_link_eee); +int aq2_fw_get_stats(struct aq_softc *, struct aq_hw_stats_s *); + const struct aq_firmware_ops aq_fw1x_ops = { .reset = aq_fw1x_reset, .get_mac_addr = aq1_get_mac_addr, @@ -947,6 +1191,14 @@ const struct aq_firmware_ops aq_fw2x_ops = { .get_stats = aq_fw2x_get_stats, }; +const struct aq_firmware_ops aq2_fw_ops = { + .reset = aq2_fw_reset, + .get_mac_addr = aq2_get_mac_addr, + .set_mode = aq2_fw_set_mode, + .get_mode = aq2_fw_get_mode, + .get_stats = aq2_fw_get_stats +}; + const struct cfattach aq_ca = { sizeof(struct aq_softc), aq_match, aq_attach, NULL, aq_activate @@ -1026,7 +1278,8 @@ aq_attach(struct device *parent, struct device *self, void *aux) if (pci_intr_map_msix(pa, 0, &ih) == 0) { int nmsix = pci_intr_msix_count(pa); - if (nmsix > 1) { + /* don't do rss on aq2 yet */ + if (aqp->aq_hwtype == HWTYPE_AQ1 && nmsix > 1) { nmsix--; sc->sc_intrmap = intrmap_create(&sc->sc_dev, nmsix, AQ_MAXQ, INTRMAP_POWEROF2); @@ -1062,6 +1315,10 @@ aq_attach(struct device *parent, struct device *self, void *aux) if (aq1_fw_reboot(sc)) return; break; + case HWTYPE_AQ2: + if (aq2_fw_reboot(sc)) + return; + break; default: return; } @@ -1104,6 +1361,12 @@ aq_attach(struct device *parent, struct device *self, void *aux) ifmedia_init(&sc->sc_media, IFM_IMASK, aq_ifmedia_change, aq_ifmedia_status); + if (sc->sc_available_rates & AQ_LINK_10M) { + ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_T, 0, NULL); + ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_T|IFM_FDX, 0, + NULL); + } + if (sc->sc_available_rates & AQ_LINK_100M) { ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_100_TX, 0, NULL); ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, @@ -1200,12 +1463,21 @@ aq_attach(struct device *parent, struct device *self, void *aux) tx->tx_irq = irqnum++; } - AQ_WRITE_REG_BIT(sc, TX_INTR_MODERATION_CTL_REG(i), - TX_INTR_MODERATION_CTL_MIN, txmin); - AQ_WRITE_REG_BIT(sc, TX_INTR_MODERATION_CTL_REG(i), - TX_INTR_MODERATION_CTL_MAX, txmax); - AQ_WRITE_REG_BIT(sc, TX_INTR_MODERATION_CTL_REG(i), - TX_INTR_MODERATION_CTL_EN, 1); + if (HWTYPE_AQ2_P(sc)) { + AQ_WRITE_REG_BIT(sc, AQ2_TX_INTR_MODERATION_CTL_REG(i), + AQ2_TX_INTR_MODERATION_CTL_MIN, txmin); + AQ_WRITE_REG_BIT(sc, AQ2_TX_INTR_MODERATION_CTL_REG(i), + AQ2_TX_INTR_MODERATION_CTL_MAX, txmax); + AQ_WRITE_REG_BIT(sc, AQ2_TX_INTR_MODERATION_CTL_REG(i), + AQ2_TX_INTR_MODERATION_CTL_EN, 1); + } else { + AQ_WRITE_REG_BIT(sc, TX_INTR_MODERATION_CTL_REG(i), + TX_INTR_MODERATION_CTL_MIN, txmin); + AQ_WRITE_REG_BIT(sc, TX_INTR_MODERATION_CTL_REG(i), + TX_INTR_MODERATION_CTL_MAX, txmax); + AQ_WRITE_REG_BIT(sc, TX_INTR_MODERATION_CTL_REG(i), + TX_INTR_MODERATION_CTL_EN, 1); + } AQ_WRITE_REG_BIT(sc, RX_INTR_MODERATION_CTL_REG(i), RX_INTR_MODERATION_CTL_MIN, rxmin); AQ_WRITE_REG_BIT(sc, RX_INTR_MODERATION_CTL_REG(i), @@ -1575,6 +1847,141 @@ aq1_hw_init_ucp(struct aq_softc *sc) return 0; } +int +aq2_interface_buffer_read(struct aq_softc *sc, uint32_t reg0, uint32_t *data0, + uint32_t size0) +{ + uint32_t tid0, tid1, reg, *data, size; + int timo; + + for (timo = 10000; timo > 0; timo--) { + tid0 = AQ_READ_REG(sc, 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; + } + + for (reg = reg0, data = data0, size = size0; + size >= 4; reg += 4, data++, size -= 4) { + *data = AQ_READ_REG(sc, reg); + } + + tid1 = AQ_READ_REG(sc, AQ2_FW_INTERFACE_OUT_TRANSACTION_ID_REG); + if (tid0 == tid1) + break; + } + if (timo == 0) { + printf("%s: interface buffer read timeout\n", DEVNAME(sc)); + return ETIMEDOUT; + } + return 0; +} + +int +aq2_fw_reboot(struct aq_softc *sc) +{ + uint32_t v; + int timo, err; + char buf[32]; + uint32_t filter_caps[3]; + + sc->sc_fw_ops = &aq2_fw_ops; + sc->sc_features = FEATURES_AQ2; + + AQ_WRITE_REG(sc, AQ2_MCP_HOST_REQ_INT_CLR_REG, 1); + AQ_WRITE_REG(sc, AQ2_MIF_BOOT_REG, 1); /* reboot request */ + for (timo = 200000; timo > 0; timo--) { + v = AQ_READ_REG(sc, AQ2_MIF_BOOT_REG); + if ((v & AQ2_MIF_BOOT_BOOT_STARTED) && v != 0xffffffff) + break; + delay(10); + } + if (timo <= 0) { + printf(": FW reboot timeout\n"); + return ETIMEDOUT; + } + + for (timo = 2000000; timo > 0; timo--) { + v = AQ_READ_REG(sc, AQ2_MIF_BOOT_REG); + if ((v & AQ2_MIF_BOOT_FW_INIT_FAILED) || + (v & AQ2_MIF_BOOT_FW_INIT_COMP_SUCCESS)) + break; + v = AQ_READ_REG(sc, AQ2_MCP_HOST_REQ_INT_REG); + if (v & AQ2_MCP_HOST_REQ_INT_READY) + break; + delay(10); + } + if (timo <= 0) { + printf(": FW restart timeout\n"); + return ETIMEDOUT; + } + + v = AQ_READ_REG(sc, AQ2_MIF_BOOT_REG); + if (v & AQ2_MIF_BOOT_FW_INIT_FAILED) { + printf(": FW restart failed\n"); + return ETIMEDOUT; + } + + v = AQ_READ_REG(sc, AQ2_MCP_HOST_REQ_INT_REG); + if (v & AQ2_MCP_HOST_REQ_INT_READY) { + printf(": firmware required\n"); + return ENXIO; + } + + /* + * Get aq2 firmware version. + * Note that the bit layout and its meaning are different from aq1. + */ + err = aq2_interface_buffer_read(sc, AQ2_FW_INTERFACE_OUT_VERSION_BUNDLE_REG, + (uint32_t *)&v, sizeof(v)); + if (err != 0) + return err; + + sc->sc_fw_version = + (((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_interface_buffer_read(sc, AQ2_FW_INTERFACE_OUT_VERSION_IFACE_REG, + (uint32_t *)&v, sizeof(v)); + if (err != 0) + return err; + + switch (v & AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER) { + case AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_A0: + sc->sc_features |= FEATURES_AQ2_IFACE_A0; + strncpy(buf, "A0", sizeof(buf)); + break; + case AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_B0: + sc->sc_features |= FEATURES_AQ2_IFACE_B0; + strncpy(buf, "B0", sizeof(buf)); + break; + default: + snprintf(buf, sizeof(buf), "(unknown 0x%08x)", v); + break; + } + printf(", Atlantic2 %s, F/W version %d.%d.%d\n", buf, + FW_VERSION_MAJOR(sc), FW_VERSION_MINOR(sc), FW_VERSION_BUILD(sc)); + + aq2_interface_buffer_read(sc, AQ2_FW_INTERFACE_OUT_FILTER_CAPS_REG, + filter_caps, sizeof(filter_caps)); + sc->sc_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; + + /* debug info */ + v = AQ_READ_REG(sc, AQ_HW_REVISION_REG); + DPRINTF(("%s: HW Rev: 0x%08x\n", DEVNAME(sc), v)); + + return 0; +} + int aq_hw_reset(struct aq_softc *sc) { @@ -1801,6 +2208,204 @@ aq_fw2x_get_stats(struct aq_softc *sc, struct aq_hw_stats_s *w) return 0; } +static int +aq2_fw_wait_shared_ack(struct aq_softc *sc) +{ + int error; + + AQ_WRITE_REG(sc, AQ2_MIF_HOST_FINISHED_STATUS_WRITE_REG, + AQ2_MIF_HOST_FINISHED_STATUS_ACK); + WAIT_FOR((AQ_READ_REG(sc, AQ2_MIF_HOST_FINISHED_STATUS_READ_REG) & + AQ2_MIF_HOST_FINISHED_STATUS_ACK) == 0, 100, 100000, &error); + + return error; +} + +int +aq2_fw_reset(struct aq_softc *sc) +{ + uint32_t v; + int error; + + AQ_WRITE_REG_BIT(sc, AQ2_FW_INTERFACE_IN_LINK_CONTROL_REG, + AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE, + AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_ACTIVE); + + AQ_WRITE_REG(sc, AQ2_FW_INTERFACE_IN_MTU_REG, + /*AQ2_JUMBO_MTU*/ MCLBYTES + sizeof(struct ether_header)); + + v = AQ_READ_REG(sc, 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(sc, AQ2_FW_INTERFACE_IN_REQUEST_POLICY_REG, v); + + error = aq2_fw_wait_shared_ack(sc); + if (error != 0) + printf(": reset timed out\n"); + return error; +} + +int +aq2_get_mac_addr(struct aq_softc *sc) +{ + uint32_t mac_addr[2]; + + memset(mac_addr, 0, sizeof(mac_addr)); + AQ_READ_REGS(sc, AQ2_FW_INTERFACE_IN_MAC_ADDRESS_REG, + mac_addr, nitems(mac_addr)); + + if (mac_addr[0] == 0 && mac_addr[1] == 0) { + printf(": mac address not found\n"); + return ENXIO; + } + + mac_addr[0] = htole32(mac_addr[0]); + mac_addr[1] = htole32(mac_addr[1]); + + memcpy(sc->sc_enaddr.ether_addr_octet, + (uint8_t *)mac_addr, ETHER_ADDR_LEN); + return 0; +} + +int +aq2_fw_set_mode(struct aq_softc *sc, enum aq_hw_fw_mpi_state w, + enum aq_link_speed speed, enum aq_link_fc fc, enum aq_link_eee eee) +{ + uint32_t v, ov; + int error; + + AQ_MPI_LOCK(sc); + + v = AQ_READ_REG(sc, 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; + ov = v; + + if (speed & AQ_LINK_10G) + v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10G; + if (speed & AQ_LINK_5G) + v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_N5G | + AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_5G; + if (speed & AQ_LINK_2G5) + v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_N2G5 | + AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_2G5; + if (speed & AQ_LINK_1G) + v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_1G | + AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_1G_HD; + if (speed & AQ_LINK_100M) + v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_100M | + AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_100M_HD; + if (speed & AQ_LINK_10M) { + v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10M | + AQ2_FW_INTERFACE_IN_LINK_OPTIONS_RATE_10M_HD; + } + + /* flow control */ + v &= ~(AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_TX | + AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_RX); + if (fc & AQ_FC_TX) + v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_TX; + if (fc & AQ_FC_RX) + v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_PAUSE_RX; + + if (speed == AQ_LINK_NONE) { + AQ_WRITE_REG_BIT(sc, AQ2_FW_INTERFACE_IN_LINK_CONTROL_REG, + AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE, + AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_SHUTDOWN); + } else { + AQ_WRITE_REG_BIT(sc, AQ2_FW_INTERFACE_IN_LINK_CONTROL_REG, + AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE, + AQ2_FW_INTERFACE_IN_LINK_CONTROL_MODE_ACTIVE); + v |= AQ2_FW_INTERFACE_IN_LINK_OPTIONS_LINK_UP; + } + + AQ_WRITE_REG(sc, AQ2_FW_INTERFACE_IN_LINK_OPTIONS_REG, v); + error = aq2_fw_wait_shared_ack(sc); + + AQ_MPI_UNLOCK(sc); + return error; +} + +int +aq2_fw_get_mode(struct aq_softc *sc, enum aq_hw_fw_mpi_state *modep, + enum aq_link_speed *speedp, enum aq_link_fc *fcp, enum aq_link_eee *eeep) +{ + uint32_t v; + enum aq_link_speed speed; + enum aq_link_fc fc = 0; + enum aq_link_eee eee; + + if (modep != NULL) + *modep = MPI_INIT; + + v = AQ_READ_REG(sc, 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_LINK_10G; + break; + case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_5G: + speed = AQ_LINK_5G; + break; + case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_2G5: + speed = AQ_LINK_2G5; + break; + case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_1G: + speed = AQ_LINK_1G; + break; + case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_100M: + speed = AQ_LINK_100M; + break; + case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_10M: + speed = AQ_LINK_10M; + break; + case AQ2_FW_INTERFACE_OUT_LINK_STATUS_RATE_INVALID: + default: + speed = AQ_LINK_NONE; + break; + } + if (speedp != NULL) + *speedp = speed; + + if (v & AQ2_FW_INTERFACE_OUT_LINK_STATUS_PAUSE_TX) + fc |= AQ_FC_TX; + if (v & AQ2_FW_INTERFACE_OUT_LINK_STATUS_PAUSE_RX) + fc |= AQ_FC_RX; + if (fcp != NULL) + *fcp = fc; + + eee = (v & AQ2_FW_INTERFACE_OUT_LINK_STATUS_EEE) ? + AQ_EEE_ENABLE : AQ_EEE_DISABLE; + if (eeep != NULL) + *eeep = eee; + + return 0; +} + +int +aq2_fw_get_stats(struct aq_softc *sc, struct aq_hw_stats_s *w) +{ + return 0; +} + void aq_hw_l3_filter_set(struct aq_softc *sc) { @@ -1818,16 +2423,32 @@ aq_hw_init(struct aq_softc *sc, int irqmode, int multivec) { uint32_t v; - /* Force limit MRRS on RDM/TDM to 2K */ - v = AQ_READ_REG(sc, AQ_PCI_REG_CONTROL_6_REG); - AQ_WRITE_REG(sc, AQ_PCI_REG_CONTROL_6_REG, (v & ~0x0707) | 0x0404); + if (HWTYPE_AQ1_P(sc)) { + /* Force limit MRRS on RDM/TDM to 2K */ + v = AQ_READ_REG(sc, AQ_PCI_REG_CONTROL_6_REG); + AQ_WRITE_REG(sc, AQ_PCI_REG_CONTROL_6_REG, + (v & ~0x0707) | 0x0404); - /* - * 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(sc, AQ_HW_TX_DMA_TOTAL_REQ_LIMIT_REG, 24); + /* + * 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(sc, AQ_HW_TX_DMA_TOTAL_REQ_LIMIT_REG, 24); + } + + if (HWTYPE_AQ2_P(sc)) { + uint32_t fpgaver, speed; + fpgaver = AQ_READ_REG(sc, AQ2_HW_FPGA_VERSION_REG); + if (fpgaver < 0x01000000) + speed = AQ2_LAUNCHTIME_CTRL_RATIO_SPEED_FULL; + else if (fpgaver >= 0x01008502) + speed = AQ2_LAUNCHTIME_CTRL_RATIO_SPEED_HALF; + else + speed = AQ2_LAUNCHTIME_CTRL_RATIO_SPEED_QUARTER; + AQ_WRITE_REG_BIT(sc, AQ2_LAUNCHTIME_CTRL_REG, + AQ2_LAUNCHTIME_CTRL_RATIO, speed); + } aq_hw_init_tx_path(sc); aq_hw_init_rx_path(sc); @@ -1839,6 +2460,11 @@ aq_hw_init(struct aq_softc *sc, int irqmode, int multivec) aq_hw_qos_set(sc); + if (HWTYPE_AQ2_P(sc)) { + AQ_WRITE_REG_BIT(sc, AQ2_RPF_NEW_CTRL_REG, + AQ2_RPF_NEW_CTRL_ENABLE, 1); + } + /* Enable interrupt */ AQ_WRITE_REG(sc, AQ_INTR_CTRL_REG, AQ_INTR_CTRL_RESET_DIS); AQ_WRITE_REG_BIT(sc, AQ_INTR_CTRL_REG, AQ_INTR_CTRL_MULTIVEC, multivec); @@ -1879,6 +2505,10 @@ aq_hw_init_tx_path(struct aq_softc *sc) AQ_WRITE_REG_BIT(sc, TDM_DCA_REG, TDM_DCA_MODE, 0); AQ_WRITE_REG_BIT(sc, TPB_TX_BUF_REG, TPB_TX_BUF_SCP_INS_EN, 1); + + if ((sc->sc_features & FEATURES_AQ1_REV_B) || HWTYPE_AQ2_P(sc)) { + AQ_WRITE_REG_BIT(sc, TPB_TX_BUF_REG, TPB_TX_BUF_CLK_GATE_EN, 0); + } } void @@ -1889,10 +2519,10 @@ aq_hw_init_rx_path(struct aq_softc *sc) /* clear setting */ AQ_WRITE_REG_BIT(sc, RPB_RPF_RX_REG, RPB_RPF_RX_TC_MODE, 0); AQ_WRITE_REG_BIT(sc, RPB_RPF_RX_REG, RPB_RPF_RX_FC_MODE, 0); - AQ_WRITE_REG(sc, RX_FLR_RSS_CONTROL1_REG, 0); - for (i = 0; i < 32; i++) { - AQ_WRITE_REG_BIT(sc, RPF_ETHERTYPE_FILTER_REG(i), - RPF_ETHERTYPE_FILTER_EN, 0); + + if (HWTYPE_AQ2_P(sc)) { + AQ_WRITE_REG_BIT(sc, AQ2_RPF_REDIR2_REG, + AQ2_RPF_REDIR2_HASHTYPE, AQ2_RPF_REDIR2_HASHTYPE_ALL); } if (sc->sc_nqueues > 1) { @@ -1915,6 +2545,15 @@ aq_hw_init_rx_path(struct aq_softc *sc) AQ_WRITE_REG(sc, RX_FLR_RSS_CONTROL1_REG, RX_FLR_RSS_CONTROL1_EN | bits); + } else { + AQ_WRITE_REG(sc, RX_FLR_RSS_CONTROL1_REG, 0); + } + + if (HWTYPE_AQ1_P(sc)) { + for (i = 0; i < 32; i++) { + AQ_WRITE_REG_BIT(sc, RPF_ETHERTYPE_FILTER_REG(i), + RPF_ETHERTYPE_FILTER_EN, 0); + } } /* L2 and Multicast filters */ @@ -1933,21 +2572,45 @@ aq_hw_init_rx_path(struct aq_softc *sc) ETHERTYPE_VLAN); AQ_WRITE_REG_BIT(sc, RPF_VLAN_MODE_REG, RPF_VLAN_MODE_PROMISC, 1); - if (sc->sc_features & FEATURES_AQ1_REV_B) { + if ((sc->sc_features & FEATURES_AQ1_REV_B) || HWTYPE_AQ2_P(sc)) { AQ_WRITE_REG_BIT(sc, RPF_VLAN_MODE_REG, RPF_VLAN_MODE_ACCEPT_UNTAGGED, 1); AQ_WRITE_REG_BIT(sc, RPF_VLAN_MODE_REG, RPF_VLAN_MODE_UNTAGGED_ACTION, RPF_ACTION_HOST); } - if (sc->sc_features & FEATURES_RPF2) - AQ_WRITE_REG(sc, RX_TCP_RSS_HASH_REG, RX_TCP_RSS_HASH_RPF2); - else - AQ_WRITE_REG(sc, RX_TCP_RSS_HASH_REG, 0); + if (HWTYPE_AQ2_P(sc)) { + AQ_WRITE_REG_BIT(sc, AQ2_RPF_REC_TAB_ENABLE_REG, + AQ2_RPF_REC_TAB_ENABLE_MASK, 0xffff); + AQ_WRITE_REG_BIT(sc, RPF_L2UC_MSW_REG(0), + RPF_L2UC_MSW_TAG, 1); + AQ_WRITE_REG_BIT(sc, AQ2_RPF_L2BC_TAG_REG, + AQ2_RPF_L2BC_TAG_MASK, 1); + + aq2_filter_art_set(sc, AQ2_RPF_INDEX_L2_PROMISC_OFF, + 0, AQ2_RPF_TAG_UC_MASK | AQ2_RPF_TAG_ALLMC_MASK, + AQ2_ART_ACTION_DROP); + aq2_filter_art_set(sc, AQ2_RPF_INDEX_VLAN_PROMISC_OFF, + 0, AQ2_RPF_TAG_VLAN_MASK | AQ2_RPF_TAG_UNTAG_MASK, + AQ2_ART_ACTION_DROP); + + for (int i = 0; i < 8; i++) { + aq2_filter_art_set(sc, AQ2_RPF_INDEX_PCP_TO_TC + i, + (i << AQ2_RPF_TAG_PCP_SHIFT), AQ2_RPF_TAG_PCP_MASK, + AQ2_ART_ACTION_ASSIGN_TC(i % sc->sc_nqueues)); + } - /* we might want to figure out what this magic number does */ - AQ_WRITE_REG_BIT(sc, RX_TCP_RSS_HASH_REG, RX_TCP_RSS_HASH_TYPE, - 0x001e); + } else if (HWTYPE_AQ1_P(sc)) { + if (sc->sc_features & FEATURES_RPF2) + AQ_WRITE_REG(sc, RX_TCP_RSS_HASH_REG, + RX_TCP_RSS_HASH_RPF2); + else + AQ_WRITE_REG(sc, RX_TCP_RSS_HASH_REG, 0); + + /* we might want to figure out what this magic number does */ + AQ_WRITE_REG_BIT(sc, RX_TCP_RSS_HASH_REG, + RX_TCP_RSS_HASH_TYPE, 0x001e); + } AQ_WRITE_REG_BIT(sc, RPF_L2BC_REG, RPF_L2BC_EN, 1); AQ_WRITE_REG_BIT(sc, RPF_L2BC_REG, RPF_L2BC_ACTION, RPF_ACTION_HOST); @@ -1982,7 +2645,11 @@ aq_set_mac_addr(struct aq_softc *sc, int index, uint8_t *enaddr) AQ_WRITE_REG(sc, RPF_L2UC_LSW_REG(index), l); AQ_WRITE_REG_BIT(sc, RPF_L2UC_MSW_REG(index), RPF_L2UC_MSW_MACADDR_HI, h); - AQ_WRITE_REG_BIT(sc, RPF_L2UC_MSW_REG(index), RPF_L2UC_MSW_ACTION, 1); + AQ_WRITE_REG_BIT(sc, RPF_L2UC_MSW_REG(index), + RPF_L2UC_MSW_ACTION, RPF_ACTION_HOST); + if (HWTYPE_AQ2_P(sc)) + AQ_WRITE_REG_BIT(sc, RPF_L2UC_MSW_REG(index), + RPF_L2UC_MSW_TAG, 1); AQ_WRITE_REG_BIT(sc, RPF_L2UC_MSW_REG(index), RPF_L2UC_MSW_EN, 1); return 0; @@ -2966,6 +3633,9 @@ aq_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr) case AQ_LINK_100M: media = IFM_100_TX; break; + case AQ_LINK_10M: + media = IFM_10_T; + break; case AQ_LINK_NONE: media = 0; break; @@ -3001,6 +3671,9 @@ aq_ifmedia_change(struct ifnet *ifp) case IFM_NONE: rate = AQ_LINK_NONE; break; + case IFM_10_T: + rate = AQ_LINK_10M; + break; case IFM_100_TX: rate = AQ_LINK_100M; break; @@ -3121,6 +3794,32 @@ aq_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return error; } +int +aq2_filter_art_set(struct aq_softc *sc, uint32_t idx, + uint32_t tag, uint32_t mask, uint32_t action) +{ + int error; + + AQ_MPI_LOCK(sc); + + WAIT_FOR(AQ_READ_REG(sc, AQ2_ART_SEM_REG) == 1, 10, 1000, &error); + if (error != 0) { + printf("%s: AQ2_ART_SEM_REG timeout\n", DEVNAME(sc)); + goto out; + } + + idx += sc->sc_art_filter_base_index; + AQ_WRITE_REG(sc, AQ2_RPF_ACT_ART_REQ_TAG_REG(idx), tag); + AQ_WRITE_REG(sc, AQ2_RPF_ACT_ART_REQ_MASK_REG(idx), mask); + AQ_WRITE_REG(sc, AQ2_RPF_ACT_ART_REQ_ACTION_REG(idx), action); + + AQ_WRITE_REG(sc, AQ2_ART_SEM_REG, 1); + + out: + AQ_MPI_UNLOCK(sc); + return error; +} + void aq_iff(struct aq_softc *sc) { @@ -3128,8 +3827,18 @@ aq_iff(struct aq_softc *sc) struct arpcom *ac = &sc->sc_arpcom; struct ether_multi *enm; struct ether_multistep step; + uint32_t action; int idx; + if (HWTYPE_AQ2_P(sc)) { + action = (ifp->if_flags & IFF_PROMISC) ? + AQ2_ART_ACTION_DISABLE : AQ2_ART_ACTION_DROP; + aq2_filter_art_set(sc, AQ2_RPF_INDEX_L2_PROMISC_OFF, 0, + AQ2_RPF_TAG_UC_MASK | AQ2_RPF_TAG_ALLMC_MASK, action); + aq2_filter_art_set(sc, AQ2_RPF_INDEX_VLAN_PROMISC_OFF, 0, + AQ2_RPF_TAG_VLAN_MASK | AQ2_RPF_TAG_UNTAG_MASK, action); + } + if (ifp->if_flags & IFF_PROMISC) { ifp->if_flags |= IFF_ALLMULTI; AQ_WRITE_REG_BIT(sc, RPF_L2BC_REG, RPF_L2BC_PROMISC, 1);