#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bitstring.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_var.h>
#include <net/iflib.h>
#include "aq_common.h"
#include "aq_device.h"
#include "aq_ring.h"
#include "aq_dbg.h"
#include "aq_hw.h"
#include "aq_hw_llh.h"
int
aq_update_hw_stats(aq_dev_t *aq_dev)
{
struct aq_hw *hw = &aq_dev->hw;
struct aq_hw_fw_mbox mbox;
aq_hw_mpi_read_stats(hw, &mbox);
#define AQ_SDELTA(_N_) (aq_dev->curr_stats._N_ += \
mbox.stats._N_ - aq_dev->last_stats._N_)
if (aq_dev->linkup) {
AQ_SDELTA(uprc);
AQ_SDELTA(mprc);
AQ_SDELTA(bprc);
AQ_SDELTA(cprc);
AQ_SDELTA(erpt);
AQ_SDELTA(uptc);
AQ_SDELTA(mptc);
AQ_SDELTA(bptc);
AQ_SDELTA(erpr);
AQ_SDELTA(ubrc);
AQ_SDELTA(ubtc);
AQ_SDELTA(mbrc);
AQ_SDELTA(mbtc);
AQ_SDELTA(bbrc);
AQ_SDELTA(bbtc);
AQ_SDELTA(ptc);
AQ_SDELTA(prc);
AQ_SDELTA(dpc);
aq_dev->curr_stats.brc = aq_dev->curr_stats.ubrc +
aq_dev->curr_stats.mbrc + aq_dev->curr_stats.bbrc;
aq_dev->curr_stats.btc = aq_dev->curr_stats.ubtc +
aq_dev->curr_stats.mbtc + aq_dev->curr_stats.bbtc;
}
#undef AQ_SDELTA
memcpy(&aq_dev->last_stats, &mbox.stats, sizeof(mbox.stats));
return (0);
}
void
aq_if_update_admin_status(if_ctx_t ctx)
{
aq_dev_t *aq_dev = iflib_get_softc(ctx);
struct aq_hw *hw = &aq_dev->hw;
uint32_t link_speed;
struct aq_hw_fc_info fc_neg;
aq_hw_get_link_state(hw, &link_speed, &fc_neg);
if (link_speed && !aq_dev->linkup) {
device_printf(aq_dev->dev, "atlantic: link UP: speed=%d\n", link_speed);
aq_dev->linkup = 1;
#if __FreeBSD__ >= 12
if (link_speed < 1000 && (iflib_get_softc_ctx(ctx)->isc_capabilities & (IFCAP_TSO4 | IFCAP_TSO6))) {
iflib_get_softc_ctx(ctx)->isc_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);
device_printf(aq_dev->dev, "atlantic: TSO disabled for link speed < 1G");
}else{
iflib_get_softc_ctx(ctx)->isc_capabilities |= (IFCAP_TSO4 | IFCAP_TSO6);
}
#endif
rpb_rx_xoff_en_per_tc_set(hw, fc_neg.fc_rx, 0);
iflib_link_state_change(ctx, LINK_STATE_UP, IF_Mbps(link_speed));
aq_mediastatus_update(aq_dev, link_speed, &fc_neg);
aq_hw_interrupt_moderation_set(hw);
} else if (link_speed == 0U && aq_dev->linkup) {
device_printf(aq_dev->dev, "atlantic: link DOWN\n");
aq_dev->linkup = 0;
rpb_rx_xoff_en_per_tc_set(hw, 0, 0);
iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
aq_mediastatus_update(aq_dev, link_speed, &fc_neg);
}
aq_update_hw_stats(aq_dev);
}
int
aq_isr_rx(void *arg)
{
struct aq_ring *ring = arg;
struct aq_dev *aq_dev = ring->dev;
struct aq_hw *hw = &aq_dev->hw;
itr_irq_status_clearlsw_set(hw, BIT(ring->msix));
ring->stats.irq++;
return (FILTER_SCHEDULE_THREAD);
}
int
aq_linkstat_isr(void *arg)
{
aq_dev_t *aq_dev = arg;
struct aq_hw *hw = &aq_dev->hw;
itr_irq_status_clearlsw_set(hw, aq_dev->msix);
iflib_admin_intr_deferred(aq_dev->ctx);
return (FILTER_HANDLED);
}