/*1* aQuantia Corporation Network Driver2* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7*8* (1) Redistributions of source code must retain the above9* copyright notice, this list of conditions and the following10* disclaimer.11*12* (2) Redistributions in binary form must reproduce the above13* copyright notice, this list of conditions and the following14* disclaimer in the documentation and/or other materials provided15* with the distribution.16*17* (3)The name of the author may not be used to endorse or promote18* products derived from this software without specific prior19* written permission.20*21* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS22* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED23* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY25* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE27* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS28* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,29* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING30* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS31* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.32*/333435#include <sys/cdefs.h>36__FBSDID("$FreeBSD$");3738#include <sys/param.h>39#include <sys/bitstring.h>40#include <sys/kernel.h>41#include <sys/socket.h>42#include <net/ethernet.h>43#include <net/if.h>44#include <net/if_dl.h>45#include <net/if_media.h>46#include <net/if_var.h>47#include <net/iflib.h>4849#include "aq_common.h"50#include "aq_device.h"51#include "aq_ring.h"52#include "aq_dbg.h"53#include "aq_hw.h"54#include "aq_hw_llh.h"5556int57aq_update_hw_stats(aq_dev_t *aq_dev)58{59struct aq_hw *hw = &aq_dev->hw;60struct aq_hw_fw_mbox mbox;6162aq_hw_mpi_read_stats(hw, &mbox);6364#define AQ_SDELTA(_N_) (aq_dev->curr_stats._N_ += \65mbox.stats._N_ - aq_dev->last_stats._N_)66if (aq_dev->linkup) {67AQ_SDELTA(uprc);68AQ_SDELTA(mprc);69AQ_SDELTA(bprc);70AQ_SDELTA(cprc);71AQ_SDELTA(erpt);7273AQ_SDELTA(uptc);74AQ_SDELTA(mptc);75AQ_SDELTA(bptc);76AQ_SDELTA(erpr);7778AQ_SDELTA(ubrc);79AQ_SDELTA(ubtc);80AQ_SDELTA(mbrc);81AQ_SDELTA(mbtc);82AQ_SDELTA(bbrc);83AQ_SDELTA(bbtc);8485AQ_SDELTA(ptc);86AQ_SDELTA(prc);8788AQ_SDELTA(dpc);8990aq_dev->curr_stats.brc = aq_dev->curr_stats.ubrc +91aq_dev->curr_stats.mbrc + aq_dev->curr_stats.bbrc;92aq_dev->curr_stats.btc = aq_dev->curr_stats.ubtc +93aq_dev->curr_stats.mbtc + aq_dev->curr_stats.bbtc;9495}96#undef AQ_SDELTA9798memcpy(&aq_dev->last_stats, &mbox.stats, sizeof(mbox.stats));99100return (0);101}102103104void105aq_if_update_admin_status(if_ctx_t ctx)106{107aq_dev_t *aq_dev = iflib_get_softc(ctx);108struct aq_hw *hw = &aq_dev->hw;109uint32_t link_speed;110111// AQ_DBG_ENTER();112113struct aq_hw_fc_info fc_neg;114aq_hw_get_link_state(hw, &link_speed, &fc_neg);115// AQ_DBG_PRINT(" link_speed=%d aq_dev->linkup=%d", link_speed, aq_dev->linkup);116if (link_speed && !aq_dev->linkup) { /* link was DOWN */117device_printf(aq_dev->dev, "atlantic: link UP: speed=%d\n", link_speed);118119aq_dev->linkup = 1;120121#if __FreeBSD__ >= 12122/* Disable TSO if link speed < 1G */123if (link_speed < 1000 && (iflib_get_softc_ctx(ctx)->isc_capabilities & (IFCAP_TSO4 | IFCAP_TSO6))) {124iflib_get_softc_ctx(ctx)->isc_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);125device_printf(aq_dev->dev, "atlantic: TSO disabled for link speed < 1G");126}else{127iflib_get_softc_ctx(ctx)->isc_capabilities |= (IFCAP_TSO4 | IFCAP_TSO6);128}129#endif130/* turn on/off RX Pause in RPB */131rpb_rx_xoff_en_per_tc_set(hw, fc_neg.fc_rx, 0);132133134iflib_link_state_change(ctx, LINK_STATE_UP, IF_Mbps(link_speed));135aq_mediastatus_update(aq_dev, link_speed, &fc_neg);136137/* update ITR settings according new link speed */138aq_hw_interrupt_moderation_set(hw);139} else if (link_speed == 0U && aq_dev->linkup) { /* link was UP */140device_printf(aq_dev->dev, "atlantic: link DOWN\n");141142aq_dev->linkup = 0;143144/* turn off RX Pause in RPB */145rpb_rx_xoff_en_per_tc_set(hw, 0, 0);146147iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);148aq_mediastatus_update(aq_dev, link_speed, &fc_neg);149}150151aq_update_hw_stats(aq_dev);152// AQ_DBG_EXIT(0);153}154155/**************************************************************************/156/* interrupt service routine (Top half) */157/**************************************************************************/158int159aq_isr_rx(void *arg)160{161struct aq_ring *ring = arg;162struct aq_dev *aq_dev = ring->dev;163struct aq_hw *hw = &aq_dev->hw;164165/* clear interrupt status */166itr_irq_status_clearlsw_set(hw, BIT(ring->msix));167ring->stats.irq++;168return (FILTER_SCHEDULE_THREAD);169}170171/**************************************************************************/172/* interrupt service routine (Top half) */173/**************************************************************************/174int175aq_linkstat_isr(void *arg)176{177aq_dev_t *aq_dev = arg;178struct aq_hw *hw = &aq_dev->hw;179180/* clear interrupt status */181itr_irq_status_clearlsw_set(hw, aq_dev->msix);182183iflib_admin_intr_deferred(aq_dev->ctx);184185return (FILTER_HANDLED);186}187188189