1493d26c5SEd Maste /* 2493d26c5SEd Maste * aQuantia Corporation Network Driver 3493d26c5SEd Maste * Copyright (C) 2019 aQuantia Corporation. All rights reserved 4493d26c5SEd Maste * 5493d26c5SEd Maste * Redistribution and use in source and binary forms, with or without 6493d26c5SEd Maste * modification, are permitted provided that the following conditions 7493d26c5SEd Maste * are met: 8493d26c5SEd Maste * 9493d26c5SEd Maste * (1) Redistributions of source code must retain the above 10493d26c5SEd Maste * copyright notice, this list of conditions and the following 11493d26c5SEd Maste * disclaimer. 12493d26c5SEd Maste * 13493d26c5SEd Maste * (2) Redistributions in binary form must reproduce the above 14493d26c5SEd Maste * copyright notice, this list of conditions and the following 15493d26c5SEd Maste * disclaimer in the documentation and/or other materials provided 16493d26c5SEd Maste * with the distribution. 17493d26c5SEd Maste * 18493d26c5SEd Maste * (3)The name of the author may not be used to endorse or promote 19493d26c5SEd Maste * products derived from this software without specific prior 20493d26c5SEd Maste * written permission. 21493d26c5SEd Maste * 22493d26c5SEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 23493d26c5SEd Maste * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24493d26c5SEd Maste * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25493d26c5SEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 26493d26c5SEd Maste * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27493d26c5SEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 28493d26c5SEd Maste * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29493d26c5SEd Maste * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30493d26c5SEd Maste * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31493d26c5SEd Maste * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32493d26c5SEd Maste * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33493d26c5SEd Maste */ 34493d26c5SEd Maste 35493d26c5SEd Maste 36493d26c5SEd Maste #include <sys/cdefs.h> 37493d26c5SEd Maste __FBSDID("$FreeBSD$"); 38493d26c5SEd Maste 39493d26c5SEd Maste #include <sys/param.h> 40493d26c5SEd Maste #include <sys/malloc.h> 41493d26c5SEd Maste #include <sys/socket.h> 42493d26c5SEd Maste #include <sys/kernel.h> 43493d26c5SEd Maste #include <sys/bus.h> 44493d26c5SEd Maste #include <sys/module.h> 45493d26c5SEd Maste #include <sys/rman.h> 46493d26c5SEd Maste #include <sys/endian.h> 47493d26c5SEd Maste #include <sys/sockio.h> 48493d26c5SEd Maste #include <sys/priv.h> 49493d26c5SEd Maste #include <sys/sysctl.h> 50493d26c5SEd Maste #include <sys/sbuf.h> 51493d26c5SEd Maste #include <sys/bitstring.h> 52493d26c5SEd Maste 53493d26c5SEd Maste #include <machine/bus.h> 54493d26c5SEd Maste #include <machine/resource.h> 55493d26c5SEd Maste 56493d26c5SEd Maste #include <dev/pci/pcireg.h> 57493d26c5SEd Maste #include <dev/pci/pcivar.h> 58493d26c5SEd Maste 59493d26c5SEd Maste #include <net/if.h> 60493d26c5SEd Maste #include <net/if_media.h> 61493d26c5SEd Maste #include <net/if_var.h> 62493d26c5SEd Maste #include <net/if_dl.h> 63493d26c5SEd Maste #include <net/ethernet.h> 64493d26c5SEd Maste #include <net/iflib.h> 65493d26c5SEd Maste #include <net/rss_config.h> 66493d26c5SEd Maste 67493d26c5SEd Maste #include "opt_inet.h" 68493d26c5SEd Maste #include "opt_inet6.h" 69493d26c5SEd Maste #include "opt_rss.h" 70493d26c5SEd Maste 71493d26c5SEd Maste #include "ifdi_if.h" 72493d26c5SEd Maste 73493d26c5SEd Maste #include "aq_device.h" 74493d26c5SEd Maste #include "aq_fw.h" 75493d26c5SEd Maste #include "aq_hw.h" 76493d26c5SEd Maste #include "aq_hw_llh.h" 77493d26c5SEd Maste #include "aq_ring.h" 78493d26c5SEd Maste #include "aq_dbg.h" 79493d26c5SEd Maste 80493d26c5SEd Maste 81493d26c5SEd Maste #define AQ_XXX_UNIMPLEMENTED_FUNCTION do { \ 82493d26c5SEd Maste printf("atlantic: unimplemented function: %s@%s:%d\n", __func__, \ 83493d26c5SEd Maste __FILE__, __LINE__); \ 84493d26c5SEd Maste } while (0) 85493d26c5SEd Maste 86493d26c5SEd Maste MALLOC_DEFINE(M_AQ, "aq", "Aquantia"); 87493d26c5SEd Maste 88493d26c5SEd Maste char aq_driver_version[] = AQ_VER; 89493d26c5SEd Maste 90493d26c5SEd Maste #define AQUANTIA_VENDOR_ID 0x1D6A 91493d26c5SEd Maste 92493d26c5SEd Maste #define AQ_DEVICE_ID_0001 0x0001 93493d26c5SEd Maste #define AQ_DEVICE_ID_D100 0xD100 94493d26c5SEd Maste #define AQ_DEVICE_ID_D107 0xD107 95493d26c5SEd Maste #define AQ_DEVICE_ID_D108 0xD108 96493d26c5SEd Maste #define AQ_DEVICE_ID_D109 0xD109 97493d26c5SEd Maste 98493d26c5SEd Maste #define AQ_DEVICE_ID_AQC100 0x00B1 99493d26c5SEd Maste #define AQ_DEVICE_ID_AQC107 0x07B1 100493d26c5SEd Maste #define AQ_DEVICE_ID_AQC108 0x08B1 101493d26c5SEd Maste #define AQ_DEVICE_ID_AQC109 0x09B1 102493d26c5SEd Maste #define AQ_DEVICE_ID_AQC111 0x11B1 103493d26c5SEd Maste #define AQ_DEVICE_ID_AQC112 0x12B1 104493d26c5SEd Maste 105493d26c5SEd Maste #define AQ_DEVICE_ID_AQC100S 0x80B1 106493d26c5SEd Maste #define AQ_DEVICE_ID_AQC107S 0x87B1 107493d26c5SEd Maste #define AQ_DEVICE_ID_AQC108S 0x88B1 108493d26c5SEd Maste #define AQ_DEVICE_ID_AQC109S 0x89B1 109493d26c5SEd Maste #define AQ_DEVICE_ID_AQC111S 0x91B1 110493d26c5SEd Maste #define AQ_DEVICE_ID_AQC112S 0x92B1 111493d26c5SEd Maste 112493d26c5SEd Maste static pci_vendor_info_t aq_vendor_info_array[] = { 113493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_0001, "Aquantia AQtion 10Gbit Network Adapter"), 114493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_D107, "Aquantia AQtion 10Gbit Network Adapter"), 115493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_D108, "Aquantia AQtion 5Gbit Network Adapter"), 116493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_D109, "Aquantia AQtion 2.5Gbit Network Adapter"), 117493d26c5SEd Maste 118493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC107, "Aquantia AQtion 10Gbit Network Adapter"), 119493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC108, "Aquantia AQtion 5Gbit Network Adapter"), 120493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC109, "Aquantia AQtion 2.5Gbit Network Adapter"), 121493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC100, "Aquantia AQtion 10Gbit Network Adapter"), 122493d26c5SEd Maste 123493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC107S, "Aquantia AQtion 10Gbit Network Adapter"), 124493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC108S, "Aquantia AQtion 5Gbit Network Adapter"), 125493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC109S, "Aquantia AQtion 2.5Gbit Network Adapter"), 126493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC100S, "Aquantia AQtion 10Gbit Network Adapter"), 127493d26c5SEd Maste 128493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC111, "Aquantia AQtion 5Gbit Network Adapter"), 129493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC112, "Aquantia AQtion 2.5Gbit Network Adapter"), 130493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC111S, "Aquantia AQtion 5Gbit Network Adapter"), 131493d26c5SEd Maste PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC112S, "Aquantia AQtion 2.5Gbit Network Adapter"), 132493d26c5SEd Maste 133493d26c5SEd Maste PVID_END 134493d26c5SEd Maste }; 135493d26c5SEd Maste 136493d26c5SEd Maste 137493d26c5SEd Maste /* Device setup, teardown, etc */ 138493d26c5SEd Maste static void *aq_register(device_t dev); 139493d26c5SEd Maste static int aq_if_attach_pre(if_ctx_t ctx); 140493d26c5SEd Maste static int aq_if_attach_post(if_ctx_t ctx); 141493d26c5SEd Maste static int aq_if_detach(if_ctx_t ctx); 142493d26c5SEd Maste static int aq_if_shutdown(if_ctx_t ctx); 143493d26c5SEd Maste static int aq_if_suspend(if_ctx_t ctx); 144493d26c5SEd Maste static int aq_if_resume(if_ctx_t ctx); 145493d26c5SEd Maste 146493d26c5SEd Maste /* Soft queue setup and teardown */ 147493d26c5SEd Maste static int aq_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, 148493d26c5SEd Maste uint64_t *paddrs, int ntxqs, int ntxqsets); 149493d26c5SEd Maste static int aq_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, 150493d26c5SEd Maste uint64_t *paddrs, int nrxqs, int nrxqsets); 151493d26c5SEd Maste static void aq_if_queues_free(if_ctx_t ctx); 152493d26c5SEd Maste 153493d26c5SEd Maste /* Device configuration */ 154493d26c5SEd Maste static void aq_if_init(if_ctx_t ctx); 155493d26c5SEd Maste static void aq_if_stop(if_ctx_t ctx); 156493d26c5SEd Maste static void aq_if_multi_set(if_ctx_t ctx); 157493d26c5SEd Maste static int aq_if_mtu_set(if_ctx_t ctx, uint32_t mtu); 158493d26c5SEd Maste static void aq_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr); 159493d26c5SEd Maste static int aq_if_media_change(if_ctx_t ctx); 160493d26c5SEd Maste static int aq_if_promisc_set(if_ctx_t ctx, int flags); 161493d26c5SEd Maste static uint64_t aq_if_get_counter(if_ctx_t ctx, ift_counter cnt); 162493d26c5SEd Maste static void aq_if_timer(if_ctx_t ctx, uint16_t qid); 163493d26c5SEd Maste static int aq_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data); 164493d26c5SEd Maste static int aq_hw_capabilities(struct aq_dev *softc); 165493d26c5SEd Maste static void aq_add_stats_sysctls(struct aq_dev *softc); 166493d26c5SEd Maste 167493d26c5SEd Maste /* Interrupt enable / disable */ 168493d26c5SEd Maste static void aq_if_enable_intr(if_ctx_t ctx); 169493d26c5SEd Maste static void aq_if_disable_intr(if_ctx_t ctx); 170493d26c5SEd Maste static int aq_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid); 171493d26c5SEd Maste static int aq_if_msix_intr_assign(if_ctx_t ctx, int msix); 172493d26c5SEd Maste 173493d26c5SEd Maste /* VLAN support */ 174493d26c5SEd Maste static bool aq_is_vlan_promisc_required(struct aq_dev *softc); 175493d26c5SEd Maste static void aq_update_vlan_filters(struct aq_dev *softc); 176493d26c5SEd Maste static void aq_if_vlan_register(if_ctx_t ctx, uint16_t vtag); 177493d26c5SEd Maste static void aq_if_vlan_unregister(if_ctx_t ctx, uint16_t vtag); 178493d26c5SEd Maste 179493d26c5SEd Maste /* Informational/diagnostic */ 180493d26c5SEd Maste static void aq_if_debug(if_ctx_t ctx); 181493d26c5SEd Maste static void aq_if_led_func(if_ctx_t ctx, int onoff); 182493d26c5SEd Maste 183493d26c5SEd Maste static device_method_t aq_methods[] = { 184493d26c5SEd Maste DEVMETHOD(device_register, aq_register), 185493d26c5SEd Maste DEVMETHOD(device_probe, iflib_device_probe), 186493d26c5SEd Maste DEVMETHOD(device_attach, iflib_device_attach), 187493d26c5SEd Maste DEVMETHOD(device_detach, iflib_device_detach), 188493d26c5SEd Maste DEVMETHOD(device_shutdown, iflib_device_shutdown), 189493d26c5SEd Maste DEVMETHOD(device_suspend, iflib_device_suspend), 190493d26c5SEd Maste DEVMETHOD(device_resume, iflib_device_resume), 191493d26c5SEd Maste 192493d26c5SEd Maste DEVMETHOD_END 193493d26c5SEd Maste }; 194493d26c5SEd Maste 195493d26c5SEd Maste static driver_t aq_driver = { 196493d26c5SEd Maste "aq", aq_methods, sizeof(struct aq_dev), 197493d26c5SEd Maste }; 198493d26c5SEd Maste 199*2b587c0cSJohn Baldwin #if __FreeBSD_version >= 1400058 200*2b587c0cSJohn Baldwin DRIVER_MODULE(atlantic, pci, aq_driver, 0, 0); 201*2b587c0cSJohn Baldwin #else 202493d26c5SEd Maste static devclass_t aq_devclass; 203493d26c5SEd Maste DRIVER_MODULE(atlantic, pci, aq_driver, aq_devclass, 0, 0); 204*2b587c0cSJohn Baldwin #endif 205493d26c5SEd Maste 206493d26c5SEd Maste MODULE_DEPEND(atlantic, pci, 1, 1, 1); 207493d26c5SEd Maste MODULE_DEPEND(atlantic, ether, 1, 1, 1); 208493d26c5SEd Maste MODULE_DEPEND(atlantic, iflib, 1, 1, 1); 209493d26c5SEd Maste 210493d26c5SEd Maste IFLIB_PNP_INFO(pci, atlantic, aq_vendor_info_array); 211493d26c5SEd Maste 212493d26c5SEd Maste static device_method_t aq_if_methods[] = { 213493d26c5SEd Maste /* Device setup, teardown, etc */ 214493d26c5SEd Maste DEVMETHOD(ifdi_attach_pre, aq_if_attach_pre), 215493d26c5SEd Maste DEVMETHOD(ifdi_attach_post, aq_if_attach_post), 216493d26c5SEd Maste DEVMETHOD(ifdi_detach, aq_if_detach), 217493d26c5SEd Maste 218493d26c5SEd Maste DEVMETHOD(ifdi_shutdown, aq_if_shutdown), 219493d26c5SEd Maste DEVMETHOD(ifdi_suspend, aq_if_suspend), 220493d26c5SEd Maste DEVMETHOD(ifdi_resume, aq_if_resume), 221493d26c5SEd Maste 222493d26c5SEd Maste /* Soft queue setup and teardown */ 223493d26c5SEd Maste DEVMETHOD(ifdi_tx_queues_alloc, aq_if_tx_queues_alloc), 224493d26c5SEd Maste DEVMETHOD(ifdi_rx_queues_alloc, aq_if_rx_queues_alloc), 225493d26c5SEd Maste DEVMETHOD(ifdi_queues_free, aq_if_queues_free), 226493d26c5SEd Maste 227493d26c5SEd Maste /* Device configuration */ 228493d26c5SEd Maste DEVMETHOD(ifdi_init, aq_if_init), 229493d26c5SEd Maste DEVMETHOD(ifdi_stop, aq_if_stop), 230493d26c5SEd Maste DEVMETHOD(ifdi_multi_set, aq_if_multi_set), 231493d26c5SEd Maste DEVMETHOD(ifdi_mtu_set, aq_if_mtu_set), 232493d26c5SEd Maste DEVMETHOD(ifdi_media_status, aq_if_media_status), 233493d26c5SEd Maste DEVMETHOD(ifdi_media_change, aq_if_media_change), 234493d26c5SEd Maste DEVMETHOD(ifdi_promisc_set, aq_if_promisc_set), 235493d26c5SEd Maste DEVMETHOD(ifdi_get_counter, aq_if_get_counter), 236493d26c5SEd Maste DEVMETHOD(ifdi_update_admin_status, aq_if_update_admin_status), 237493d26c5SEd Maste DEVMETHOD(ifdi_timer, aq_if_timer), 238493d26c5SEd Maste // DEVMETHOD(ifdi_priv_ioctl, aq_if_priv_ioctl), 239493d26c5SEd Maste 240493d26c5SEd Maste /* Interrupt enable / disable */ 241493d26c5SEd Maste DEVMETHOD(ifdi_intr_enable, aq_if_enable_intr), 242493d26c5SEd Maste DEVMETHOD(ifdi_intr_disable, aq_if_disable_intr), 243493d26c5SEd Maste DEVMETHOD(ifdi_rx_queue_intr_enable, aq_if_rx_queue_intr_enable), 244493d26c5SEd Maste DEVMETHOD(ifdi_tx_queue_intr_enable, aq_if_rx_queue_intr_enable), 245493d26c5SEd Maste DEVMETHOD(ifdi_msix_intr_assign, aq_if_msix_intr_assign), 246493d26c5SEd Maste 247493d26c5SEd Maste /* VLAN support */ 248493d26c5SEd Maste DEVMETHOD(ifdi_vlan_register, aq_if_vlan_register), 249493d26c5SEd Maste DEVMETHOD(ifdi_vlan_unregister, aq_if_vlan_unregister), 250493d26c5SEd Maste 251493d26c5SEd Maste /* Informational/diagnostic */ 252493d26c5SEd Maste DEVMETHOD(ifdi_led_func, aq_if_led_func), 253493d26c5SEd Maste // DEVMETHOD(ifdi_debug, aq_if_debug), 254493d26c5SEd Maste 255493d26c5SEd Maste DEVMETHOD_END 256493d26c5SEd Maste }; 257493d26c5SEd Maste 258493d26c5SEd Maste static driver_t aq_if_driver = { 259493d26c5SEd Maste "aq_if", aq_if_methods, sizeof(struct aq_dev) 260493d26c5SEd Maste }; 261493d26c5SEd Maste 262493d26c5SEd Maste static struct if_shared_ctx aq_sctx_init = { 263493d26c5SEd Maste .isc_magic = IFLIB_MAGIC, 264493d26c5SEd Maste .isc_q_align = PAGE_SIZE, 265493d26c5SEd Maste .isc_tx_maxsize = HW_ATL_B0_TSO_SIZE, 266493d26c5SEd Maste .isc_tx_maxsegsize = HW_ATL_B0_MTU_JUMBO, 267493d26c5SEd Maste #if __FreeBSD__ >= 12 268493d26c5SEd Maste .isc_tso_maxsize = HW_ATL_B0_TSO_SIZE, 269493d26c5SEd Maste .isc_tso_maxsegsize = HW_ATL_B0_MTU_JUMBO, 270493d26c5SEd Maste #endif 271493d26c5SEd Maste .isc_rx_maxsize = HW_ATL_B0_MTU_JUMBO, 272493d26c5SEd Maste .isc_rx_nsegments = 16, 273493d26c5SEd Maste .isc_rx_maxsegsize = PAGE_SIZE, 274493d26c5SEd Maste .isc_nfl = 1, 275493d26c5SEd Maste .isc_nrxqs = 1, 276493d26c5SEd Maste .isc_ntxqs = 1, 277493d26c5SEd Maste .isc_admin_intrcnt = 1, 278493d26c5SEd Maste .isc_vendor_info = aq_vendor_info_array, 279493d26c5SEd Maste .isc_driver_version = aq_driver_version, 280493d26c5SEd Maste .isc_driver = &aq_if_driver, 281493d26c5SEd Maste .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP | 282493d26c5SEd Maste IFLIB_NEED_ZERO_CSUM, 283493d26c5SEd Maste 284493d26c5SEd Maste .isc_nrxd_min = {HW_ATL_B0_MIN_RXD}, 285493d26c5SEd Maste .isc_ntxd_min = {HW_ATL_B0_MIN_TXD}, 286493d26c5SEd Maste .isc_nrxd_max = {HW_ATL_B0_MAX_RXD}, 287493d26c5SEd Maste .isc_ntxd_max = {HW_ATL_B0_MAX_TXD}, 288493d26c5SEd Maste .isc_nrxd_default = {PAGE_SIZE / sizeof(aq_txc_desc_t) * 4}, 289493d26c5SEd Maste .isc_ntxd_default = {PAGE_SIZE / sizeof(aq_txc_desc_t) * 4}, 290493d26c5SEd Maste }; 291493d26c5SEd Maste 292493d26c5SEd Maste /* 293493d26c5SEd Maste * TUNEABLE PARAMETERS: 294493d26c5SEd Maste */ 295493d26c5SEd Maste 296493d26c5SEd Maste static SYSCTL_NODE(_hw, OID_AUTO, aq, CTLFLAG_RD, 0, "Atlantic driver parameters"); 297493d26c5SEd Maste /* UDP Receive-Side Scaling */ 298493d26c5SEd Maste static int aq_enable_rss_udp = 1; 299493d26c5SEd Maste SYSCTL_INT(_hw_aq, OID_AUTO, enable_rss_udp, CTLFLAG_RDTUN, &aq_enable_rss_udp, 0, 300493d26c5SEd Maste "Enable Receive-Side Scaling (RSS) for UDP"); 301493d26c5SEd Maste 302493d26c5SEd Maste 303493d26c5SEd Maste /* 304493d26c5SEd Maste * Device Methods 305493d26c5SEd Maste */ 306493d26c5SEd Maste static void *aq_register(device_t dev) 307493d26c5SEd Maste { 308493d26c5SEd Maste return (&aq_sctx_init); 309493d26c5SEd Maste } 310493d26c5SEd Maste 311493d26c5SEd Maste static int aq_if_attach_pre(if_ctx_t ctx) 312493d26c5SEd Maste { 313493d26c5SEd Maste struct aq_dev *softc; 314493d26c5SEd Maste struct aq_hw *hw; 315493d26c5SEd Maste if_softc_ctx_t scctx; 316493d26c5SEd Maste int rc; 317493d26c5SEd Maste 318493d26c5SEd Maste AQ_DBG_ENTER(); 319493d26c5SEd Maste softc = iflib_get_softc(ctx); 320493d26c5SEd Maste rc = 0; 321493d26c5SEd Maste 322493d26c5SEd Maste softc->ctx = ctx; 323493d26c5SEd Maste softc->dev = iflib_get_dev(ctx); 324493d26c5SEd Maste softc->media = iflib_get_media(ctx); 325493d26c5SEd Maste softc->scctx = iflib_get_softc_ctx(ctx); 326493d26c5SEd Maste softc->sctx = iflib_get_sctx(ctx); 327493d26c5SEd Maste scctx = softc->scctx; 328493d26c5SEd Maste 329493d26c5SEd Maste softc->mmio_rid = PCIR_BAR(0); 330493d26c5SEd Maste softc->mmio_res = bus_alloc_resource_any(softc->dev, SYS_RES_MEMORY, 331493d26c5SEd Maste &softc->mmio_rid, RF_ACTIVE|RF_SHAREABLE); 332493d26c5SEd Maste if (softc->mmio_res == NULL) { 333493d26c5SEd Maste device_printf(softc->dev, 334493d26c5SEd Maste "failed to allocate MMIO resources\n"); 335493d26c5SEd Maste rc = ENXIO; 336493d26c5SEd Maste goto fail; 337493d26c5SEd Maste } 338493d26c5SEd Maste 339493d26c5SEd Maste softc->mmio_tag = rman_get_bustag(softc->mmio_res); 340493d26c5SEd Maste softc->mmio_handle = rman_get_bushandle(softc->mmio_res); 341493d26c5SEd Maste softc->mmio_size = rman_get_size(softc->mmio_res); 342493d26c5SEd Maste softc->hw.hw_addr = (u8*) softc->mmio_handle; 343493d26c5SEd Maste hw = &softc->hw; 344493d26c5SEd Maste hw->link_rate = aq_fw_speed_auto; 345493d26c5SEd Maste hw->itr = -1; 346493d26c5SEd Maste hw->fc.fc_rx = 1; 347493d26c5SEd Maste hw->fc.fc_tx = 1; 348493d26c5SEd Maste softc->linkup = 0U; 349493d26c5SEd Maste 350493d26c5SEd Maste /* Look up ops and caps. */ 351493d26c5SEd Maste rc = aq_hw_mpi_create(hw); 352493d26c5SEd Maste if (rc < 0) { 353493d26c5SEd Maste AQ_DBG_ERROR(" %s: aq_hw_mpi_create fail err=%d", __func__, rc); 354493d26c5SEd Maste goto fail; 355493d26c5SEd Maste } 356493d26c5SEd Maste 357493d26c5SEd Maste if (hw->fast_start_enabled) { 358493d26c5SEd Maste if (hw->fw_ops && hw->fw_ops->reset) 359493d26c5SEd Maste hw->fw_ops->reset(hw); 360493d26c5SEd Maste } else 361493d26c5SEd Maste aq_hw_reset(&softc->hw); 362493d26c5SEd Maste aq_hw_capabilities(softc); 363493d26c5SEd Maste 364493d26c5SEd Maste if (aq_hw_get_mac_permanent(hw, hw->mac_addr) < 0) { 365493d26c5SEd Maste AQ_DBG_ERROR("Unable to get mac addr from hw"); 366493d26c5SEd Maste goto fail; 367493d26c5SEd Maste }; 368493d26c5SEd Maste 369493d26c5SEd Maste softc->admin_ticks = 0; 370493d26c5SEd Maste 371493d26c5SEd Maste iflib_set_mac(ctx, hw->mac_addr); 372493d26c5SEd Maste #if __FreeBSD__ < 13 373493d26c5SEd Maste /* since FreeBSD13 deadlock due to calling iflib_led_func() under CTX_LOCK() */ 374493d26c5SEd Maste iflib_led_create(ctx); 375493d26c5SEd Maste #endif 376493d26c5SEd Maste scctx->isc_tx_csum_flags = CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO; 377493d26c5SEd Maste #if __FreeBSD__ >= 12 378493d26c5SEd Maste scctx->isc_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_HWCSUM | IFCAP_TSO | 379493d26c5SEd Maste IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER | 380493d26c5SEd Maste IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | 381493d26c5SEd Maste IFCAP_VLAN_HWCSUM; 382493d26c5SEd Maste scctx->isc_capenable = scctx->isc_capabilities; 383493d26c5SEd Maste #else 384493d26c5SEd Maste if_t ifp; 385493d26c5SEd Maste ifp = iflib_get_ifp(ctx); 3864756f5ffSOlivier Cochard if_setcapenable(ifp, IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_HWCSUM | IFCAP_TSO | 387493d26c5SEd Maste IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER | 388493d26c5SEd Maste IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | 389493d26c5SEd Maste IFCAP_VLAN_HWCSUM; 390493d26c5SEd Maste #endif 391493d26c5SEd Maste scctx->isc_tx_nsegments = 31, 392493d26c5SEd Maste scctx->isc_tx_tso_segments_max = 31; 393493d26c5SEd Maste scctx->isc_tx_tso_size_max = HW_ATL_B0_TSO_SIZE - sizeof(struct ether_vlan_header); 394493d26c5SEd Maste scctx->isc_tx_tso_segsize_max = HW_ATL_B0_MTU_JUMBO; 395493d26c5SEd Maste scctx->isc_min_frame_size = 52; 396493d26c5SEd Maste scctx->isc_txrx = &aq_txrx; 397493d26c5SEd Maste 398493d26c5SEd Maste scctx->isc_txqsizes[0] = sizeof(aq_tx_desc_t) * scctx->isc_ntxd[0]; 399493d26c5SEd Maste scctx->isc_rxqsizes[0] = sizeof(aq_rx_desc_t) * scctx->isc_nrxd[0]; 400493d26c5SEd Maste 401493d26c5SEd Maste scctx->isc_ntxqsets_max = HW_ATL_B0_RINGS_MAX; 402493d26c5SEd Maste scctx->isc_nrxqsets_max = HW_ATL_B0_RINGS_MAX; 403493d26c5SEd Maste 404493d26c5SEd Maste /* iflib will map and release this bar */ 405493d26c5SEd Maste scctx->isc_msix_bar = pci_msix_table_bar(softc->dev); 406493d26c5SEd Maste 407493d26c5SEd Maste softc->vlan_tags = bit_alloc(4096, M_AQ, M_NOWAIT); 408493d26c5SEd Maste 409493d26c5SEd Maste AQ_DBG_EXIT(rc); 410493d26c5SEd Maste return (rc); 411493d26c5SEd Maste 412493d26c5SEd Maste fail: 413493d26c5SEd Maste if (softc->mmio_res != NULL) 414493d26c5SEd Maste bus_release_resource(softc->dev, SYS_RES_MEMORY, 415493d26c5SEd Maste softc->mmio_rid, softc->mmio_res); 416493d26c5SEd Maste 417493d26c5SEd Maste AQ_DBG_EXIT(rc); 418493d26c5SEd Maste return (ENXIO); 419493d26c5SEd Maste } 420493d26c5SEd Maste 421493d26c5SEd Maste 422493d26c5SEd Maste static int aq_if_attach_post(if_ctx_t ctx) 423493d26c5SEd Maste { 424493d26c5SEd Maste struct aq_dev *softc; 425493d26c5SEd Maste int rc; 426493d26c5SEd Maste 427493d26c5SEd Maste AQ_DBG_ENTER(); 428493d26c5SEd Maste 429493d26c5SEd Maste softc = iflib_get_softc(ctx); 430493d26c5SEd Maste rc = 0; 431493d26c5SEd Maste 432493d26c5SEd Maste aq_update_hw_stats(softc); 433493d26c5SEd Maste 434493d26c5SEd Maste aq_initmedia(softc); 435493d26c5SEd Maste 436493d26c5SEd Maste 437493d26c5SEd Maste switch (softc->scctx->isc_intr) { 438493d26c5SEd Maste case IFLIB_INTR_LEGACY: 439493d26c5SEd Maste rc = EOPNOTSUPP; 440493d26c5SEd Maste goto exit; 441493d26c5SEd Maste goto exit; 442493d26c5SEd Maste break; 443493d26c5SEd Maste case IFLIB_INTR_MSI: 444493d26c5SEd Maste break; 445493d26c5SEd Maste case IFLIB_INTR_MSIX: 446493d26c5SEd Maste break; 447493d26c5SEd Maste default: 448493d26c5SEd Maste device_printf(softc->dev, "unknown interrupt mode\n"); 449493d26c5SEd Maste rc = EOPNOTSUPP; 450493d26c5SEd Maste goto exit; 451493d26c5SEd Maste } 452493d26c5SEd Maste 453493d26c5SEd Maste aq_add_stats_sysctls(softc); 454493d26c5SEd Maste /* RSS */ 455493d26c5SEd Maste arc4rand(softc->rss_key, HW_ATL_RSS_HASHKEY_SIZE, 0); 456493d26c5SEd Maste for (int i = ARRAY_SIZE(softc->rss_table); i--;){ 457493d26c5SEd Maste softc->rss_table[i] = i & (softc->rx_rings_count - 1); 458493d26c5SEd Maste } 459493d26c5SEd Maste exit: 460493d26c5SEd Maste AQ_DBG_EXIT(rc); 461493d26c5SEd Maste return (rc); 462493d26c5SEd Maste } 463493d26c5SEd Maste 464493d26c5SEd Maste 465493d26c5SEd Maste static int aq_if_detach(if_ctx_t ctx) 466493d26c5SEd Maste { 467493d26c5SEd Maste struct aq_dev *softc; 468493d26c5SEd Maste int i; 469493d26c5SEd Maste 470493d26c5SEd Maste AQ_DBG_ENTER(); 471493d26c5SEd Maste softc = iflib_get_softc(ctx); 472493d26c5SEd Maste 473493d26c5SEd Maste aq_hw_deinit(&softc->hw); 474493d26c5SEd Maste 475493d26c5SEd Maste for (i = 0; i < softc->scctx->isc_nrxqsets; i++) 476493d26c5SEd Maste iflib_irq_free(ctx, &softc->rx_rings[i]->irq); 477493d26c5SEd Maste iflib_irq_free(ctx, &softc->irq); 478493d26c5SEd Maste 479493d26c5SEd Maste 480493d26c5SEd Maste if (softc->mmio_res != NULL) 481493d26c5SEd Maste bus_release_resource(softc->dev, SYS_RES_MEMORY, 482493d26c5SEd Maste softc->mmio_rid, softc->mmio_res); 483493d26c5SEd Maste 484493d26c5SEd Maste free(softc->vlan_tags, M_AQ); 485493d26c5SEd Maste 486493d26c5SEd Maste AQ_DBG_EXIT(0); 487493d26c5SEd Maste return (0); 488493d26c5SEd Maste } 489493d26c5SEd Maste 490493d26c5SEd Maste static int aq_if_shutdown(if_ctx_t ctx) 491493d26c5SEd Maste { 492493d26c5SEd Maste 493493d26c5SEd Maste AQ_DBG_ENTER(); 494493d26c5SEd Maste 495493d26c5SEd Maste AQ_XXX_UNIMPLEMENTED_FUNCTION; 496493d26c5SEd Maste 497493d26c5SEd Maste AQ_DBG_EXIT(0); 498493d26c5SEd Maste return (0); 499493d26c5SEd Maste } 500493d26c5SEd Maste 501493d26c5SEd Maste static int aq_if_suspend(if_ctx_t ctx) 502493d26c5SEd Maste { 503493d26c5SEd Maste AQ_DBG_ENTER(); 504493d26c5SEd Maste 505493d26c5SEd Maste AQ_XXX_UNIMPLEMENTED_FUNCTION; 506493d26c5SEd Maste 507493d26c5SEd Maste AQ_DBG_EXIT(0); 508493d26c5SEd Maste return (0); 509493d26c5SEd Maste } 510493d26c5SEd Maste 511493d26c5SEd Maste static int aq_if_resume(if_ctx_t ctx) 512493d26c5SEd Maste { 513493d26c5SEd Maste AQ_DBG_ENTER(); 514493d26c5SEd Maste 515493d26c5SEd Maste AQ_XXX_UNIMPLEMENTED_FUNCTION; 516493d26c5SEd Maste 517493d26c5SEd Maste AQ_DBG_EXIT(0); 518493d26c5SEd Maste return (0); 519493d26c5SEd Maste } 520493d26c5SEd Maste 521493d26c5SEd Maste /* Soft queue setup and teardown */ 522493d26c5SEd Maste static int aq_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, 523493d26c5SEd Maste uint64_t *paddrs, int ntxqs, int ntxqsets) 524493d26c5SEd Maste { 525493d26c5SEd Maste struct aq_dev *softc; 526493d26c5SEd Maste struct aq_ring *ring; 527493d26c5SEd Maste int rc = 0, i; 528493d26c5SEd Maste 529493d26c5SEd Maste AQ_DBG_ENTERA("ntxqs=%d, ntxqsets=%d", ntxqs, ntxqsets); 530493d26c5SEd Maste softc = iflib_get_softc(ctx); 531493d26c5SEd Maste AQ_DBG_PRINT("tx descriptors number %d", softc->scctx->isc_ntxd[0]); 532493d26c5SEd Maste 533493d26c5SEd Maste for (i = 0; i < ntxqsets; i++) { 534493d26c5SEd Maste ring = softc->tx_rings[i] = malloc(sizeof(struct aq_ring), 535493d26c5SEd Maste M_AQ, M_NOWAIT | M_ZERO); 536493d26c5SEd Maste if (!ring){ 537493d26c5SEd Maste rc = ENOMEM; 538493d26c5SEd Maste device_printf(softc->dev, "atlantic: tx_ring malloc fail\n"); 539493d26c5SEd Maste goto fail; 540493d26c5SEd Maste } 541493d26c5SEd Maste ring->tx_descs = (aq_tx_desc_t*)vaddrs[i]; 542493d26c5SEd Maste ring->tx_size = softc->scctx->isc_ntxd[0]; 543493d26c5SEd Maste ring->tx_descs_phys = paddrs[i]; 544493d26c5SEd Maste ring->tx_head = ring->tx_tail = 0; 545493d26c5SEd Maste ring->index = i; 546493d26c5SEd Maste ring->dev = softc; 547493d26c5SEd Maste 548493d26c5SEd Maste softc->tx_rings_count++; 549493d26c5SEd Maste } 550493d26c5SEd Maste 551493d26c5SEd Maste AQ_DBG_EXIT(rc); 552493d26c5SEd Maste return (rc); 553493d26c5SEd Maste 554493d26c5SEd Maste fail: 555493d26c5SEd Maste aq_if_queues_free(ctx); 556493d26c5SEd Maste AQ_DBG_EXIT(rc); 557493d26c5SEd Maste return (rc); 558493d26c5SEd Maste } 559493d26c5SEd Maste 560493d26c5SEd Maste static int aq_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, 561493d26c5SEd Maste uint64_t *paddrs, int nrxqs, int nrxqsets) 562493d26c5SEd Maste { 563493d26c5SEd Maste struct aq_dev *softc; 564493d26c5SEd Maste struct aq_ring *ring; 565493d26c5SEd Maste int rc = 0, i; 566493d26c5SEd Maste 567493d26c5SEd Maste AQ_DBG_ENTERA("nrxqs=%d, nrxqsets=%d", nrxqs, nrxqsets); 568493d26c5SEd Maste softc = iflib_get_softc(ctx); 569493d26c5SEd Maste 570493d26c5SEd Maste for (i = 0; i < nrxqsets; i++) { 571493d26c5SEd Maste ring = softc->rx_rings[i] = malloc(sizeof(struct aq_ring), 572493d26c5SEd Maste M_AQ, M_NOWAIT | M_ZERO); 573493d26c5SEd Maste if (!ring){ 574493d26c5SEd Maste rc = ENOMEM; 575493d26c5SEd Maste device_printf(softc->dev, "atlantic: rx_ring malloc fail\n"); 576493d26c5SEd Maste goto fail; 577493d26c5SEd Maste } 578493d26c5SEd Maste 579493d26c5SEd Maste ring->rx_descs = (aq_rx_desc_t*)vaddrs[i]; 580493d26c5SEd Maste ring->rx_descs_phys = paddrs[i]; 581493d26c5SEd Maste ring->rx_size = softc->scctx->isc_nrxd[0]; 582493d26c5SEd Maste ring->index = i; 583493d26c5SEd Maste ring->dev = softc; 584493d26c5SEd Maste 585493d26c5SEd Maste switch (MCLBYTES) { 586493d26c5SEd Maste case (4 * 1024): 587493d26c5SEd Maste case (8 * 1024): 588493d26c5SEd Maste case (16 * 1024): 589493d26c5SEd Maste ring->rx_max_frame_size = MCLBYTES; 590493d26c5SEd Maste break; 591493d26c5SEd Maste default: 592493d26c5SEd Maste ring->rx_max_frame_size = 2048; 593493d26c5SEd Maste break; 594493d26c5SEd Maste } 595493d26c5SEd Maste 596493d26c5SEd Maste softc->rx_rings_count++; 597493d26c5SEd Maste } 598493d26c5SEd Maste 599493d26c5SEd Maste AQ_DBG_EXIT(rc); 600493d26c5SEd Maste return (rc); 601493d26c5SEd Maste 602493d26c5SEd Maste fail: 603493d26c5SEd Maste aq_if_queues_free(ctx); 604493d26c5SEd Maste AQ_DBG_EXIT(rc); 605493d26c5SEd Maste return (rc); 606493d26c5SEd Maste } 607493d26c5SEd Maste 608493d26c5SEd Maste static void aq_if_queues_free(if_ctx_t ctx) 609493d26c5SEd Maste { 610493d26c5SEd Maste struct aq_dev *softc; 611493d26c5SEd Maste int i; 612493d26c5SEd Maste 613493d26c5SEd Maste AQ_DBG_ENTER(); 614493d26c5SEd Maste softc = iflib_get_softc(ctx); 615493d26c5SEd Maste 616493d26c5SEd Maste for (i = 0; i < softc->tx_rings_count; i++) { 617493d26c5SEd Maste if (softc->tx_rings[i]) { 618493d26c5SEd Maste free(softc->tx_rings[i], M_AQ); 619493d26c5SEd Maste softc->tx_rings[i] = NULL; 620493d26c5SEd Maste } 621493d26c5SEd Maste } 622493d26c5SEd Maste softc->tx_rings_count = 0; 623493d26c5SEd Maste for (i = 0; i < softc->rx_rings_count; i++) { 624493d26c5SEd Maste if (softc->rx_rings[i]){ 625493d26c5SEd Maste free(softc->rx_rings[i], M_AQ); 626493d26c5SEd Maste softc->rx_rings[i] = NULL; 627493d26c5SEd Maste } 628493d26c5SEd Maste } 629493d26c5SEd Maste softc->rx_rings_count = 0; 630493d26c5SEd Maste 631493d26c5SEd Maste AQ_DBG_EXIT(0); 632493d26c5SEd Maste return; 633493d26c5SEd Maste } 634493d26c5SEd Maste 635493d26c5SEd Maste /* Device configuration */ 636493d26c5SEd Maste static void aq_if_init(if_ctx_t ctx) 637493d26c5SEd Maste { 638493d26c5SEd Maste struct aq_dev *softc; 639493d26c5SEd Maste struct aq_hw *hw; 640493d26c5SEd Maste struct ifmediareq ifmr; 641493d26c5SEd Maste int i, err; 642493d26c5SEd Maste 643493d26c5SEd Maste AQ_DBG_ENTER(); 644493d26c5SEd Maste softc = iflib_get_softc(ctx); 645493d26c5SEd Maste hw = &softc->hw; 646493d26c5SEd Maste 647493d26c5SEd Maste err = aq_hw_init(&softc->hw, softc->hw.mac_addr, softc->msix, 648493d26c5SEd Maste softc->scctx->isc_intr == IFLIB_INTR_MSIX); 649493d26c5SEd Maste if (err != EOK) { 650493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_hw_init: %d", err); 651493d26c5SEd Maste } 652493d26c5SEd Maste 653493d26c5SEd Maste aq_if_media_status(ctx, &ifmr); 654493d26c5SEd Maste 655493d26c5SEd Maste aq_update_vlan_filters(softc); 656493d26c5SEd Maste 657493d26c5SEd Maste for (i = 0; i < softc->tx_rings_count; i++) { 658493d26c5SEd Maste struct aq_ring *ring = softc->tx_rings[i]; 659493d26c5SEd Maste err = aq_ring_tx_init(&softc->hw, ring); 660493d26c5SEd Maste if (err) { 661493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_ring_tx_init: %d", err); 662493d26c5SEd Maste } 663493d26c5SEd Maste err = aq_ring_tx_start(hw, ring); 664493d26c5SEd Maste if (err != EOK) { 665493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_ring_tx_start: %d", err); 666493d26c5SEd Maste } 667493d26c5SEd Maste } 668493d26c5SEd Maste for (i = 0; i < softc->rx_rings_count; i++) { 669493d26c5SEd Maste struct aq_ring *ring = softc->rx_rings[i]; 670493d26c5SEd Maste err = aq_ring_rx_init(&softc->hw, ring); 671493d26c5SEd Maste if (err) { 672493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_ring_rx_init: %d", err); 673493d26c5SEd Maste } 674493d26c5SEd Maste err = aq_ring_rx_start(hw, ring); 675493d26c5SEd Maste if (err != EOK) { 676493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_ring_rx_start: %d", err); 677493d26c5SEd Maste } 678493d26c5SEd Maste aq_if_rx_queue_intr_enable(ctx, i); 679493d26c5SEd Maste } 680493d26c5SEd Maste 681493d26c5SEd Maste aq_hw_start(hw); 682493d26c5SEd Maste aq_if_enable_intr(ctx); 683493d26c5SEd Maste aq_hw_rss_hash_set(&softc->hw, softc->rss_key); 684493d26c5SEd Maste aq_hw_rss_set(&softc->hw, softc->rss_table); 685493d26c5SEd Maste aq_hw_udp_rss_enable(hw, aq_enable_rss_udp); 686493d26c5SEd Maste aq_hw_set_link_speed(hw, hw->link_rate); 687493d26c5SEd Maste 688493d26c5SEd Maste AQ_DBG_EXIT(0); 689493d26c5SEd Maste } 690493d26c5SEd Maste 691493d26c5SEd Maste 692493d26c5SEd Maste static void aq_if_stop(if_ctx_t ctx) 693493d26c5SEd Maste { 694493d26c5SEd Maste struct aq_dev *softc; 695493d26c5SEd Maste struct aq_hw *hw; 696493d26c5SEd Maste int i; 697493d26c5SEd Maste 698493d26c5SEd Maste AQ_DBG_ENTER(); 699493d26c5SEd Maste 700493d26c5SEd Maste softc = iflib_get_softc(ctx); 701493d26c5SEd Maste hw = &softc->hw; 702493d26c5SEd Maste 703493d26c5SEd Maste /* disable interrupt */ 704493d26c5SEd Maste aq_if_disable_intr(ctx); 705493d26c5SEd Maste 706493d26c5SEd Maste for (i = 0; i < softc->tx_rings_count; i++) { 707493d26c5SEd Maste aq_ring_tx_stop(hw, softc->tx_rings[i]); 708493d26c5SEd Maste softc->tx_rings[i]->tx_head = 0; 709493d26c5SEd Maste softc->tx_rings[i]->tx_tail = 0; 710493d26c5SEd Maste } 711493d26c5SEd Maste for (i = 0; i < softc->rx_rings_count; i++) { 712493d26c5SEd Maste aq_ring_rx_stop(hw, softc->rx_rings[i]); 713493d26c5SEd Maste } 714493d26c5SEd Maste 715493d26c5SEd Maste aq_hw_reset(&softc->hw); 716493d26c5SEd Maste memset(&softc->last_stats, 0, sizeof(softc->last_stats)); 717493d26c5SEd Maste softc->linkup = false; 718493d26c5SEd Maste aq_if_update_admin_status(ctx); 719493d26c5SEd Maste AQ_DBG_EXIT(0); 720493d26c5SEd Maste } 721493d26c5SEd Maste 722493d26c5SEd Maste static uint64_t aq_if_get_counter(if_ctx_t ctx, ift_counter cnt) 723493d26c5SEd Maste { 724493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 7254756f5ffSOlivier Cochard if_t ifp = iflib_get_ifp(ctx); 726493d26c5SEd Maste 727493d26c5SEd Maste switch (cnt) { 728493d26c5SEd Maste case IFCOUNTER_IERRORS: 729493d26c5SEd Maste return (softc->curr_stats.erpr); 730493d26c5SEd Maste case IFCOUNTER_IQDROPS: 731493d26c5SEd Maste return (softc->curr_stats.dpc); 732493d26c5SEd Maste case IFCOUNTER_OERRORS: 733493d26c5SEd Maste return (softc->curr_stats.erpt); 734493d26c5SEd Maste default: 735493d26c5SEd Maste return (if_get_counter_default(ifp, cnt)); 736493d26c5SEd Maste } 737493d26c5SEd Maste } 738493d26c5SEd Maste 739493d26c5SEd Maste #if __FreeBSD_version >= 1300054 740493d26c5SEd Maste static u_int aq_mc_filter_apply(void *arg, struct sockaddr_dl *dl, u_int count) 741493d26c5SEd Maste { 742493d26c5SEd Maste struct aq_dev *softc = arg; 743493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 744493d26c5SEd Maste u8 *mac_addr = NULL; 745493d26c5SEd Maste 746493d26c5SEd Maste if (count == AQ_HW_MAC_MAX) 747493d26c5SEd Maste return (0); 748493d26c5SEd Maste 749493d26c5SEd Maste mac_addr = LLADDR(dl); 750493d26c5SEd Maste aq_hw_mac_addr_set(hw, mac_addr, count + 1); 751493d26c5SEd Maste 752493d26c5SEd Maste aq_log_detail("set %d mc address %6D", count + 1, mac_addr, ":"); 753493d26c5SEd Maste return (1); 754493d26c5SEd Maste } 755493d26c5SEd Maste #else 756493d26c5SEd Maste static int aq_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count) 757493d26c5SEd Maste { 758493d26c5SEd Maste struct aq_dev *softc = arg; 759493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 760493d26c5SEd Maste u8 *mac_addr = NULL; 761493d26c5SEd Maste 762493d26c5SEd Maste if (ifma->ifma_addr->sa_family != AF_LINK) 763493d26c5SEd Maste return (0); 764493d26c5SEd Maste if (count == AQ_HW_MAC_MAX) 765493d26c5SEd Maste return (0); 766493d26c5SEd Maste 767493d26c5SEd Maste mac_addr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 768493d26c5SEd Maste aq_hw_mac_addr_set(hw, mac_addr, count + 1); 769493d26c5SEd Maste 770493d26c5SEd Maste aq_log_detail("set %d mc address %6D", count + 1, mac_addr, ":"); 771493d26c5SEd Maste return (1); 772493d26c5SEd Maste } 773493d26c5SEd Maste #endif 774493d26c5SEd Maste 775493d26c5SEd Maste static bool aq_is_mc_promisc_required(struct aq_dev *softc) 776493d26c5SEd Maste { 777493d26c5SEd Maste return (softc->mcnt >= AQ_HW_MAC_MAX); 778493d26c5SEd Maste } 779493d26c5SEd Maste 780493d26c5SEd Maste static void aq_if_multi_set(if_ctx_t ctx) 781493d26c5SEd Maste { 782493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 7834756f5ffSOlivier Cochard if_t ifp = iflib_get_ifp(ctx); 784493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 785493d26c5SEd Maste AQ_DBG_ENTER(); 786493d26c5SEd Maste #if __FreeBSD_version >= 1300054 787493d26c5SEd Maste softc->mcnt = if_llmaddr_count(iflib_get_ifp(ctx)); 788493d26c5SEd Maste #else 789493d26c5SEd Maste softc->mcnt = if_multiaddr_count(iflib_get_ifp(ctx), AQ_HW_MAC_MAX); 790493d26c5SEd Maste #endif 791493d26c5SEd Maste if (softc->mcnt >= AQ_HW_MAC_MAX) 792493d26c5SEd Maste { 7934756f5ffSOlivier Cochard aq_hw_set_promisc(hw, !!(if_getflags(ifp) & IFF_PROMISC), 794493d26c5SEd Maste aq_is_vlan_promisc_required(softc), 7954756f5ffSOlivier Cochard !!(if_getflags(ifp) & IFF_ALLMULTI) || aq_is_mc_promisc_required(softc)); 796493d26c5SEd Maste }else{ 797493d26c5SEd Maste #if __FreeBSD_version >= 1300054 798493d26c5SEd Maste if_foreach_llmaddr(iflib_get_ifp(ctx), &aq_mc_filter_apply, softc); 799493d26c5SEd Maste #else 800493d26c5SEd Maste if_multi_apply(iflib_get_ifp(ctx), aq_mc_filter_apply, softc); 801493d26c5SEd Maste #endif 802493d26c5SEd Maste } 803493d26c5SEd Maste AQ_DBG_EXIT(0); 804493d26c5SEd Maste } 805493d26c5SEd Maste 806493d26c5SEd Maste static int aq_if_mtu_set(if_ctx_t ctx, uint32_t mtu) 807493d26c5SEd Maste { 808493d26c5SEd Maste int err = 0; 809493d26c5SEd Maste AQ_DBG_ENTER(); 810493d26c5SEd Maste 811493d26c5SEd Maste AQ_DBG_EXIT(err); 812493d26c5SEd Maste return (err); 813493d26c5SEd Maste } 814493d26c5SEd Maste 815493d26c5SEd Maste static void aq_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr) 816493d26c5SEd Maste { 8174756f5ffSOlivier Cochard if_t ifp; 818493d26c5SEd Maste 819493d26c5SEd Maste AQ_DBG_ENTER(); 820493d26c5SEd Maste 821493d26c5SEd Maste ifp = iflib_get_ifp(ctx); 822493d26c5SEd Maste 823493d26c5SEd Maste aq_mediastatus(ifp, ifmr); 824493d26c5SEd Maste 825493d26c5SEd Maste AQ_DBG_EXIT(0); 826493d26c5SEd Maste } 827493d26c5SEd Maste 828493d26c5SEd Maste static int aq_if_media_change(if_ctx_t ctx) 829493d26c5SEd Maste { 830493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 8314756f5ffSOlivier Cochard if_t ifp = iflib_get_ifp(ctx); 832493d26c5SEd Maste int rc = 0; 833493d26c5SEd Maste 834493d26c5SEd Maste AQ_DBG_ENTER(); 835493d26c5SEd Maste 836493d26c5SEd Maste /* Not allowd in UP state, since causes unsync of rings */ 8374756f5ffSOlivier Cochard if ((if_getflags(ifp) & IFF_UP)){ 838493d26c5SEd Maste rc = EPERM; 839493d26c5SEd Maste goto exit; 840493d26c5SEd Maste } 841493d26c5SEd Maste 842493d26c5SEd Maste ifp = iflib_get_ifp(softc->ctx); 843493d26c5SEd Maste 844493d26c5SEd Maste rc = aq_mediachange(ifp); 845493d26c5SEd Maste 846493d26c5SEd Maste exit: 847493d26c5SEd Maste AQ_DBG_EXIT(rc); 848493d26c5SEd Maste return (rc); 849493d26c5SEd Maste } 850493d26c5SEd Maste 851493d26c5SEd Maste static int aq_if_promisc_set(if_ctx_t ctx, int flags) 852493d26c5SEd Maste { 853493d26c5SEd Maste struct aq_dev *softc; 854493d26c5SEd Maste 855493d26c5SEd Maste AQ_DBG_ENTER(); 856493d26c5SEd Maste 857493d26c5SEd Maste softc = iflib_get_softc(ctx); 858493d26c5SEd Maste 859493d26c5SEd Maste aq_hw_set_promisc(&softc->hw, !!(flags & IFF_PROMISC), 860493d26c5SEd Maste aq_is_vlan_promisc_required(softc), 861493d26c5SEd Maste !!(flags & IFF_ALLMULTI) || aq_is_mc_promisc_required(softc)); 862493d26c5SEd Maste 863493d26c5SEd Maste AQ_DBG_EXIT(0); 864493d26c5SEd Maste return (0); 865493d26c5SEd Maste } 866493d26c5SEd Maste 867493d26c5SEd Maste static void aq_if_timer(if_ctx_t ctx, uint16_t qid) 868493d26c5SEd Maste { 869493d26c5SEd Maste struct aq_dev *softc; 870493d26c5SEd Maste uint64_t ticks_now; 871493d26c5SEd Maste 872493d26c5SEd Maste // AQ_DBG_ENTER(); 873493d26c5SEd Maste 874493d26c5SEd Maste softc = iflib_get_softc(ctx); 875493d26c5SEd Maste ticks_now = ticks; 876493d26c5SEd Maste 877493d26c5SEd Maste /* Schedule aqc_if_update_admin_status() once per sec */ 878493d26c5SEd Maste if (ticks_now - softc->admin_ticks >= hz) { 879493d26c5SEd Maste softc->admin_ticks = ticks_now; 880493d26c5SEd Maste iflib_admin_intr_deferred(ctx); 881493d26c5SEd Maste } 882493d26c5SEd Maste 883493d26c5SEd Maste // AQ_DBG_EXIT(0); 884493d26c5SEd Maste return; 885493d26c5SEd Maste 886493d26c5SEd Maste } 887493d26c5SEd Maste 888493d26c5SEd Maste /* Interrupt enable / disable */ 889493d26c5SEd Maste static void aq_if_enable_intr(if_ctx_t ctx) 890493d26c5SEd Maste { 891493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 892493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 893493d26c5SEd Maste 894493d26c5SEd Maste AQ_DBG_ENTER(); 895493d26c5SEd Maste 896493d26c5SEd Maste /* Enable interrupts */ 897493d26c5SEd Maste itr_irq_msk_setlsw_set(hw, BIT(softc->msix + 1) - 1); 898493d26c5SEd Maste 899493d26c5SEd Maste AQ_DBG_EXIT(0); 900493d26c5SEd Maste } 901493d26c5SEd Maste 902493d26c5SEd Maste static void aq_if_disable_intr(if_ctx_t ctx) 903493d26c5SEd Maste { 904493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 905493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 906493d26c5SEd Maste 907493d26c5SEd Maste AQ_DBG_ENTER(); 908493d26c5SEd Maste 909493d26c5SEd Maste /* Disable interrupts */ 910493d26c5SEd Maste itr_irq_msk_clearlsw_set(hw, BIT(softc->msix + 1) - 1); 911493d26c5SEd Maste 912493d26c5SEd Maste AQ_DBG_EXIT(0); 913493d26c5SEd Maste } 914493d26c5SEd Maste 915493d26c5SEd Maste static int aq_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid) 916493d26c5SEd Maste { 917493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 918493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 919493d26c5SEd Maste 920493d26c5SEd Maste AQ_DBG_ENTER(); 921493d26c5SEd Maste 922493d26c5SEd Maste itr_irq_msk_setlsw_set(hw, BIT(softc->rx_rings[rxqid]->msix)); 923493d26c5SEd Maste 924493d26c5SEd Maste AQ_DBG_EXIT(0); 925493d26c5SEd Maste return (0); 926493d26c5SEd Maste } 927493d26c5SEd Maste 928493d26c5SEd Maste static int aq_if_msix_intr_assign(if_ctx_t ctx, int msix) 929493d26c5SEd Maste { 930493d26c5SEd Maste struct aq_dev *softc; 931493d26c5SEd Maste int i, vector = 0, rc; 932493d26c5SEd Maste char irq_name[16]; 933493d26c5SEd Maste int rx_vectors; 934493d26c5SEd Maste 935493d26c5SEd Maste AQ_DBG_ENTER(); 936493d26c5SEd Maste softc = iflib_get_softc(ctx); 937493d26c5SEd Maste 938493d26c5SEd Maste for (i = 0; i < softc->rx_rings_count; i++, vector++) { 939493d26c5SEd Maste snprintf(irq_name, sizeof(irq_name), "rxq%d", i); 940493d26c5SEd Maste rc = iflib_irq_alloc_generic(ctx, &softc->rx_rings[i]->irq, 941493d26c5SEd Maste vector + 1, IFLIB_INTR_RX, aq_isr_rx, softc->rx_rings[i], 942493d26c5SEd Maste softc->rx_rings[i]->index, irq_name); 943493d26c5SEd Maste device_printf(softc->dev, "Assign IRQ %u to rx ring %u\n", 944493d26c5SEd Maste vector, softc->rx_rings[i]->index); 945493d26c5SEd Maste 946493d26c5SEd Maste if (rc) { 947493d26c5SEd Maste device_printf(softc->dev, "failed to set up RX handler\n"); 948493d26c5SEd Maste i--; 949493d26c5SEd Maste goto fail; 950493d26c5SEd Maste } 951493d26c5SEd Maste 952493d26c5SEd Maste softc->rx_rings[i]->msix = vector; 953493d26c5SEd Maste } 954493d26c5SEd Maste 955493d26c5SEd Maste rx_vectors = vector; 956493d26c5SEd Maste 957493d26c5SEd Maste for (i = 0; i < softc->tx_rings_count; i++, vector++) { 958493d26c5SEd Maste snprintf(irq_name, sizeof(irq_name), "txq%d", i); 959493d26c5SEd Maste iflib_softirq_alloc_generic(ctx, &softc->rx_rings[i]->irq, IFLIB_INTR_TX, 960493d26c5SEd Maste softc->tx_rings[i], i, irq_name); 961493d26c5SEd Maste 962493d26c5SEd Maste softc->tx_rings[i]->msix = (vector % softc->rx_rings_count); 963493d26c5SEd Maste device_printf(softc->dev, "Assign IRQ %u to tx ring %u\n", 964493d26c5SEd Maste softc->tx_rings[i]->msix, softc->tx_rings[i]->index); 965493d26c5SEd Maste } 966493d26c5SEd Maste 967493d26c5SEd Maste rc = iflib_irq_alloc_generic(ctx, &softc->irq, rx_vectors + 1, 968493d26c5SEd Maste IFLIB_INTR_ADMIN, aq_linkstat_isr, 969493d26c5SEd Maste softc, 0, "aq"); 970493d26c5SEd Maste softc->msix = rx_vectors; 971493d26c5SEd Maste device_printf(softc->dev, "Assign IRQ %u to admin proc \n", 972493d26c5SEd Maste rx_vectors); 973493d26c5SEd Maste if (rc) { 974493d26c5SEd Maste device_printf(iflib_get_dev(ctx), "Failed to register admin handler"); 975493d26c5SEd Maste i = softc->rx_rings_count; 976493d26c5SEd Maste goto fail; 977493d26c5SEd Maste } 978493d26c5SEd Maste AQ_DBG_EXIT(0); 979493d26c5SEd Maste return (0); 980493d26c5SEd Maste 981493d26c5SEd Maste fail: 982493d26c5SEd Maste for (; i >= 0; i--) 983493d26c5SEd Maste iflib_irq_free(ctx, &softc->rx_rings[i]->irq); 984493d26c5SEd Maste AQ_DBG_EXIT(rc); 985493d26c5SEd Maste return (rc); 986493d26c5SEd Maste } 987493d26c5SEd Maste 988493d26c5SEd Maste static bool aq_is_vlan_promisc_required(struct aq_dev *softc) 989493d26c5SEd Maste { 990493d26c5SEd Maste int vlan_tag_count; 991493d26c5SEd Maste 992493d26c5SEd Maste bit_count(softc->vlan_tags, 0, 4096, &vlan_tag_count); 993493d26c5SEd Maste 994493d26c5SEd Maste if (vlan_tag_count <= AQ_HW_VLAN_MAX_FILTERS) 995493d26c5SEd Maste return (false); 996493d26c5SEd Maste else 997493d26c5SEd Maste return (true); 998493d26c5SEd Maste 999493d26c5SEd Maste } 1000493d26c5SEd Maste 1001493d26c5SEd Maste static void aq_update_vlan_filters(struct aq_dev *softc) 1002493d26c5SEd Maste { 1003493d26c5SEd Maste struct aq_rx_filter_vlan aq_vlans[AQ_HW_VLAN_MAX_FILTERS]; 1004493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 1005493d26c5SEd Maste int bit_pos = 0; 1006493d26c5SEd Maste int vlan_tag = -1; 1007493d26c5SEd Maste int i; 1008493d26c5SEd Maste 1009493d26c5SEd Maste hw_atl_b0_hw_vlan_promisc_set(hw, true); 1010493d26c5SEd Maste for (i = 0; i < AQ_HW_VLAN_MAX_FILTERS; i++) { 1011493d26c5SEd Maste bit_ffs_at(softc->vlan_tags, bit_pos, 4096, &vlan_tag); 1012493d26c5SEd Maste if (vlan_tag != -1) { 1013493d26c5SEd Maste aq_vlans[i].enable = true; 1014493d26c5SEd Maste aq_vlans[i].location = i; 1015493d26c5SEd Maste aq_vlans[i].queue = 0xFF; 1016493d26c5SEd Maste aq_vlans[i].vlan_id = vlan_tag; 1017493d26c5SEd Maste bit_pos = vlan_tag; 1018493d26c5SEd Maste } else { 1019493d26c5SEd Maste aq_vlans[i].enable = false; 1020493d26c5SEd Maste } 1021493d26c5SEd Maste } 1022493d26c5SEd Maste 1023493d26c5SEd Maste hw_atl_b0_hw_vlan_set(hw, aq_vlans); 1024493d26c5SEd Maste hw_atl_b0_hw_vlan_promisc_set(hw, aq_is_vlan_promisc_required(softc)); 1025493d26c5SEd Maste } 1026493d26c5SEd Maste 1027493d26c5SEd Maste /* VLAN support */ 1028493d26c5SEd Maste static void aq_if_vlan_register(if_ctx_t ctx, uint16_t vtag) 1029493d26c5SEd Maste { 1030493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 1031493d26c5SEd Maste 1032493d26c5SEd Maste AQ_DBG_ENTERA("%d", vtag); 1033493d26c5SEd Maste 1034493d26c5SEd Maste bit_set(softc->vlan_tags, vtag); 1035493d26c5SEd Maste 1036493d26c5SEd Maste aq_update_vlan_filters(softc); 1037493d26c5SEd Maste 1038493d26c5SEd Maste AQ_DBG_EXIT(0); 1039493d26c5SEd Maste } 1040493d26c5SEd Maste 1041493d26c5SEd Maste static void aq_if_vlan_unregister(if_ctx_t ctx, uint16_t vtag) 1042493d26c5SEd Maste { 1043493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 1044493d26c5SEd Maste 1045493d26c5SEd Maste AQ_DBG_ENTERA("%d", vtag); 1046493d26c5SEd Maste 1047493d26c5SEd Maste bit_clear(softc->vlan_tags, vtag); 1048493d26c5SEd Maste 1049493d26c5SEd Maste aq_update_vlan_filters(softc); 1050493d26c5SEd Maste 1051493d26c5SEd Maste AQ_DBG_EXIT(0); 1052493d26c5SEd Maste } 1053493d26c5SEd Maste 1054493d26c5SEd Maste static void aq_if_led_func(if_ctx_t ctx, int onoff) 1055493d26c5SEd Maste { 1056493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 1057493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 1058493d26c5SEd Maste 1059493d26c5SEd Maste AQ_DBG_ENTERA("%d", onoff); 1060493d26c5SEd Maste if (hw->fw_ops && hw->fw_ops->led_control) 1061493d26c5SEd Maste hw->fw_ops->led_control(hw, onoff); 1062493d26c5SEd Maste 1063493d26c5SEd Maste AQ_DBG_EXIT(0); 1064493d26c5SEd Maste } 1065493d26c5SEd Maste 1066493d26c5SEd Maste static int aq_hw_capabilities(struct aq_dev *softc) 1067493d26c5SEd Maste { 1068493d26c5SEd Maste 1069493d26c5SEd Maste if (pci_get_vendor(softc->dev) != AQUANTIA_VENDOR_ID) 1070493d26c5SEd Maste return (ENXIO); 1071493d26c5SEd Maste 1072493d26c5SEd Maste switch (pci_get_device(softc->dev)) { 1073493d26c5SEd Maste case AQ_DEVICE_ID_D100: 1074493d26c5SEd Maste case AQ_DEVICE_ID_AQC100: 1075493d26c5SEd Maste case AQ_DEVICE_ID_AQC100S: 1076493d26c5SEd Maste softc->media_type = AQ_MEDIA_TYPE_FIBRE; 1077493d26c5SEd Maste softc->link_speeds = AQ_LINK_ALL & ~AQ_LINK_10G; 1078493d26c5SEd Maste break; 1079493d26c5SEd Maste 1080493d26c5SEd Maste case AQ_DEVICE_ID_0001: 1081493d26c5SEd Maste case AQ_DEVICE_ID_D107: 1082493d26c5SEd Maste case AQ_DEVICE_ID_AQC107: 1083493d26c5SEd Maste case AQ_DEVICE_ID_AQC107S: 1084493d26c5SEd Maste softc->media_type = AQ_MEDIA_TYPE_TP; 1085493d26c5SEd Maste softc->link_speeds = AQ_LINK_ALL; 1086493d26c5SEd Maste break; 1087493d26c5SEd Maste 1088493d26c5SEd Maste case AQ_DEVICE_ID_D108: 1089493d26c5SEd Maste case AQ_DEVICE_ID_AQC108: 1090493d26c5SEd Maste case AQ_DEVICE_ID_AQC108S: 1091493d26c5SEd Maste case AQ_DEVICE_ID_AQC111: 1092493d26c5SEd Maste case AQ_DEVICE_ID_AQC111S: 1093493d26c5SEd Maste softc->media_type = AQ_MEDIA_TYPE_TP; 1094493d26c5SEd Maste softc->link_speeds = AQ_LINK_ALL & ~AQ_LINK_10G; 1095493d26c5SEd Maste break; 1096493d26c5SEd Maste 1097493d26c5SEd Maste case AQ_DEVICE_ID_D109: 1098493d26c5SEd Maste case AQ_DEVICE_ID_AQC109: 1099493d26c5SEd Maste case AQ_DEVICE_ID_AQC109S: 1100493d26c5SEd Maste case AQ_DEVICE_ID_AQC112: 1101493d26c5SEd Maste case AQ_DEVICE_ID_AQC112S: 1102493d26c5SEd Maste softc->media_type = AQ_MEDIA_TYPE_TP; 1103493d26c5SEd Maste softc->link_speeds = AQ_LINK_ALL & ~(AQ_LINK_10G | AQ_LINK_5G); 1104493d26c5SEd Maste break; 1105493d26c5SEd Maste 1106493d26c5SEd Maste default: 1107493d26c5SEd Maste return (ENXIO); 1108493d26c5SEd Maste } 1109493d26c5SEd Maste 1110493d26c5SEd Maste return (0); 1111493d26c5SEd Maste } 1112493d26c5SEd Maste 1113493d26c5SEd Maste static int aq_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS) 1114493d26c5SEd Maste { 1115493d26c5SEd Maste struct aq_dev *softc = (struct aq_dev *)arg1; 1116493d26c5SEd Maste device_t dev = softc->dev; 1117493d26c5SEd Maste struct sbuf *buf; 1118493d26c5SEd Maste int error = 0; 1119493d26c5SEd Maste 1120493d26c5SEd Maste buf = sbuf_new_for_sysctl(NULL, NULL, 256, req); 1121493d26c5SEd Maste if (!buf) { 1122493d26c5SEd Maste device_printf(dev, "Could not allocate sbuf for output.\n"); 1123493d26c5SEd Maste return (ENOMEM); 1124493d26c5SEd Maste } 1125493d26c5SEd Maste 1126493d26c5SEd Maste /* Print out the redirection table */ 1127493d26c5SEd Maste sbuf_cat(buf, "\nRSS Indirection table:\n"); 1128493d26c5SEd Maste for (int i = 0; i < HW_ATL_RSS_INDIRECTION_TABLE_MAX; i++) { 1129493d26c5SEd Maste sbuf_printf(buf, "%d ", softc->rss_table[i]); 1130493d26c5SEd Maste if ((i+1) % 10 == 0) 1131493d26c5SEd Maste sbuf_printf(buf, "\n"); 1132493d26c5SEd Maste } 1133493d26c5SEd Maste 1134493d26c5SEd Maste sbuf_cat(buf, "\nRSS Key:\n"); 1135493d26c5SEd Maste for (int i = 0; i < HW_ATL_RSS_HASHKEY_SIZE; i++) { 1136493d26c5SEd Maste sbuf_printf(buf, "0x%02x ", softc->rss_key[i]); 1137493d26c5SEd Maste } 1138493d26c5SEd Maste sbuf_printf(buf, "\n"); 1139493d26c5SEd Maste 1140493d26c5SEd Maste error = sbuf_finish(buf); 1141493d26c5SEd Maste if (error) 1142493d26c5SEd Maste device_printf(dev, "Error finishing sbuf: %d\n", error); 1143493d26c5SEd Maste 1144493d26c5SEd Maste sbuf_delete(buf); 1145493d26c5SEd Maste 1146493d26c5SEd Maste return (0); 1147493d26c5SEd Maste } 1148493d26c5SEd Maste 1149493d26c5SEd Maste static int aq_sysctl_print_tx_head(SYSCTL_HANDLER_ARGS) 1150493d26c5SEd Maste { 1151493d26c5SEd Maste struct aq_ring *ring = arg1; 1152493d26c5SEd Maste int error = 0; 1153493d26c5SEd Maste unsigned int val; 1154493d26c5SEd Maste 1155493d26c5SEd Maste if (!ring) 1156493d26c5SEd Maste return (0); 1157493d26c5SEd Maste 1158493d26c5SEd Maste val = tdm_tx_desc_head_ptr_get(&ring->dev->hw, ring->index); 1159493d26c5SEd Maste 1160493d26c5SEd Maste error = sysctl_handle_int(oidp, &val, 0, req); 1161493d26c5SEd Maste if (error || !req->newptr) 1162493d26c5SEd Maste return (error); 1163493d26c5SEd Maste 1164493d26c5SEd Maste return (0); 1165493d26c5SEd Maste } 1166493d26c5SEd Maste 1167493d26c5SEd Maste static int aq_sysctl_print_tx_tail(SYSCTL_HANDLER_ARGS) 1168493d26c5SEd Maste { 1169493d26c5SEd Maste struct aq_ring *ring = arg1; 1170493d26c5SEd Maste int error = 0; 1171493d26c5SEd Maste unsigned int val; 1172493d26c5SEd Maste 1173493d26c5SEd Maste if (!ring) 1174493d26c5SEd Maste return (0); 1175493d26c5SEd Maste 1176493d26c5SEd Maste val = reg_tx_dma_desc_tail_ptr_get(&ring->dev->hw, ring->index); 1177493d26c5SEd Maste 1178493d26c5SEd Maste error = sysctl_handle_int(oidp, &val, 0, req); 1179493d26c5SEd Maste if (error || !req->newptr) 1180493d26c5SEd Maste return (error); 1181493d26c5SEd Maste 1182493d26c5SEd Maste return (0); 1183493d26c5SEd Maste } 1184493d26c5SEd Maste 1185493d26c5SEd Maste static int aq_sysctl_print_rx_head(SYSCTL_HANDLER_ARGS) 1186493d26c5SEd Maste { 1187493d26c5SEd Maste struct aq_ring *ring = arg1; 1188493d26c5SEd Maste int error = 0; 1189493d26c5SEd Maste unsigned int val; 1190493d26c5SEd Maste 1191493d26c5SEd Maste if (!ring) 1192493d26c5SEd Maste return (0); 1193493d26c5SEd Maste 1194493d26c5SEd Maste val = rdm_rx_desc_head_ptr_get(&ring->dev->hw, ring->index); 1195493d26c5SEd Maste 1196493d26c5SEd Maste error = sysctl_handle_int(oidp, &val, 0, req); 1197493d26c5SEd Maste if (error || !req->newptr) 1198493d26c5SEd Maste return (error); 1199493d26c5SEd Maste 1200493d26c5SEd Maste return (0); 1201493d26c5SEd Maste } 1202493d26c5SEd Maste 1203493d26c5SEd Maste static int aq_sysctl_print_rx_tail(SYSCTL_HANDLER_ARGS) 1204493d26c5SEd Maste { 1205493d26c5SEd Maste struct aq_ring *ring = arg1; 1206493d26c5SEd Maste int error = 0; 1207493d26c5SEd Maste unsigned int val; 1208493d26c5SEd Maste 1209493d26c5SEd Maste if (!ring) 1210493d26c5SEd Maste return (0); 1211493d26c5SEd Maste 1212493d26c5SEd Maste val = reg_rx_dma_desc_tail_ptr_get(&ring->dev->hw, ring->index); 1213493d26c5SEd Maste 1214493d26c5SEd Maste error = sysctl_handle_int(oidp, &val, 0, req); 1215493d26c5SEd Maste if (error || !req->newptr) 1216493d26c5SEd Maste return (error); 1217493d26c5SEd Maste 1218493d26c5SEd Maste return (0); 1219493d26c5SEd Maste } 1220493d26c5SEd Maste 1221493d26c5SEd Maste static void aq_add_stats_sysctls(struct aq_dev *softc) 1222493d26c5SEd Maste { 1223493d26c5SEd Maste device_t dev = softc->dev; 1224493d26c5SEd Maste struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 1225493d26c5SEd Maste struct sysctl_oid *tree = device_get_sysctl_tree(dev); 1226493d26c5SEd Maste struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 1227493d26c5SEd Maste struct aq_stats_s *stats = &softc->curr_stats; 1228493d26c5SEd Maste struct sysctl_oid *stat_node, *queue_node; 1229493d26c5SEd Maste struct sysctl_oid_list *stat_list, *queue_list; 1230493d26c5SEd Maste 1231493d26c5SEd Maste #define QUEUE_NAME_LEN 32 1232493d26c5SEd Maste char namebuf[QUEUE_NAME_LEN]; 1233493d26c5SEd Maste /* RSS configuration */ 1234493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config", 1235493d26c5SEd Maste CTLTYPE_STRING | CTLFLAG_RD, softc, 0, 1236493d26c5SEd Maste aq_sysctl_print_rss_config, "A", "Prints RSS Configuration"); 1237493d26c5SEd Maste 1238493d26c5SEd Maste /* Driver Statistics */ 1239493d26c5SEd Maste for (int i = 0; i < softc->tx_rings_count; i++) { 1240493d26c5SEd Maste struct aq_ring *ring = softc->tx_rings[i]; 1241493d26c5SEd Maste snprintf(namebuf, QUEUE_NAME_LEN, "tx_queue%d", i); 1242493d26c5SEd Maste queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 1243493d26c5SEd Maste CTLFLAG_RD, NULL, "Queue Name"); 1244493d26c5SEd Maste queue_list = SYSCTL_CHILDREN(queue_node); 1245493d26c5SEd Maste 1246493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_pkts", 1247493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.tx_pkts), "TX Packets"); 1248493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 1249493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.tx_bytes), "TX Octets"); 1250493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_drops", 1251493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.tx_drops), "TX Drops"); 1252493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_queue_full", 1253493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.tx_queue_full), "TX Queue Full"); 1254493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "tx_head", 1255493d26c5SEd Maste CTLTYPE_UINT | CTLFLAG_RD, ring, 0, 1256493d26c5SEd Maste aq_sysctl_print_tx_head, "IU", "ring head pointer"); 1257493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "tx_tail", 1258493d26c5SEd Maste CTLTYPE_UINT | CTLFLAG_RD, ring, 0, 1259493d26c5SEd Maste aq_sysctl_print_tx_tail, "IU", "ring tail pointer"); 1260493d26c5SEd Maste } 1261493d26c5SEd Maste 1262493d26c5SEd Maste for (int i = 0; i < softc->rx_rings_count; i++) { 1263493d26c5SEd Maste struct aq_ring *ring = softc->rx_rings[i]; 1264493d26c5SEd Maste snprintf(namebuf, QUEUE_NAME_LEN, "rx_queue%d", i); 1265493d26c5SEd Maste queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 1266493d26c5SEd Maste CTLFLAG_RD, NULL, "Queue Name"); 1267493d26c5SEd Maste queue_list = SYSCTL_CHILDREN(queue_node); 1268493d26c5SEd Maste 1269493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_pkts", 1270493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.rx_pkts), "RX Packets"); 1271493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 1272493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.rx_bytes), "TX Octets"); 1273493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "jumbo_pkts", 1274493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.jumbo_pkts), "Jumbo Packets"); 1275493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_err", 1276493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.rx_err), "RX Errors"); 1277493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irq", 1278493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.irq), "RX interrupts"); 1279493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rx_head", 1280493d26c5SEd Maste CTLTYPE_UINT | CTLFLAG_RD, ring, 0, 1281493d26c5SEd Maste aq_sysctl_print_rx_head, "IU", "ring head pointer"); 1282493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rx_tail", 1283493d26c5SEd Maste CTLTYPE_UINT | CTLFLAG_RD, ring, 0, 1284493d26c5SEd Maste aq_sysctl_print_rx_tail, "IU", " ring tail pointer"); 1285493d26c5SEd Maste } 1286493d26c5SEd Maste 1287493d26c5SEd Maste stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 1288493d26c5SEd Maste CTLFLAG_RD, NULL, "Statistics (read from HW registers)"); 1289493d26c5SEd Maste stat_list = SYSCTL_CHILDREN(stat_node); 1290493d26c5SEd Maste 1291493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", 1292493d26c5SEd Maste CTLFLAG_RD, &stats->prc, "Good Packets Received"); 1293493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_pkts_rcvd", 1294493d26c5SEd Maste CTLFLAG_RD, &stats->uprc, "Unicast Packets Received"); 1295493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", 1296493d26c5SEd Maste CTLFLAG_RD, &stats->mprc, "Multicast Packets Received"); 1297493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", 1298493d26c5SEd Maste CTLFLAG_RD, &stats->bprc, "Broadcast Packets Received"); 1299493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rsc_pkts_rcvd", 1300493d26c5SEd Maste CTLFLAG_RD, &stats->cprc, "Coalesced Packets Received"); 1301493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "err_pkts_rcvd", 1302493d26c5SEd Maste CTLFLAG_RD, &stats->erpr, "Errors of Packet Receive"); 1303493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "drop_pkts_dma", 1304493d26c5SEd Maste CTLFLAG_RD, &stats->dpc, "Dropped Packets in DMA"); 1305493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", 1306493d26c5SEd Maste CTLFLAG_RD, &stats->brc, "Good Octets Received"); 1307493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_octets_rcvd", 1308493d26c5SEd Maste CTLFLAG_RD, &stats->ubrc, "Unicast Octets Received"); 1309493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_octets_rcvd", 1310493d26c5SEd Maste CTLFLAG_RD, &stats->mbrc, "Multicast Octets Received"); 1311493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_octets_rcvd", 1312493d26c5SEd Maste CTLFLAG_RD, &stats->bbrc, "Broadcast Octets Received"); 1313493d26c5SEd Maste 1314493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", 1315493d26c5SEd Maste CTLFLAG_RD, &stats->ptc, "Good Packets Transmitted"); 1316493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_pkts_txd", 1317493d26c5SEd Maste CTLFLAG_RD, &stats->uptc, "Unicast Packets Transmitted"); 1318493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", 1319493d26c5SEd Maste CTLFLAG_RD, &stats->mptc, "Multicast Packets Transmitted"); 1320493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", 1321493d26c5SEd Maste CTLFLAG_RD, &stats->bptc, "Broadcast Packets Transmitted"); 1322493d26c5SEd Maste 1323493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "err_pkts_txd", 1324493d26c5SEd Maste CTLFLAG_RD, &stats->erpt, "Errors of Packet Transmit"); 1325493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", 1326493d26c5SEd Maste CTLFLAG_RD, &stats->btc, "Good Octets Transmitted"); 1327493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_octets_txd", 1328493d26c5SEd Maste CTLFLAG_RD, &stats->ubtc, "Unicast Octets Transmitted"); 1329493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_octets_txd", 1330493d26c5SEd Maste CTLFLAG_RD, &stats->mbtc, "Multicast Octets Transmitted"); 1331493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_octets_txd", 1332493d26c5SEd Maste CTLFLAG_RD, &stats->bbtc, "Broadcast Octets Transmitted"); 1333493d26c5SEd Maste } 1334