/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
/* File hw_atl_b0.c: Definition of Atlantic hardware specific functions. */
#include "../aq_hw.h"
#include "../aq_hw_utils.h"
#include "../aq_ring.h"
#include "hw_atl_b0.h"
#include "hw_atl_utils.h"
#include "hw_atl_llh.h"
#include "hw_atl_b0_internal.h"
#include "hw_atl_llh_internal.h"
static int hw_atl_b0_get_hw_caps(struct aq_hw_s *self,
struct aq_hw_caps_s *aq_hw_caps,
unsigned short device,
unsigned short subsystem_device)
{
memcpy(aq_hw_caps, &hw_atl_b0_hw_caps_, sizeof(*aq_hw_caps));
if (device == HW_ATL_DEVICE_ID_D108 && subsystem_device == 0x0001)
aq_hw_caps->link_speed_msk &= ~HW_ATL_B0_RATE_10G;
if (device == HW_ATL_DEVICE_ID_D109 && subsystem_device == 0x0001) {
aq_hw_caps->link_speed_msk &= ~HW_ATL_B0_RATE_10G;
aq_hw_caps->link_speed_msk &= ~HW_ATL_B0_RATE_5G;
}
return 0;
}
static struct aq_hw_s *hw_atl_b0_create(struct aq_pci_func_s *aq_pci_func,
unsigned int port,
struct aq_hw_ops *ops)
{
struct hw_atl_s *self = NULL;
self = kzalloc(sizeof(*self), GFP_KERNEL);
if (!self)
goto err_exit;
self->base.aq_pci_func = aq_pci_func;
self->base.not_ff_addr = 0x10U;
err_exit:
return (struct aq_hw_s *)self;
}
static void hw_atl_b0_destroy(struct aq_hw_s *self)
{
kfree(self);
}
static int hw_atl_b0_hw_reset(struct aq_hw_s *self)
{
int err = 0;
glb_glb_reg_res_dis_set(self, 1U);
pci_pci_reg_res_dis_set(self, 0U);
rx_rx_reg_res_dis_set(self, 0U);
tx_tx_reg_res_dis_set(self, 0U);
HW_ATL_FLUSH();
glb_soft_res_set(self, 1);
/* check 10 times by 1ms */
AQ_HW_WAIT_FOR(glb_soft_res_get(self) == 0, 1000U, 10U);
if (err < 0)
goto err_exit;
itr_irq_reg_res_dis_set(self, 0U);
itr_res_irq_set(self, 1U);
/* check 10 times by 1ms */
AQ_HW_WAIT_FOR(itr_res_irq_get(self) == 0, 1000U, 10U);
if (err < 0)
goto err_exit;
hw_atl_utils_mpi_set(self, MPI_RESET, 0x0U);
err = aq_hw_err_from_flags(self);
err_exit:
return err;
}
static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
{
u32 tc = 0U;
u32 buff_size = 0U;
unsigned int i_priority = 0U;
bool is_rx_flow_control = false;
/* TPS Descriptor rate init */
tps_tx_pkt_shed_desc_rate_curr_time_res_set(self, 0x0U);
tps_tx_pkt_shed_desc_rate_lim_set(self, 0xA);
/* TPS VM init */
tps_tx_pkt_shed_desc_vm_arb_mode_set(self, 0U);
/* TPS TC credits init */
tps_tx_pkt_shed_desc_tc_arb_mode_set(self, 0U);
tps_tx_pkt_shed_data_arb_mode_set(self, 0U);
tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF, 0U);
tps_tx_pkt_shed_tc_data_weight_set(self, 0x64, 0U);
tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0x50, 0U);
tps_tx_pkt_shed_desc_tc_weight_set(self, 0x1E, 0U);
/* Tx buf size */
buff_size = HW_ATL_B0_TXBUF_MAX;
tpb_tx_pkt_buff_size_per_tc_set(self, buff_size, tc);
tpb_tx_buff_hi_threshold_per_tc_set(self,
(buff_size * (1024 / 32U) * 66U) /
100U, tc);
tpb_tx_buff_lo_threshold_per_tc_set(self,
(buff_size * (1024 / 32U) * 50U) /
100U, tc);
/* QoS Rx buf size per TC */
tc = 0;
is_rx_flow_control = (AQ_NIC_FC_RX & self->aq_nic_cfg->flow_control);
buff_size = HW_ATL_B0_RXBUF_MAX;
rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc);
rpb_rx_buff_hi_threshold_per_tc_set(self,
(buff_size *
(1024U / 32U) * 66U) /
100U, tc);
rpb_rx_buff_lo_threshold_per_tc_set(self,
(buff_size *
(1024U / 32U) * 50U) /
100U, tc);
rpb_rx_xoff_en_per_tc_set(self, is_rx_flow_control ?