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 199493d26c5SEd Maste static devclass_t aq_devclass; 200493d26c5SEd Maste DRIVER_MODULE(atlantic, pci, aq_driver, aq_devclass, 0, 0); 201493d26c5SEd Maste 202493d26c5SEd Maste MODULE_DEPEND(atlantic, pci, 1, 1, 1); 203493d26c5SEd Maste MODULE_DEPEND(atlantic, ether, 1, 1, 1); 204493d26c5SEd Maste MODULE_DEPEND(atlantic, iflib, 1, 1, 1); 205493d26c5SEd Maste 206493d26c5SEd Maste IFLIB_PNP_INFO(pci, atlantic, aq_vendor_info_array); 207493d26c5SEd Maste 208493d26c5SEd Maste static device_method_t aq_if_methods[] = { 209493d26c5SEd Maste /* Device setup, teardown, etc */ 210493d26c5SEd Maste DEVMETHOD(ifdi_attach_pre, aq_if_attach_pre), 211493d26c5SEd Maste DEVMETHOD(ifdi_attach_post, aq_if_attach_post), 212493d26c5SEd Maste DEVMETHOD(ifdi_detach, aq_if_detach), 213493d26c5SEd Maste 214493d26c5SEd Maste DEVMETHOD(ifdi_shutdown, aq_if_shutdown), 215493d26c5SEd Maste DEVMETHOD(ifdi_suspend, aq_if_suspend), 216493d26c5SEd Maste DEVMETHOD(ifdi_resume, aq_if_resume), 217493d26c5SEd Maste 218493d26c5SEd Maste /* Soft queue setup and teardown */ 219493d26c5SEd Maste DEVMETHOD(ifdi_tx_queues_alloc, aq_if_tx_queues_alloc), 220493d26c5SEd Maste DEVMETHOD(ifdi_rx_queues_alloc, aq_if_rx_queues_alloc), 221493d26c5SEd Maste DEVMETHOD(ifdi_queues_free, aq_if_queues_free), 222493d26c5SEd Maste 223493d26c5SEd Maste /* Device configuration */ 224493d26c5SEd Maste DEVMETHOD(ifdi_init, aq_if_init), 225493d26c5SEd Maste DEVMETHOD(ifdi_stop, aq_if_stop), 226493d26c5SEd Maste DEVMETHOD(ifdi_multi_set, aq_if_multi_set), 227493d26c5SEd Maste DEVMETHOD(ifdi_mtu_set, aq_if_mtu_set), 228493d26c5SEd Maste DEVMETHOD(ifdi_media_status, aq_if_media_status), 229493d26c5SEd Maste DEVMETHOD(ifdi_media_change, aq_if_media_change), 230493d26c5SEd Maste DEVMETHOD(ifdi_promisc_set, aq_if_promisc_set), 231493d26c5SEd Maste DEVMETHOD(ifdi_get_counter, aq_if_get_counter), 232493d26c5SEd Maste DEVMETHOD(ifdi_update_admin_status, aq_if_update_admin_status), 233493d26c5SEd Maste DEVMETHOD(ifdi_timer, aq_if_timer), 234493d26c5SEd Maste // DEVMETHOD(ifdi_priv_ioctl, aq_if_priv_ioctl), 235493d26c5SEd Maste 236493d26c5SEd Maste /* Interrupt enable / disable */ 237493d26c5SEd Maste DEVMETHOD(ifdi_intr_enable, aq_if_enable_intr), 238493d26c5SEd Maste DEVMETHOD(ifdi_intr_disable, aq_if_disable_intr), 239493d26c5SEd Maste DEVMETHOD(ifdi_rx_queue_intr_enable, aq_if_rx_queue_intr_enable), 240493d26c5SEd Maste DEVMETHOD(ifdi_tx_queue_intr_enable, aq_if_rx_queue_intr_enable), 241493d26c5SEd Maste DEVMETHOD(ifdi_msix_intr_assign, aq_if_msix_intr_assign), 242493d26c5SEd Maste 243493d26c5SEd Maste /* VLAN support */ 244493d26c5SEd Maste DEVMETHOD(ifdi_vlan_register, aq_if_vlan_register), 245493d26c5SEd Maste DEVMETHOD(ifdi_vlan_unregister, aq_if_vlan_unregister), 246493d26c5SEd Maste 247493d26c5SEd Maste /* Informational/diagnostic */ 248493d26c5SEd Maste DEVMETHOD(ifdi_led_func, aq_if_led_func), 249493d26c5SEd Maste // DEVMETHOD(ifdi_debug, aq_if_debug), 250493d26c5SEd Maste 251493d26c5SEd Maste DEVMETHOD_END 252493d26c5SEd Maste }; 253493d26c5SEd Maste 254493d26c5SEd Maste static driver_t aq_if_driver = { 255493d26c5SEd Maste "aq_if", aq_if_methods, sizeof(struct aq_dev) 256493d26c5SEd Maste }; 257493d26c5SEd Maste 258493d26c5SEd Maste static struct if_shared_ctx aq_sctx_init = { 259493d26c5SEd Maste .isc_magic = IFLIB_MAGIC, 260493d26c5SEd Maste .isc_q_align = PAGE_SIZE, 261493d26c5SEd Maste .isc_tx_maxsize = HW_ATL_B0_TSO_SIZE, 262493d26c5SEd Maste .isc_tx_maxsegsize = HW_ATL_B0_MTU_JUMBO, 263493d26c5SEd Maste #if __FreeBSD__ >= 12 264493d26c5SEd Maste .isc_tso_maxsize = HW_ATL_B0_TSO_SIZE, 265493d26c5SEd Maste .isc_tso_maxsegsize = HW_ATL_B0_MTU_JUMBO, 266493d26c5SEd Maste #endif 267493d26c5SEd Maste .isc_rx_maxsize = HW_ATL_B0_MTU_JUMBO, 268493d26c5SEd Maste .isc_rx_nsegments = 16, 269493d26c5SEd Maste .isc_rx_maxsegsize = PAGE_SIZE, 270493d26c5SEd Maste .isc_nfl = 1, 271493d26c5SEd Maste .isc_nrxqs = 1, 272493d26c5SEd Maste .isc_ntxqs = 1, 273493d26c5SEd Maste .isc_admin_intrcnt = 1, 274493d26c5SEd Maste .isc_vendor_info = aq_vendor_info_array, 275493d26c5SEd Maste .isc_driver_version = aq_driver_version, 276493d26c5SEd Maste .isc_driver = &aq_if_driver, 277493d26c5SEd Maste .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP | 278493d26c5SEd Maste IFLIB_NEED_ZERO_CSUM, 279493d26c5SEd Maste 280493d26c5SEd Maste .isc_nrxd_min = {HW_ATL_B0_MIN_RXD}, 281493d26c5SEd Maste .isc_ntxd_min = {HW_ATL_B0_MIN_TXD}, 282493d26c5SEd Maste .isc_nrxd_max = {HW_ATL_B0_MAX_RXD}, 283493d26c5SEd Maste .isc_ntxd_max = {HW_ATL_B0_MAX_TXD}, 284493d26c5SEd Maste .isc_nrxd_default = {PAGE_SIZE / sizeof(aq_txc_desc_t) * 4}, 285493d26c5SEd Maste .isc_ntxd_default = {PAGE_SIZE / sizeof(aq_txc_desc_t) * 4}, 286493d26c5SEd Maste }; 287493d26c5SEd Maste 288493d26c5SEd Maste /* 289493d26c5SEd Maste * TUNEABLE PARAMETERS: 290493d26c5SEd Maste */ 291493d26c5SEd Maste 292493d26c5SEd Maste static SYSCTL_NODE(_hw, OID_AUTO, aq, CTLFLAG_RD, 0, "Atlantic driver parameters"); 293493d26c5SEd Maste /* UDP Receive-Side Scaling */ 294493d26c5SEd Maste static int aq_enable_rss_udp = 1; 295493d26c5SEd Maste SYSCTL_INT(_hw_aq, OID_AUTO, enable_rss_udp, CTLFLAG_RDTUN, &aq_enable_rss_udp, 0, 296493d26c5SEd Maste "Enable Receive-Side Scaling (RSS) for UDP"); 297493d26c5SEd Maste 298493d26c5SEd Maste 299493d26c5SEd Maste /* 300493d26c5SEd Maste * Device Methods 301493d26c5SEd Maste */ 302493d26c5SEd Maste static void *aq_register(device_t dev) 303493d26c5SEd Maste { 304493d26c5SEd Maste return (&aq_sctx_init); 305493d26c5SEd Maste } 306493d26c5SEd Maste 307493d26c5SEd Maste static int aq_if_attach_pre(if_ctx_t ctx) 308493d26c5SEd Maste { 309493d26c5SEd Maste struct aq_dev *softc; 310493d26c5SEd Maste struct aq_hw *hw; 311493d26c5SEd Maste if_softc_ctx_t scctx; 312493d26c5SEd Maste int rc; 313493d26c5SEd Maste 314493d26c5SEd Maste AQ_DBG_ENTER(); 315493d26c5SEd Maste softc = iflib_get_softc(ctx); 316493d26c5SEd Maste rc = 0; 317493d26c5SEd Maste 318493d26c5SEd Maste softc->ctx = ctx; 319493d26c5SEd Maste softc->dev = iflib_get_dev(ctx); 320493d26c5SEd Maste softc->media = iflib_get_media(ctx); 321493d26c5SEd Maste softc->scctx = iflib_get_softc_ctx(ctx); 322493d26c5SEd Maste softc->sctx = iflib_get_sctx(ctx); 323493d26c5SEd Maste scctx = softc->scctx; 324493d26c5SEd Maste 325493d26c5SEd Maste softc->mmio_rid = PCIR_BAR(0); 326493d26c5SEd Maste softc->mmio_res = bus_alloc_resource_any(softc->dev, SYS_RES_MEMORY, 327493d26c5SEd Maste &softc->mmio_rid, RF_ACTIVE|RF_SHAREABLE); 328493d26c5SEd Maste if (softc->mmio_res == NULL) { 329493d26c5SEd Maste device_printf(softc->dev, 330493d26c5SEd Maste "failed to allocate MMIO resources\n"); 331493d26c5SEd Maste rc = ENXIO; 332493d26c5SEd Maste goto fail; 333493d26c5SEd Maste } 334493d26c5SEd Maste 335493d26c5SEd Maste softc->mmio_tag = rman_get_bustag(softc->mmio_res); 336493d26c5SEd Maste softc->mmio_handle = rman_get_bushandle(softc->mmio_res); 337493d26c5SEd Maste softc->mmio_size = rman_get_size(softc->mmio_res); 338493d26c5SEd Maste softc->hw.hw_addr = (u8*) softc->mmio_handle; 339493d26c5SEd Maste hw = &softc->hw; 340493d26c5SEd Maste hw->link_rate = aq_fw_speed_auto; 341493d26c5SEd Maste hw->itr = -1; 342493d26c5SEd Maste hw->fc.fc_rx = 1; 343493d26c5SEd Maste hw->fc.fc_tx = 1; 344493d26c5SEd Maste softc->linkup = 0U; 345493d26c5SEd Maste 346493d26c5SEd Maste /* Look up ops and caps. */ 347493d26c5SEd Maste rc = aq_hw_mpi_create(hw); 348493d26c5SEd Maste if (rc < 0) { 349493d26c5SEd Maste AQ_DBG_ERROR(" %s: aq_hw_mpi_create fail err=%d", __func__, rc); 350493d26c5SEd Maste goto fail; 351493d26c5SEd Maste } 352493d26c5SEd Maste 353493d26c5SEd Maste if (hw->fast_start_enabled) { 354493d26c5SEd Maste if (hw->fw_ops && hw->fw_ops->reset) 355493d26c5SEd Maste hw->fw_ops->reset(hw); 356493d26c5SEd Maste } else 357493d26c5SEd Maste aq_hw_reset(&softc->hw); 358493d26c5SEd Maste aq_hw_capabilities(softc); 359493d26c5SEd Maste 360493d26c5SEd Maste if (aq_hw_get_mac_permanent(hw, hw->mac_addr) < 0) { 361493d26c5SEd Maste AQ_DBG_ERROR("Unable to get mac addr from hw"); 362493d26c5SEd Maste goto fail; 363493d26c5SEd Maste }; 364493d26c5SEd Maste 365493d26c5SEd Maste softc->admin_ticks = 0; 366493d26c5SEd Maste 367493d26c5SEd Maste iflib_set_mac(ctx, hw->mac_addr); 368493d26c5SEd Maste #if __FreeBSD__ < 13 369493d26c5SEd Maste /* since FreeBSD13 deadlock due to calling iflib_led_func() under CTX_LOCK() */ 370493d26c5SEd Maste iflib_led_create(ctx); 371493d26c5SEd Maste #endif 372493d26c5SEd Maste scctx->isc_tx_csum_flags = CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO; 373493d26c5SEd Maste #if __FreeBSD__ >= 12 374493d26c5SEd Maste scctx->isc_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_HWCSUM | IFCAP_TSO | 375493d26c5SEd Maste IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER | 376493d26c5SEd Maste IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | 377493d26c5SEd Maste IFCAP_VLAN_HWCSUM; 378493d26c5SEd Maste scctx->isc_capenable = scctx->isc_capabilities; 379493d26c5SEd Maste #else 380493d26c5SEd Maste if_t ifp; 381493d26c5SEd Maste ifp = iflib_get_ifp(ctx); 382*4756f5ffSOlivier Cochard if_setcapenable(ifp, IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_HWCSUM | IFCAP_TSO | 383493d26c5SEd Maste IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER | 384493d26c5SEd Maste IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | 385493d26c5SEd Maste IFCAP_VLAN_HWCSUM; 386493d26c5SEd Maste #endif 387493d26c5SEd Maste scctx->isc_tx_nsegments = 31, 388493d26c5SEd Maste scctx->isc_tx_tso_segments_max = 31; 389493d26c5SEd Maste scctx->isc_tx_tso_size_max = HW_ATL_B0_TSO_SIZE - sizeof(struct ether_vlan_header); 390493d26c5SEd Maste scctx->isc_tx_tso_segsize_max = HW_ATL_B0_MTU_JUMBO; 391493d26c5SEd Maste scctx->isc_min_frame_size = 52; 392493d26c5SEd Maste scctx->isc_txrx = &aq_txrx; 393493d26c5SEd Maste 394493d26c5SEd Maste scctx->isc_txqsizes[0] = sizeof(aq_tx_desc_t) * scctx->isc_ntxd[0]; 395493d26c5SEd Maste scctx->isc_rxqsizes[0] = sizeof(aq_rx_desc_t) * scctx->isc_nrxd[0]; 396493d26c5SEd Maste 397493d26c5SEd Maste scctx->isc_ntxqsets_max = HW_ATL_B0_RINGS_MAX; 398493d26c5SEd Maste scctx->isc_nrxqsets_max = HW_ATL_B0_RINGS_MAX; 399493d26c5SEd Maste 400493d26c5SEd Maste /* iflib will map and release this bar */ 401493d26c5SEd Maste scctx->isc_msix_bar = pci_msix_table_bar(softc->dev); 402493d26c5SEd Maste 403493d26c5SEd Maste softc->vlan_tags = bit_alloc(4096, M_AQ, M_NOWAIT); 404493d26c5SEd Maste 405493d26c5SEd Maste AQ_DBG_EXIT(rc); 406493d26c5SEd Maste return (rc); 407493d26c5SEd Maste 408493d26c5SEd Maste fail: 409493d26c5SEd Maste if (softc->mmio_res != NULL) 410493d26c5SEd Maste bus_release_resource(softc->dev, SYS_RES_MEMORY, 411493d26c5SEd Maste softc->mmio_rid, softc->mmio_res); 412493d26c5SEd Maste 413493d26c5SEd Maste AQ_DBG_EXIT(rc); 414493d26c5SEd Maste return (ENXIO); 415493d26c5SEd Maste } 416493d26c5SEd Maste 417493d26c5SEd Maste 418493d26c5SEd Maste static int aq_if_attach_post(if_ctx_t ctx) 419493d26c5SEd Maste { 420493d26c5SEd Maste struct aq_dev *softc; 421493d26c5SEd Maste int rc; 422493d26c5SEd Maste 423493d26c5SEd Maste AQ_DBG_ENTER(); 424493d26c5SEd Maste 425493d26c5SEd Maste softc = iflib_get_softc(ctx); 426493d26c5SEd Maste rc = 0; 427493d26c5SEd Maste 428493d26c5SEd Maste aq_update_hw_stats(softc); 429493d26c5SEd Maste 430493d26c5SEd Maste aq_initmedia(softc); 431493d26c5SEd Maste 432493d26c5SEd Maste 433493d26c5SEd Maste switch (softc->scctx->isc_intr) { 434493d26c5SEd Maste case IFLIB_INTR_LEGACY: 435493d26c5SEd Maste rc = EOPNOTSUPP; 436493d26c5SEd Maste goto exit; 437493d26c5SEd Maste goto exit; 438493d26c5SEd Maste break; 439493d26c5SEd Maste case IFLIB_INTR_MSI: 440493d26c5SEd Maste break; 441493d26c5SEd Maste case IFLIB_INTR_MSIX: 442493d26c5SEd Maste break; 443493d26c5SEd Maste default: 444493d26c5SEd Maste device_printf(softc->dev, "unknown interrupt mode\n"); 445493d26c5SEd Maste rc = EOPNOTSUPP; 446493d26c5SEd Maste goto exit; 447493d26c5SEd Maste } 448493d26c5SEd Maste 449493d26c5SEd Maste aq_add_stats_sysctls(softc); 450493d26c5SEd Maste /* RSS */ 451493d26c5SEd Maste arc4rand(softc->rss_key, HW_ATL_RSS_HASHKEY_SIZE, 0); 452493d26c5SEd Maste for (int i = ARRAY_SIZE(softc->rss_table); i--;){ 453493d26c5SEd Maste softc->rss_table[i] = i & (softc->rx_rings_count - 1); 454493d26c5SEd Maste } 455493d26c5SEd Maste exit: 456493d26c5SEd Maste AQ_DBG_EXIT(rc); 457493d26c5SEd Maste return (rc); 458493d26c5SEd Maste } 459493d26c5SEd Maste 460493d26c5SEd Maste 461493d26c5SEd Maste static int aq_if_detach(if_ctx_t ctx) 462493d26c5SEd Maste { 463493d26c5SEd Maste struct aq_dev *softc; 464493d26c5SEd Maste int i; 465493d26c5SEd Maste 466493d26c5SEd Maste AQ_DBG_ENTER(); 467493d26c5SEd Maste softc = iflib_get_softc(ctx); 468493d26c5SEd Maste 469493d26c5SEd Maste aq_hw_deinit(&softc->hw); 470493d26c5SEd Maste 471493d26c5SEd Maste for (i = 0; i < softc->scctx->isc_nrxqsets; i++) 472493d26c5SEd Maste iflib_irq_free(ctx, &softc->rx_rings[i]->irq); 473493d26c5SEd Maste iflib_irq_free(ctx, &softc->irq); 474493d26c5SEd Maste 475493d26c5SEd Maste 476493d26c5SEd Maste if (softc->mmio_res != NULL) 477493d26c5SEd Maste bus_release_resource(softc->dev, SYS_RES_MEMORY, 478493d26c5SEd Maste softc->mmio_rid, softc->mmio_res); 479493d26c5SEd Maste 480493d26c5SEd Maste free(softc->vlan_tags, M_AQ); 481493d26c5SEd Maste 482493d26c5SEd Maste AQ_DBG_EXIT(0); 483493d26c5SEd Maste return (0); 484493d26c5SEd Maste } 485493d26c5SEd Maste 486493d26c5SEd Maste static int aq_if_shutdown(if_ctx_t ctx) 487493d26c5SEd Maste { 488493d26c5SEd Maste 489493d26c5SEd Maste AQ_DBG_ENTER(); 490493d26c5SEd Maste 491493d26c5SEd Maste AQ_XXX_UNIMPLEMENTED_FUNCTION; 492493d26c5SEd Maste 493493d26c5SEd Maste AQ_DBG_EXIT(0); 494493d26c5SEd Maste return (0); 495493d26c5SEd Maste } 496493d26c5SEd Maste 497493d26c5SEd Maste static int aq_if_suspend(if_ctx_t ctx) 498493d26c5SEd Maste { 499493d26c5SEd Maste AQ_DBG_ENTER(); 500493d26c5SEd Maste 501493d26c5SEd Maste AQ_XXX_UNIMPLEMENTED_FUNCTION; 502493d26c5SEd Maste 503493d26c5SEd Maste AQ_DBG_EXIT(0); 504493d26c5SEd Maste return (0); 505493d26c5SEd Maste } 506493d26c5SEd Maste 507493d26c5SEd Maste static int aq_if_resume(if_ctx_t ctx) 508493d26c5SEd Maste { 509493d26c5SEd Maste AQ_DBG_ENTER(); 510493d26c5SEd Maste 511493d26c5SEd Maste AQ_XXX_UNIMPLEMENTED_FUNCTION; 512493d26c5SEd Maste 513493d26c5SEd Maste AQ_DBG_EXIT(0); 514493d26c5SEd Maste return (0); 515493d26c5SEd Maste } 516493d26c5SEd Maste 517493d26c5SEd Maste /* Soft queue setup and teardown */ 518493d26c5SEd Maste static int aq_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, 519493d26c5SEd Maste uint64_t *paddrs, int ntxqs, int ntxqsets) 520493d26c5SEd Maste { 521493d26c5SEd Maste struct aq_dev *softc; 522493d26c5SEd Maste struct aq_ring *ring; 523493d26c5SEd Maste int rc = 0, i; 524493d26c5SEd Maste 525493d26c5SEd Maste AQ_DBG_ENTERA("ntxqs=%d, ntxqsets=%d", ntxqs, ntxqsets); 526493d26c5SEd Maste softc = iflib_get_softc(ctx); 527493d26c5SEd Maste AQ_DBG_PRINT("tx descriptors number %d", softc->scctx->isc_ntxd[0]); 528493d26c5SEd Maste 529493d26c5SEd Maste for (i = 0; i < ntxqsets; i++) { 530493d26c5SEd Maste ring = softc->tx_rings[i] = malloc(sizeof(struct aq_ring), 531493d26c5SEd Maste M_AQ, M_NOWAIT | M_ZERO); 532493d26c5SEd Maste if (!ring){ 533493d26c5SEd Maste rc = ENOMEM; 534493d26c5SEd Maste device_printf(softc->dev, "atlantic: tx_ring malloc fail\n"); 535493d26c5SEd Maste goto fail; 536493d26c5SEd Maste } 537493d26c5SEd Maste ring->tx_descs = (aq_tx_desc_t*)vaddrs[i]; 538493d26c5SEd Maste ring->tx_size = softc->scctx->isc_ntxd[0]; 539493d26c5SEd Maste ring->tx_descs_phys = paddrs[i]; 540493d26c5SEd Maste ring->tx_head = ring->tx_tail = 0; 541493d26c5SEd Maste ring->index = i; 542493d26c5SEd Maste ring->dev = softc; 543493d26c5SEd Maste 544493d26c5SEd Maste softc->tx_rings_count++; 545493d26c5SEd Maste } 546493d26c5SEd Maste 547493d26c5SEd Maste AQ_DBG_EXIT(rc); 548493d26c5SEd Maste return (rc); 549493d26c5SEd Maste 550493d26c5SEd Maste fail: 551493d26c5SEd Maste aq_if_queues_free(ctx); 552493d26c5SEd Maste AQ_DBG_EXIT(rc); 553493d26c5SEd Maste return (rc); 554493d26c5SEd Maste } 555493d26c5SEd Maste 556493d26c5SEd Maste static int aq_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, 557493d26c5SEd Maste uint64_t *paddrs, int nrxqs, int nrxqsets) 558493d26c5SEd Maste { 559493d26c5SEd Maste struct aq_dev *softc; 560493d26c5SEd Maste struct aq_ring *ring; 561493d26c5SEd Maste int rc = 0, i; 562493d26c5SEd Maste 563493d26c5SEd Maste AQ_DBG_ENTERA("nrxqs=%d, nrxqsets=%d", nrxqs, nrxqsets); 564493d26c5SEd Maste softc = iflib_get_softc(ctx); 565493d26c5SEd Maste 566493d26c5SEd Maste for (i = 0; i < nrxqsets; i++) { 567493d26c5SEd Maste ring = softc->rx_rings[i] = malloc(sizeof(struct aq_ring), 568493d26c5SEd Maste M_AQ, M_NOWAIT | M_ZERO); 569493d26c5SEd Maste if (!ring){ 570493d26c5SEd Maste rc = ENOMEM; 571493d26c5SEd Maste device_printf(softc->dev, "atlantic: rx_ring malloc fail\n"); 572493d26c5SEd Maste goto fail; 573493d26c5SEd Maste } 574493d26c5SEd Maste 575493d26c5SEd Maste ring->rx_descs = (aq_rx_desc_t*)vaddrs[i]; 576493d26c5SEd Maste ring->rx_descs_phys = paddrs[i]; 577493d26c5SEd Maste ring->rx_size = softc->scctx->isc_nrxd[0]; 578493d26c5SEd Maste ring->index = i; 579493d26c5SEd Maste ring->dev = softc; 580493d26c5SEd Maste 581493d26c5SEd Maste switch (MCLBYTES) { 582493d26c5SEd Maste case (4 * 1024): 583493d26c5SEd Maste case (8 * 1024): 584493d26c5SEd Maste case (16 * 1024): 585493d26c5SEd Maste ring->rx_max_frame_size = MCLBYTES; 586493d26c5SEd Maste break; 587493d26c5SEd Maste default: 588493d26c5SEd Maste ring->rx_max_frame_size = 2048; 589493d26c5SEd Maste break; 590493d26c5SEd Maste } 591493d26c5SEd Maste 592493d26c5SEd Maste softc->rx_rings_count++; 593493d26c5SEd Maste } 594493d26c5SEd Maste 595493d26c5SEd Maste AQ_DBG_EXIT(rc); 596493d26c5SEd Maste return (rc); 597493d26c5SEd Maste 598493d26c5SEd Maste fail: 599493d26c5SEd Maste aq_if_queues_free(ctx); 600493d26c5SEd Maste AQ_DBG_EXIT(rc); 601493d26c5SEd Maste return (rc); 602493d26c5SEd Maste } 603493d26c5SEd Maste 604493d26c5SEd Maste static void aq_if_queues_free(if_ctx_t ctx) 605493d26c5SEd Maste { 606493d26c5SEd Maste struct aq_dev *softc; 607493d26c5SEd Maste int i; 608493d26c5SEd Maste 609493d26c5SEd Maste AQ_DBG_ENTER(); 610493d26c5SEd Maste softc = iflib_get_softc(ctx); 611493d26c5SEd Maste 612493d26c5SEd Maste for (i = 0; i < softc->tx_rings_count; i++) { 613493d26c5SEd Maste if (softc->tx_rings[i]) { 614493d26c5SEd Maste free(softc->tx_rings[i], M_AQ); 615493d26c5SEd Maste softc->tx_rings[i] = NULL; 616493d26c5SEd Maste } 617493d26c5SEd Maste } 618493d26c5SEd Maste softc->tx_rings_count = 0; 619493d26c5SEd Maste for (i = 0; i < softc->rx_rings_count; i++) { 620493d26c5SEd Maste if (softc->rx_rings[i]){ 621493d26c5SEd Maste free(softc->rx_rings[i], M_AQ); 622493d26c5SEd Maste softc->rx_rings[i] = NULL; 623493d26c5SEd Maste } 624493d26c5SEd Maste } 625493d26c5SEd Maste softc->rx_rings_count = 0; 626493d26c5SEd Maste 627493d26c5SEd Maste AQ_DBG_EXIT(0); 628493d26c5SEd Maste return; 629493d26c5SEd Maste } 630493d26c5SEd Maste 631493d26c5SEd Maste /* Device configuration */ 632493d26c5SEd Maste static void aq_if_init(if_ctx_t ctx) 633493d26c5SEd Maste { 634493d26c5SEd Maste struct aq_dev *softc; 635493d26c5SEd Maste struct aq_hw *hw; 636493d26c5SEd Maste struct ifmediareq ifmr; 637493d26c5SEd Maste int i, err; 638493d26c5SEd Maste 639493d26c5SEd Maste AQ_DBG_ENTER(); 640493d26c5SEd Maste softc = iflib_get_softc(ctx); 641493d26c5SEd Maste hw = &softc->hw; 642493d26c5SEd Maste 643493d26c5SEd Maste err = aq_hw_init(&softc->hw, softc->hw.mac_addr, softc->msix, 644493d26c5SEd Maste softc->scctx->isc_intr == IFLIB_INTR_MSIX); 645493d26c5SEd Maste if (err != EOK) { 646493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_hw_init: %d", err); 647493d26c5SEd Maste } 648493d26c5SEd Maste 649493d26c5SEd Maste aq_if_media_status(ctx, &ifmr); 650493d26c5SEd Maste 651493d26c5SEd Maste aq_update_vlan_filters(softc); 652493d26c5SEd Maste 653493d26c5SEd Maste for (i = 0; i < softc->tx_rings_count; i++) { 654493d26c5SEd Maste struct aq_ring *ring = softc->tx_rings[i]; 655493d26c5SEd Maste err = aq_ring_tx_init(&softc->hw, ring); 656493d26c5SEd Maste if (err) { 657493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_ring_tx_init: %d", err); 658493d26c5SEd Maste } 659493d26c5SEd Maste err = aq_ring_tx_start(hw, ring); 660493d26c5SEd Maste if (err != EOK) { 661493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_ring_tx_start: %d", err); 662493d26c5SEd Maste } 663493d26c5SEd Maste } 664493d26c5SEd Maste for (i = 0; i < softc->rx_rings_count; i++) { 665493d26c5SEd Maste struct aq_ring *ring = softc->rx_rings[i]; 666493d26c5SEd Maste err = aq_ring_rx_init(&softc->hw, ring); 667493d26c5SEd Maste if (err) { 668493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_ring_rx_init: %d", err); 669493d26c5SEd Maste } 670493d26c5SEd Maste err = aq_ring_rx_start(hw, ring); 671493d26c5SEd Maste if (err != EOK) { 672493d26c5SEd Maste device_printf(softc->dev, "atlantic: aq_ring_rx_start: %d", err); 673493d26c5SEd Maste } 674493d26c5SEd Maste aq_if_rx_queue_intr_enable(ctx, i); 675493d26c5SEd Maste } 676493d26c5SEd Maste 677493d26c5SEd Maste aq_hw_start(hw); 678493d26c5SEd Maste aq_if_enable_intr(ctx); 679493d26c5SEd Maste aq_hw_rss_hash_set(&softc->hw, softc->rss_key); 680493d26c5SEd Maste aq_hw_rss_set(&softc->hw, softc->rss_table); 681493d26c5SEd Maste aq_hw_udp_rss_enable(hw, aq_enable_rss_udp); 682493d26c5SEd Maste aq_hw_set_link_speed(hw, hw->link_rate); 683493d26c5SEd Maste 684493d26c5SEd Maste AQ_DBG_EXIT(0); 685493d26c5SEd Maste } 686493d26c5SEd Maste 687493d26c5SEd Maste 688493d26c5SEd Maste static void aq_if_stop(if_ctx_t ctx) 689493d26c5SEd Maste { 690493d26c5SEd Maste struct aq_dev *softc; 691493d26c5SEd Maste struct aq_hw *hw; 692493d26c5SEd Maste int i; 693493d26c5SEd Maste 694493d26c5SEd Maste AQ_DBG_ENTER(); 695493d26c5SEd Maste 696493d26c5SEd Maste softc = iflib_get_softc(ctx); 697493d26c5SEd Maste hw = &softc->hw; 698493d26c5SEd Maste 699493d26c5SEd Maste /* disable interrupt */ 700493d26c5SEd Maste aq_if_disable_intr(ctx); 701493d26c5SEd Maste 702493d26c5SEd Maste for (i = 0; i < softc->tx_rings_count; i++) { 703493d26c5SEd Maste aq_ring_tx_stop(hw, softc->tx_rings[i]); 704493d26c5SEd Maste softc->tx_rings[i]->tx_head = 0; 705493d26c5SEd Maste softc->tx_rings[i]->tx_tail = 0; 706493d26c5SEd Maste } 707493d26c5SEd Maste for (i = 0; i < softc->rx_rings_count; i++) { 708493d26c5SEd Maste aq_ring_rx_stop(hw, softc->rx_rings[i]); 709493d26c5SEd Maste } 710493d26c5SEd Maste 711493d26c5SEd Maste aq_hw_reset(&softc->hw); 712493d26c5SEd Maste memset(&softc->last_stats, 0, sizeof(softc->last_stats)); 713493d26c5SEd Maste softc->linkup = false; 714493d26c5SEd Maste aq_if_update_admin_status(ctx); 715493d26c5SEd Maste AQ_DBG_EXIT(0); 716493d26c5SEd Maste } 717493d26c5SEd Maste 718493d26c5SEd Maste static uint64_t aq_if_get_counter(if_ctx_t ctx, ift_counter cnt) 719493d26c5SEd Maste { 720493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 721*4756f5ffSOlivier Cochard if_t ifp = iflib_get_ifp(ctx); 722493d26c5SEd Maste 723493d26c5SEd Maste switch (cnt) { 724493d26c5SEd Maste case IFCOUNTER_IERRORS: 725493d26c5SEd Maste return (softc->curr_stats.erpr); 726493d26c5SEd Maste case IFCOUNTER_IQDROPS: 727493d26c5SEd Maste return (softc->curr_stats.dpc); 728493d26c5SEd Maste case IFCOUNTER_OERRORS: 729493d26c5SEd Maste return (softc->curr_stats.erpt); 730493d26c5SEd Maste default: 731493d26c5SEd Maste return (if_get_counter_default(ifp, cnt)); 732493d26c5SEd Maste } 733493d26c5SEd Maste } 734493d26c5SEd Maste 735493d26c5SEd Maste #if __FreeBSD_version >= 1300054 736493d26c5SEd Maste static u_int aq_mc_filter_apply(void *arg, struct sockaddr_dl *dl, u_int count) 737493d26c5SEd Maste { 738493d26c5SEd Maste struct aq_dev *softc = arg; 739493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 740493d26c5SEd Maste u8 *mac_addr = NULL; 741493d26c5SEd Maste 742493d26c5SEd Maste if (count == AQ_HW_MAC_MAX) 743493d26c5SEd Maste return (0); 744493d26c5SEd Maste 745493d26c5SEd Maste mac_addr = LLADDR(dl); 746493d26c5SEd Maste aq_hw_mac_addr_set(hw, mac_addr, count + 1); 747493d26c5SEd Maste 748493d26c5SEd Maste aq_log_detail("set %d mc address %6D", count + 1, mac_addr, ":"); 749493d26c5SEd Maste return (1); 750493d26c5SEd Maste } 751493d26c5SEd Maste #else 752493d26c5SEd Maste static int aq_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count) 753493d26c5SEd Maste { 754493d26c5SEd Maste struct aq_dev *softc = arg; 755493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 756493d26c5SEd Maste u8 *mac_addr = NULL; 757493d26c5SEd Maste 758493d26c5SEd Maste if (ifma->ifma_addr->sa_family != AF_LINK) 759493d26c5SEd Maste return (0); 760493d26c5SEd Maste if (count == AQ_HW_MAC_MAX) 761493d26c5SEd Maste return (0); 762493d26c5SEd Maste 763493d26c5SEd Maste mac_addr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 764493d26c5SEd Maste aq_hw_mac_addr_set(hw, mac_addr, count + 1); 765493d26c5SEd Maste 766493d26c5SEd Maste aq_log_detail("set %d mc address %6D", count + 1, mac_addr, ":"); 767493d26c5SEd Maste return (1); 768493d26c5SEd Maste } 769493d26c5SEd Maste #endif 770493d26c5SEd Maste 771493d26c5SEd Maste static bool aq_is_mc_promisc_required(struct aq_dev *softc) 772493d26c5SEd Maste { 773493d26c5SEd Maste return (softc->mcnt >= AQ_HW_MAC_MAX); 774493d26c5SEd Maste } 775493d26c5SEd Maste 776493d26c5SEd Maste static void aq_if_multi_set(if_ctx_t ctx) 777493d26c5SEd Maste { 778493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 779*4756f5ffSOlivier Cochard if_t ifp = iflib_get_ifp(ctx); 780493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 781493d26c5SEd Maste AQ_DBG_ENTER(); 782493d26c5SEd Maste #if __FreeBSD_version >= 1300054 783493d26c5SEd Maste softc->mcnt = if_llmaddr_count(iflib_get_ifp(ctx)); 784493d26c5SEd Maste #else 785493d26c5SEd Maste softc->mcnt = if_multiaddr_count(iflib_get_ifp(ctx), AQ_HW_MAC_MAX); 786493d26c5SEd Maste #endif 787493d26c5SEd Maste if (softc->mcnt >= AQ_HW_MAC_MAX) 788493d26c5SEd Maste { 789*4756f5ffSOlivier Cochard aq_hw_set_promisc(hw, !!(if_getflags(ifp) & IFF_PROMISC), 790493d26c5SEd Maste aq_is_vlan_promisc_required(softc), 791*4756f5ffSOlivier Cochard !!(if_getflags(ifp) & IFF_ALLMULTI) || aq_is_mc_promisc_required(softc)); 792493d26c5SEd Maste }else{ 793493d26c5SEd Maste #if __FreeBSD_version >= 1300054 794493d26c5SEd Maste if_foreach_llmaddr(iflib_get_ifp(ctx), &aq_mc_filter_apply, softc); 795493d26c5SEd Maste #else 796493d26c5SEd Maste if_multi_apply(iflib_get_ifp(ctx), aq_mc_filter_apply, softc); 797493d26c5SEd Maste #endif 798493d26c5SEd Maste } 799493d26c5SEd Maste AQ_DBG_EXIT(0); 800493d26c5SEd Maste } 801493d26c5SEd Maste 802493d26c5SEd Maste static int aq_if_mtu_set(if_ctx_t ctx, uint32_t mtu) 803493d26c5SEd Maste { 804493d26c5SEd Maste int err = 0; 805493d26c5SEd Maste AQ_DBG_ENTER(); 806493d26c5SEd Maste 807493d26c5SEd Maste AQ_DBG_EXIT(err); 808493d26c5SEd Maste return (err); 809493d26c5SEd Maste } 810493d26c5SEd Maste 811493d26c5SEd Maste static void aq_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr) 812493d26c5SEd Maste { 813*4756f5ffSOlivier Cochard if_t ifp; 814493d26c5SEd Maste 815493d26c5SEd Maste AQ_DBG_ENTER(); 816493d26c5SEd Maste 817493d26c5SEd Maste ifp = iflib_get_ifp(ctx); 818493d26c5SEd Maste 819493d26c5SEd Maste aq_mediastatus(ifp, ifmr); 820493d26c5SEd Maste 821493d26c5SEd Maste AQ_DBG_EXIT(0); 822493d26c5SEd Maste } 823493d26c5SEd Maste 824493d26c5SEd Maste static int aq_if_media_change(if_ctx_t ctx) 825493d26c5SEd Maste { 826493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 827*4756f5ffSOlivier Cochard if_t ifp = iflib_get_ifp(ctx); 828493d26c5SEd Maste int rc = 0; 829493d26c5SEd Maste 830493d26c5SEd Maste AQ_DBG_ENTER(); 831493d26c5SEd Maste 832493d26c5SEd Maste /* Not allowd in UP state, since causes unsync of rings */ 833*4756f5ffSOlivier Cochard if ((if_getflags(ifp) & IFF_UP)){ 834493d26c5SEd Maste rc = EPERM; 835493d26c5SEd Maste goto exit; 836493d26c5SEd Maste } 837493d26c5SEd Maste 838493d26c5SEd Maste ifp = iflib_get_ifp(softc->ctx); 839493d26c5SEd Maste 840493d26c5SEd Maste rc = aq_mediachange(ifp); 841493d26c5SEd Maste 842493d26c5SEd Maste exit: 843493d26c5SEd Maste AQ_DBG_EXIT(rc); 844493d26c5SEd Maste return (rc); 845493d26c5SEd Maste } 846493d26c5SEd Maste 847493d26c5SEd Maste static int aq_if_promisc_set(if_ctx_t ctx, int flags) 848493d26c5SEd Maste { 849493d26c5SEd Maste struct aq_dev *softc; 850493d26c5SEd Maste 851493d26c5SEd Maste AQ_DBG_ENTER(); 852493d26c5SEd Maste 853493d26c5SEd Maste softc = iflib_get_softc(ctx); 854493d26c5SEd Maste 855493d26c5SEd Maste aq_hw_set_promisc(&softc->hw, !!(flags & IFF_PROMISC), 856493d26c5SEd Maste aq_is_vlan_promisc_required(softc), 857493d26c5SEd Maste !!(flags & IFF_ALLMULTI) || aq_is_mc_promisc_required(softc)); 858493d26c5SEd Maste 859493d26c5SEd Maste AQ_DBG_EXIT(0); 860493d26c5SEd Maste return (0); 861493d26c5SEd Maste } 862493d26c5SEd Maste 863493d26c5SEd Maste static void aq_if_timer(if_ctx_t ctx, uint16_t qid) 864493d26c5SEd Maste { 865493d26c5SEd Maste struct aq_dev *softc; 866493d26c5SEd Maste uint64_t ticks_now; 867493d26c5SEd Maste 868493d26c5SEd Maste // AQ_DBG_ENTER(); 869493d26c5SEd Maste 870493d26c5SEd Maste softc = iflib_get_softc(ctx); 871493d26c5SEd Maste ticks_now = ticks; 872493d26c5SEd Maste 873493d26c5SEd Maste /* Schedule aqc_if_update_admin_status() once per sec */ 874493d26c5SEd Maste if (ticks_now - softc->admin_ticks >= hz) { 875493d26c5SEd Maste softc->admin_ticks = ticks_now; 876493d26c5SEd Maste iflib_admin_intr_deferred(ctx); 877493d26c5SEd Maste } 878493d26c5SEd Maste 879493d26c5SEd Maste // AQ_DBG_EXIT(0); 880493d26c5SEd Maste return; 881493d26c5SEd Maste 882493d26c5SEd Maste } 883493d26c5SEd Maste 884493d26c5SEd Maste /* Interrupt enable / disable */ 885493d26c5SEd Maste static void aq_if_enable_intr(if_ctx_t ctx) 886493d26c5SEd Maste { 887493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 888493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 889493d26c5SEd Maste 890493d26c5SEd Maste AQ_DBG_ENTER(); 891493d26c5SEd Maste 892493d26c5SEd Maste /* Enable interrupts */ 893493d26c5SEd Maste itr_irq_msk_setlsw_set(hw, BIT(softc->msix + 1) - 1); 894493d26c5SEd Maste 895493d26c5SEd Maste AQ_DBG_EXIT(0); 896493d26c5SEd Maste } 897493d26c5SEd Maste 898493d26c5SEd Maste static void aq_if_disable_intr(if_ctx_t ctx) 899493d26c5SEd Maste { 900493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 901493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 902493d26c5SEd Maste 903493d26c5SEd Maste AQ_DBG_ENTER(); 904493d26c5SEd Maste 905493d26c5SEd Maste /* Disable interrupts */ 906493d26c5SEd Maste itr_irq_msk_clearlsw_set(hw, BIT(softc->msix + 1) - 1); 907493d26c5SEd Maste 908493d26c5SEd Maste AQ_DBG_EXIT(0); 909493d26c5SEd Maste } 910493d26c5SEd Maste 911493d26c5SEd Maste static int aq_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid) 912493d26c5SEd Maste { 913493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 914493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 915493d26c5SEd Maste 916493d26c5SEd Maste AQ_DBG_ENTER(); 917493d26c5SEd Maste 918493d26c5SEd Maste itr_irq_msk_setlsw_set(hw, BIT(softc->rx_rings[rxqid]->msix)); 919493d26c5SEd Maste 920493d26c5SEd Maste AQ_DBG_EXIT(0); 921493d26c5SEd Maste return (0); 922493d26c5SEd Maste } 923493d26c5SEd Maste 924493d26c5SEd Maste static int aq_if_msix_intr_assign(if_ctx_t ctx, int msix) 925493d26c5SEd Maste { 926493d26c5SEd Maste struct aq_dev *softc; 927493d26c5SEd Maste int i, vector = 0, rc; 928493d26c5SEd Maste char irq_name[16]; 929493d26c5SEd Maste int rx_vectors; 930493d26c5SEd Maste 931493d26c5SEd Maste AQ_DBG_ENTER(); 932493d26c5SEd Maste softc = iflib_get_softc(ctx); 933493d26c5SEd Maste 934493d26c5SEd Maste for (i = 0; i < softc->rx_rings_count; i++, vector++) { 935493d26c5SEd Maste snprintf(irq_name, sizeof(irq_name), "rxq%d", i); 936493d26c5SEd Maste rc = iflib_irq_alloc_generic(ctx, &softc->rx_rings[i]->irq, 937493d26c5SEd Maste vector + 1, IFLIB_INTR_RX, aq_isr_rx, softc->rx_rings[i], 938493d26c5SEd Maste softc->rx_rings[i]->index, irq_name); 939493d26c5SEd Maste device_printf(softc->dev, "Assign IRQ %u to rx ring %u\n", 940493d26c5SEd Maste vector, softc->rx_rings[i]->index); 941493d26c5SEd Maste 942493d26c5SEd Maste if (rc) { 943493d26c5SEd Maste device_printf(softc->dev, "failed to set up RX handler\n"); 944493d26c5SEd Maste i--; 945493d26c5SEd Maste goto fail; 946493d26c5SEd Maste } 947493d26c5SEd Maste 948493d26c5SEd Maste softc->rx_rings[i]->msix = vector; 949493d26c5SEd Maste } 950493d26c5SEd Maste 951493d26c5SEd Maste rx_vectors = vector; 952493d26c5SEd Maste 953493d26c5SEd Maste for (i = 0; i < softc->tx_rings_count; i++, vector++) { 954493d26c5SEd Maste snprintf(irq_name, sizeof(irq_name), "txq%d", i); 955493d26c5SEd Maste iflib_softirq_alloc_generic(ctx, &softc->rx_rings[i]->irq, IFLIB_INTR_TX, 956493d26c5SEd Maste softc->tx_rings[i], i, irq_name); 957493d26c5SEd Maste 958493d26c5SEd Maste softc->tx_rings[i]->msix = (vector % softc->rx_rings_count); 959493d26c5SEd Maste device_printf(softc->dev, "Assign IRQ %u to tx ring %u\n", 960493d26c5SEd Maste softc->tx_rings[i]->msix, softc->tx_rings[i]->index); 961493d26c5SEd Maste } 962493d26c5SEd Maste 963493d26c5SEd Maste rc = iflib_irq_alloc_generic(ctx, &softc->irq, rx_vectors + 1, 964493d26c5SEd Maste IFLIB_INTR_ADMIN, aq_linkstat_isr, 965493d26c5SEd Maste softc, 0, "aq"); 966493d26c5SEd Maste softc->msix = rx_vectors; 967493d26c5SEd Maste device_printf(softc->dev, "Assign IRQ %u to admin proc \n", 968493d26c5SEd Maste rx_vectors); 969493d26c5SEd Maste if (rc) { 970493d26c5SEd Maste device_printf(iflib_get_dev(ctx), "Failed to register admin handler"); 971493d26c5SEd Maste i = softc->rx_rings_count; 972493d26c5SEd Maste goto fail; 973493d26c5SEd Maste } 974493d26c5SEd Maste AQ_DBG_EXIT(0); 975493d26c5SEd Maste return (0); 976493d26c5SEd Maste 977493d26c5SEd Maste fail: 978493d26c5SEd Maste for (; i >= 0; i--) 979493d26c5SEd Maste iflib_irq_free(ctx, &softc->rx_rings[i]->irq); 980493d26c5SEd Maste AQ_DBG_EXIT(rc); 981493d26c5SEd Maste return (rc); 982493d26c5SEd Maste } 983493d26c5SEd Maste 984493d26c5SEd Maste static bool aq_is_vlan_promisc_required(struct aq_dev *softc) 985493d26c5SEd Maste { 986493d26c5SEd Maste int vlan_tag_count; 987493d26c5SEd Maste 988493d26c5SEd Maste bit_count(softc->vlan_tags, 0, 4096, &vlan_tag_count); 989493d26c5SEd Maste 990493d26c5SEd Maste if (vlan_tag_count <= AQ_HW_VLAN_MAX_FILTERS) 991493d26c5SEd Maste return (false); 992493d26c5SEd Maste else 993493d26c5SEd Maste return (true); 994493d26c5SEd Maste 995493d26c5SEd Maste } 996493d26c5SEd Maste 997493d26c5SEd Maste static void aq_update_vlan_filters(struct aq_dev *softc) 998493d26c5SEd Maste { 999493d26c5SEd Maste struct aq_rx_filter_vlan aq_vlans[AQ_HW_VLAN_MAX_FILTERS]; 1000493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 1001493d26c5SEd Maste int bit_pos = 0; 1002493d26c5SEd Maste int vlan_tag = -1; 1003493d26c5SEd Maste int i; 1004493d26c5SEd Maste 1005493d26c5SEd Maste hw_atl_b0_hw_vlan_promisc_set(hw, true); 1006493d26c5SEd Maste for (i = 0; i < AQ_HW_VLAN_MAX_FILTERS; i++) { 1007493d26c5SEd Maste bit_ffs_at(softc->vlan_tags, bit_pos, 4096, &vlan_tag); 1008493d26c5SEd Maste if (vlan_tag != -1) { 1009493d26c5SEd Maste aq_vlans[i].enable = true; 1010493d26c5SEd Maste aq_vlans[i].location = i; 1011493d26c5SEd Maste aq_vlans[i].queue = 0xFF; 1012493d26c5SEd Maste aq_vlans[i].vlan_id = vlan_tag; 1013493d26c5SEd Maste bit_pos = vlan_tag; 1014493d26c5SEd Maste } else { 1015493d26c5SEd Maste aq_vlans[i].enable = false; 1016493d26c5SEd Maste } 1017493d26c5SEd Maste } 1018493d26c5SEd Maste 1019493d26c5SEd Maste hw_atl_b0_hw_vlan_set(hw, aq_vlans); 1020493d26c5SEd Maste hw_atl_b0_hw_vlan_promisc_set(hw, aq_is_vlan_promisc_required(softc)); 1021493d26c5SEd Maste } 1022493d26c5SEd Maste 1023493d26c5SEd Maste /* VLAN support */ 1024493d26c5SEd Maste static void aq_if_vlan_register(if_ctx_t ctx, uint16_t vtag) 1025493d26c5SEd Maste { 1026493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 1027493d26c5SEd Maste 1028493d26c5SEd Maste AQ_DBG_ENTERA("%d", vtag); 1029493d26c5SEd Maste 1030493d26c5SEd Maste bit_set(softc->vlan_tags, vtag); 1031493d26c5SEd Maste 1032493d26c5SEd Maste aq_update_vlan_filters(softc); 1033493d26c5SEd Maste 1034493d26c5SEd Maste AQ_DBG_EXIT(0); 1035493d26c5SEd Maste } 1036493d26c5SEd Maste 1037493d26c5SEd Maste static void aq_if_vlan_unregister(if_ctx_t ctx, uint16_t vtag) 1038493d26c5SEd Maste { 1039493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 1040493d26c5SEd Maste 1041493d26c5SEd Maste AQ_DBG_ENTERA("%d", vtag); 1042493d26c5SEd Maste 1043493d26c5SEd Maste bit_clear(softc->vlan_tags, vtag); 1044493d26c5SEd Maste 1045493d26c5SEd Maste aq_update_vlan_filters(softc); 1046493d26c5SEd Maste 1047493d26c5SEd Maste AQ_DBG_EXIT(0); 1048493d26c5SEd Maste } 1049493d26c5SEd Maste 1050493d26c5SEd Maste static void aq_if_led_func(if_ctx_t ctx, int onoff) 1051493d26c5SEd Maste { 1052493d26c5SEd Maste struct aq_dev *softc = iflib_get_softc(ctx); 1053493d26c5SEd Maste struct aq_hw *hw = &softc->hw; 1054493d26c5SEd Maste 1055493d26c5SEd Maste AQ_DBG_ENTERA("%d", onoff); 1056493d26c5SEd Maste if (hw->fw_ops && hw->fw_ops->led_control) 1057493d26c5SEd Maste hw->fw_ops->led_control(hw, onoff); 1058493d26c5SEd Maste 1059493d26c5SEd Maste AQ_DBG_EXIT(0); 1060493d26c5SEd Maste } 1061493d26c5SEd Maste 1062493d26c5SEd Maste static int aq_hw_capabilities(struct aq_dev *softc) 1063493d26c5SEd Maste { 1064493d26c5SEd Maste 1065493d26c5SEd Maste if (pci_get_vendor(softc->dev) != AQUANTIA_VENDOR_ID) 1066493d26c5SEd Maste return (ENXIO); 1067493d26c5SEd Maste 1068493d26c5SEd Maste switch (pci_get_device(softc->dev)) { 1069493d26c5SEd Maste case AQ_DEVICE_ID_D100: 1070493d26c5SEd Maste case AQ_DEVICE_ID_AQC100: 1071493d26c5SEd Maste case AQ_DEVICE_ID_AQC100S: 1072493d26c5SEd Maste softc->media_type = AQ_MEDIA_TYPE_FIBRE; 1073493d26c5SEd Maste softc->link_speeds = AQ_LINK_ALL & ~AQ_LINK_10G; 1074493d26c5SEd Maste break; 1075493d26c5SEd Maste 1076493d26c5SEd Maste case AQ_DEVICE_ID_0001: 1077493d26c5SEd Maste case AQ_DEVICE_ID_D107: 1078493d26c5SEd Maste case AQ_DEVICE_ID_AQC107: 1079493d26c5SEd Maste case AQ_DEVICE_ID_AQC107S: 1080493d26c5SEd Maste softc->media_type = AQ_MEDIA_TYPE_TP; 1081493d26c5SEd Maste softc->link_speeds = AQ_LINK_ALL; 1082493d26c5SEd Maste break; 1083493d26c5SEd Maste 1084493d26c5SEd Maste case AQ_DEVICE_ID_D108: 1085493d26c5SEd Maste case AQ_DEVICE_ID_AQC108: 1086493d26c5SEd Maste case AQ_DEVICE_ID_AQC108S: 1087493d26c5SEd Maste case AQ_DEVICE_ID_AQC111: 1088493d26c5SEd Maste case AQ_DEVICE_ID_AQC111S: 1089493d26c5SEd Maste softc->media_type = AQ_MEDIA_TYPE_TP; 1090493d26c5SEd Maste softc->link_speeds = AQ_LINK_ALL & ~AQ_LINK_10G; 1091493d26c5SEd Maste break; 1092493d26c5SEd Maste 1093493d26c5SEd Maste case AQ_DEVICE_ID_D109: 1094493d26c5SEd Maste case AQ_DEVICE_ID_AQC109: 1095493d26c5SEd Maste case AQ_DEVICE_ID_AQC109S: 1096493d26c5SEd Maste case AQ_DEVICE_ID_AQC112: 1097493d26c5SEd Maste case AQ_DEVICE_ID_AQC112S: 1098493d26c5SEd Maste softc->media_type = AQ_MEDIA_TYPE_TP; 1099493d26c5SEd Maste softc->link_speeds = AQ_LINK_ALL & ~(AQ_LINK_10G | AQ_LINK_5G); 1100493d26c5SEd Maste break; 1101493d26c5SEd Maste 1102493d26c5SEd Maste default: 1103493d26c5SEd Maste return (ENXIO); 1104493d26c5SEd Maste } 1105493d26c5SEd Maste 1106493d26c5SEd Maste return (0); 1107493d26c5SEd Maste } 1108493d26c5SEd Maste 1109493d26c5SEd Maste static int aq_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS) 1110493d26c5SEd Maste { 1111493d26c5SEd Maste struct aq_dev *softc = (struct aq_dev *)arg1; 1112493d26c5SEd Maste device_t dev = softc->dev; 1113493d26c5SEd Maste struct sbuf *buf; 1114493d26c5SEd Maste int error = 0; 1115493d26c5SEd Maste 1116493d26c5SEd Maste buf = sbuf_new_for_sysctl(NULL, NULL, 256, req); 1117493d26c5SEd Maste if (!buf) { 1118493d26c5SEd Maste device_printf(dev, "Could not allocate sbuf for output.\n"); 1119493d26c5SEd Maste return (ENOMEM); 1120493d26c5SEd Maste } 1121493d26c5SEd Maste 1122493d26c5SEd Maste /* Print out the redirection table */ 1123493d26c5SEd Maste sbuf_cat(buf, "\nRSS Indirection table:\n"); 1124493d26c5SEd Maste for (int i = 0; i < HW_ATL_RSS_INDIRECTION_TABLE_MAX; i++) { 1125493d26c5SEd Maste sbuf_printf(buf, "%d ", softc->rss_table[i]); 1126493d26c5SEd Maste if ((i+1) % 10 == 0) 1127493d26c5SEd Maste sbuf_printf(buf, "\n"); 1128493d26c5SEd Maste } 1129493d26c5SEd Maste 1130493d26c5SEd Maste sbuf_cat(buf, "\nRSS Key:\n"); 1131493d26c5SEd Maste for (int i = 0; i < HW_ATL_RSS_HASHKEY_SIZE; i++) { 1132493d26c5SEd Maste sbuf_printf(buf, "0x%02x ", softc->rss_key[i]); 1133493d26c5SEd Maste } 1134493d26c5SEd Maste sbuf_printf(buf, "\n"); 1135493d26c5SEd Maste 1136493d26c5SEd Maste error = sbuf_finish(buf); 1137493d26c5SEd Maste if (error) 1138493d26c5SEd Maste device_printf(dev, "Error finishing sbuf: %d\n", error); 1139493d26c5SEd Maste 1140493d26c5SEd Maste sbuf_delete(buf); 1141493d26c5SEd Maste 1142493d26c5SEd Maste return (0); 1143493d26c5SEd Maste } 1144493d26c5SEd Maste 1145493d26c5SEd Maste static int aq_sysctl_print_tx_head(SYSCTL_HANDLER_ARGS) 1146493d26c5SEd Maste { 1147493d26c5SEd Maste struct aq_ring *ring = arg1; 1148493d26c5SEd Maste int error = 0; 1149493d26c5SEd Maste unsigned int val; 1150493d26c5SEd Maste 1151493d26c5SEd Maste if (!ring) 1152493d26c5SEd Maste return (0); 1153493d26c5SEd Maste 1154493d26c5SEd Maste val = tdm_tx_desc_head_ptr_get(&ring->dev->hw, ring->index); 1155493d26c5SEd Maste 1156493d26c5SEd Maste error = sysctl_handle_int(oidp, &val, 0, req); 1157493d26c5SEd Maste if (error || !req->newptr) 1158493d26c5SEd Maste return (error); 1159493d26c5SEd Maste 1160493d26c5SEd Maste return (0); 1161493d26c5SEd Maste } 1162493d26c5SEd Maste 1163493d26c5SEd Maste static int aq_sysctl_print_tx_tail(SYSCTL_HANDLER_ARGS) 1164493d26c5SEd Maste { 1165493d26c5SEd Maste struct aq_ring *ring = arg1; 1166493d26c5SEd Maste int error = 0; 1167493d26c5SEd Maste unsigned int val; 1168493d26c5SEd Maste 1169493d26c5SEd Maste if (!ring) 1170493d26c5SEd Maste return (0); 1171493d26c5SEd Maste 1172493d26c5SEd Maste val = reg_tx_dma_desc_tail_ptr_get(&ring->dev->hw, ring->index); 1173493d26c5SEd Maste 1174493d26c5SEd Maste error = sysctl_handle_int(oidp, &val, 0, req); 1175493d26c5SEd Maste if (error || !req->newptr) 1176493d26c5SEd Maste return (error); 1177493d26c5SEd Maste 1178493d26c5SEd Maste return (0); 1179493d26c5SEd Maste } 1180493d26c5SEd Maste 1181493d26c5SEd Maste static int aq_sysctl_print_rx_head(SYSCTL_HANDLER_ARGS) 1182493d26c5SEd Maste { 1183493d26c5SEd Maste struct aq_ring *ring = arg1; 1184493d26c5SEd Maste int error = 0; 1185493d26c5SEd Maste unsigned int val; 1186493d26c5SEd Maste 1187493d26c5SEd Maste if (!ring) 1188493d26c5SEd Maste return (0); 1189493d26c5SEd Maste 1190493d26c5SEd Maste val = rdm_rx_desc_head_ptr_get(&ring->dev->hw, ring->index); 1191493d26c5SEd Maste 1192493d26c5SEd Maste error = sysctl_handle_int(oidp, &val, 0, req); 1193493d26c5SEd Maste if (error || !req->newptr) 1194493d26c5SEd Maste return (error); 1195493d26c5SEd Maste 1196493d26c5SEd Maste return (0); 1197493d26c5SEd Maste } 1198493d26c5SEd Maste 1199493d26c5SEd Maste static int aq_sysctl_print_rx_tail(SYSCTL_HANDLER_ARGS) 1200493d26c5SEd Maste { 1201493d26c5SEd Maste struct aq_ring *ring = arg1; 1202493d26c5SEd Maste int error = 0; 1203493d26c5SEd Maste unsigned int val; 1204493d26c5SEd Maste 1205493d26c5SEd Maste if (!ring) 1206493d26c5SEd Maste return (0); 1207493d26c5SEd Maste 1208493d26c5SEd Maste val = reg_rx_dma_desc_tail_ptr_get(&ring->dev->hw, ring->index); 1209493d26c5SEd Maste 1210493d26c5SEd Maste error = sysctl_handle_int(oidp, &val, 0, req); 1211493d26c5SEd Maste if (error || !req->newptr) 1212493d26c5SEd Maste return (error); 1213493d26c5SEd Maste 1214493d26c5SEd Maste return (0); 1215493d26c5SEd Maste } 1216493d26c5SEd Maste 1217493d26c5SEd Maste static void aq_add_stats_sysctls(struct aq_dev *softc) 1218493d26c5SEd Maste { 1219493d26c5SEd Maste device_t dev = softc->dev; 1220493d26c5SEd Maste struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 1221493d26c5SEd Maste struct sysctl_oid *tree = device_get_sysctl_tree(dev); 1222493d26c5SEd Maste struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 1223493d26c5SEd Maste struct aq_stats_s *stats = &softc->curr_stats; 1224493d26c5SEd Maste struct sysctl_oid *stat_node, *queue_node; 1225493d26c5SEd Maste struct sysctl_oid_list *stat_list, *queue_list; 1226493d26c5SEd Maste 1227493d26c5SEd Maste #define QUEUE_NAME_LEN 32 1228493d26c5SEd Maste char namebuf[QUEUE_NAME_LEN]; 1229493d26c5SEd Maste /* RSS configuration */ 1230493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config", 1231493d26c5SEd Maste CTLTYPE_STRING | CTLFLAG_RD, softc, 0, 1232493d26c5SEd Maste aq_sysctl_print_rss_config, "A", "Prints RSS Configuration"); 1233493d26c5SEd Maste 1234493d26c5SEd Maste /* Driver Statistics */ 1235493d26c5SEd Maste for (int i = 0; i < softc->tx_rings_count; i++) { 1236493d26c5SEd Maste struct aq_ring *ring = softc->tx_rings[i]; 1237493d26c5SEd Maste snprintf(namebuf, QUEUE_NAME_LEN, "tx_queue%d", i); 1238493d26c5SEd Maste queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 1239493d26c5SEd Maste CTLFLAG_RD, NULL, "Queue Name"); 1240493d26c5SEd Maste queue_list = SYSCTL_CHILDREN(queue_node); 1241493d26c5SEd Maste 1242493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_pkts", 1243493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.tx_pkts), "TX Packets"); 1244493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 1245493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.tx_bytes), "TX Octets"); 1246493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_drops", 1247493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.tx_drops), "TX Drops"); 1248493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_queue_full", 1249493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.tx_queue_full), "TX Queue Full"); 1250493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "tx_head", 1251493d26c5SEd Maste CTLTYPE_UINT | CTLFLAG_RD, ring, 0, 1252493d26c5SEd Maste aq_sysctl_print_tx_head, "IU", "ring head pointer"); 1253493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "tx_tail", 1254493d26c5SEd Maste CTLTYPE_UINT | CTLFLAG_RD, ring, 0, 1255493d26c5SEd Maste aq_sysctl_print_tx_tail, "IU", "ring tail pointer"); 1256493d26c5SEd Maste } 1257493d26c5SEd Maste 1258493d26c5SEd Maste for (int i = 0; i < softc->rx_rings_count; i++) { 1259493d26c5SEd Maste struct aq_ring *ring = softc->rx_rings[i]; 1260493d26c5SEd Maste snprintf(namebuf, QUEUE_NAME_LEN, "rx_queue%d", i); 1261493d26c5SEd Maste queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 1262493d26c5SEd Maste CTLFLAG_RD, NULL, "Queue Name"); 1263493d26c5SEd Maste queue_list = SYSCTL_CHILDREN(queue_node); 1264493d26c5SEd Maste 1265493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_pkts", 1266493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.rx_pkts), "RX Packets"); 1267493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 1268493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.rx_bytes), "TX Octets"); 1269493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "jumbo_pkts", 1270493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.jumbo_pkts), "Jumbo Packets"); 1271493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_err", 1272493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.rx_err), "RX Errors"); 1273493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irq", 1274493d26c5SEd Maste CTLFLAG_RD, &(ring->stats.irq), "RX interrupts"); 1275493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rx_head", 1276493d26c5SEd Maste CTLTYPE_UINT | CTLFLAG_RD, ring, 0, 1277493d26c5SEd Maste aq_sysctl_print_rx_head, "IU", "ring head pointer"); 1278493d26c5SEd Maste SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rx_tail", 1279493d26c5SEd Maste CTLTYPE_UINT | CTLFLAG_RD, ring, 0, 1280493d26c5SEd Maste aq_sysctl_print_rx_tail, "IU", " ring tail pointer"); 1281493d26c5SEd Maste } 1282493d26c5SEd Maste 1283493d26c5SEd Maste stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 1284493d26c5SEd Maste CTLFLAG_RD, NULL, "Statistics (read from HW registers)"); 1285493d26c5SEd Maste stat_list = SYSCTL_CHILDREN(stat_node); 1286493d26c5SEd Maste 1287493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", 1288493d26c5SEd Maste CTLFLAG_RD, &stats->prc, "Good Packets Received"); 1289493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_pkts_rcvd", 1290493d26c5SEd Maste CTLFLAG_RD, &stats->uprc, "Unicast Packets Received"); 1291493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", 1292493d26c5SEd Maste CTLFLAG_RD, &stats->mprc, "Multicast Packets Received"); 1293493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", 1294493d26c5SEd Maste CTLFLAG_RD, &stats->bprc, "Broadcast Packets Received"); 1295493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rsc_pkts_rcvd", 1296493d26c5SEd Maste CTLFLAG_RD, &stats->cprc, "Coalesced Packets Received"); 1297493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "err_pkts_rcvd", 1298493d26c5SEd Maste CTLFLAG_RD, &stats->erpr, "Errors of Packet Receive"); 1299493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "drop_pkts_dma", 1300493d26c5SEd Maste CTLFLAG_RD, &stats->dpc, "Dropped Packets in DMA"); 1301493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", 1302493d26c5SEd Maste CTLFLAG_RD, &stats->brc, "Good Octets Received"); 1303493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_octets_rcvd", 1304493d26c5SEd Maste CTLFLAG_RD, &stats->ubrc, "Unicast Octets Received"); 1305493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_octets_rcvd", 1306493d26c5SEd Maste CTLFLAG_RD, &stats->mbrc, "Multicast Octets Received"); 1307493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_octets_rcvd", 1308493d26c5SEd Maste CTLFLAG_RD, &stats->bbrc, "Broadcast Octets Received"); 1309493d26c5SEd Maste 1310493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", 1311493d26c5SEd Maste CTLFLAG_RD, &stats->ptc, "Good Packets Transmitted"); 1312493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_pkts_txd", 1313493d26c5SEd Maste CTLFLAG_RD, &stats->uptc, "Unicast Packets Transmitted"); 1314493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", 1315493d26c5SEd Maste CTLFLAG_RD, &stats->mptc, "Multicast Packets Transmitted"); 1316493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", 1317493d26c5SEd Maste CTLFLAG_RD, &stats->bptc, "Broadcast Packets Transmitted"); 1318493d26c5SEd Maste 1319493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "err_pkts_txd", 1320493d26c5SEd Maste CTLFLAG_RD, &stats->erpt, "Errors of Packet Transmit"); 1321493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", 1322493d26c5SEd Maste CTLFLAG_RD, &stats->btc, "Good Octets Transmitted"); 1323493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_octets_txd", 1324493d26c5SEd Maste CTLFLAG_RD, &stats->ubtc, "Unicast Octets Transmitted"); 1325493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_octets_txd", 1326493d26c5SEd Maste CTLFLAG_RD, &stats->mbtc, "Multicast Octets Transmitted"); 1327493d26c5SEd Maste SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_octets_txd", 1328493d26c5SEd Maste CTLFLAG_RD, &stats->bbtc, "Broadcast Octets Transmitted"); 1329493d26c5SEd Maste } 1330