The branch main has been updated by emaste: URL: https://cgit.FreeBSD.org/src/commit/?id=493d26c58e732dcfcdd87993ef71880adfe9d0cb
commit 493d26c58e732dcfcdd87993ef71880adfe9d0cb Author: Ed Maste <[email protected]> AuthorDate: 2025-11-13 18:48:54 +0000 Commit: Ed Maste <[email protected]> CommitDate: 2025-11-30 15:38:33 +0000 sys: Import snapshot of Aquantia ACQ107 vendor driver Obtained from https://github.com/Aquantia/aqtion-freebsd commit c61d27b1d94af72c642deefa0595884481ea7377. This is not using a vendor branch. The formerly-upstream repo is abandoned and I do not believe it will receive updates. This initial import serves as a snapshot of the vendor code, but from here we will iterate on it in the tree as our own code. Bug fixes, code cleanup, and build infrastructure will follow. NetBSD and OpenBSD have derivatives of this driver (with additional hardware support). We can look to changes in those drivers, and the Linux driver, to add support here. Reviewed by: adrian Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D53813 --- sys/dev/aq/aq_common.h | 87 + sys/dev/aq/aq_dbg.c | 237 +++ sys/dev/aq/aq_dbg.h | 138 ++ sys/dev/aq/aq_device.h | 150 ++ sys/dev/aq/aq_fw.c | 352 +++++ sys/dev/aq/aq_fw.h | 76 + sys/dev/aq/aq_fw1x.c | 313 ++++ sys/dev/aq/aq_fw2x.c | 498 ++++++ sys/dev/aq/aq_hw.c | 907 +++++++++++ sys/dev/aq/aq_hw.h | 356 +++++ sys/dev/aq/aq_hw_llh.c | 1986 +++++++++++++++++++++++ sys/dev/aq/aq_hw_llh.h | 1176 ++++++++++++++ sys/dev/aq/aq_hw_llh_internal.h | 3335 +++++++++++++++++++++++++++++++++++++++ sys/dev/aq/aq_irq.c | 185 +++ sys/dev/aq/aq_main.c | 1329 ++++++++++++++++ sys/dev/aq/aq_media.c | 219 +++ sys/dev/aq/aq_ring.c | 581 +++++++ sys/dev/aq/aq_ring.h | 184 +++ 18 files changed, 12109 insertions(+) diff --git a/sys/dev/aq/aq_common.h b/sys/dev/aq/aq_common.h new file mode 100644 index 000000000000..b123a7e6807d --- /dev/null +++ b/sys/dev/aq/aq_common.h @@ -0,0 +1,87 @@ +/* + * aQuantia Corporation Network Driver + * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * (1) Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * (2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * (3)The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _AQ_COMMON_H_ +#define _AQ_COMMON_H_ + +#include <stdint.h> + +#define ETH_MAC_LEN 6 + +/* Types definition */ +#define TRUE 1 +#define FALSE 0 + +#define s8 __int8_t +#define u8 __uint8_t +#define u16 __uint16_t +#define s16 __int16_t +#define u32 __uint32_t +#define u64 __uint64_t +#define s64 __int64_t +#define s32 int +typedef __uint32_t DWORD; + +#define ETIME ETIMEDOUT +#define EOK 0 + +#define BIT(nr) (1UL << (nr)) + +#define usec_delay(x) DELAY(x) + +#ifndef msec_delay +#define msec_delay(x) DELAY(x*1000) +#define msec_delay_irq(x) DELAY(x*1000) +#endif + +#define AQ_HW_WAIT_FOR(_B_, _US_, _N_) \ + do { \ + unsigned int i; \ + for (i = _N_; (!(_B_)) && i; --i) { \ + usec_delay(_US_); \ + } \ + if (!i) { \ + err = -1; \ + } \ + } while (0) + + +#define LODWORD(a) ((DWORD)(a)) +#define LOWORD(a) ((u16)(a)) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define AQ_VER "0.0.5" + +#endif //_AQ_COMMON_H_ + diff --git a/sys/dev/aq/aq_dbg.c b/sys/dev/aq/aq_dbg.c new file mode 100644 index 000000000000..5340fc46a223 --- /dev/null +++ b/sys/dev/aq/aq_dbg.c @@ -0,0 +1,237 @@ +/** + * aQuantia Corporation Network Driver + * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * (1) Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * (2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * (3) The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @file aq_dbg.c + * Debugging stuff. + * @date 2017.12.13 @author [email protected] + */ + + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include "aq_common.h" +#include "aq_dbg.h" + + +const aq_debug_level dbg_level_ = lvl_detail; +const u32 dbg_categories_ = dbg_init | dbg_config | dbg_fw; + + + +#define DESCR_FIELD(DESCR, BIT_BEGIN, BIT_END) \ + ((DESCR >> BIT_END) &\ + (BIT(BIT_BEGIN - BIT_END + 1) -1)) + +#define __field(TYPE, VAR) TYPE VAR; +void trace_aq_tx_descr(int ring_idx, unsigned int pointer, volatile u64 descr[2]) +{ +#if AQ_CFG_DEBUG_LVL > 2 + struct __entry{ + __field(unsigned int, ring_idx) + __field(unsigned int, pointer) + /* Tx Descriptor */ + __field(u64, data_buf_addr) + __field(u32, pay_len) + __field(u8, ct_en) + __field(u8, ct_idx) + __field(u16, rsvd2) + __field(u8, tx_cmd) + __field(u8, eop) + __field(u8, dd) + __field(u16, buf_len) + __field(u8, rsvd1) + __field(u8, des_typ) + } entry; + + entry.ring_idx = ring_idx; + entry.pointer = pointer; + entry.data_buf_addr = descr[0]; + entry.pay_len = DESCR_FIELD(descr[1], 63, 46); + entry.ct_en = DESCR_FIELD(descr[1], 45, 45); + entry.ct_idx = DESCR_FIELD(descr[1], 44, 44); + entry.rsvd2 = DESCR_FIELD(descr[1], 43, 30); + entry.tx_cmd = DESCR_FIELD(descr[1], 29, 22); + entry.eop = DESCR_FIELD(descr[1], 21, 21); + entry.dd = DESCR_FIELD(descr[1], 20, 20); + entry.buf_len = DESCR_FIELD(descr[1], 19, 4); + entry.rsvd1 = DESCR_FIELD(descr[1], 3, 3); + entry.des_typ = DESCR_FIELD(descr[1], 2, 0); + + + aq_log_detail("trace_aq_tx_descr ring=%d descr=%u pay_len=%u ct_en=%u ct_idx=%u rsvd2=0x%x tx_cmd=0x%x eop=%u dd=%u buf_len=%u rsvd1=%u des_typ=0x%x", + entry.ring_idx, entry.pointer, entry.pay_len, + entry.ct_en, entry.ct_idx, entry.rsvd2, + entry.tx_cmd, entry.eop, entry.dd, entry.buf_len, + entry.rsvd1, entry.des_typ); +#endif +} + +void trace_aq_rx_descr(int ring_idx, unsigned int pointer, volatile u64 descr[2]) +{ +#if AQ_CFG_DEBUG_LVL > 2 + u8 dd; + u8 eop; + u8 rx_stat; + u8 rx_estat; + u8 rsc_cnt; + u16 pkt_len; + u16 next_desp; + u16 vlan_tag; + + u8 rss_type; + u8 pkt_type; + u8 rdm_err; + u8 avb_ts; + u8 rsvd; + u8 rx_cntl; + u8 sph; + u16 hdr_len; + u32 rss_hash; + + rss_hash = DESCR_FIELD(descr[0], 63, 32); + hdr_len = DESCR_FIELD(descr[0], 31, 22); + sph = DESCR_FIELD(descr[0], 21, 21); + rx_cntl = DESCR_FIELD(descr[0], 20, 19); + rsvd = DESCR_FIELD(descr[0], 18, 14); + avb_ts = DESCR_FIELD(descr[0], 13, 13); + rdm_err = DESCR_FIELD(descr[0], 12, 12); + pkt_type = DESCR_FIELD(descr[0], 11, 4); + rss_type = DESCR_FIELD(descr[0], 3, 0); + + vlan_tag = DESCR_FIELD(descr[1], 63, 48); + next_desp = DESCR_FIELD(descr[1], 47, 32); + pkt_len = DESCR_FIELD(descr[1], 31, 16); + rsc_cnt = DESCR_FIELD(descr[1], 15, 12); + rx_estat = DESCR_FIELD(descr[1], 11, 6); + rx_stat = DESCR_FIELD(descr[1], 5, 2); + eop = DESCR_FIELD(descr[1], 1, 1); + dd = DESCR_FIELD(descr[1], 0, 0); + + printf("trace_aq_rx_descr ring=%d descr=%u rss_hash=0x%x hdr_len=%u sph=%u rx_cntl=%u rsvd=0x%x avb_ts=%u rdm_err=%u pkt_type=%u rss_type=%u vlan_tag=%u next_desp=%u pkt_len=%u rsc_cnt=%u rx_estat=0x%x rx_stat=0x%x eop=%u dd=%u\n", + ring_idx, pointer, rss_hash, + hdr_len, sph, rx_cntl, + rsvd, avb_ts, rdm_err, + pkt_type, rss_type, vlan_tag, + next_desp, pkt_len, rsc_cnt, + rx_estat, rx_stat, eop, dd); +#endif +} + +void trace_aq_tx_context_descr(int ring_idx, unsigned int pointer, volatile u64 descr[2]) +{ +#if AQ_CFG_DEBUG_LVL > 2 + struct __entry_s{ + __field(unsigned int, ring_idx) + __field(unsigned int, pointer) + /* Tx Context Descriptor */ + __field(u16, out_len) + __field(u8, tun_len) + __field(u64, resvd3) + __field(u16, mss_len) + __field(u8, l4_len) + __field(u8, l3_len) + __field(u8, l2_len) + __field(u8, ct_cmd) + __field(u16, vlan_tag) + __field(u8, ct_idx) + __field(u8, des_typ) + } entry; + struct __entry_s *__entry = &entry; + __entry->ring_idx = ring_idx; + __entry->pointer = pointer; + __entry->out_len = DESCR_FIELD(descr[0], 63, 48); + __entry->tun_len = DESCR_FIELD(descr[0], 47, 40); + __entry->resvd3 = DESCR_FIELD(descr[0], 39, 0); + __entry->mss_len = DESCR_FIELD(descr[1], 63, 48); + __entry->l4_len = DESCR_FIELD(descr[1], 47, 40); + __entry->l3_len = DESCR_FIELD(descr[1], 39, 31); + __entry->l2_len = DESCR_FIELD(descr[1], 30, 24); + __entry->ct_cmd = DESCR_FIELD(descr[1], 23, 20); + __entry->vlan_tag = DESCR_FIELD(descr[1], 19, 4); + __entry->ct_idx = DESCR_FIELD(descr[1], 3, 3); + __entry->des_typ = DESCR_FIELD(descr[1], 2, 0); + + printf("trace_aq_tx_context_descr ring=%d descr=%u out_len=%u tun_len=%u resvd3=%lu mss_len=%u l4_len=%u l3_len=%u l2_len=%d ct_cmd=%u vlan_tag=%u ct_idx=%u des_typ=0x%x\n", + __entry->ring_idx, __entry->pointer, __entry->out_len, + __entry->tun_len, __entry->resvd3, __entry->mss_len, + __entry->l4_len, __entry->l3_len, __entry->l2_len, + __entry->ct_cmd, __entry->vlan_tag, __entry->ct_idx, + __entry->des_typ); +#endif +} + +void DumpHex(const void* data, size_t size) { +#if AQ_CFG_DEBUG_LVL > 3 + char ascii[17]; + size_t i, j; + char line[256]; + char buf[256]; + + ascii[16] = '\0'; + line[0] = '\0'; + printf("packet at %p\n", data); + + for (i = 0; i < size; ++i) { + sprintf(buf, "%02X ", ((const unsigned char*)data)[i]); + strcat(line, buf); + if (((const unsigned char*)data)[i] >= ' ' && ((const unsigned char*)data)[i] <= '~') { + ascii[i % 16] = ((const unsigned char*)data)[i]; + } else { + ascii[i % 16] = '.'; + } + if ((i+1) % 8 == 0 || i+1 == size) { + strcat(line, " "); + if ((i+1) % 16 == 0) { + sprintf(buf, "| %s \n", ascii); + strcat(line, buf); + printf("%s", line); + line[0] = '\0'; + } else if (i+1 == size) { + ascii[(i+1) % 16] = '\0'; + if ((i+1) % 16 <= 8) { + strcat(line, " "); + } + for (j = (i+1) % 16; j < 16; ++j) { + strcat(line, " "); + } + sprintf(buf, "| %s \n", ascii); + strcat(line, buf); + printf("%s", line); + line[0] = '\0'; + } + } + } +#endif +} \ No newline at end of file diff --git a/sys/dev/aq/aq_dbg.h b/sys/dev/aq/aq_dbg.h new file mode 100644 index 000000000000..bb786bf0adc6 --- /dev/null +++ b/sys/dev/aq/aq_dbg.h @@ -0,0 +1,138 @@ +/** + * aQuantia Corporation Network Driver + * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * (1) Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * (2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * (3) The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @file aq_dbg.h + * Debug print macros & definitions. + * @date 2017.12.07 @author [email protected] + */ +#ifndef AQ_DBG_H +#define AQ_DBG_H + +#include <syslog.h> +#include <sys/systm.h> +/* +Debug levels: +0 - no debug +1 - important warnings +2 - debug prints +3 - trace function calls +4 - dump descriptor +*/ + +#define AQ_CFG_DEBUG_LVL 0x0 + +#define AQ_DBG_ERROR(string, args...) printf( "atlantic: " string "\n", ##args) + +/* Debug stuff */ +#if AQ_CFG_DEBUG_LVL > 0 +#define AQ_DBG_WARNING(string, args...) printf( "atlantic: " string "\n", ##args) +#else +#define AQ_DBG_WARNING(string, ...) +#endif + +#if AQ_CFG_DEBUG_LVL > 1 +#define AQ_DBG_PRINT(string, args...) printf( "atlantic: " string "\n", ##args) +#else +#define AQ_DBG_PRINT(string, ...) +#endif + +#if AQ_CFG_DEBUG_LVL > 2 +#define AQ_DBG_ENTER() printf( "atlantic: %s() {\n", __func__) +#define AQ_DBG_ENTERA(s, args...) printf( "atlantic: %s(" s ") {\n", __func__, ##args) +#define AQ_DBG_EXIT(err) printf( "atlantic: } %s(), err=%d\n", __func__, err) +#else +#define AQ_DBG_ENTER() +#define AQ_DBG_ENTERA(s, args...) +#define AQ_DBG_EXIT(err) +#endif + +#if AQ_CFG_DEBUG_LVL > 2 +#define AQ_DBG_DUMP_DESC(desc) { \ + volatile u8 *raw = (volatile u8*)(desc); \ + printf( "07-00 %02X%02X%02X%02X %02X%02X%02X%02X 15-08 %02X%02X%02X%02X %02X%02X%02X%02X\n", \ + raw[7], raw[6], raw[5], raw[4], raw[3], raw[2], raw[1], raw[0], \ + raw[15], raw[14], raw[13], raw[12], raw[11], raw[10], raw[9], raw[8]); \ +}\ + +#else +#define AQ_DBG_DUMP_DESC(desc) +#endif + +typedef enum aq_debug_level +{ + lvl_error = LOG_ERR, + lvl_warn = LOG_WARNING, + lvl_trace = LOG_NOTICE, + lvl_detail = LOG_INFO, +} aq_debug_level; + +typedef enum aq_debug_category +{ + dbg_init = 1, + dbg_config = 1 << 1, + dbg_tx = 1 << 2, + dbg_rx = 1 << 3, + dbg_intr = 1 << 4, + dbg_fw = 1 << 5, +} aq_debug_category; + + +#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) + +extern const aq_debug_level dbg_level_; +extern const u32 dbg_categories_; + +#define log_base_(_lvl, _fmt, args...) printf( "atlantic: " _fmt "\n", ##args) + +#if AQ_CFG_DEBUG_LVL > 0 +#define trace_base_(_lvl, _cat, _fmt, args...) do { if (dbg_level_ >= _lvl && (_cat & dbg_categories_)) { printf( "atlantic: " _fmt " @%s,%d\n", ##args, __FILENAME__, __LINE__); }} while (0) +#else +#define trace_base_(_lvl, _cat, _fmt, ...) do {} while (0) +#endif // AQ_CFG_DEBUG_LVL > 0 + +#define aq_log_error(_fmt, args...) log_base_(lvl_error, "[!] " _fmt, ##args) +#define aq_log_warn(_fmt, args...) log_base_(lvl_warn, "/!\\ " _fmt, ##args) +#define aq_log(_fmt, args...) log_base_(lvl_trace, _fmt, ##args) +#define aq_log_detail(_fmt, args...) log_base_(lvl_detail, _fmt, ##args) + +#define trace_error(_cat,_fmt, args...) trace_base_(lvl_error, _cat, "[!] " _fmt, ##args) +#define trace_warn(_cat, _fmt, args...) trace_base_(lvl_warn, _cat, "/!\\ " _fmt, ##args) +#define trace(_cat, _fmt, args...) trace_base_(lvl_trace, _cat, _fmt, ##args) +#define trace_detail(_cat, _fmt, args...) trace_base_(lvl_detail, _cat, _fmt, ##args) + +void trace_aq_tx_descr(int ring_idx, unsigned int pointer, volatile u64 descr[2]); +void trace_aq_rx_descr(int ring_idx, unsigned int pointer, volatile u64 descr[2]); +void trace_aq_tx_context_descr(int ring_idx, unsigned int pointer, volatile u64 descr[2]); +void DumpHex(const void* data, size_t size); + +#endif // AQ_DBG_H diff --git a/sys/dev/aq/aq_device.h b/sys/dev/aq/aq_device.h new file mode 100644 index 000000000000..2c0d8df77cb9 --- /dev/null +++ b/sys/dev/aq/aq_device.h @@ -0,0 +1,150 @@ +/* + * aQuantia Corporation Network Driver + * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * (1) Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * (2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * (3)The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _AQ_DEVICE_H_ +#define _AQ_DEVICE_H_ + +#include "aq_hw.h" + +enum aq_media_type { + AQ_MEDIA_TYPE_UNKNOWN = 0, + AQ_MEDIA_TYPE_FIBRE, + AQ_MEDIA_TYPE_TP, +}; + +#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_ALL (AQ_LINK_100M | AQ_LINK_1G | AQ_LINK_2G5 | AQ_LINK_5G | \ + AQ_LINK_10G ) + +struct aq_stats_s { + u64 prc; + u64 uprc; + u64 mprc; + u64 bprc; + u64 cprc; + u64 erpr; + u64 dpc; + u64 brc; + u64 ubrc; + u64 mbrc; + u64 bbrc; + + u64 ptc; + u64 uptc; + u64 mptc; + u64 bptc; + u64 erpt; + u64 btc; + u64 ubtc; + u64 mbtc; + u64 bbtc; +}; + +enum aq_dev_state_e { + AQ_DEV_STATE_UNLOAD, + AQ_DEV_STATE_PCI_STOP, + AQ_DEV_STATE_DOWN, + AQ_DEV_STATE_UP, +}; + +struct aq_rx_filters { + unsigned int rule_cnt; + struct aq_rx_filter_vlan vlan_filters[AQ_HW_VLAN_MAX_FILTERS]; + struct aq_rx_filter_l2 etype_filters[AQ_HW_ETYPE_MAX_FILTERS]; +}; + +struct aq_vlan_tag { + SLIST_ENTRY(aq_vlan_tag) next; + uint16_t tag; +}; + +struct aq_dev { + device_t dev; + if_ctx_t ctx; + if_softc_ctx_t scctx; + if_shared_ctx_t sctx; + struct ifmedia * media; + + struct aq_hw hw; + + enum aq_media_type media_type; + uint32_t link_speeds; + uint32_t chip_features; + uint32_t mbox_addr; + uint8_t mac_addr[ETHER_ADDR_LEN]; + uint64_t admin_ticks; + struct if_irq irq; + int msix; + + int mmio_rid; + struct resource * mmio_res; + bus_space_tag_t mmio_tag; + bus_space_handle_t mmio_handle; + bus_size_t mmio_size; + + struct aq_ring *tx_rings[HW_ATL_B0_RINGS_MAX]; + struct aq_ring *rx_rings[HW_ATL_B0_RINGS_MAX]; + uint32_t tx_rings_count; + uint32_t rx_rings_count; + bool linkup; + int media_active; + + struct aq_hw_stats_s last_stats; + struct aq_stats_s curr_stats; + + bitstr_t *vlan_tags; + int mcnt; + + uint8_t rss_key[HW_ATL_RSS_HASHKEY_SIZE]; + uint8_t rss_table[HW_ATL_RSS_INDIRECTION_TABLE_MAX]; +}; + +typedef struct aq_dev aq_dev_t; + +int aq_update_hw_stats(aq_dev_t *aq_dev); +void aq_initmedia(aq_dev_t *aq_dev); +int aq_linkstat_isr(void *arg); +int aq_isr_rx(void *arg); +void aq_mediastatus_update(aq_dev_t *aq_dev, u32 link_speed, const struct aq_hw_fc_info *fc_neg); +void aq_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr); +int aq_mediachange(struct ifnet *ifp); +void aq_if_update_admin_status(if_ctx_t ctx); + +#endif diff --git a/sys/dev/aq/aq_fw.c b/sys/dev/aq/aq_fw.c new file mode 100644 index 000000000000..619a3048cc28 --- /dev/null +++ b/sys/dev/aq/aq_fw.c @@ -0,0 +1,352 @@ +/* + * aQuantia Corporation Network Driver + * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * (1) Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * (2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * (3) The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @file aq_fw.c + * Firmware-related functions implementation. + * @date 2017.12.07 @author [email protected] + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <errno.h> + +#include "aq_common.h" + +#include "aq_hw.h" +#include "aq_hw_llh.h" +#include "aq_hw_llh_internal.h" + +#include "aq_fw.h" +#include "aq_common.h" + +#include "aq_dbg.h" + + +typedef enum aq_fw_bootloader_mode +{ + boot_mode_unknown = 0, + boot_mode_flb, + boot_mode_rbl_flash, + boot_mode_rbl_host_bootload, +} aq_fw_bootloader_mode; + +#define AQ_CFG_HOST_BOOT_DISABLE 0 +// Timeouts +#define RBL_TIMEOUT_MS 10000 +#define MAC_FW_START_TIMEOUT_MS 10000 +#define FW_LOADER_START_TIMEOUT_MS 10000 + +const u32 NO_RESET_SCRATCHPAD_ADDRESS = 0; +const u32 NO_RESET_SCRATCHPAD_LEN_RES = 1; +const u32 NO_RESET_SCRATCHPAD_RBL_STATUS = 2; +const u32 NO_RESET_SCRATCHPAD_RBL_STATUS_2 = 3; +const u32 WRITE_DATA_COMPLETE = 0x55555555; +const u32 WRITE_DATA_CHUNK_DONE = 0xaaaaaaaa; +const u32 WRITE_DATA_FAIL_WRONG_ADDRESS = 0x66666666; + +const u32 WAIT_WRITE_TIMEOUT = 1; +const u32 WAIT_WRITE_TIMEOUT_COUNT = 1000; + +const u32 RBL_STATUS_SUCCESS = 0xabba; +const u32 RBL_STATUS_FAILURE = 0xbad; +const u32 RBL_STATUS_HOST_BOOT = 0xf1a7; + +const u32 SCRATCHPAD_FW_LOADER_STATUS = (0x40 / sizeof(u32)); + + +extern struct aq_firmware_ops aq_fw1x_ops; +extern struct aq_firmware_ops aq_fw2x_ops; + + +int mac_soft_reset_(struct aq_hw* hw, aq_fw_bootloader_mode* mode); +int mac_soft_reset_flb_(struct aq_hw* hw); +int mac_soft_reset_rbl_(struct aq_hw* hw, aq_fw_bootloader_mode* mode); +int wait_init_mac_firmware_(struct aq_hw* hw); + + +int aq_fw_reset(struct aq_hw* hw) +{ + int ver = AQ_READ_REG(hw, 0x18); + u32 bootExitCode = 0; + int k; + + for (k = 0; k < 1000; ++k) { + u32 flbStatus = reg_glb_daisy_chain_status1_get(hw); + bootExitCode = AQ_READ_REG(hw, 0x388); + if (flbStatus != 0x06000000 || bootExitCode != 0) + break; + } + + if (k == 1000) { + aq_log_error("Neither RBL nor FLB started"); + return (-EBUSY); + } + + hw->rbl_enabled = bootExitCode != 0; + + trace(dbg_init, "RBL enabled = %d", hw->rbl_enabled); + + /* Having FW version 0 is an indicator that cold start + * is in progress. This means two things: + * 1) Driver have to wait for FW/HW to finish boot (500ms giveup) + * 2) Driver may skip reset sequence and save time. + */ + if (hw->fast_start_enabled && !ver) { + int err = wait_init_mac_firmware_(hw); + /* Skip reset as it just completed */ + if (!err) + return (0); + } + + aq_fw_bootloader_mode mode = boot_mode_unknown; + int err = mac_soft_reset_(hw, &mode); + if (err < 0) { + aq_log_error("MAC reset failed: %d", err); + return (err); + } + + switch (mode) { + case boot_mode_flb: + aq_log("FLB> F/W successfully loaded from flash."); + hw->flash_present = true; + return wait_init_mac_firmware_(hw); + + case boot_mode_rbl_flash: + aq_log("RBL> F/W loaded from flash. Host Bootload disabled."); + hw->flash_present = true; + return wait_init_mac_firmware_(hw); + + case boot_mode_unknown: + aq_log_error("F/W bootload error: unknown bootloader type"); + return (-ENOTSUP); + + case boot_mode_rbl_host_bootload: +#if AQ_CFG_HOST_BOOT_DISABLE + aq_log_error("RBL> Host Bootload mode: this driver does not support Host Boot"); + return (-ENOTSUP); +#else + trace(dbg_init, "RBL> Host Bootload mode"); + break; +#endif // HOST_BOOT_DISABLE + } + + /* + * #todo: Host Boot + */ + aq_log_error("RBL> F/W Host Bootload not implemented"); + + return (-ENOTSUP); +} + +int aq_fw_ops_init(struct aq_hw* hw) +{ + if (hw->fw_version.raw == 0) + hw->fw_version.raw = AQ_READ_REG(hw, 0x18); + + aq_log("MAC F/W version is %d.%d.%d", + hw->fw_version.major_version, hw->fw_version.minor_version, + hw->fw_version.build_number); + + if (hw->fw_version.major_version == 1) { + trace(dbg_init, "using F/W ops v1.x"); + hw->fw_ops = &aq_fw1x_ops; + return (EOK); + } else if (hw->fw_version.major_version >= 2) { + trace(dbg_init, "using F/W ops v2.x"); + hw->fw_ops = &aq_fw2x_ops; + return (EOK); + } + + aq_log_error("aq_fw_ops_init(): invalid F/W version %#x", hw->fw_version.raw); + return (-ENOTSUP); +} + + +int mac_soft_reset_(struct aq_hw* hw, aq_fw_bootloader_mode* mode /*= nullptr*/) +{ + if (hw->rbl_enabled) { + return mac_soft_reset_rbl_(hw, mode); + } else { + if (mode) + *mode = boot_mode_flb; + + return mac_soft_reset_flb_(hw); + } +} + +int mac_soft_reset_flb_(struct aq_hw* hw) +{ + int k; + + reg_global_ctl2_set(hw, 0x40e1); + // Let Felicity hardware to complete SMBUS transaction before Global software reset. + msec_delay(50); + + /* + * If SPI burst transaction was interrupted(before running the script), global software + * reset may not clear SPI interface. Clean it up manually before global reset. + */ + reg_glb_nvr_provisioning2_set(hw, 0xa0); + reg_glb_nvr_interface1_set(hw, 0x9f); + reg_glb_nvr_interface1_set(hw, 0x809f); + msec_delay(50); + + reg_glb_standard_ctl1_set(hw, (reg_glb_standard_ctl1_get(hw) & ~glb_reg_res_dis_msk) | glb_soft_res_msk); + + // Kickstart. + reg_global_ctl2_set(hw, 0x80e0); + reg_mif_power_gating_enable_control_set(hw, 0); + if (!hw->fast_start_enabled) + reg_glb_general_provisioning9_set(hw, 1); + + /* + * For the case SPI burst transaction was interrupted (by MCP reset above), + * wait until it is completed by hardware. + */ + msec_delay(50); // Sleep for 10 ms. + + /* MAC Kickstart */ + if (!hw->fast_start_enabled) { + reg_global_ctl2_set(hw, 0x180e0); + + u32 flb_status = 0; + int k; + for (k = 0; k < 1000; ++k) { + flb_status = reg_glb_daisy_chain_status1_get(hw) & 0x10; + if (flb_status != 0) + break; + msec_delay(10); // Sleep for 10 ms. + } + + if (flb_status == 0) { + trace_error(dbg_init, "FLB> MAC kickstart failed: timed out"); + return (false); + } + + trace(dbg_init, "FLB> MAC kickstart done, %d ms", k); + /* FW reset */ + reg_global_ctl2_set(hw, 0x80e0); + // Let Felicity hardware complete SMBUS transaction before Global software reset. + msec_delay(50); + } + reg_glb_cpu_sem_set(hw, 1, 0); + + // PHY Kickstart: #undone + + // Global software reset + rx_rx_reg_res_dis_set(hw, 0); + tx_tx_reg_res_dis_set(hw, 0); + mpi_tx_reg_res_dis_set(hw, 0); + reg_glb_standard_ctl1_set(hw, (reg_glb_standard_ctl1_get(hw) & ~glb_reg_res_dis_msk) | glb_soft_res_msk); + + bool restart_completed = false; + for (k = 0; k < 1000; ++k) { + restart_completed = reg_glb_fw_image_id1_get(hw) != 0; + if (restart_completed) + break; + msec_delay(10); + } + + if (!restart_completed) { + trace_error(dbg_init, "FLB> Global Soft Reset failed"); + return (false); + } + + trace(dbg_init, "FLB> F/W restart: %d ms", k * 10); + return (true); +} + +int mac_soft_reset_rbl_(struct aq_hw* hw, aq_fw_bootloader_mode* mode) +{ + trace(dbg_init, "RBL> MAC reset STARTED!"); + + reg_global_ctl2_set(hw, 0x40e1); *** 11281 LINES SKIPPED ***
