Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,26 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# aQuantia device configuration
#
config NET_VENDOR_AQUANTIA
bool "aQuantia devices"
default y
help
Set this to y if you have an Ethernet network cards that uses the aQuantia
AQC107/AQC108 chipset.
This option does not build any drivers; it causes the aQuantia
drivers that can be built to appear in the list of Ethernet drivers.
if NET_VENDOR_AQUANTIA
config AQTION
tristate "aQuantia AQtion(tm) Support"
depends on PCI
depends on MACSEC || MACSEC=n
help
This enables the support for the aQuantia AQtion(tm) Ethernet card.
endif # NET_VENDOR_AQUANTIA
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the aQuantia device drivers.
#
obj-$(CONFIG_AQTION) += atlantic/
@@ -0,0 +1,36 @@
# SPDX-License-Identifier: GPL-2.0-only
################################################################################
#
# aQuantia Ethernet Controller AQtion Linux Driver
# Copyright(c) 2014-2017 aQuantia Corporation.
#
################################################################################
obj-$(CONFIG_AQTION) += atlantic.o
ccflags-y += -I$(src)
atlantic-objs := aq_main.o \
aq_nic.o \
aq_pci_func.o \
aq_vec.o \
aq_ring.o \
aq_hw_utils.o \
aq_ethtool.o \
aq_drvinfo.o \
aq_filters.o \
aq_phy.o \
hw_atl/hw_atl_a0.o \
hw_atl/hw_atl_b0.o \
hw_atl/hw_atl_utils.o \
hw_atl/hw_atl_utils_fw2x.o \
hw_atl/hw_atl_llh.o \
hw_atl2/hw_atl2.o \
hw_atl2/hw_atl2_utils.o \
hw_atl2/hw_atl2_utils_fw.o \
hw_atl2/hw_atl2_llh.o \
macsec/macsec_api.o
atlantic-$(CONFIG_MACSEC) += aq_macsec.o
atlantic-$(CONFIG_PTP_1588_CLOCK) += aq_ptp.o
@@ -0,0 +1,86 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File aq_cfg.h: Definition of configuration parameters and constants. */
#ifndef AQ_CFG_H
#define AQ_CFG_H
#define AQ_CFG_VECS_DEF 8U
#define AQ_CFG_TCS_DEF 1U
#define AQ_CFG_TXDS_DEF 4096U
#define AQ_CFG_RXDS_DEF 2048U
#define AQ_CFG_IS_POLLING_DEF 0U
#define AQ_CFG_FORCE_INTX 0U
#define AQ_CFG_INTERRUPT_MODERATION_OFF 0
#define AQ_CFG_INTERRUPT_MODERATION_ON 1
#define AQ_CFG_INTERRUPT_MODERATION_AUTO 0xFFFFU
#define AQ_CFG_INTERRUPT_MODERATION_USEC_MAX (0x1FF * 2)
#define AQ_CFG_IRQ_MASK 0x3FFU
#define AQ_CFG_VECS_MAX 8U
#define AQ_CFG_TCS_MAX 8U
#define AQ_CFG_TX_FRAME_MAX (16U * 1024U)
#define AQ_CFG_RX_FRAME_MAX (2U * 1024U)
#define AQ_CFG_TX_CLEAN_BUDGET 256U
#define AQ_CFG_RX_REFILL_THRES 32U
#define AQ_CFG_RX_HDR_SIZE 256U
#define AQ_CFG_RX_PAGEORDER 0U
#define AQ_CFG_XDP_PAGEORDER 2U
/* LRO */
#define AQ_CFG_IS_LRO_DEF 1U
/* RSS */
#define AQ_CFG_RSS_INDIRECTION_TABLE_MAX 64U
#define AQ_CFG_RSS_HASHKEY_SIZE 40U
#define AQ_CFG_IS_RSS_DEF 1U
#define AQ_CFG_NUM_RSS_QUEUES_DEF AQ_CFG_VECS_DEF
#define AQ_CFG_RSS_BASE_CPU_NUM_DEF 0U
#define AQ_CFG_PCI_FUNC_MSIX_IRQS 9U
#define AQ_CFG_PCI_FUNC_PORTS 2U
#define AQ_CFG_SERVICE_TIMER_INTERVAL (1 * HZ)
#define AQ_CFG_POLLING_TIMER_INTERVAL ((unsigned int)(2 * HZ))
#define AQ_CFG_SKB_FRAGS_MAX 32U
/* Number of descriptors available in one ring to resume this ring queue
*/
#define AQ_CFG_RESTART_DESC_THRES (AQ_CFG_SKB_FRAGS_MAX * 2)
/*#define AQ_CFG_MAC_ADDR_PERMANENT {0x30, 0x0E, 0xE3, 0x12, 0x34, 0x56}*/
#define AQ_CFG_FC_MODE AQ_NIC_FC_FULL
/* Default WOL modes used on initialization */
#define AQ_CFG_WOL_MODES WAKE_MAGIC
#define AQ_CFG_SPEED_MSK 0xFFFFU /* 0xFFFFU==auto_neg */
#define AQ_CFG_IS_AUTONEG_DEF 1U
#define AQ_CFG_MTU_DEF 1514U
#define AQ_CFG_LOCK_TRYS 100U
#define AQ_CFG_DRV_AUTHOR "Marvell"
#define AQ_CFG_DRV_DESC "Marvell (Aquantia) Corporation(R) Network Driver"
#define AQ_CFG_DRV_NAME "atlantic"
#endif /* AQ_CFG_H */
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_common.h: Basic includes for all files in project. */
#ifndef AQ_COMMON_H
#define AQ_COMMON_H
#include <linux/etherdevice.h>
#include <linux/pci.h>
#include <linux/if_vlan.h>
#include "aq_cfg.h"
#include "aq_utils.h"
#define PCI_VENDOR_ID_AQUANTIA 0x1D6A
#define AQ_DEVICE_ID_0001 0x0001
#define AQ_DEVICE_ID_D100 0xD100
#define AQ_DEVICE_ID_D107 0xD107
#define AQ_DEVICE_ID_D108 0xD108
#define AQ_DEVICE_ID_D109 0xD109
#define AQ_DEVICE_ID_AQC100 0x00B1
#define AQ_DEVICE_ID_AQC107 0x07B1
#define AQ_DEVICE_ID_AQC108 0x08B1
#define AQ_DEVICE_ID_AQC109 0x09B1
#define AQ_DEVICE_ID_AQC111 0x11B1
#define AQ_DEVICE_ID_AQC112 0x12B1
#define AQ_DEVICE_ID_AQC100S 0x80B1
#define AQ_DEVICE_ID_AQC107S 0x87B1
#define AQ_DEVICE_ID_AQC108S 0x88B1
#define AQ_DEVICE_ID_AQC109S 0x89B1
#define AQ_DEVICE_ID_AQC111S 0x91B1
#define AQ_DEVICE_ID_AQC112S 0x92B1
#define AQ_DEVICE_ID_AQC113DEV 0x00C0
#define AQ_DEVICE_ID_AQC113CS 0x94C0
#define AQ_DEVICE_ID_AQC113CA 0x34C0
#define AQ_DEVICE_ID_AQC114CS 0x93C0
#define AQ_DEVICE_ID_AQC113 0x04C0
#define AQ_DEVICE_ID_AQC113C 0x14C0
#define AQ_DEVICE_ID_AQC115C 0x12C0
#define AQ_DEVICE_ID_AQC116C 0x11C0
#define HW_ATL_NIC_NAME "Marvell (aQuantia) AQtion 10Gbit Network Adapter"
#define AQ_HWREV_ANY 0
#define AQ_HWREV_1 1
#define AQ_HWREV_2 2
#define AQ_NIC_RATE_10G BIT(0)
#define AQ_NIC_RATE_5G BIT(1)
#define AQ_NIC_RATE_2G5 BIT(2)
#define AQ_NIC_RATE_1G BIT(3)
#define AQ_NIC_RATE_100M BIT(4)
#define AQ_NIC_RATE_10M BIT(5)
#define AQ_NIC_RATE_1G_HALF BIT(6)
#define AQ_NIC_RATE_100M_HALF BIT(7)
#define AQ_NIC_RATE_10M_HALF BIT(8)
#define AQ_NIC_RATE_EEE_10G BIT(9)
#define AQ_NIC_RATE_EEE_5G BIT(10)
#define AQ_NIC_RATE_EEE_2G5 BIT(11)
#define AQ_NIC_RATE_EEE_1G BIT(12)
#define AQ_NIC_RATE_EEE_100M BIT(13)
#define AQ_NIC_RATE_EEE_MSK (AQ_NIC_RATE_EEE_10G |\
AQ_NIC_RATE_EEE_5G |\
AQ_NIC_RATE_EEE_2G5 |\
AQ_NIC_RATE_EEE_1G |\
AQ_NIC_RATE_EEE_100M)
#endif /* AQ_COMMON_H */
@@ -0,0 +1,148 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/hwmon.h>
#include <linux/uaccess.h>
#include "aq_drvinfo.h"
#include "aq_nic.h"
#if IS_REACHABLE(CONFIG_HWMON)
static const char * const atl_temp_label[] = {
"PHY Temperature",
"MAC Temperature",
};
static int aq_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *value)
{
struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
int err = 0;
int temp;
if (!aq_nic)
return -EIO;
if (type != hwmon_temp || attr != hwmon_temp_input)
return -EOPNOTSUPP;
switch (channel) {
case 0:
if (!aq_nic->aq_fw_ops->get_phy_temp)
return -EOPNOTSUPP;
err = aq_nic->aq_fw_ops->get_phy_temp(aq_nic->aq_hw, &temp);
*value = temp;
break;
case 1:
if (!aq_nic->aq_fw_ops->get_mac_temp &&
!aq_nic->aq_hw_ops->hw_get_mac_temp)
return -EOPNOTSUPP;
if (aq_nic->aq_fw_ops->get_mac_temp)
err = aq_nic->aq_fw_ops->get_mac_temp(aq_nic->aq_hw, &temp);
else
err = aq_nic->aq_hw_ops->hw_get_mac_temp(aq_nic->aq_hw, &temp);
*value = temp;
break;
default:
return -EOPNOTSUPP;
}
return err;
}
static int aq_hwmon_read_string(struct device *dev,
enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{
struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
if (!aq_nic)
return -EIO;
if (type != hwmon_temp || attr != hwmon_temp_label)
return -EOPNOTSUPP;
if (channel < ARRAY_SIZE(atl_temp_label))
*str = atl_temp_label[channel];
else
return -EOPNOTSUPP;
return 0;
}
static umode_t aq_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
const struct aq_nic_s *nic = data;
if (type != hwmon_temp)
return 0;
if (channel == 0 && !nic->aq_fw_ops->get_phy_temp)
return 0;
else if (channel == 1 && !nic->aq_fw_ops->get_mac_temp &&
!nic->aq_hw_ops->hw_get_mac_temp)
return 0;
switch (attr) {
case hwmon_temp_input:
case hwmon_temp_label:
return 0444;
default:
return 0;
}
}
static const struct hwmon_ops aq_hwmon_ops = {
.is_visible = aq_hwmon_is_visible,
.read = aq_hwmon_read,
.read_string = aq_hwmon_read_string,
};
static const struct hwmon_channel_info * const aq_hwmon_info[] = {
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
NULL,
};
static const struct hwmon_chip_info aq_hwmon_chip_info = {
.ops = &aq_hwmon_ops,
.info = aq_hwmon_info,
};
int aq_drvinfo_init(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct device *dev = &aq_nic->pdev->dev;
struct device *hwmon_dev;
int err = 0;
hwmon_dev = devm_hwmon_device_register_with_info(dev,
ndev->name,
aq_nic,
&aq_hwmon_chip_info,
NULL);
if (IS_ERR(hwmon_dev))
err = PTR_ERR(hwmon_dev);
return err;
}
#else
int aq_drvinfo_init(struct net_device *ndev) { return 0; }
#endif
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_drvinfo.h: Declaration of common code for firmware info in sys.*/
#ifndef AQ_DRVINFO_H
#define AQ_DRVINFO_H
struct net_device;
int aq_drvinfo_init(struct net_device *ndev);
#endif /* AQ_DRVINFO_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
*/
/* File aq_ethtool.h: Declaration of ethertool related functions. */
#ifndef AQ_ETHTOOL_H
#define AQ_ETHTOOL_H
#include "aq_common.h"
extern const struct ethtool_ops aq_ethtool_ops;
#define AQ_PRIV_FLAGS_MASK (AQ_HW_LOOPBACK_MASK)
#define SFF_8472_ID_ADDR 0x50
#define SFF_8472_DIAGNOSTICS_ADDR 0x51
#define SFF_8472_COMP_ADDR 0x5e
#define SFF_8472_DOM_TYPE_ADDR 0x5c
#define SFF_8472_ADDRESS_CHANGE_REQ_MASK 0x4
#endif /* AQ_ETHTOOL_H */
@@ -0,0 +1,915 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2014-2019 aQuantia Corporation. */
/* File aq_filters.c: RX filters related functions. */
#include "aq_filters.h"
static bool __must_check
aq_rule_is_approve(struct ethtool_rx_flow_spec *fsp)
{
if (fsp->flow_type & FLOW_MAC_EXT)
return false;
switch (fsp->flow_type & ~FLOW_EXT) {
case ETHER_FLOW:
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case IPV4_FLOW:
case IPV6_FLOW:
return true;
case IP_USER_FLOW:
switch (fsp->h_u.usr_ip4_spec.proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_SCTP:
case IPPROTO_IP:
return true;
default:
return false;
}
case IPV6_USER_FLOW:
switch (fsp->h_u.usr_ip6_spec.l4_proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_SCTP:
case IPPROTO_IP:
return true;
default:
return false;
}
default:
return false;
}
return false;
}
static bool __must_check
aq_match_filter(struct ethtool_rx_flow_spec *fsp1,
struct ethtool_rx_flow_spec *fsp2)
{
if (fsp1->flow_type != fsp2->flow_type ||
memcmp(&fsp1->h_u, &fsp2->h_u, sizeof(fsp2->h_u)) ||
memcmp(&fsp1->h_ext, &fsp2->h_ext, sizeof(fsp2->h_ext)) ||
memcmp(&fsp1->m_u, &fsp2->m_u, sizeof(fsp2->m_u)) ||
memcmp(&fsp1->m_ext, &fsp2->m_ext, sizeof(fsp2->m_ext)))
return false;
return true;
}
static bool __must_check
aq_rule_already_exists(struct aq_nic_s *aq_nic,
struct ethtool_rx_flow_spec *fsp)
{
struct aq_rx_filter *rule;
struct hlist_node *aq_node2;
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
hlist_for_each_entry_safe(rule, aq_node2,
&rx_fltrs->filter_list, aq_node) {
if (rule->aq_fsp.location == fsp->location)
continue;
if (aq_match_filter(&rule->aq_fsp, fsp)) {
netdev_err(aq_nic->ndev,
"ethtool: This filter is already set\n");
return true;
}
}
return false;
}
static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
struct aq_hw_rx_fltrs_s *rx_fltrs,
struct ethtool_rx_flow_spec *fsp)
{
u32 last_location = AQ_RX_LAST_LOC_FL3L4 -
aq_nic->aq_hw_rx_fltrs.fl3l4.reserved_count;
if (fsp->location < AQ_RX_FIRST_LOC_FL3L4 ||
fsp->location > last_location) {
netdev_err(aq_nic->ndev,
"ethtool: location must be in range [%d, %d]",
AQ_RX_FIRST_LOC_FL3L4, last_location);
return -EINVAL;
}
if (rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv4) {
rx_fltrs->fl3l4.is_ipv6 = false;
netdev_err(aq_nic->ndev,
"ethtool: mixing ipv4 and ipv6 is not allowed");
return -EINVAL;
} else if (!rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv6) {
rx_fltrs->fl3l4.is_ipv6 = true;
netdev_err(aq_nic->ndev,
"ethtool: mixing ipv4 and ipv6 is not allowed");
return -EINVAL;
} else if (rx_fltrs->fl3l4.is_ipv6 &&
fsp->location != AQ_RX_FIRST_LOC_FL3L4 + 4 &&
fsp->location != AQ_RX_FIRST_LOC_FL3L4) {
netdev_err(aq_nic->ndev,
"ethtool: The specified location for ipv6 must be %d or %d",
AQ_RX_FIRST_LOC_FL3L4, AQ_RX_FIRST_LOC_FL3L4 + 4);
return -EINVAL;
}
return 0;
}
static int __must_check
aq_check_approve_fl2(struct aq_nic_s *aq_nic,
struct aq_hw_rx_fltrs_s *rx_fltrs,
struct ethtool_rx_flow_spec *fsp)
{
u32 last_location = AQ_RX_LAST_LOC_FETHERT -
aq_nic->aq_hw_rx_fltrs.fet_reserved_count;
if (fsp->location < AQ_RX_FIRST_LOC_FETHERT ||
fsp->location > last_location) {
netdev_err(aq_nic->ndev,
"ethtool: location must be in range [%d, %d]",
AQ_RX_FIRST_LOC_FETHERT,
last_location);
return -EINVAL;
}
if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK &&
fsp->m_u.ether_spec.h_proto == 0U) {
netdev_err(aq_nic->ndev,
"ethtool: proto (ether_type) parameter must be specified");
return -EINVAL;
}
return 0;
}
static int __must_check
aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
struct aq_hw_rx_fltrs_s *rx_fltrs,
struct ethtool_rx_flow_spec *fsp)
{
struct aq_nic_cfg_s *cfg = &aq_nic->aq_nic_cfg;
if (fsp->location < AQ_RX_FIRST_LOC_FVLANID ||
fsp->location > AQ_RX_LAST_LOC_FVLANID) {
netdev_err(aq_nic->ndev,
"ethtool: location must be in range [%d, %d]",
AQ_RX_FIRST_LOC_FVLANID,
AQ_RX_LAST_LOC_FVLANID);
return -EINVAL;
}
if ((aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
(!test_bit(be16_to_cpu(fsp->h_ext.vlan_tci) & VLAN_VID_MASK,
aq_nic->active_vlans))) {
netdev_err(aq_nic->ndev,
"ethtool: unknown vlan-id specified");
return -EINVAL;
}
if (fsp->ring_cookie > cfg->num_rss_queues * cfg->tcs) {
netdev_err(aq_nic->ndev,
"ethtool: queue number must be in range [0, %d]",
cfg->num_rss_queues * cfg->tcs - 1);
return -EINVAL;
}
return 0;
}
static bool aq_is_ipv6_flow_type(const struct ethtool_rx_flow_spec *fsp)
{
switch (fsp->flow_type & ~FLOW_EXT) {
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case IPV6_FLOW:
case IPV6_USER_FLOW:
return true;
default:
return false;
}
}
static int __must_check
aq_check_filter(struct aq_nic_s *aq_nic,
struct ethtool_rx_flow_spec *fsp)
{
int err = 0;
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
if (fsp->flow_type & FLOW_EXT) {
if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_VID_MASK) {
err = aq_check_approve_fvlan(aq_nic, rx_fltrs, fsp);
} else if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK) {
err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
} else {
netdev_err(aq_nic->ndev,
"ethtool: invalid vlan mask 0x%x specified",
be16_to_cpu(fsp->m_ext.vlan_tci));
err = -EINVAL;
}
} else {
switch (fsp->flow_type & ~FLOW_EXT) {
case ETHER_FLOW:
err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
break;
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
case IPV4_FLOW:
case IP_USER_FLOW:
rx_fltrs->fl3l4.is_ipv6 = false;
err = aq_check_approve_fl3l4(aq_nic, rx_fltrs, fsp);
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case IPV6_FLOW:
case IPV6_USER_FLOW:
rx_fltrs->fl3l4.is_ipv6 = true;
err = aq_check_approve_fl3l4(aq_nic, rx_fltrs, fsp);
break;
default:
netdev_err(aq_nic->ndev,
"ethtool: unknown flow-type specified");
err = -EINVAL;
}
}
return err;
}
static bool __must_check
aq_rule_is_not_support(struct aq_nic_s *aq_nic,
struct ethtool_rx_flow_spec *fsp)
{
bool rule_is_not_support = false;
if (!(aq_nic->ndev->features & NETIF_F_NTUPLE)) {
netdev_err(aq_nic->ndev,
"ethtool: Please, to enable the RX flow control:\n"
"ethtool -K %s ntuple on\n", aq_nic->ndev->name);
rule_is_not_support = true;
} else if (!aq_rule_is_approve(fsp)) {
netdev_err(aq_nic->ndev,
"ethtool: The specified flow type is not supported\n");
rule_is_not_support = true;
} else if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW &&
(fsp->h_u.tcp_ip4_spec.tos ||
fsp->h_u.tcp_ip6_spec.tclass)) {
netdev_err(aq_nic->ndev,
"ethtool: The specified tos tclass are not supported\n");
rule_is_not_support = true;
} else if (fsp->flow_type & FLOW_MAC_EXT) {
netdev_err(aq_nic->ndev,
"ethtool: MAC_EXT is not supported");
rule_is_not_support = true;
}
return rule_is_not_support;
}
static bool __must_check
aq_rule_is_not_correct(struct aq_nic_s *aq_nic,
struct ethtool_rx_flow_spec *fsp)
{
struct aq_nic_cfg_s *cfg = &aq_nic->aq_nic_cfg;
bool rule_is_not_correct = false;
if (!aq_nic) {
rule_is_not_correct = true;
} else if (fsp->location > AQ_RX_MAX_RXNFC_LOC) {
netdev_err(aq_nic->ndev,
"ethtool: The specified number %u rule is invalid\n",
fsp->location);
rule_is_not_correct = true;
} else if (aq_check_filter(aq_nic, fsp)) {
rule_is_not_correct = true;
} else if (fsp->ring_cookie != RX_CLS_FLOW_DISC) {
if (fsp->ring_cookie >= cfg->num_rss_queues * cfg->tcs) {
netdev_err(aq_nic->ndev,
"ethtool: The specified action is invalid.\n"
"Maximum allowable value action is %u.\n",
cfg->num_rss_queues * cfg->tcs - 1);
rule_is_not_correct = true;
}
}
return rule_is_not_correct;
}
static int __must_check
aq_check_rule(struct aq_nic_s *aq_nic,
struct ethtool_rx_flow_spec *fsp)
{
int err = 0;
if (aq_rule_is_not_correct(aq_nic, fsp))
err = -EINVAL;
else if (aq_rule_is_not_support(aq_nic, fsp))
err = -EOPNOTSUPP;
else if (aq_rule_already_exists(aq_nic, fsp))
err = -EEXIST;
return err;
}
static void aq_set_data_fl2(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr,
struct aq_rx_filter_l2 *data, bool add)
{
const struct ethtool_rx_flow_spec *fsp = &aq_rx_fltr->aq_fsp;
memset(data, 0, sizeof(*data));
data->location = fsp->location - AQ_RX_FIRST_LOC_FETHERT;
if (fsp->ring_cookie != RX_CLS_FLOW_DISC)
data->queue = fsp->ring_cookie;
else
data->queue = -1;
data->ethertype = be16_to_cpu(fsp->h_u.ether_spec.h_proto);
data->user_priority_en = be16_to_cpu(fsp->m_ext.vlan_tci)
== VLAN_PRIO_MASK;
data->user_priority = (be16_to_cpu(fsp->h_ext.vlan_tci)
& VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
}
static int aq_add_del_fether(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr, bool add)
{
struct aq_rx_filter_l2 data;
struct aq_hw_s *aq_hw = aq_nic->aq_hw;
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
aq_set_data_fl2(aq_nic, aq_rx_fltr, &data, add);
if (unlikely(!aq_hw_ops->hw_filter_l2_set))
return -EOPNOTSUPP;
if (unlikely(!aq_hw_ops->hw_filter_l2_clear))
return -EOPNOTSUPP;
if (add)
return aq_hw_ops->hw_filter_l2_set(aq_hw, &data);
else
return aq_hw_ops->hw_filter_l2_clear(aq_hw, &data);
}
static bool aq_fvlan_is_busy(struct aq_rx_filter_vlan *aq_vlans, int vlan)
{
int i;
for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
if (aq_vlans[i].enable &&
aq_vlans[i].queue != AQ_RX_QUEUE_NOT_ASSIGNED &&
aq_vlans[i].vlan_id == vlan) {
return true;
}
}
return false;
}
/* Function rebuilds array of vlan filters so that filters with assigned
* queue have a precedence over just vlans on the interface.
*/
static void aq_fvlan_rebuild(struct aq_nic_s *aq_nic,
unsigned long *active_vlans,
struct aq_rx_filter_vlan *aq_vlans)
{
bool vlan_busy = false;
int vlan = -1;
int i;
for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
if (aq_vlans[i].enable &&
aq_vlans[i].queue != AQ_RX_QUEUE_NOT_ASSIGNED)
continue;
do {
vlan = find_next_bit(active_vlans,
VLAN_N_VID,
vlan + 1);
if (vlan == VLAN_N_VID) {
aq_vlans[i].enable = 0U;
aq_vlans[i].queue = AQ_RX_QUEUE_NOT_ASSIGNED;
aq_vlans[i].vlan_id = 0;
continue;
}
vlan_busy = aq_fvlan_is_busy(aq_vlans, vlan);
if (!vlan_busy) {
aq_vlans[i].enable = 1U;
aq_vlans[i].queue = AQ_RX_QUEUE_NOT_ASSIGNED;
aq_vlans[i].vlan_id = vlan;
}
} while (vlan_busy && vlan != VLAN_N_VID);
}
}
static int aq_set_data_fvlan(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr,
struct aq_rx_filter_vlan *aq_vlans, bool add)
{
const struct ethtool_rx_flow_spec *fsp = &aq_rx_fltr->aq_fsp;
int location = fsp->location - AQ_RX_FIRST_LOC_FVLANID;
int i;
memset(&aq_vlans[location], 0, sizeof(aq_vlans[location]));
if (!add)
return 0;
/* remove vlan if it was in table without queue assignment */
for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
if (aq_vlans[i].vlan_id ==
(be16_to_cpu(fsp->h_ext.vlan_tci) & VLAN_VID_MASK)) {
aq_vlans[i].enable = false;
}
}
aq_vlans[location].location = location;
aq_vlans[location].vlan_id = be16_to_cpu(fsp->h_ext.vlan_tci)
& VLAN_VID_MASK;
aq_vlans[location].queue = fsp->ring_cookie & 0x1FU;
aq_vlans[location].enable = 1U;
return 0;
}
int aq_del_fvlan_by_vlan(struct aq_nic_s *aq_nic, u16 vlan_id)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
struct aq_rx_filter *rule = NULL;
struct hlist_node *aq_node2;
hlist_for_each_entry_safe(rule, aq_node2,
&rx_fltrs->filter_list, aq_node) {
if (be16_to_cpu(rule->aq_fsp.h_ext.vlan_tci) == vlan_id)
break;
}
if (rule && rule->type == aq_rx_filter_vlan &&
be16_to_cpu(rule->aq_fsp.h_ext.vlan_tci) == vlan_id) {
struct ethtool_rxnfc cmd;
cmd.fs.location = rule->aq_fsp.location;
return aq_del_rxnfc_rule(aq_nic, &cmd);
}
return -ENOENT;
}
static int aq_add_del_fvlan(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr, bool add)
{
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
return -EOPNOTSUPP;
aq_set_data_fvlan(aq_nic,
aq_rx_fltr,
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans,
add);
return aq_filters_vlans_update(aq_nic);
}
int aq_set_data_fl3l4(const struct ethtool_rx_flow_spec *fsp,
struct aq_rx_filter_l3l4 *data,
int location, bool add)
{
u32 flow = fsp->flow_type & ~FLOW_EXT;
memset(data, 0, sizeof(*data));
data->is_ipv6 = aq_is_ipv6_flow_type(fsp);
data->location = location;
if (!add)
return 0;
data->cmd |= HW_ATL_RX_ENABLE_FLTR_L3L4;
switch (flow) {
case TCP_V4_FLOW:
case TCP_V6_FLOW:
data->cmd |= HW_ATL_RX_ENABLE_CMP_PROT_L4;
break;
case UDP_V4_FLOW:
case UDP_V6_FLOW:
data->cmd |= HW_ATL_RX_UDP;
data->cmd |= HW_ATL_RX_ENABLE_CMP_PROT_L4;
break;
case SCTP_V4_FLOW:
case SCTP_V6_FLOW:
data->cmd |= HW_ATL_RX_SCTP;
data->cmd |= HW_ATL_RX_ENABLE_CMP_PROT_L4;
break;
default:
break;
}
if (!data->is_ipv6) {
data->ip_src[0] =
ntohl(fsp->h_u.tcp_ip4_spec.ip4src);
data->ip_dst[0] =
ntohl(fsp->h_u.tcp_ip4_spec.ip4dst);
} else {
int i;
for (i = 0; i < HW_ATL_RX_CNT_REG_ADDR_IPV6; ++i) {
data->ip_dst[i] =
ntohl(fsp->h_u.tcp_ip6_spec.ip6dst[i]);
data->ip_src[i] =
ntohl(fsp->h_u.tcp_ip6_spec.ip6src[i]);
}
data->cmd |= HW_ATL_RX_ENABLE_L3_IPV6;
}
if (flow == TCP_V4_FLOW || flow == UDP_V4_FLOW ||
flow == SCTP_V4_FLOW) {
data->p_dst = ntohs(fsp->h_u.tcp_ip4_spec.pdst);
data->p_src = ntohs(fsp->h_u.tcp_ip4_spec.psrc);
}
if (flow == TCP_V6_FLOW || flow == UDP_V6_FLOW ||
flow == SCTP_V6_FLOW) {
data->p_dst = ntohs(fsp->h_u.tcp_ip6_spec.pdst);
data->p_src = ntohs(fsp->h_u.tcp_ip6_spec.psrc);
}
if (data->ip_src[0] ||
(data->is_ipv6 && (data->ip_src[1] || data->ip_src[2] ||
data->ip_src[3])))
data->cmd |= HW_ATL_RX_ENABLE_CMP_SRC_ADDR_L3;
if (data->ip_dst[0] ||
(data->is_ipv6 && (data->ip_dst[1] || data->ip_dst[2] ||
data->ip_dst[3])))
data->cmd |= HW_ATL_RX_ENABLE_CMP_DEST_ADDR_L3;
if (data->p_dst)
data->cmd |= HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4;
if (data->p_src)
data->cmd |= HW_ATL_RX_ENABLE_CMP_SRC_PORT_L4;
if (fsp->ring_cookie != RX_CLS_FLOW_DISC) {
data->cmd |= HW_ATL_RX_HOST << HW_ATL_RX_ACTION_FL3F4_SHIFT;
data->cmd |= fsp->ring_cookie << HW_ATL_RX_QUEUE_FL3L4_SHIFT;
data->cmd |= HW_ATL_RX_ENABLE_QUEUE_L3L4;
} else {
data->cmd |= HW_ATL_RX_DISCARD << HW_ATL_RX_ACTION_FL3F4_SHIFT;
}
return 0;
}
static int aq_set_fl3l4(struct aq_hw_s *aq_hw,
const struct aq_hw_ops *aq_hw_ops,
struct aq_rx_filter_l3l4 *data)
{
if (unlikely(!aq_hw_ops->hw_filter_l3l4_set))
return -EOPNOTSUPP;
return aq_hw_ops->hw_filter_l3l4_set(aq_hw, data);
}
static int aq_add_del_fl3l4(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr, bool add)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
struct aq_hw_s *aq_hw = aq_nic->aq_hw;
struct aq_rx_filter_l3l4 data;
int location;
int err;
if (unlikely(aq_rx_fltr->aq_fsp.location < AQ_RX_FIRST_LOC_FL3L4 ||
aq_rx_fltr->aq_fsp.location > AQ_RX_LAST_LOC_FL3L4))
return -EINVAL;
location = HW_ATL_GET_REG_LOCATION_FL3L4(aq_rx_fltr->aq_fsp.location);
aq_set_data_fl3l4(&aq_rx_fltr->aq_fsp, &data, location, add);
err = aq_set_fl3l4(aq_hw, aq_hw_ops, &data);
if (err)
return err;
if (add) {
if (!data.is_ipv6)
rx_fltrs->fl3l4.active_ipv4 |= BIT(data.location);
else
rx_fltrs->fl3l4.active_ipv6 |= BIT(data.location / 4);
} else {
if (!data.is_ipv6)
rx_fltrs->fl3l4.active_ipv4 &= ~BIT(data.location);
else
rx_fltrs->fl3l4.active_ipv6 &= ~BIT(data.location / 4);
}
return 0;
}
static int aq_add_del_rule(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr, bool add)
{
int err = -EINVAL;
if (aq_rx_fltr->aq_fsp.flow_type & FLOW_EXT) {
if (be16_to_cpu(aq_rx_fltr->aq_fsp.m_ext.vlan_tci)
== VLAN_VID_MASK) {
aq_rx_fltr->type = aq_rx_filter_vlan;
err = aq_add_del_fvlan(aq_nic, aq_rx_fltr, add);
} else if (be16_to_cpu(aq_rx_fltr->aq_fsp.m_ext.vlan_tci)
== VLAN_PRIO_MASK) {
aq_rx_fltr->type = aq_rx_filter_ethertype;
err = aq_add_del_fether(aq_nic, aq_rx_fltr, add);
}
} else {
switch (aq_rx_fltr->aq_fsp.flow_type & ~FLOW_EXT) {
case ETHER_FLOW:
aq_rx_fltr->type = aq_rx_filter_ethertype;
err = aq_add_del_fether(aq_nic, aq_rx_fltr, add);
break;
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
case IP_USER_FLOW:
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case IPV6_USER_FLOW:
aq_rx_fltr->type = aq_rx_filter_l3l4;
err = aq_add_del_fl3l4(aq_nic, aq_rx_fltr, add);
break;
default:
err = -EINVAL;
break;
}
}
return err;
}
static int aq_update_table_filters(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr, u16 index,
struct ethtool_rxnfc *cmd)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
struct aq_rx_filter *rule = NULL, *parent = NULL;
struct hlist_node *aq_node2;
int err = -EINVAL;
hlist_for_each_entry_safe(rule, aq_node2,
&rx_fltrs->filter_list, aq_node) {
if (rule->aq_fsp.location >= index)
break;
parent = rule;
}
if (rule && rule->aq_fsp.location == index) {
err = aq_add_del_rule(aq_nic, rule, false);
hlist_del(&rule->aq_node);
kfree(rule);
--rx_fltrs->active_filters;
}
if (unlikely(!aq_rx_fltr))
return err;
INIT_HLIST_NODE(&aq_rx_fltr->aq_node);
if (parent)
hlist_add_behind(&aq_rx_fltr->aq_node, &parent->aq_node);
else
hlist_add_head(&aq_rx_fltr->aq_node, &rx_fltrs->filter_list);
++rx_fltrs->active_filters;
return 0;
}
u16 aq_get_rxnfc_count_all_rules(struct aq_nic_s *aq_nic)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
return rx_fltrs->active_filters;
}
struct aq_hw_rx_fltrs_s *aq_get_hw_rx_fltrs(struct aq_nic_s *aq_nic)
{
return &aq_nic->aq_hw_rx_fltrs;
}
int aq_add_rxnfc_rule(struct aq_nic_s *aq_nic, const struct ethtool_rxnfc *cmd)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
struct ethtool_rx_flow_spec *fsp =
(struct ethtool_rx_flow_spec *)&cmd->fs;
struct aq_rx_filter *aq_rx_fltr;
int err = 0;
err = aq_check_rule(aq_nic, fsp);
if (err)
goto err_exit;
aq_rx_fltr = kzalloc_obj(*aq_rx_fltr);
if (unlikely(!aq_rx_fltr)) {
err = -ENOMEM;
goto err_exit;
}
memcpy(&aq_rx_fltr->aq_fsp, fsp, sizeof(*fsp));
err = aq_update_table_filters(aq_nic, aq_rx_fltr, fsp->location, NULL);
if (unlikely(err))
goto err_free;
err = aq_add_del_rule(aq_nic, aq_rx_fltr, true);
if (unlikely(err)) {
hlist_del(&aq_rx_fltr->aq_node);
--rx_fltrs->active_filters;
goto err_free;
}
return 0;
err_free:
kfree(aq_rx_fltr);
err_exit:
return err;
}
int aq_del_rxnfc_rule(struct aq_nic_s *aq_nic, const struct ethtool_rxnfc *cmd)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
struct aq_rx_filter *rule = NULL;
struct hlist_node *aq_node2;
int err = -EINVAL;
hlist_for_each_entry_safe(rule, aq_node2,
&rx_fltrs->filter_list, aq_node) {
if (rule->aq_fsp.location == cmd->fs.location)
break;
}
if (rule && rule->aq_fsp.location == cmd->fs.location) {
err = aq_add_del_rule(aq_nic, rule, false);
hlist_del(&rule->aq_node);
kfree(rule);
--rx_fltrs->active_filters;
}
return err;
}
int aq_get_rxnfc_rule(struct aq_nic_s *aq_nic, struct ethtool_rxnfc *cmd)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
struct ethtool_rx_flow_spec *fsp =
(struct ethtool_rx_flow_spec *)&cmd->fs;
struct aq_rx_filter *rule = NULL;
struct hlist_node *aq_node2;
hlist_for_each_entry_safe(rule, aq_node2,
&rx_fltrs->filter_list, aq_node)
if (fsp->location <= rule->aq_fsp.location)
break;
if (unlikely(!rule || fsp->location != rule->aq_fsp.location))
return -EINVAL;
memcpy(fsp, &rule->aq_fsp, sizeof(*fsp));
return 0;
}
int aq_get_rxnfc_all_rules(struct aq_nic_s *aq_nic, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
struct hlist_node *aq_node2;
struct aq_rx_filter *rule;
int count = 0;
cmd->data = aq_get_rxnfc_count_all_rules(aq_nic);
hlist_for_each_entry_safe(rule, aq_node2,
&rx_fltrs->filter_list, aq_node) {
if (unlikely(count == cmd->rule_cnt))
return -EMSGSIZE;
rule_locs[count++] = rule->aq_fsp.location;
}
cmd->rule_cnt = count;
return 0;
}
int aq_clear_rxnfc_all_rules(struct aq_nic_s *aq_nic)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
struct hlist_node *aq_node2;
struct aq_rx_filter *rule;
int err = 0;
hlist_for_each_entry_safe(rule, aq_node2,
&rx_fltrs->filter_list, aq_node) {
err = aq_add_del_rule(aq_nic, rule, false);
if (err)
goto err_exit;
hlist_del(&rule->aq_node);
kfree(rule);
--rx_fltrs->active_filters;
}
err_exit:
return err;
}
int aq_reapply_rxnfc_all_rules(struct aq_nic_s *aq_nic)
{
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
struct hlist_node *aq_node2;
struct aq_rx_filter *rule;
int err = 0;
hlist_for_each_entry_safe(rule, aq_node2,
&rx_fltrs->filter_list, aq_node) {
err = aq_add_del_rule(aq_nic, rule, true);
if (err)
goto err_exit;
}
err_exit:
return err;
}
int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
{
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
struct aq_hw_s *aq_hw = aq_nic->aq_hw;
int hweight = 0;
int err = 0;
if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
return -EOPNOTSUPP;
if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl))
return -EOPNOTSUPP;
aq_fvlan_rebuild(aq_nic, aq_nic->active_vlans,
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans);
if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
hweight = bitmap_weight(aq_nic->active_vlans, VLAN_N_VID);
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
if (err)
return err;
}
err = aq_hw_ops->hw_filter_vlan_set(aq_hw,
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans
);
if (err)
return err;
if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
if (hweight <= AQ_VLAN_MAX_FILTERS && hweight > 0) {
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw,
!(aq_nic->packet_filter & IFF_PROMISC));
aq_nic->aq_nic_cfg.is_vlan_force_promisc = false;
} else {
/* otherwise left in promiscue mode */
aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
}
}
return err;
}
int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic)
{
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
struct aq_hw_s *aq_hw = aq_nic->aq_hw;
int err = 0;
bitmap_zero(aq_nic->active_vlans, VLAN_N_VID);
aq_fvlan_rebuild(aq_nic, aq_nic->active_vlans,
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans);
if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
return -EOPNOTSUPP;
if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl))
return -EOPNOTSUPP;
aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
if (err)
return err;
err = aq_hw_ops->hw_filter_vlan_set(aq_hw,
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans
);
return err;
}
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* File aq_filters.h: RX filters related functions. */
#ifndef AQ_FILTERS_H
#define AQ_FILTERS_H
#include "aq_nic.h"
enum aq_rx_filter_type {
aq_rx_filter_ethertype,
aq_rx_filter_vlan,
aq_rx_filter_l3l4
};
struct aq_rx_filter {
struct hlist_node aq_node;
enum aq_rx_filter_type type;
struct ethtool_rx_flow_spec aq_fsp;
};
u16 aq_get_rxnfc_count_all_rules(struct aq_nic_s *aq_nic);
struct aq_hw_rx_fltrs_s *aq_get_hw_rx_fltrs(struct aq_nic_s *aq_nic);
int aq_add_rxnfc_rule(struct aq_nic_s *aq_nic, const struct ethtool_rxnfc *cmd);
int aq_del_rxnfc_rule(struct aq_nic_s *aq_nic, const struct ethtool_rxnfc *cmd);
int aq_get_rxnfc_rule(struct aq_nic_s *aq_nic, struct ethtool_rxnfc *cmd);
int aq_get_rxnfc_all_rules(struct aq_nic_s *aq_nic, struct ethtool_rxnfc *cmd,
u32 *rule_locs);
int aq_del_fvlan_by_vlan(struct aq_nic_s *aq_nic, u16 vlan_id);
int aq_clear_rxnfc_all_rules(struct aq_nic_s *aq_nic);
int aq_reapply_rxnfc_all_rules(struct aq_nic_s *aq_nic);
int aq_filters_vlans_update(struct aq_nic_s *aq_nic);
int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic);
int aq_set_data_fl3l4(const struct ethtool_rx_flow_spec *fsp,
struct aq_rx_filter_l3l4 *data,
int location, bool add);
#endif /* AQ_FILTERS_H */
@@ -0,0 +1,441 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_hw.h: Declaration of abstract interface for NIC hardware specific
* functions.
*/
#ifndef AQ_HW_H
#define AQ_HW_H
#include "aq_common.h"
#include "aq_rss.h"
#include "hw_atl/hw_atl_utils.h"
#include "hw_atl2/hw_atl2.h"
#define AQ_HW_MAC_COUNTER_HZ 312500000ll
#define AQ_HW_PHY_COUNTER_HZ 160000000ll
#define AQ_HW_TXD_CTL_TS_EN 0x40000000U
#define AQ_HW_TXD_CTL_TS_TSG0 0x80000000U
enum aq_tc_mode {
AQ_TC_MODE_INVALID = -1,
AQ_TC_MODE_8TCS,
AQ_TC_MODE_4TCS,
};
#define AQ_RX_FIRST_LOC_FVLANID 0U
#define AQ_RX_LAST_LOC_FVLANID 15U
#define AQ_RX_FIRST_LOC_FETHERT 16U
#define AQ_RX_LAST_LOC_FETHERT 31U
#define AQ_RX_FIRST_LOC_FL3L4 32U
#define AQ_RX_LAST_LOC_FL3L4 39U
#define AQ_RX_MAX_RXNFC_LOC AQ_RX_LAST_LOC_FL3L4
#define AQ_VLAN_MAX_FILTERS \
(AQ_RX_LAST_LOC_FVLANID - AQ_RX_FIRST_LOC_FVLANID + 1U)
#define AQ_RX_QUEUE_NOT_ASSIGNED 0xFFU
#define AQ_FRAC_PER_NS 0x100000000LL
#define AQ2_HW_PTP_COUNTER_HZ 156250000ll
/* Used for rate to Mbps conversion */
#define AQ_MBPS_DIVISOR 125000 /* 1000000 / 8 */
/* NIC H/W capabilities */
struct aq_hw_caps_s {
u64 hw_features;
u64 link_speed_msk;
unsigned int hw_priv_flags;
u32 media_type;
u32 rxds_max;
u32 txds_max;
u32 rxds_min;
u32 txds_min;
u32 txhwb_alignment;
u32 irq_mask;
u32 vecs;
u32 mtu;
u32 mac_regs_count;
u32 hw_alive_check_addr;
u8 msix_irqs;
u8 tcs_max;
u8 rxd_alignment;
u8 rxd_size;
u8 txd_alignment;
u8 txd_size;
u8 tx_rings;
u8 rx_rings;
bool flow_control;
bool is_64_dma;
bool op64bit;
u32 quirks;
u32 priv_data_len;
};
struct aq_hw_link_status_s {
unsigned int mbps;
bool full_duplex;
u32 lp_link_speed_msk;
u32 lp_flow_control;
};
struct aq_stats_s {
u64 brc;
u64 btc;
u64 uprc;
u64 mprc;
u64 bprc;
u64 erpt;
u64 uptc;
u64 mptc;
u64 bptc;
u64 erpr;
u64 mbtc;
u64 bbtc;
u64 mbrc;
u64 bbrc;
u64 ubrc;
u64 ubtc;
u64 dpc;
u64 dma_pkt_rc;
u64 dma_pkt_tc;
u64 dma_oct_rc;
u64 dma_oct_tc;
};
#define AQ_HW_IRQ_INVALID 0U
#define AQ_HW_IRQ_INTX 1U
#define AQ_HW_IRQ_MSI 2U
#define AQ_HW_IRQ_MSIX 3U
#define AQ_HW_SERVICE_IRQS 1U
#define AQ_HW_PTP_IRQS 1U
#define AQ_HW_POWER_STATE_D0 0U
#define AQ_HW_POWER_STATE_D3 3U
#define AQ_FW_WAKE_ON_LINK_RTPM BIT(10)
#define AQ_HW_FLAG_STARTED 0x00000004U
#define AQ_HW_FLAG_STOPPING 0x00000008U
#define AQ_HW_FLAG_RESETTING 0x00000010U
#define AQ_HW_FLAG_CLOSING 0x00000020U
#define AQ_HW_PTP_AVAILABLE 0x01000000U
#define AQ_HW_LINK_DOWN 0x04000000U
#define AQ_HW_FLAG_ERR_UNPLUG 0x40000000U
#define AQ_HW_FLAG_ERR_HW 0x80000000U
#define AQ_HW_FLAG_ERRORS (AQ_HW_FLAG_ERR_HW | AQ_HW_FLAG_ERR_UNPLUG)
#define AQ_NIC_FLAGS_IS_NOT_READY (AQ_NIC_FLAG_STOPPING | \
AQ_NIC_FLAG_RESETTING | AQ_NIC_FLAG_CLOSING | \
AQ_NIC_FLAG_ERR_UNPLUG | AQ_NIC_FLAG_ERR_HW)
#define AQ_NIC_FLAGS_IS_NOT_TX_READY (AQ_NIC_FLAGS_IS_NOT_READY | \
AQ_NIC_LINK_DOWN)
#define AQ_HW_MEDIA_TYPE_TP 1U
#define AQ_HW_MEDIA_TYPE_FIBRE 2U
#define AQ_HW_TXD_MULTIPLE 8U
#define AQ_HW_RXD_MULTIPLE 8U
#define AQ_HW_QUEUES_MAX 32U
#define AQ_HW_MULTICAST_ADDRESS_MAX 32U
#define AQ_HW_PTP_TC 2U
#define AQ_HW_LED_BLINK 0x2U
#define AQ_HW_LED_DEFAULT 0x0U
#define AQ_HW_MEDIA_DETECT_CNT 6000
enum aq_priv_flags {
AQ_HW_LOOPBACK_DMA_SYS,
AQ_HW_LOOPBACK_PKT_SYS,
AQ_HW_LOOPBACK_DMA_NET,
AQ_HW_LOOPBACK_PHYINT_SYS,
AQ_HW_LOOPBACK_PHYEXT_SYS,
};
enum {
AQ_HW_PTP_DISABLE = 0,
AQ_HW_PTP_L2_ENABLE = BIT(1),
AQ_HW_PTP_L4_ENABLE = BIT(2),
};
#define ATL_TSG_CLOCK_SEL_0 0
#define ATL_TSG_CLOCK_SEL_1 1
#define AQ_HW_LOOPBACK_MASK (BIT(AQ_HW_LOOPBACK_DMA_SYS) |\
BIT(AQ_HW_LOOPBACK_PKT_SYS) |\
BIT(AQ_HW_LOOPBACK_DMA_NET) |\
BIT(AQ_HW_LOOPBACK_PHYINT_SYS) |\
BIT(AQ_HW_LOOPBACK_PHYEXT_SYS))
#define ATL_HW_CHIP_MIPS 0x00000001U
#define ATL_HW_CHIP_TPO2 0x00000002U
#define ATL_HW_CHIP_RPF2 0x00000004U
#define ATL_HW_CHIP_MPI_AQ 0x00000010U
#define ATL_HW_CHIP_ATLANTIC 0x00800000U
#define ATL_HW_CHIP_REVISION_A0 0x01000000U
#define ATL_HW_CHIP_REVISION_B0 0x02000000U
#define ATL_HW_CHIP_REVISION_B1 0x04000000U
#define ATL_HW_CHIP_ANTIGUA 0x08000000U
#define ATL_HW_IS_CHIP_FEATURE(_HW_, _F_) (!!(ATL_HW_CHIP_##_F_ & \
(_HW_)->chip_features))
struct aq_hw_s {
atomic_t flags;
u8 rbl_enabled:1;
struct aq_nic_cfg_s *aq_nic_cfg;
const struct aq_fw_ops *aq_fw_ops;
void __iomem *mmio;
struct aq_hw_link_status_s aq_link_status;
struct hw_atl_utils_mbox mbox;
struct hw_atl_stats_s last_stats;
struct aq_stats_s curr_stats;
u64 speed;
u32 itr_tx;
u32 itr_rx;
unsigned int chip_features;
u32 fw_ver_actual;
atomic_t dpc;
u32 mbox_addr;
u32 rpc_addr;
u32 settings_addr;
u32 rpc_tid;
struct hw_atl_utils_fw_rpc rpc;
s64 ptp_clk_offset;
s8 clk_select;
u16 phy_id;
void *priv;
};
struct aq_ring_s;
struct aq_ring_param_s;
struct sk_buff;
struct aq_rx_filter_l3l4;
struct aq_hw_ops {
int (*hw_ring_tx_xmit)(struct aq_hw_s *self, struct aq_ring_s *aq_ring,
unsigned int frags);
int (*hw_ring_rx_receive)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring);
int (*hw_ring_rx_fill)(struct aq_hw_s *self, struct aq_ring_s *aq_ring,
unsigned int sw_tail_old);
int (*hw_ring_tx_head_update)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring);
int (*hw_set_mac_address)(struct aq_hw_s *self, const u8 *mac_addr);
int (*hw_soft_reset)(struct aq_hw_s *self);
int (*hw_prepare)(struct aq_hw_s *self,
const struct aq_fw_ops **fw_ops);
int (*hw_reset)(struct aq_hw_s *self);
int (*hw_init)(struct aq_hw_s *self, const u8 *mac_addr);
int (*hw_start)(struct aq_hw_s *self);
int (*hw_stop)(struct aq_hw_s *self);
int (*hw_ring_tx_init)(struct aq_hw_s *self, struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param);
int (*hw_ring_tx_start)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring);
int (*hw_ring_tx_stop)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring);
int (*hw_ring_rx_init)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param);
int (*hw_ring_rx_start)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring);
int (*hw_ring_rx_stop)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring);
int (*hw_irq_enable)(struct aq_hw_s *self, u64 mask);
int (*hw_irq_disable)(struct aq_hw_s *self, u64 mask);
int (*hw_irq_read)(struct aq_hw_s *self, u64 *mask);
int (*hw_packet_filter_set)(struct aq_hw_s *self,
unsigned int packet_filter);
int (*hw_filter_l3l4_set)(struct aq_hw_s *self,
struct aq_rx_filter_l3l4 *data);
int (*hw_filter_l3l4_clear)(struct aq_hw_s *self,
struct aq_rx_filter_l3l4 *data);
int (*hw_filter_l2_set)(struct aq_hw_s *self,
struct aq_rx_filter_l2 *data);
int (*hw_filter_l2_clear)(struct aq_hw_s *self,
struct aq_rx_filter_l2 *data);
int (*hw_filter_vlan_set)(struct aq_hw_s *self,
struct aq_rx_filter_vlan *aq_vlans);
int (*hw_filter_vlan_ctrl)(struct aq_hw_s *self, bool enable);
int (*hw_multicast_list_set)(struct aq_hw_s *self,
u8 ar_mac[AQ_HW_MULTICAST_ADDRESS_MAX]
[ETH_ALEN],
u32 count);
int (*hw_interrupt_moderation_set)(struct aq_hw_s *self);
int (*hw_rss_set)(struct aq_hw_s *self,
struct aq_rss_parameters *rss_params);
int (*hw_rss_hash_set)(struct aq_hw_s *self,
struct aq_rss_parameters *rss_params);
int (*hw_tc_rate_limit_set)(struct aq_hw_s *self);
int (*hw_get_regs)(struct aq_hw_s *self,
const struct aq_hw_caps_s *aq_hw_caps,
u32 *regs_buff);
struct aq_stats_s *(*hw_get_hw_stats)(struct aq_hw_s *self);
u32 (*hw_get_fw_version)(struct aq_hw_s *self);
int (*hw_set_offload)(struct aq_hw_s *self,
struct aq_nic_cfg_s *aq_nic_cfg);
int (*hw_ring_hwts_rx_fill)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring);
int (*hw_ring_hwts_rx_receive)(struct aq_hw_s *self,
struct aq_ring_s *ring);
void (*hw_get_ptp_ts)(struct aq_hw_s *self, u64 *stamp);
int (*hw_adj_clock_freq)(struct aq_hw_s *self, s32 delta);
int (*hw_adj_sys_clock)(struct aq_hw_s *self, s64 delta);
int (*hw_set_sys_clock)(struct aq_hw_s *self, u64 time, u64 ts);
int (*hw_ts_to_sys_clock)(struct aq_hw_s *self, u64 ts, u64 *time);
int (*hw_gpio_pulse)(struct aq_hw_s *self, u32 index,
u32 clk_sel, u64 start,
u32 period, u32 hightime);
int (*hw_extts_gpio_enable)(struct aq_hw_s *self, u32 index,
u32 channel, int enable);
void (*enable_ptp)(struct aq_hw_s *self, unsigned int param,
int enable);
int (*hw_get_sync_ts)(struct aq_hw_s *self, u64 *ts);
u16 (*rx_extract_ts)(struct aq_hw_s *self, u8 *p, unsigned int len,
u64 *timestamp);
int (*extract_hwts)(struct aq_hw_s *self, u8 *p, unsigned int len,
u64 *timestamp);
u64 (*hw_ring_tx_ptp_get_ts)(struct aq_ring_s *ring);
int (*hw_tx_ptp_ring_init)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring);
int (*hw_rx_ptp_ring_init)(struct aq_hw_s *self,
struct aq_ring_s *aq_ring);
u32 (*hw_get_clk_sel)(struct aq_hw_s *self);
int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc);
int (*hw_set_loopback)(struct aq_hw_s *self, u32 mode, bool enable);
int (*hw_get_mac_temp)(struct aq_hw_s *self, u32 *temp);
int (*hw_read_module_eeprom)(struct aq_hw_s *self, u8 dev_addr,
u8 reg_start_addr, int len, u8 *data);
};
struct aq_fw_ops {
int (*init)(struct aq_hw_s *self);
int (*deinit)(struct aq_hw_s *self);
int (*reset)(struct aq_hw_s *self);
int (*renegotiate)(struct aq_hw_s *self);
int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
int (*set_link_speed)(struct aq_hw_s *self, u32 speed);
int (*set_state)(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state);
int (*update_link_status)(struct aq_hw_s *self);
int (*update_stats)(struct aq_hw_s *self);
int (*get_mac_temp)(struct aq_hw_s *self, int *temp);
int (*get_phy_temp)(struct aq_hw_s *self, int *temp);
u32 (*get_flow_control)(struct aq_hw_s *self, u32 *fcmode);
int (*set_flow_control)(struct aq_hw_s *self);
int (*led_control)(struct aq_hw_s *self, u32 mode);
int (*set_phyloopback)(struct aq_hw_s *self, u32 mode, bool enable);
int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
const u8 *mac);
int (*send_fw_request)(struct aq_hw_s *self,
const struct hw_fw_request_iface *fw_req,
size_t size);
void (*enable_ptp)(struct aq_hw_s *self, int enable);
void (*adjust_ptp)(struct aq_hw_s *self, uint64_t adj);
int (*set_eee_rate)(struct aq_hw_s *self, u32 speed);
int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate,
u32 *supported_rates);
int (*set_downshift)(struct aq_hw_s *self, u32 counter);
int (*set_media_detect)(struct aq_hw_s *self, bool enable);
u32 (*get_link_capabilities)(struct aq_hw_s *self);
int (*send_macsec_req)(struct aq_hw_s *self,
struct macsec_msg_fw_request *msg,
struct macsec_msg_fw_response *resp);
int (*read_module_eeprom)(struct aq_hw_s *self, u8 dev_addr,
u8 reg_start_addr, int len, u8 *data);
};
#endif /* AQ_HW_H */
@@ -0,0 +1,147 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_hw_utils.c: Definitions of helper functions used across
* hardware layer.
*/
#include "aq_hw_utils.h"
#include <linux/io-64-nonatomic-lo-hi.h>
#include "aq_hw.h"
#include "aq_nic.h"
#include "hw_atl/hw_atl_llh.h"
void aq_hw_write_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk,
u32 shift, u32 val)
{
if (msk ^ ~0) {
u32 reg_old, reg_new;
reg_old = aq_hw_read_reg(aq_hw, addr);
reg_new = (reg_old & (~msk)) | (val << shift);
if (reg_old != reg_new)
aq_hw_write_reg(aq_hw, addr, reg_new);
} else {
aq_hw_write_reg(aq_hw, addr, val);
}
}
u32 aq_hw_read_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk, u32 shift)
{
return ((aq_hw_read_reg(aq_hw, addr) & msk) >> shift);
}
u32 aq_hw_read_reg(struct aq_hw_s *hw, u32 reg)
{
u32 value = readl(hw->mmio + reg);
if (value == U32_MAX &&
readl(hw->mmio + hw->aq_nic_cfg->aq_hw_caps->hw_alive_check_addr) == U32_MAX)
aq_utils_obj_set(&hw->flags, AQ_HW_FLAG_ERR_UNPLUG);
return value;
}
void aq_hw_write_reg(struct aq_hw_s *hw, u32 reg, u32 value)
{
writel(value, hw->mmio + reg);
}
/* Most of 64-bit registers are in LSW, MSW form.
Counters are normally implemented by HW as latched pairs:
reading LSW first locks MSW, to overcome LSW overflow
*/
u64 aq_hw_read_reg64(struct aq_hw_s *hw, u32 reg)
{
u64 value = U64_MAX;
if (hw->aq_nic_cfg->aq_hw_caps->op64bit)
value = readq(hw->mmio + reg);
else
value = lo_hi_readq(hw->mmio + reg);
if (value == U64_MAX &&
readl(hw->mmio + hw->aq_nic_cfg->aq_hw_caps->hw_alive_check_addr) == U32_MAX)
aq_utils_obj_set(&hw->flags, AQ_HW_FLAG_ERR_UNPLUG);
return value;
}
void aq_hw_write_reg64(struct aq_hw_s *hw, u32 reg, u64 value)
{
if (hw->aq_nic_cfg->aq_hw_caps->op64bit)
writeq(value, hw->mmio + reg);
else
lo_hi_writeq(value, hw->mmio + reg);
}
int aq_hw_invalidate_descriptor_cache(struct aq_hw_s *hw)
{
int err;
u32 val;
/* Invalidate Descriptor Cache to prevent writing to the cached
* descriptors and to the data pointer of those descriptors
*/
hw_atl_rdm_rx_dma_desc_cache_init_tgl(hw);
err = aq_hw_err_from_flags(hw);
if (err)
goto err_exit;
readx_poll_timeout_atomic(hw_atl_rdm_rx_dma_desc_cache_init_done_get,
hw, val, val == 1, 1000U, 10000U);
err_exit:
return err;
}
int aq_hw_err_from_flags(struct aq_hw_s *hw)
{
int err = 0;
if (aq_utils_obj_test(&hw->flags, AQ_HW_FLAG_ERR_UNPLUG)) {
err = -ENXIO;
goto err_exit;
}
if (aq_utils_obj_test(&hw->flags, AQ_HW_FLAG_ERR_HW)) {
err = -EIO;
goto err_exit;
}
err_exit:
return err;
}
int aq_hw_num_tcs(struct aq_hw_s *hw)
{
switch (hw->aq_nic_cfg->tc_mode) {
case AQ_TC_MODE_8TCS:
return 8;
case AQ_TC_MODE_4TCS:
return 4;
default:
break;
}
return 1;
}
int aq_hw_q_per_tc(struct aq_hw_s *hw)
{
switch (hw->aq_nic_cfg->tc_mode) {
case AQ_TC_MODE_8TCS:
return 4;
case AQ_TC_MODE_4TCS:
return 8;
default:
return 4;
}
}
@@ -0,0 +1,43 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_hw_utils.h: Declaration of helper functions used across hardware
* layer.
*/
#ifndef AQ_HW_UTILS_H
#define AQ_HW_UTILS_H
#include <linux/iopoll.h>
#include "aq_common.h"
#ifndef HIDWORD
#define LODWORD(_qw) ((u32)(_qw))
#define HIDWORD(_qw) ((u32)(((_qw) >> 32) & 0xffffffff))
#endif
#define AQ_HW_SLEEP(_US_) mdelay(_US_)
#define aq_pr_err(...) pr_err(AQ_CFG_DRV_NAME ": " __VA_ARGS__)
#define aq_pr_trace(...) pr_info(AQ_CFG_DRV_NAME ": " __VA_ARGS__)
struct aq_hw_s;
void aq_hw_write_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk,
u32 shift, u32 val);
u32 aq_hw_read_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk, u32 shift);
u32 aq_hw_read_reg(struct aq_hw_s *hw, u32 reg);
void aq_hw_write_reg(struct aq_hw_s *hw, u32 reg, u32 value);
u64 aq_hw_read_reg64(struct aq_hw_s *hw, u32 reg);
void aq_hw_write_reg64(struct aq_hw_s *hw, u32 reg, u64 value);
int aq_hw_invalidate_descriptor_cache(struct aq_hw_s *hw);
int aq_hw_err_from_flags(struct aq_hw_s *hw);
int aq_hw_num_tcs(struct aq_hw_s *hw);
int aq_hw_q_per_tc(struct aq_hw_s *hw);
#endif /* AQ_HW_UTILS_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,133 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef AQ_MACSEC_H
#define AQ_MACSEC_H
#include <linux/netdevice.h>
#if IS_ENABLED(CONFIG_MACSEC)
#include "net/macsec.h"
struct aq_nic_s;
#define AQ_MACSEC_MAX_SC 32
#define AQ_MACSEC_MAX_SA 32
enum aq_macsec_sc_sa {
aq_macsec_sa_sc_4sa_8sc,
aq_macsec_sa_sc_not_used,
aq_macsec_sa_sc_2sa_16sc,
aq_macsec_sa_sc_1sa_32sc,
};
struct aq_macsec_common_stats {
/* Ingress Common Counters */
struct {
u64 ctl_pkts;
u64 tagged_miss_pkts;
u64 untagged_miss_pkts;
u64 notag_pkts;
u64 untagged_pkts;
u64 bad_tag_pkts;
u64 no_sci_pkts;
u64 unknown_sci_pkts;
u64 ctrl_prt_pass_pkts;
u64 unctrl_prt_pass_pkts;
u64 ctrl_prt_fail_pkts;
u64 unctrl_prt_fail_pkts;
u64 too_long_pkts;
u64 igpoc_ctl_pkts;
u64 ecc_error_pkts;
u64 unctrl_hit_drop_redir;
} in;
/* Egress Common Counters */
struct {
u64 ctl_pkts;
u64 unknown_sa_pkts;
u64 untagged_pkts;
u64 too_long;
u64 ecc_error_pkts;
u64 unctrl_hit_drop_redir;
} out;
};
/* Ingress SA Counters */
struct aq_macsec_rx_sa_stats {
u64 untagged_hit_pkts;
u64 ctrl_hit_drop_redir_pkts;
u64 not_using_sa;
u64 unused_sa;
u64 not_valid_pkts;
u64 invalid_pkts;
u64 ok_pkts;
u64 late_pkts;
u64 delayed_pkts;
u64 unchecked_pkts;
u64 validated_octets;
u64 decrypted_octets;
};
/* Egress SA Counters */
struct aq_macsec_tx_sa_stats {
u64 sa_hit_drop_redirect;
u64 sa_protected2_pkts;
u64 sa_protected_pkts;
u64 sa_encrypted_pkts;
};
/* Egress SC Counters */
struct aq_macsec_tx_sc_stats {
u64 sc_protected_pkts;
u64 sc_encrypted_pkts;
u64 sc_protected_octets;
u64 sc_encrypted_octets;
};
struct aq_macsec_txsc {
u32 hw_sc_idx;
unsigned long tx_sa_idx_busy;
const struct macsec_secy *sw_secy;
u8 tx_sa_key[MACSEC_NUM_AN][MACSEC_MAX_KEY_LEN];
struct aq_macsec_tx_sc_stats stats;
struct aq_macsec_tx_sa_stats tx_sa_stats[MACSEC_NUM_AN];
};
struct aq_macsec_rxsc {
u32 hw_sc_idx;
unsigned long rx_sa_idx_busy;
const struct macsec_secy *sw_secy;
const struct macsec_rx_sc *sw_rxsc;
u8 rx_sa_key[MACSEC_NUM_AN][MACSEC_MAX_KEY_LEN];
struct aq_macsec_rx_sa_stats rx_sa_stats[MACSEC_NUM_AN];
};
struct aq_macsec_cfg {
enum aq_macsec_sc_sa sc_sa;
/* Egress channel configuration */
unsigned long txsc_idx_busy;
struct aq_macsec_txsc aq_txsc[AQ_MACSEC_MAX_SC];
/* Ingress channel configuration */
unsigned long rxsc_idx_busy;
struct aq_macsec_rxsc aq_rxsc[AQ_MACSEC_MAX_SC];
/* Statistics / counters */
struct aq_macsec_common_stats stats;
};
extern const struct macsec_ops aq_macsec_ops;
int aq_macsec_init(struct aq_nic_s *nic);
void aq_macsec_free(struct aq_nic_s *nic);
int aq_macsec_enable(struct aq_nic_s *nic);
void aq_macsec_work(struct aq_nic_s *nic);
u64 *aq_macsec_get_stats(struct aq_nic_s *nic, u64 *data);
int aq_macsec_rx_sa_cnt(struct aq_nic_s *nic);
int aq_macsec_tx_sc_cnt(struct aq_nic_s *nic);
int aq_macsec_tx_sa_cnt(struct aq_nic_s *nic);
#endif
#endif /* AQ_MACSEC_H */
@@ -0,0 +1,507 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_main.c: Main file for aQuantia Linux driver. */
#include "aq_main.h"
#include "aq_nic.h"
#include "aq_pci_func.h"
#include "aq_ethtool.h"
#include "aq_ptp.h"
#include "aq_filters.h"
#include "aq_hw_utils.h"
#include "aq_vec.h"
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <net/pkt_cls.h>
#include <linux/ptp_classify.h>
#include <net/pkt_sched.h>
#include <linux/filter.h>
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR(AQ_CFG_DRV_AUTHOR);
MODULE_DESCRIPTION(AQ_CFG_DRV_DESC);
DEFINE_STATIC_KEY_FALSE(aq_xdp_locking_key);
EXPORT_SYMBOL(aq_xdp_locking_key);
static const char aq_ndev_driver_name[] = AQ_CFG_DRV_NAME;
static const struct net_device_ops aq_ndev_ops;
static struct workqueue_struct *aq_ndev_wq;
void aq_ndev_schedule_work(struct work_struct *work)
{
queue_work(aq_ndev_wq, work);
}
struct net_device *aq_ndev_alloc(void)
{
struct net_device *ndev = NULL;
struct aq_nic_s *aq_nic = NULL;
ndev = alloc_etherdev_mq(sizeof(struct aq_nic_s), AQ_HW_QUEUES_MAX);
if (!ndev)
return NULL;
aq_nic = netdev_priv(ndev);
aq_nic->ndev = ndev;
ndev->netdev_ops = &aq_ndev_ops;
ndev->ethtool_ops = &aq_ethtool_ops;
return ndev;
}
int aq_ndev_open(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
int err = 0;
err = aq_nic_init(aq_nic);
if (err < 0)
goto err_exit;
err = aq_nic_start(aq_nic);
if (err < 0) {
aq_nic_stop(aq_nic);
goto err_exit;
}
err_exit:
if (err < 0)
aq_nic_deinit(aq_nic, true);
return err;
}
int aq_ndev_close(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
int err = 0;
err = aq_nic_stop(aq_nic);
aq_nic_deinit(aq_nic, true);
return err;
}
static netdev_tx_t aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
if (unlikely(aq_utils_obj_test(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP))) {
/* Hardware adds the Timestamp for PTPv2 802.AS1
* and PTPv2 IPv4 UDP.
* We have to push even general 320 port messages to the ptp
* queue explicitly. This is a limitation of current firmware
* and hardware PTP design of the chip. Otherwise ptp stream
* will fail to sync
*/
if (unlikely(skb->protocol == htons(ETH_P_IP) &&
ip_hdr(skb)->protocol == IPPROTO_UDP &&
(udp_hdr(skb)->dest == htons(PTP_EV_PORT) ||
udp_hdr(skb)->dest == htons(PTP_GEN_PORT))))
return aq_ptp_xmit(aq_nic, skb);
/* PTP over IPv6 does not use extension headers */
if (unlikely(skb->protocol == htons(ETH_P_IPV6) &&
ipv6_hdr(skb)->nexthdr == IPPROTO_UDP &&
(udp_hdr(skb)->dest == htons(PTP_EV_PORT) ||
udp_hdr(skb)->dest == htons(PTP_GEN_PORT))))
return aq_ptp_xmit(aq_nic, skb);
if (unlikely(eth_hdr(skb)->h_proto == htons(ETH_P_1588)))
return aq_ptp_xmit(aq_nic, skb);
}
#endif
return aq_nic_xmit(aq_nic, skb);
}
static int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu)
{
int new_frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN;
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct bpf_prog *prog;
int err;
prog = READ_ONCE(aq_nic->xdp_prog);
if (prog && !prog->aux->xdp_has_frags &&
new_frame_size > AQ_CFG_RX_FRAME_MAX) {
netdev_err(ndev, "Illegal MTU %d for XDP prog without frags\n",
ndev->mtu);
return -EOPNOTSUPP;
}
err = aq_nic_set_mtu(aq_nic, new_mtu + ETH_HLEN);
if (err < 0)
goto err_exit;
WRITE_ONCE(ndev->mtu, new_mtu);
err_exit:
return err;
}
static int aq_ndev_set_features(struct net_device *ndev,
netdev_features_t features)
{
bool is_vlan_tx_insert = !!(features & NETIF_F_HW_VLAN_CTAG_TX);
bool is_vlan_rx_strip = !!(features & NETIF_F_HW_VLAN_CTAG_RX);
struct aq_nic_s *aq_nic = netdev_priv(ndev);
bool need_ndev_restart = false;
struct aq_nic_cfg_s *aq_cfg;
bool is_lro = false;
int err = 0;
aq_cfg = aq_nic_get_cfg(aq_nic);
if (!(features & NETIF_F_NTUPLE)) {
if (aq_nic->ndev->features & NETIF_F_NTUPLE) {
err = aq_clear_rxnfc_all_rules(aq_nic);
if (unlikely(err))
goto err_exit;
}
}
if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
err = aq_filters_vlan_offload_off(aq_nic);
if (unlikely(err))
goto err_exit;
}
}
aq_cfg->features = features;
if (aq_cfg->aq_hw_caps->hw_features & NETIF_F_LRO) {
is_lro = features & NETIF_F_LRO;
if (aq_cfg->is_lro != is_lro) {
aq_cfg->is_lro = is_lro;
need_ndev_restart = true;
}
}
if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM) {
err = aq_nic->aq_hw_ops->hw_set_offload(aq_nic->aq_hw,
aq_cfg);
if (unlikely(err))
goto err_exit;
}
if (aq_cfg->is_vlan_rx_strip != is_vlan_rx_strip) {
aq_cfg->is_vlan_rx_strip = is_vlan_rx_strip;
need_ndev_restart = true;
}
if (aq_cfg->is_vlan_tx_insert != is_vlan_tx_insert) {
aq_cfg->is_vlan_tx_insert = is_vlan_tx_insert;
need_ndev_restart = true;
}
if (need_ndev_restart && netif_running(ndev)) {
aq_ndev_close(ndev);
aq_ndev_open(ndev);
}
err_exit:
return err;
}
static netdev_features_t aq_ndev_fix_features(struct net_device *ndev,
netdev_features_t features)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct bpf_prog *prog;
if (!(features & NETIF_F_RXCSUM))
features &= ~NETIF_F_LRO;
prog = READ_ONCE(aq_nic->xdp_prog);
if (prog && !prog->aux->xdp_has_frags &&
aq_nic->xdp_prog && features & NETIF_F_LRO) {
netdev_err(ndev, "LRO is not supported with single buffer XDP, disabling\n");
features &= ~NETIF_F_LRO;
}
return features;
}
static int aq_ndev_set_mac_address(struct net_device *ndev, void *addr)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
int err = 0;
err = eth_mac_addr(ndev, addr);
if (err < 0)
goto err_exit;
err = aq_nic_set_mac(aq_nic, ndev);
if (err < 0)
goto err_exit;
err_exit:
return err;
}
static void aq_ndev_set_multicast_settings(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
(void)aq_nic_set_multicast_list(aq_nic, ndev);
}
static int aq_ndev_hwtstamp_set(struct net_device *netdev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct aq_nic_s *aq_nic = netdev_priv(netdev);
if (!IS_REACHABLE(CONFIG_PTP_1588_CLOCK) || !aq_nic->aq_ptp)
return -EOPNOTSUPP;
switch (config->tx_type) {
case HWTSTAMP_TX_OFF:
case HWTSTAMP_TX_ON:
break;
default:
return -ERANGE;
}
switch (config->rx_filter) {
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_NONE:
break;
default:
return -ERANGE;
}
return aq_ptp_hwtstamp_config_set(aq_nic->aq_ptp, config);
}
static int aq_ndev_hwtstamp_get(struct net_device *netdev,
struct kernel_hwtstamp_config *config)
{
struct aq_nic_s *aq_nic = netdev_priv(netdev);
if (!aq_nic->aq_ptp)
return -EOPNOTSUPP;
aq_ptp_hwtstamp_config_get(aq_nic->aq_ptp, config);
return 0;
}
static int aq_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto,
u16 vid)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
return -EOPNOTSUPP;
set_bit(vid, aq_nic->active_vlans);
return aq_filters_vlans_update(aq_nic);
}
static int aq_ndo_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto,
u16 vid)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
return -EOPNOTSUPP;
clear_bit(vid, aq_nic->active_vlans);
if (-ENOENT == aq_del_fvlan_by_vlan(aq_nic, vid))
return aq_filters_vlans_update(aq_nic);
return 0;
}
static int aq_validate_mqprio_opt(struct aq_nic_s *self,
struct tc_mqprio_qopt_offload *mqprio,
const unsigned int num_tc)
{
const bool has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(self);
const unsigned int tcs_max = min_t(u8, aq_nic_cfg->aq_hw_caps->tcs_max,
AQ_CFG_TCS_MAX);
if (num_tc > tcs_max) {
netdev_err(self->ndev, "Too many TCs requested\n");
return -EOPNOTSUPP;
}
if (num_tc != 0 && !is_power_of_2(num_tc)) {
netdev_err(self->ndev, "TC count should be power of 2\n");
return -EOPNOTSUPP;
}
if (has_min_rate && !ATL_HW_IS_CHIP_FEATURE(self->aq_hw, ANTIGUA)) {
netdev_err(self->ndev, "Min tx rate is not supported\n");
return -EOPNOTSUPP;
}
return 0;
}
static int aq_ndo_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
struct tc_mqprio_qopt_offload *mqprio = type_data;
struct aq_nic_s *aq_nic = netdev_priv(dev);
bool has_min_rate;
bool has_max_rate;
int err;
int i;
if (type != TC_SETUP_QDISC_MQPRIO)
return -EOPNOTSUPP;
has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
has_max_rate = !!(mqprio->flags & TC_MQPRIO_F_MAX_RATE);
err = aq_validate_mqprio_opt(aq_nic, mqprio, mqprio->qopt.num_tc);
if (err)
return err;
for (i = 0; i < mqprio->qopt.num_tc; i++) {
if (has_max_rate) {
u64 max_rate = mqprio->max_rate[i];
do_div(max_rate, AQ_MBPS_DIVISOR);
aq_nic_setup_tc_max_rate(aq_nic, i, (u32)max_rate);
}
if (has_min_rate) {
u64 min_rate = mqprio->min_rate[i];
do_div(min_rate, AQ_MBPS_DIVISOR);
aq_nic_setup_tc_min_rate(aq_nic, i, (u32)min_rate);
}
}
return aq_nic_setup_tc_mqprio(aq_nic, mqprio->qopt.num_tc,
mqprio->qopt.prio_tc_map);
}
static int aq_xdp_setup(struct net_device *ndev, struct bpf_prog *prog,
struct netlink_ext_ack *extack)
{
bool need_update, running = netif_running(ndev);
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct bpf_prog *old_prog;
if (prog && !prog->aux->xdp_has_frags) {
if (ndev->mtu > AQ_CFG_RX_FRAME_MAX) {
NL_SET_ERR_MSG_MOD(extack,
"prog does not support XDP frags");
return -EOPNOTSUPP;
}
if (prog && ndev->features & NETIF_F_LRO) {
netdev_err(ndev,
"LRO is not supported with single buffer XDP, disabling\n");
ndev->features &= ~NETIF_F_LRO;
}
}
need_update = !!aq_nic->xdp_prog != !!prog;
if (running && need_update)
aq_ndev_close(ndev);
old_prog = xchg(&aq_nic->xdp_prog, prog);
if (old_prog)
bpf_prog_put(old_prog);
if (!old_prog && prog)
static_branch_inc(&aq_xdp_locking_key);
else if (old_prog && !prog)
static_branch_dec(&aq_xdp_locking_key);
if (running && need_update)
return aq_ndev_open(ndev);
return 0;
}
static int aq_xdp(struct net_device *dev, struct netdev_bpf *xdp)
{
switch (xdp->command) {
case XDP_SETUP_PROG:
return aq_xdp_setup(dev, xdp->prog, xdp->extack);
default:
return -EINVAL;
}
}
static const struct net_device_ops aq_ndev_ops = {
.ndo_open = aq_ndev_open,
.ndo_stop = aq_ndev_close,
.ndo_start_xmit = aq_ndev_start_xmit,
.ndo_set_rx_mode = aq_ndev_set_multicast_settings,
.ndo_change_mtu = aq_ndev_change_mtu,
.ndo_set_mac_address = aq_ndev_set_mac_address,
.ndo_set_features = aq_ndev_set_features,
.ndo_fix_features = aq_ndev_fix_features,
.ndo_vlan_rx_add_vid = aq_ndo_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = aq_ndo_vlan_rx_kill_vid,
.ndo_setup_tc = aq_ndo_setup_tc,
.ndo_bpf = aq_xdp,
.ndo_xdp_xmit = aq_xdp_xmit,
.ndo_hwtstamp_get = aq_ndev_hwtstamp_get,
.ndo_hwtstamp_set = aq_ndev_hwtstamp_set,
};
static int __init aq_ndev_init_module(void)
{
int ret;
aq_ndev_wq = create_singlethread_workqueue(aq_ndev_driver_name);
if (!aq_ndev_wq) {
pr_err("Failed to create workqueue\n");
return -ENOMEM;
}
ret = aq_pci_func_register_driver();
if (ret) {
destroy_workqueue(aq_ndev_wq);
return ret;
}
return 0;
}
static void __exit aq_ndev_exit_module(void)
{
aq_pci_func_unregister_driver();
if (aq_ndev_wq) {
destroy_workqueue(aq_ndev_wq);
aq_ndev_wq = NULL;
}
}
module_init(aq_ndev_init_module);
module_exit(aq_ndev_exit_module);
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
*/
/* File aq_main.h: Main file for aQuantia Linux driver. */
#ifndef AQ_MAIN_H
#define AQ_MAIN_H
#include "aq_common.h"
#include "aq_nic.h"
DECLARE_STATIC_KEY_FALSE(aq_xdp_locking_key);
void aq_ndev_schedule_work(struct work_struct *work);
struct net_device *aq_ndev_alloc(void);
int aq_ndev_open(struct net_device *ndev);
int aq_ndev_close(struct net_device *ndev);
#endif /* AQ_MAIN_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,221 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_nic.h: Declaration of common code for NIC. */
#ifndef AQ_NIC_H
#define AQ_NIC_H
#include <linux/ethtool.h>
#include <net/xdp.h>
#include <linux/bpf.h>
#include "aq_common.h"
#include "aq_rss.h"
#include "aq_hw.h"
struct aq_ring_s;
struct aq_hw_ops;
struct aq_fw_s;
struct aq_vec_s;
struct aq_macsec_cfg;
struct aq_ptp_s;
enum aq_rx_filter_type;
enum aq_fc_mode {
AQ_NIC_FC_OFF = 0,
AQ_NIC_FC_TX,
AQ_NIC_FC_RX,
AQ_NIC_FC_FULL,
};
struct aq_fc_info {
enum aq_fc_mode req;
enum aq_fc_mode cur;
};
struct aq_nic_cfg_s {
const struct aq_hw_caps_s *aq_hw_caps;
u64 features;
u32 rxds; /* rx ring size, descriptors # */
u32 txds; /* tx ring size, descriptors # */
u32 vecs; /* allocated rx/tx vectors */
u32 link_irq_vec;
u32 irq_type;
u32 itr;
u16 rx_itr;
u16 tx_itr;
u32 rxpageorder;
u32 num_rss_queues;
u32 mtu;
struct aq_fc_info fc;
u32 link_speed_msk;
u32 wol;
u8 is_vlan_rx_strip;
u8 is_vlan_tx_insert;
bool is_vlan_force_promisc;
u16 is_mc_list_enabled;
u16 mc_list_count;
bool is_autoneg;
bool is_polling;
bool is_rss;
bool is_lro;
bool is_qos;
bool is_ptp;
bool is_media_detect;
int downshift_counter;
enum aq_tc_mode tc_mode;
u32 priv_flags;
u8 tcs;
u8 prio_tc_map[8];
u32 tc_max_rate[AQ_CFG_TCS_MAX];
unsigned long tc_min_rate_msk;
u32 tc_min_rate[AQ_CFG_TCS_MAX];
struct aq_rss_parameters aq_rss;
u32 eee_speeds;
};
#define AQ_NIC_FLAG_STARTED 0x00000004U
#define AQ_NIC_FLAG_STOPPING 0x00000008U
#define AQ_NIC_FLAG_RESETTING 0x00000010U
#define AQ_NIC_FLAG_CLOSING 0x00000020U
#define AQ_NIC_PTP_DPATH_UP 0x02000000U
#define AQ_NIC_LINK_DOWN 0x04000000U
#define AQ_NIC_FLAG_ERR_UNPLUG 0x40000000U
#define AQ_NIC_FLAG_ERR_HW 0x80000000U
#define AQ_NIC_QUIRK_BAD_PTP BIT(0)
#define AQ_NIC_WOL_MODES (WAKE_MAGIC |\
WAKE_PHY)
#define AQ_NIC_CFG_RING_PER_TC(_NIC_CFG_) \
(((_NIC_CFG_)->tc_mode == AQ_TC_MODE_4TCS) ? 8 : 4)
#define AQ_NIC_CFG_TCVEC2RING(_NIC_CFG_, _TC_, _VEC_) \
((_TC_) * AQ_NIC_CFG_RING_PER_TC(_NIC_CFG_) + (_VEC_))
#define AQ_NIC_RING2QMAP(_NIC_, _ID_) \
((_ID_) / AQ_NIC_CFG_RING_PER_TC(&(_NIC_)->aq_nic_cfg) * \
(_NIC_)->aq_vecs + \
((_ID_) % AQ_NIC_CFG_RING_PER_TC(&(_NIC_)->aq_nic_cfg)))
struct aq_hw_rx_fl2 {
struct aq_rx_filter_vlan aq_vlans[AQ_VLAN_MAX_FILTERS];
};
struct aq_hw_rx_fl3l4 {
u8 active_ipv4;
u8 active_ipv6:2;
u8 is_ipv6;
u8 reserved_count;
};
struct aq_hw_rx_fltrs_s {
struct hlist_head filter_list;
u16 active_filters;
struct aq_hw_rx_fl2 fl2;
struct aq_hw_rx_fl3l4 fl3l4;
/* filter ether type */
u8 fet_reserved_count;
};
struct aq_nic_s {
atomic_t flags;
u32 msg_enable;
struct aq_vec_s *aq_vec[AQ_CFG_VECS_MAX];
struct aq_ring_s *aq_ring_tx[AQ_HW_QUEUES_MAX];
struct aq_hw_s *aq_hw;
struct bpf_prog *xdp_prog;
struct net_device *ndev;
unsigned int aq_vecs;
unsigned int packet_filter;
unsigned int power_state;
u8 port;
const struct aq_hw_ops *aq_hw_ops;
const struct aq_fw_ops *aq_fw_ops;
struct aq_nic_cfg_s aq_nic_cfg;
struct timer_list service_timer;
struct work_struct service_task;
struct timer_list polling_timer;
struct aq_hw_link_status_s link_status;
struct {
u32 count;
u8 ar[AQ_HW_MULTICAST_ADDRESS_MAX][ETH_ALEN];
} mc_list;
/* Bitmask of currently assigned vlans from linux */
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
struct pci_dev *pdev;
unsigned int msix_entry_mask;
u32 irqvecs;
/* mutex to serialize FW interface access operations */
struct mutex fwreq_mutex;
#if IS_ENABLED(CONFIG_MACSEC)
struct aq_macsec_cfg *macsec_cfg;
/* mutex to protect data in macsec_cfg */
struct mutex macsec_mutex;
#endif
/* PTP support */
struct aq_ptp_s *aq_ptp;
struct aq_hw_rx_fltrs_s aq_hw_rx_fltrs;
};
static inline struct device *aq_nic_get_dev(struct aq_nic_s *self)
{
return self->ndev->dev.parent;
}
void aq_nic_ndev_init(struct aq_nic_s *self);
struct aq_nic_s *aq_nic_alloc_hot(struct net_device *ndev);
void aq_nic_set_tx_ring(struct aq_nic_s *self, unsigned int idx,
struct aq_ring_s *ring);
struct net_device *aq_nic_get_ndev(struct aq_nic_s *self);
int aq_nic_init(struct aq_nic_s *self);
void aq_nic_cfg_start(struct aq_nic_s *self);
int aq_nic_ndev_register(struct aq_nic_s *self);
void aq_nic_ndev_free(struct aq_nic_s *self);
int aq_nic_start(struct aq_nic_s *self);
unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb,
struct aq_ring_s *ring);
int aq_nic_xmit_xdpf(struct aq_nic_s *aq_nic, struct aq_ring_s *tx_ring,
struct xdp_frame *xdpf);
int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb);
int aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p);
int aq_nic_get_regs_count(struct aq_nic_s *self);
u64 *aq_nic_get_stats(struct aq_nic_s *self, u64 *data);
int aq_nic_stop(struct aq_nic_s *self);
void aq_nic_deinit(struct aq_nic_s *self, bool link_down);
void aq_nic_set_power(struct aq_nic_s *self);
void aq_nic_free_hot_resources(struct aq_nic_s *self);
void aq_nic_free_vectors(struct aq_nic_s *self);
int aq_nic_realloc_vectors(struct aq_nic_s *self);
int aq_nic_set_mtu(struct aq_nic_s *self, int new_mtu);
int aq_nic_set_mac(struct aq_nic_s *self, struct net_device *ndev);
int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags);
int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev);
unsigned int aq_nic_get_link_speed(struct aq_nic_s *self);
void aq_nic_get_link_ksettings(struct aq_nic_s *self,
struct ethtool_link_ksettings *cmd);
int aq_nic_set_link_ksettings(struct aq_nic_s *self,
const struct ethtool_link_ksettings *cmd);
struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self);
u32 aq_nic_get_fw_version(struct aq_nic_s *self);
int aq_nic_set_loopback(struct aq_nic_s *self);
int aq_nic_set_downshift(struct aq_nic_s *self, int val);
int aq_nic_set_media_detect(struct aq_nic_s *self, int val);
int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);
void aq_nic_shutdown(struct aq_nic_s *self);
u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type);
void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type,
u32 location);
int aq_nic_setup_tc_mqprio(struct aq_nic_s *self, u32 tcs, u8 *prio_tc_map);
int aq_nic_setup_tc_max_rate(struct aq_nic_s *self, const unsigned int tc,
const u32 max_rate);
int aq_nic_setup_tc_min_rate(struct aq_nic_s *self, const unsigned int tc,
const u32 min_rate);
#endif /* AQ_NIC_H */
@@ -0,0 +1,487 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_pci_func.c: Definition of PCI functions. */
#include <linux/interrupt.h>
#include <linux/module.h>
#include "aq_main.h"
#include "aq_nic.h"
#include "aq_vec.h"
#include "aq_hw.h"
#include "aq_pci_func.h"
#include "hw_atl/hw_atl_a0.h"
#include "hw_atl/hw_atl_b0.h"
#include "hw_atl2/hw_atl2.h"
#include "aq_filters.h"
#include "aq_drvinfo.h"
#include "aq_macsec.h"
static const struct pci_device_id aq_pci_tbl[] = {
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_0001), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_D100), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_D107), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_D108), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_D109), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC100), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC107), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC108), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC109), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC111), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC112), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC100S), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC107S), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC108S), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC109S), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC111S), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC112S), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC113DEV), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC113CS), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC114CS), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC113), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC113C), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC115C), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC113CA), },
{ PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC116C), },
{}
};
static const struct aq_board_revision_s hw_atl_boards[] = {
{ AQ_DEVICE_ID_0001, AQ_HWREV_1, &hw_atl_ops_a0, &hw_atl_a0_caps_aqc107, },
{ AQ_DEVICE_ID_D100, AQ_HWREV_1, &hw_atl_ops_a0, &hw_atl_a0_caps_aqc100, },
{ AQ_DEVICE_ID_D107, AQ_HWREV_1, &hw_atl_ops_a0, &hw_atl_a0_caps_aqc107, },
{ AQ_DEVICE_ID_D108, AQ_HWREV_1, &hw_atl_ops_a0, &hw_atl_a0_caps_aqc108, },
{ AQ_DEVICE_ID_D109, AQ_HWREV_1, &hw_atl_ops_a0, &hw_atl_a0_caps_aqc109, },
{ AQ_DEVICE_ID_0001, AQ_HWREV_2, &hw_atl_ops_b0, &hw_atl_b0_caps_aqc107, },
{ AQ_DEVICE_ID_D100, AQ_HWREV_2, &hw_atl_ops_b0, &hw_atl_b0_caps_aqc100, },
{ AQ_DEVICE_ID_D107, AQ_HWREV_2, &hw_atl_ops_b0, &hw_atl_b0_caps_aqc107, },
{ AQ_DEVICE_ID_D108, AQ_HWREV_2, &hw_atl_ops_b0, &hw_atl_b0_caps_aqc108, },
{ AQ_DEVICE_ID_D109, AQ_HWREV_2, &hw_atl_ops_b0, &hw_atl_b0_caps_aqc109, },
{ AQ_DEVICE_ID_AQC100, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc100, },
{ AQ_DEVICE_ID_AQC107, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc107, },
{ AQ_DEVICE_ID_AQC108, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc108, },
{ AQ_DEVICE_ID_AQC109, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc109, },
{ AQ_DEVICE_ID_AQC111, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc111, },
{ AQ_DEVICE_ID_AQC112, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc112, },
{ AQ_DEVICE_ID_AQC100S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc100s, },
{ AQ_DEVICE_ID_AQC107S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc107s, },
{ AQ_DEVICE_ID_AQC108S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc108s, },
{ AQ_DEVICE_ID_AQC109S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc109s, },
{ AQ_DEVICE_ID_AQC111S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc111s, },
{ AQ_DEVICE_ID_AQC112S, AQ_HWREV_ANY, &hw_atl_ops_b1, &hw_atl_b0_caps_aqc112s, },
{ AQ_DEVICE_ID_AQC113DEV, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
{ AQ_DEVICE_ID_AQC113, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
{ AQ_DEVICE_ID_AQC113CS, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
{ AQ_DEVICE_ID_AQC114CS, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
{ AQ_DEVICE_ID_AQC113C, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
{ AQ_DEVICE_ID_AQC115C, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc115c, },
{ AQ_DEVICE_ID_AQC113CA, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
{ AQ_DEVICE_ID_AQC116C, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc116c, },
};
MODULE_DEVICE_TABLE(pci, aq_pci_tbl);
static int aq_pci_probe_get_hw_by_id(struct pci_dev *pdev,
const struct aq_hw_ops **ops,
const struct aq_hw_caps_s **caps)
{
int i;
if (pdev->vendor != PCI_VENDOR_ID_AQUANTIA)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(hw_atl_boards); i++) {
if (hw_atl_boards[i].devid == pdev->device &&
(hw_atl_boards[i].revision == AQ_HWREV_ANY ||
hw_atl_boards[i].revision == pdev->revision)) {
*ops = hw_atl_boards[i].ops;
*caps = hw_atl_boards[i].caps;
break;
}
}
if (i == ARRAY_SIZE(hw_atl_boards))
return -EINVAL;
return 0;
}
static int aq_pci_func_init(struct pci_dev *pdev)
{
int err;
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (err)
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
err = -ENOSR;
goto err_exit;
}
err = pci_request_regions(pdev, AQ_CFG_DRV_NAME "_mmio");
if (err < 0)
goto err_exit;
pci_set_master(pdev);
return 0;
err_exit:
return err;
}
int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i,
char *name, irq_handler_t irq_handler,
void *irq_arg, cpumask_t *affinity_mask)
{
struct pci_dev *pdev = self->pdev;
int err;
if (pdev->msix_enabled || pdev->msi_enabled)
err = request_irq(pci_irq_vector(pdev, i), irq_handler, 0,
name, irq_arg);
else
err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr_legacy,
IRQF_SHARED, name, irq_arg);
if (err >= 0) {
self->msix_entry_mask |= (1 << i);
if (pdev->msix_enabled && affinity_mask)
irq_update_affinity_hint(pci_irq_vector(pdev, i),
affinity_mask);
}
return err;
}
void aq_pci_func_free_irqs(struct aq_nic_s *self)
{
struct pci_dev *pdev = self->pdev;
unsigned int i;
void *irq_data;
for (i = 32U; i--;) {
if (!((1U << i) & self->msix_entry_mask))
continue;
if (self->aq_nic_cfg.link_irq_vec &&
i == self->aq_nic_cfg.link_irq_vec)
irq_data = self;
else if (i < AQ_CFG_VECS_MAX)
irq_data = self->aq_vec[i];
else
continue;
if (pdev->msix_enabled)
irq_update_affinity_hint(pci_irq_vector(pdev, i), NULL);
free_irq(pci_irq_vector(pdev, i), irq_data);
self->msix_entry_mask &= ~(1U << i);
}
}
unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self)
{
if (self->pdev->msix_enabled)
return AQ_HW_IRQ_MSIX;
if (self->pdev->msi_enabled)
return AQ_HW_IRQ_MSI;
return AQ_HW_IRQ_INTX;
}
static void aq_pci_free_irq_vectors(struct aq_nic_s *self)
{
pci_free_irq_vectors(self->pdev);
}
static int aq_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
struct net_device *ndev;
resource_size_t mmio_pa;
struct aq_nic_s *self;
u32 numvecs;
u32 bar;
int err;
err = pci_enable_device(pdev);
if (err)
return err;
err = aq_pci_func_init(pdev);
if (err)
goto err_pci_func;
ndev = aq_ndev_alloc();
if (!ndev) {
err = -ENOMEM;
goto err_ndev;
}
self = netdev_priv(ndev);
self->pdev = pdev;
SET_NETDEV_DEV(ndev, &pdev->dev);
pci_set_drvdata(pdev, self);
mutex_init(&self->fwreq_mutex);
err = aq_pci_probe_get_hw_by_id(pdev, &self->aq_hw_ops,
&aq_nic_get_cfg(self)->aq_hw_caps);
if (err)
goto err_ioremap;
self->aq_hw = kzalloc_obj(*self->aq_hw);
if (!self->aq_hw) {
err = -ENOMEM;
goto err_ioremap;
}
self->aq_hw->aq_nic_cfg = aq_nic_get_cfg(self);
self->aq_hw->clk_select = -1;
if (self->aq_hw->aq_nic_cfg->aq_hw_caps->priv_data_len) {
int len = self->aq_hw->aq_nic_cfg->aq_hw_caps->priv_data_len;
self->aq_hw->priv = kzalloc(len, GFP_KERNEL);
if (!self->aq_hw->priv) {
err = -ENOMEM;
goto err_free_aq_hw;
}
}
for (bar = 0; bar < 4; ++bar) {
if (IORESOURCE_MEM & pci_resource_flags(pdev, bar)) {
resource_size_t reg_sz;
mmio_pa = pci_resource_start(pdev, bar);
if (mmio_pa == 0U) {
err = -EIO;
goto err_free_aq_hw_priv;
}
reg_sz = pci_resource_len(pdev, bar);
if ((reg_sz <= 24 /*ATL_REGS_SIZE*/)) {
err = -EIO;
goto err_free_aq_hw_priv;
}
self->aq_hw->mmio = ioremap(mmio_pa, reg_sz);
if (!self->aq_hw->mmio) {
err = -EIO;
goto err_free_aq_hw_priv;
}
break;
}
}
if (bar == 4) {
err = -EIO;
goto err_free_aq_hw_priv;
}
numvecs = min((u8)AQ_CFG_VECS_DEF,
aq_nic_get_cfg(self)->aq_hw_caps->msix_irqs);
numvecs = min(numvecs, num_online_cpus());
/* Request IRQ lines for PTP */
numvecs += AQ_HW_PTP_IRQS;
numvecs += AQ_HW_SERVICE_IRQS;
/*enable interrupts */
#if !AQ_CFG_FORCE_INTX
err = pci_alloc_irq_vectors(self->pdev, 1, numvecs, PCI_IRQ_ALL_TYPES);
if (err < 0)
goto err_hwinit;
numvecs = err;
#endif
self->irqvecs = numvecs;
/* net device init */
aq_nic_cfg_start(self);
aq_nic_ndev_init(self);
err = aq_nic_ndev_register(self);
if (err < 0)
goto err_register;
aq_drvinfo_init(ndev);
return 0;
err_register:
aq_nic_free_vectors(self);
aq_pci_free_irq_vectors(self);
err_hwinit:
iounmap(self->aq_hw->mmio);
err_free_aq_hw_priv:
kfree(self->aq_hw->priv);
err_free_aq_hw:
kfree(self->aq_hw);
err_ioremap:
free_netdev(ndev);
err_ndev:
pci_release_regions(pdev);
err_pci_func:
pci_disable_device(pdev);
return err;
}
static void aq_pci_remove(struct pci_dev *pdev)
{
struct aq_nic_s *self = pci_get_drvdata(pdev);
if (self->ndev) {
aq_clear_rxnfc_all_rules(self);
if (self->ndev->reg_state == NETREG_REGISTERED)
unregister_netdev(self->ndev);
#if IS_ENABLED(CONFIG_MACSEC)
aq_macsec_free(self);
#endif
aq_nic_free_vectors(self);
aq_pci_free_irq_vectors(self);
iounmap(self->aq_hw->mmio);
kfree(self->aq_hw->priv);
kfree(self->aq_hw);
pci_release_regions(pdev);
free_netdev(self->ndev);
}
pci_disable_device(pdev);
}
static void aq_pci_shutdown(struct pci_dev *pdev)
{
struct aq_nic_s *self = pci_get_drvdata(pdev);
aq_nic_shutdown(self);
pci_disable_device(pdev);
if (system_state == SYSTEM_POWER_OFF) {
pci_wake_from_d3(pdev, self->aq_hw->aq_nic_cfg->wol);
pci_set_power_state(pdev, PCI_D3hot);
}
}
#ifdef CONFIG_PM
static int aq_suspend_common(struct device *dev)
{
struct aq_nic_s *nic = pci_get_drvdata(to_pci_dev(dev));
rtnl_lock();
nic->power_state = AQ_HW_POWER_STATE_D3;
netif_device_detach(nic->ndev);
netif_tx_stop_all_queues(nic->ndev);
if (netif_running(nic->ndev))
aq_nic_stop(nic);
aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
aq_nic_set_power(nic);
rtnl_unlock();
return 0;
}
static int atl_resume_common(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct aq_nic_s *nic;
int ret = 0;
nic = pci_get_drvdata(pdev);
rtnl_lock();
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
if (netif_running(nic->ndev)) {
ret = aq_nic_init(nic);
if (ret)
goto err_exit;
ret = aq_nic_start(nic);
if (ret)
goto err_exit;
}
netif_device_attach(nic->ndev);
netif_tx_start_all_queues(nic->ndev);
err_exit:
if (ret < 0)
aq_nic_deinit(nic, true);
rtnl_unlock();
return ret;
}
static int aq_pm_freeze(struct device *dev)
{
return aq_suspend_common(dev);
}
static int aq_pm_suspend_poweroff(struct device *dev)
{
return aq_suspend_common(dev);
}
static int aq_pm_thaw(struct device *dev)
{
return atl_resume_common(dev);
}
static int aq_pm_resume_restore(struct device *dev)
{
return atl_resume_common(dev);
}
static const struct dev_pm_ops aq_pm_ops = {
.suspend = aq_pm_suspend_poweroff,
.poweroff = aq_pm_suspend_poweroff,
.freeze = aq_pm_freeze,
.resume = aq_pm_resume_restore,
.restore = aq_pm_resume_restore,
.thaw = aq_pm_thaw,
};
#endif
static struct pci_driver aq_pci_driver = {
.name = AQ_CFG_DRV_NAME,
.id_table = aq_pci_tbl,
.probe = aq_pci_probe,
.remove = aq_pci_remove,
.shutdown = aq_pci_shutdown,
#ifdef CONFIG_PM
.driver.pm = &aq_pm_ops,
#endif
};
int aq_pci_func_register_driver(void)
{
return pci_register_driver(&aq_pci_driver);
}
void aq_pci_func_unregister_driver(void)
{
pci_unregister_driver(&aq_pci_driver);
}
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_pci_func.h: Declaration of PCI functions. */
#ifndef AQ_PCI_FUNC_H
#define AQ_PCI_FUNC_H
#include "aq_common.h"
#include "aq_nic.h"
struct aq_board_revision_s {
unsigned short devid;
unsigned short revision;
const struct aq_hw_ops *ops;
const struct aq_hw_caps_s *caps;
};
int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i,
char *name, irq_handler_t irq_handler,
void *irq_arg, cpumask_t *affinity_mask);
void aq_pci_func_free_irqs(struct aq_nic_s *self);
unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self);
int aq_pci_func_register_driver(void);
void aq_pci_func_unregister_driver(void);
#endif /* AQ_PCI_FUNC_H */
@@ -0,0 +1,172 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
*
* Copyright (C) 2018-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
#include "aq_phy.h"
#define HW_ATL_PTP_DISABLE_MSK BIT(10)
bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw)
{
int err = 0;
u32 val;
err = readx_poll_timeout_atomic(hw_atl_mdio_busy_get, aq_hw,
val, val == 0U, 10U, 100000U);
if (err < 0)
return false;
return true;
}
u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr)
{
u16 phy_addr = aq_hw->phy_id << 5 | mmd;
/* Set Address register. */
hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) <<
HW_ATL_MDIO_ADDRESS_SHIFT);
/* Send Address command. */
hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
(3 << HW_ATL_MDIO_OP_MODE_SHIFT) |
((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
aq_mdio_busy_wait(aq_hw);
/* Send Read command. */
hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
(1 << HW_ATL_MDIO_OP_MODE_SHIFT) |
((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
/* Read result. */
aq_mdio_busy_wait(aq_hw);
return (u16)hw_atl_glb_mdio_iface5_get(aq_hw);
}
void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data)
{
u16 phy_addr = aq_hw->phy_id << 5 | mmd;
/* Set Address register. */
hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) <<
HW_ATL_MDIO_ADDRESS_SHIFT);
/* Send Address command. */
hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
(3 << HW_ATL_MDIO_OP_MODE_SHIFT) |
((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
aq_mdio_busy_wait(aq_hw);
hw_atl_glb_mdio_iface3_set(aq_hw, (data & HW_ATL_MDIO_WRITE_DATA_MSK) <<
HW_ATL_MDIO_WRITE_DATA_SHIFT);
/* Send Write command. */
hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
(2 << HW_ATL_MDIO_OP_MODE_SHIFT) |
((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
aq_mdio_busy_wait(aq_hw);
}
u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address)
{
int err = 0;
u32 val;
err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw,
val, val == 1U, 10U, 100000U);
if (err < 0) {
err = 0xffff;
goto err_exit;
}
err = aq_mdio_read_word(aq_hw, mmd, address);
hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO);
err_exit:
return err;
}
void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data)
{
int err = 0;
u32 val;
err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw,
val, val == 1U, 10U, 100000U);
if (err < 0)
return;
aq_mdio_write_word(aq_hw, mmd, address, data);
hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO);
}
bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw)
{
u16 val;
for (aq_hw->phy_id = 0; aq_hw->phy_id < HW_ATL_PHY_ID_MAX;
++aq_hw->phy_id) {
/* PMA Standard Device Identifier 2: Address 1.3 */
val = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3);
if (val != 0xffff)
return true;
}
return false;
}
bool aq_phy_init(struct aq_hw_s *aq_hw)
{
u32 dev_id;
if (aq_hw->phy_id == HW_ATL_PHY_ID_MAX)
if (!aq_phy_init_phy_id(aq_hw))
return false;
/* PMA Standard Device Identifier:
* Address 1.2 = MSW,
* Address 1.3 = LSW
*/
dev_id = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 2);
dev_id <<= 16;
dev_id |= aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3);
if (dev_id == 0xffffffff) {
aq_hw->phy_id = HW_ATL_PHY_ID_MAX;
return false;
}
return true;
}
void aq_phy_disable_ptp(struct aq_hw_s *aq_hw)
{
static const u16 ptp_registers[] = {
0x031e,
0x031d,
0x031c,
0x031b,
};
u16 val;
int i;
for (i = 0; i < ARRAY_SIZE(ptp_registers); i++) {
val = aq_phy_read_reg(aq_hw, MDIO_MMD_VEND1,
ptp_registers[i]);
aq_phy_write_reg(aq_hw, MDIO_MMD_VEND1,
ptp_registers[i],
val & ~HW_ATL_PTP_DISABLE_MSK);
}
}
@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2018-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
#ifndef AQ_PHY_H
#define AQ_PHY_H
#include <linux/mdio.h>
#include "hw_atl/hw_atl_llh.h"
#include "hw_atl/hw_atl_llh_internal.h"
#include "aq_hw_utils.h"
#include "aq_hw.h"
#define HW_ATL_PHY_ID_MAX 32U
bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw);
u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr);
void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data);
u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address);
void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data);
bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw);
bool aq_phy_init(struct aq_hw_s *aq_hw);
void aq_phy_disable_ptp(struct aq_hw_s *aq_hw);
#endif /* AQ_PHY_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,172 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_ptp.h: Declaration of PTP functions.
*/
#ifndef AQ_PTP_H
#define AQ_PTP_H
#include <linux/net_tstamp.h>
#include "aq_ring.h"
enum aq_ptp_state {
AQ_PTP_NO_LINK = 0,
AQ_PTP_FIRST_INIT = 1,
AQ_PTP_LINK_UP = 2,
};
#define PTP_8TC_RING_IDX 8
#define PTP_4TC_RING_IDX 16
#define PTP_HWST_RING_IDX 31
/* Index must to be 8 (8 TCs) or 16 (4 TCs).
* It depends from Traffic Class mode.
*/
static inline unsigned int aq_ptp_ring_idx(const enum aq_tc_mode tc_mode)
{
if (tc_mode == AQ_TC_MODE_8TCS)
return PTP_8TC_RING_IDX;
return PTP_4TC_RING_IDX;
}
#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
/* Common functions */
int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_ptp_vec);
void aq_ptp_unregister(struct aq_nic_s *aq_nic);
void aq_ptp_free(struct aq_nic_s *aq_nic);
int aq_ptp_irq_alloc(struct aq_nic_s *aq_nic);
void aq_ptp_irq_free(struct aq_nic_s *aq_nic);
int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic);
void aq_ptp_ring_free(struct aq_nic_s *aq_nic);
int aq_ptp_ring_init(struct aq_nic_s *aq_nic);
int aq_ptp_ring_start(struct aq_nic_s *aq_nic);
void aq_ptp_ring_stop(struct aq_nic_s *aq_nic);
void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic);
void aq_ptp_service_task(struct aq_nic_s *aq_nic);
void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, unsigned int mbps);
void aq_ptp_clock_init(struct aq_nic_s *aq_nic, enum aq_ptp_state state);
void aq_ptp_tx_skb_drop_head(struct aq_nic_s *aq_nic);
/* Traffic processing functions */
int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb);
void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp);
/* Must be to check available of PTP before call */
void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp,
struct kernel_hwtstamp_config *config);
int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp,
struct kernel_hwtstamp_config *config);
/* Return either ring is belong to PTP or not*/
bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring);
u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct skb_shared_hwtstamps *shhwtstamps, u8 *p,
unsigned int len);
struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp);
int aq_ptp_link_change(struct aq_nic_s *aq_nic);
/* PTP ring statistics */
int aq_ptp_get_ring_cnt(struct aq_nic_s *aq_nic, const enum atl_ring_type ring_type);
u64 *aq_ptp_get_stats(struct aq_nic_s *aq_nic, u64 *data);
#else
static inline int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_ptp_vec)
{
return 0;
}
static inline void aq_ptp_unregister(struct aq_nic_s *aq_nic) {}
static inline void aq_ptp_free(struct aq_nic_s *aq_nic)
{
}
static inline int aq_ptp_irq_alloc(struct aq_nic_s *aq_nic)
{
return 0;
}
static inline void aq_ptp_irq_free(struct aq_nic_s *aq_nic)
{
}
static inline int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
{
return 0;
}
static inline void aq_ptp_ring_free(struct aq_nic_s *aq_nic) {}
static inline int aq_ptp_ring_init(struct aq_nic_s *aq_nic)
{
return 0;
}
static inline int aq_ptp_ring_start(struct aq_nic_s *aq_nic)
{
return 0;
}
static inline void aq_ptp_ring_stop(struct aq_nic_s *aq_nic) {}
static inline void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic) {}
static inline void aq_ptp_service_task(struct aq_nic_s *aq_nic) {}
static inline void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic,
unsigned int mbps) {}
static inline void aq_ptp_clock_init(struct aq_nic_s *aq_nic,
enum aq_ptp_state state) {}
static inline void aq_ptp_tx_skb_drop_head(struct aq_nic_s *aq_nic) {}
static inline int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb)
{
return -EOPNOTSUPP;
}
static inline void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp) {}
static inline void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp,
struct kernel_hwtstamp_config *config) {}
static inline int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp,
struct kernel_hwtstamp_config *config)
{
return 0;
}
static inline bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring)
{
return false;
}
static inline u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic,
struct skb_shared_hwtstamps *shhwtstamps, u8 *p,
unsigned int len)
{
return 0;
}
static inline struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp)
{
return NULL;
}
static inline int aq_ptp_link_change(struct aq_nic_s *aq_nic)
{
return 0;
}
#endif
#endif /* AQ_PTP_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,222 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_ring.h: Declaration of functions for Rx/Tx rings. */
#ifndef AQ_RING_H
#define AQ_RING_H
#include "aq_common.h"
#include "aq_vec.h"
#define AQ_XDP_HEADROOM ALIGN(max(NET_SKB_PAD, XDP_PACKET_HEADROOM), 8)
#define AQ_XDP_TAILROOM SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
struct page;
struct aq_nic_cfg_s;
struct aq_rxpage {
struct page *page;
dma_addr_t daddr;
unsigned int order;
unsigned int pg_off;
};
/* TxC SOP DX EOP
* +----------+----------+----------+-----------
* 8bytes|len l3,l4 | pa | pa | pa
* +----------+----------+----------+-----------
* 4/8bytes|len pkt |len pkt | | skb
* +----------+----------+----------+-----------
* 4/8bytes|is_gso |len,flags |len |len,is_eop
* +----------+----------+----------+-----------
*
* This aq_ring_buff_s doesn't have endianness dependency.
* It is __packed for cache line optimizations.
*/
struct __packed aq_ring_buff_s {
union {
/* RX/TX */
dma_addr_t pa;
/* RX */
struct {
u32 rss_hash;
u16 next;
u8 is_hash_l4;
u8 rsvd1;
struct aq_rxpage rxdata;
u16 vlan_rx_tag;
};
/* EOP */
struct {
dma_addr_t pa_eop;
struct sk_buff *skb;
struct xdp_frame *xdpf;
};
/* TxC */
struct {
u32 mss;
u8 len_l2;
u8 len_l3;
u8 len_l4;
u8 is_ipv6:1;
u8 rsvd2:7;
u32 len_pkt;
u16 vlan_tx_tag;
};
};
union {
struct {
u32 len:16;
u32 is_ip_cso:1;
u32 is_udp_cso:1;
u32 is_tcp_cso:1;
u32 is_cso_err:1;
u32 is_sop:1;
u32 is_eop:1;
u32 is_gso_tcp:1;
u32 is_gso_udp:1;
u32 is_mapped:1;
u32 is_cleaned:1;
u32 is_error:1;
u32 is_vlan:1;
u32 is_lro:1;
u32 request_ts:1;
u32 clk_sel:1;
u32 rsvd3:1;
u16 eop_index;
u16 rsvd4;
};
u64 flags;
};
};
struct aq_ring_stats_rx_s {
struct u64_stats_sync syncp; /* must be first */
u64 errors;
u64 packets;
u64 bytes;
u64 lro_packets;
u64 jumbo_packets;
u64 alloc_fails;
u64 skb_alloc_fails;
u64 polls;
u64 pg_losts;
u64 pg_flips;
u64 pg_reuses;
u64 xdp_aborted;
u64 xdp_drop;
u64 xdp_pass;
u64 xdp_tx;
u64 xdp_invalid;
u64 xdp_redirect;
};
struct aq_ring_stats_tx_s {
struct u64_stats_sync syncp; /* must be first */
u64 errors;
u64 packets;
u64 bytes;
u64 queue_restarts;
};
union aq_ring_stats_s {
struct aq_ring_stats_rx_s rx;
struct aq_ring_stats_tx_s tx;
};
enum atl_ring_type {
ATL_RING_TX,
ATL_RING_RX,
};
struct aq_ring_s {
struct aq_ring_buff_s *buff_ring;
u8 *dx_ring; /* descriptors ring, dma shared mem */
struct aq_nic_s *aq_nic;
unsigned int idx; /* for HW layer registers operations */
unsigned int hw_head;
unsigned int sw_head;
unsigned int sw_tail;
unsigned int size; /* descriptors number */
unsigned int dx_size; /* TX or RX descriptor size, */
/* stored here for fater math */
u16 page_order;
u16 page_offset;
u16 frame_max;
u16 tail_size;
union aq_ring_stats_s stats;
dma_addr_t dx_ring_pa;
struct bpf_prog *xdp_prog;
enum atl_ring_type ring_type;
struct xdp_rxq_info xdp_rxq;
unsigned long ptp_ts_deadline;
};
struct aq_ring_param_s {
unsigned int vec_idx;
unsigned int cpu;
cpumask_t affinity_mask;
};
static inline void *aq_buf_vaddr(struct aq_rxpage *rxpage)
{
return page_to_virt(rxpage->page) + rxpage->pg_off;
}
static inline dma_addr_t aq_buf_daddr(struct aq_rxpage *rxpage)
{
return rxpage->daddr + rxpage->pg_off;
}
static inline unsigned int aq_ring_next_dx(struct aq_ring_s *self,
unsigned int dx)
{
return (++dx >= self->size) ? 0U : dx;
}
static inline unsigned int aq_ring_avail_dx(struct aq_ring_s *self)
{
return (((self->sw_tail >= self->sw_head)) ?
(self->size - 1) - self->sw_tail + self->sw_head :
self->sw_head - self->sw_tail - 1);
}
int aq_ring_tx_alloc(struct aq_ring_s *self,
struct aq_nic_s *aq_nic,
unsigned int idx,
struct aq_nic_cfg_s *aq_nic_cfg);
int aq_ring_rx_alloc(struct aq_ring_s *self,
struct aq_nic_s *aq_nic,
unsigned int idx,
struct aq_nic_cfg_s *aq_nic_cfg);
int aq_ring_init(struct aq_ring_s *self, const enum atl_ring_type ring_type);
void aq_ring_rx_deinit(struct aq_ring_s *self);
void aq_ring_free(struct aq_ring_s *self);
void aq_ring_update_queue_state(struct aq_ring_s *ring);
void aq_ring_queue_wake(struct aq_ring_s *ring);
void aq_ring_queue_stop(struct aq_ring_s *ring);
bool aq_ring_tx_clean(struct aq_ring_s *self);
void aq_ring_tx_deinit(struct aq_ring_s *self);
int aq_xdp_xmit(struct net_device *dev, int num_frames,
struct xdp_frame **frames, u32 flags);
int aq_ring_rx_clean(struct aq_ring_s *self,
struct napi_struct *napi,
int *work_done,
int budget);
int aq_ring_rx_fill(struct aq_ring_s *self);
int aq_ring_hwts_rx_alloc(struct aq_ring_s *self,
struct aq_nic_s *aq_nic, unsigned int idx,
unsigned int size, unsigned int dx_size);
void aq_ring_hwts_rx_free(struct aq_ring_s *self);
void aq_ring_hwts_rx_clean(struct aq_ring_s *self, struct aq_nic_s *aq_nic);
unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data);
#endif /* AQ_RING_H */
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
*/
/* File aq_rss.h: Receive Side Scaling definitions. */
#ifndef AQ_RSS_H
#define AQ_RSS_H
#include "aq_common.h"
#include "aq_cfg.h"
struct aq_rss_parameters {
u16 base_cpu_number;
u16 indirection_table_size;
u16 hash_secret_key_size;
u32 hash_secret_key[AQ_CFG_RSS_HASHKEY_SIZE / sizeof(u32)];
u8 indirection_table[AQ_CFG_RSS_INDIRECTION_TABLE_MAX];
};
#endif /* AQ_RSS_H */
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
*/
/* File aq_utils.h: Useful macro and structures used in all layers of driver. */
#ifndef AQ_UTILS_H
#define AQ_UTILS_H
#include "aq_common.h"
static inline void aq_utils_obj_set(atomic_t *flags, u32 mask)
{
unsigned long flags_old, flags_new;
do {
flags_old = atomic_read(flags);
flags_new = flags_old | (mask);
} while (atomic_cmpxchg(flags, flags_old, flags_new) != flags_old);
}
static inline void aq_utils_obj_clear(atomic_t *flags, u32 mask)
{
unsigned long flags_old, flags_new;
do {
flags_old = atomic_read(flags);
flags_new = flags_old & ~(mask);
} while (atomic_cmpxchg(flags, flags_old, flags_new) != flags_old);
}
static inline bool aq_utils_obj_test(atomic_t *flags, u32 mask)
{
return atomic_read(flags) & mask;
}
#endif /* AQ_UTILS_H */
@@ -0,0 +1,379 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_vec.c: Definition of common structure for vector of Rx and Tx rings.
* Definition of functions for Rx and Tx rings. Friendly module for aq_nic.
*/
#include "aq_vec.h"
struct aq_vec_s {
const struct aq_hw_ops *aq_hw_ops;
struct aq_hw_s *aq_hw;
struct aq_nic_s *aq_nic;
unsigned int tx_rings;
unsigned int rx_rings;
struct aq_ring_param_s aq_ring_param;
struct napi_struct napi;
struct aq_ring_s ring[AQ_CFG_TCS_MAX][2];
};
#define AQ_VEC_TX_ID 0
#define AQ_VEC_RX_ID 1
static int aq_vec_poll(struct napi_struct *napi, int budget)
{
struct aq_vec_s *self = container_of(napi, struct aq_vec_s, napi);
unsigned int sw_tail_old = 0U;
struct aq_ring_s *ring = NULL;
bool was_tx_cleaned = true;
unsigned int i = 0U;
int work_done = 0;
int err = 0;
if (!self) {
err = -EINVAL;
} else {
for (i = 0U; self->tx_rings > i; ++i) {
ring = self->ring[i];
u64_stats_update_begin(&ring[AQ_VEC_RX_ID].stats.rx.syncp);
ring[AQ_VEC_RX_ID].stats.rx.polls++;
u64_stats_update_end(&ring[AQ_VEC_RX_ID].stats.rx.syncp);
if (self->aq_hw_ops->hw_ring_tx_head_update) {
err = self->aq_hw_ops->hw_ring_tx_head_update(
self->aq_hw,
&ring[AQ_VEC_TX_ID]);
if (err < 0)
goto err_exit;
}
if (ring[AQ_VEC_TX_ID].sw_head !=
ring[AQ_VEC_TX_ID].hw_head) {
was_tx_cleaned = aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
aq_ring_update_queue_state(&ring[AQ_VEC_TX_ID]);
}
err = self->aq_hw_ops->hw_ring_rx_receive(self->aq_hw,
&ring[AQ_VEC_RX_ID]);
if (err < 0)
goto err_exit;
if (ring[AQ_VEC_RX_ID].sw_head !=
ring[AQ_VEC_RX_ID].hw_head) {
err = aq_ring_rx_clean(&ring[AQ_VEC_RX_ID],
napi,
&work_done,
budget - work_done);
if (err < 0)
goto err_exit;
sw_tail_old = ring[AQ_VEC_RX_ID].sw_tail;
err = aq_ring_rx_fill(&ring[AQ_VEC_RX_ID]);
if (err < 0)
goto err_exit;
err = self->aq_hw_ops->hw_ring_rx_fill(
self->aq_hw,
&ring[AQ_VEC_RX_ID], sw_tail_old);
if (err < 0)
goto err_exit;
}
}
err_exit:
if (!was_tx_cleaned)
work_done = budget;
if (work_done < budget) {
napi_complete_done(napi, work_done);
self->aq_hw_ops->hw_irq_enable(self->aq_hw,
1U << self->aq_ring_param.vec_idx);
}
}
return work_done;
}
struct aq_vec_s *aq_vec_alloc(struct aq_nic_s *aq_nic, unsigned int idx,
struct aq_nic_cfg_s *aq_nic_cfg)
{
struct aq_vec_s *self = NULL;
self = kzalloc_obj(*self);
if (!self)
goto err_exit;
self->aq_nic = aq_nic;
self->aq_ring_param.vec_idx = idx;
self->aq_ring_param.cpu =
idx + aq_nic_cfg->aq_rss.base_cpu_number;
cpumask_set_cpu(self->aq_ring_param.cpu,
&self->aq_ring_param.affinity_mask);
self->tx_rings = 0;
self->rx_rings = 0;
netif_napi_add(aq_nic_get_ndev(aq_nic), &self->napi, aq_vec_poll);
err_exit:
return self;
}
int aq_vec_ring_alloc(struct aq_vec_s *self, struct aq_nic_s *aq_nic,
unsigned int idx, struct aq_nic_cfg_s *aq_nic_cfg)
{
struct aq_ring_s *ring = NULL;
unsigned int i = 0U;
int err = 0;
for (i = 0; i < aq_nic_cfg->tcs; ++i) {
const unsigned int idx_ring = AQ_NIC_CFG_TCVEC2RING(aq_nic_cfg,
i, idx);
ring = &self->ring[i][AQ_VEC_TX_ID];
err = aq_ring_tx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
if (err)
goto err_exit;
++self->tx_rings;
aq_nic_set_tx_ring(aq_nic, idx_ring, ring);
ring = &self->ring[i][AQ_VEC_RX_ID];
if (xdp_rxq_info_reg(&ring->xdp_rxq,
aq_nic->ndev, idx,
self->napi.napi_id) < 0) {
err = -ENOMEM;
goto err_exit;
}
if (xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_PAGE_SHARED, NULL) < 0) {
xdp_rxq_info_unreg(&ring->xdp_rxq);
err = -ENOMEM;
goto err_exit;
}
err = aq_ring_rx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
if (err) {
xdp_rxq_info_unreg(&ring->xdp_rxq);
goto err_exit;
}
++self->rx_rings;
}
err_exit:
if (err < 0) {
aq_vec_ring_free(self);
self = NULL;
}
return err;
}
int aq_vec_init(struct aq_vec_s *self, const struct aq_hw_ops *aq_hw_ops,
struct aq_hw_s *aq_hw)
{
struct aq_ring_s *ring = NULL;
unsigned int i = 0U;
int err = 0;
self->aq_hw_ops = aq_hw_ops;
self->aq_hw = aq_hw;
for (i = 0U; self->tx_rings > i; ++i) {
ring = self->ring[i];
err = aq_ring_init(&ring[AQ_VEC_TX_ID], ATL_RING_TX);
if (err < 0)
goto err_exit;
err = self->aq_hw_ops->hw_ring_tx_init(self->aq_hw,
&ring[AQ_VEC_TX_ID],
&self->aq_ring_param);
if (err < 0)
goto err_exit;
err = aq_ring_init(&ring[AQ_VEC_RX_ID], ATL_RING_RX);
if (err < 0)
goto err_exit;
err = self->aq_hw_ops->hw_ring_rx_init(self->aq_hw,
&ring[AQ_VEC_RX_ID],
&self->aq_ring_param);
if (err < 0)
goto err_exit;
err = aq_ring_rx_fill(&ring[AQ_VEC_RX_ID]);
if (err < 0)
goto err_exit;
err = self->aq_hw_ops->hw_ring_rx_fill(self->aq_hw,
&ring[AQ_VEC_RX_ID], 0U);
if (err < 0)
goto err_exit;
}
err_exit:
return err;
}
int aq_vec_start(struct aq_vec_s *self)
{
struct aq_ring_s *ring = NULL;
unsigned int i = 0U;
int err = 0;
for (i = 0U; self->tx_rings > i; ++i) {
ring = self->ring[i];
err = self->aq_hw_ops->hw_ring_tx_start(self->aq_hw,
&ring[AQ_VEC_TX_ID]);
if (err < 0)
goto err_exit;
err = self->aq_hw_ops->hw_ring_rx_start(self->aq_hw,
&ring[AQ_VEC_RX_ID]);
if (err < 0)
goto err_exit;
}
napi_enable(&self->napi);
err_exit:
return err;
}
void aq_vec_stop(struct aq_vec_s *self)
{
struct aq_ring_s *ring = NULL;
unsigned int i = 0U;
for (i = 0U; self->tx_rings > i; ++i) {
ring = self->ring[i];
self->aq_hw_ops->hw_ring_tx_stop(self->aq_hw,
&ring[AQ_VEC_TX_ID]);
self->aq_hw_ops->hw_ring_rx_stop(self->aq_hw,
&ring[AQ_VEC_RX_ID]);
}
napi_disable(&self->napi);
}
void aq_vec_deinit(struct aq_vec_s *self)
{
struct aq_ring_s *ring = NULL;
unsigned int i = 0U;
if (!self)
goto err_exit;
for (i = 0U; self->tx_rings > i; ++i) {
ring = self->ring[i];
aq_ring_tx_deinit(&ring[AQ_VEC_TX_ID]);
aq_ring_rx_deinit(&ring[AQ_VEC_RX_ID]);
}
err_exit:;
}
void aq_vec_free(struct aq_vec_s *self)
{
if (!self)
goto err_exit;
netif_napi_del(&self->napi);
kfree(self);
err_exit:;
}
void aq_vec_ring_free(struct aq_vec_s *self)
{
struct aq_ring_s *ring = NULL;
unsigned int i = 0U;
if (!self)
goto err_exit;
for (i = 0U; self->tx_rings > i; ++i) {
ring = self->ring[i];
aq_ring_free(&ring[AQ_VEC_TX_ID]);
if (i < self->rx_rings) {
xdp_rxq_info_unreg(&ring[AQ_VEC_RX_ID].xdp_rxq);
aq_ring_free(&ring[AQ_VEC_RX_ID]);
}
}
self->tx_rings = 0;
self->rx_rings = 0;
err_exit:;
}
irqreturn_t aq_vec_isr(int irq, void *private)
{
struct aq_vec_s *self = private;
int err = 0;
if (!self) {
err = -EINVAL;
goto err_exit;
}
napi_schedule(&self->napi);
err_exit:
return err >= 0 ? IRQ_HANDLED : IRQ_NONE;
}
irqreturn_t aq_vec_isr_legacy(int irq, void *private)
{
struct aq_vec_s *self = private;
u64 irq_mask = 0U;
int err;
if (!self)
return IRQ_NONE;
err = self->aq_hw_ops->hw_irq_read(self->aq_hw, &irq_mask);
if (err < 0)
return IRQ_NONE;
if (irq_mask) {
self->aq_hw_ops->hw_irq_disable(self->aq_hw,
1U << self->aq_ring_param.vec_idx);
napi_schedule(&self->napi);
} else {
self->aq_hw_ops->hw_irq_enable(self->aq_hw, 1U);
return IRQ_NONE;
}
return IRQ_HANDLED;
}
cpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self)
{
return &self->aq_ring_param.affinity_mask;
}
bool aq_vec_is_valid_tc(struct aq_vec_s *self, const unsigned int tc)
{
return tc < self->rx_rings && tc < self->tx_rings;
}
unsigned int aq_vec_get_sw_stats(struct aq_vec_s *self, const unsigned int tc, u64 *data)
{
unsigned int count;
if (!aq_vec_is_valid_tc(self, tc))
return 0;
count = aq_ring_fill_stats_data(&self->ring[tc][AQ_VEC_RX_ID], data);
count += aq_ring_fill_stats_data(&self->ring[tc][AQ_VEC_TX_ID], data + count);
return count;
}
@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File aq_vec.h: Definition of common structures for vector of Rx and Tx rings.
* Declaration of functions for Rx and Tx rings.
*/
#ifndef AQ_VEC_H
#define AQ_VEC_H
#include "aq_common.h"
#include "aq_nic.h"
#include "aq_ring.h"
#include "aq_hw.h"
#include <linux/irqreturn.h>
#include <linux/filter.h>
#include <linux/netdevice.h>
struct aq_hw_s;
struct aq_hw_ops;
struct aq_nic_s;
struct aq_nic_cfg_s;
struct aq_ring_stats_rx_s;
struct aq_ring_stats_tx_s;
irqreturn_t aq_vec_isr(int irq, void *private);
irqreturn_t aq_vec_isr_legacy(int irq, void *private);
struct aq_vec_s *aq_vec_alloc(struct aq_nic_s *aq_nic, unsigned int idx,
struct aq_nic_cfg_s *aq_nic_cfg);
int aq_vec_ring_alloc(struct aq_vec_s *self, struct aq_nic_s *aq_nic,
unsigned int idx, struct aq_nic_cfg_s *aq_nic_cfg);
int aq_vec_init(struct aq_vec_s *self, const struct aq_hw_ops *aq_hw_ops,
struct aq_hw_s *aq_hw);
void aq_vec_deinit(struct aq_vec_s *self);
void aq_vec_free(struct aq_vec_s *self);
void aq_vec_ring_free(struct aq_vec_s *self);
int aq_vec_start(struct aq_vec_s *self);
void aq_vec_stop(struct aq_vec_s *self);
cpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self);
bool aq_vec_is_valid_tc(struct aq_vec_s *self, const unsigned int tc);
unsigned int aq_vec_get_sw_stats(struct aq_vec_s *self, const unsigned int tc, u64 *data);
#endif /* AQ_VEC_H */
@@ -0,0 +1,981 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File hw_atl_a0.c: Definition of Atlantic hardware specific functions. */
#include "../aq_hw.h"
#include "../aq_hw_utils.h"
#include "../aq_ring.h"
#include "../aq_nic.h"
#include "hw_atl_a0.h"
#include "hw_atl_utils.h"
#include "hw_atl_llh.h"
#include "hw_atl_a0_internal.h"
#define DEFAULT_A0_BOARD_BASIC_CAPABILITIES \
.is_64_dma = true, \
.op64bit = false, \
.msix_irqs = 4U, \
.irq_mask = ~0U, \
.vecs = HW_ATL_A0_RSS_MAX, \
.tcs_max = HW_ATL_A0_TC_MAX, \
.rxd_alignment = 1U, \
.rxd_size = HW_ATL_A0_RXD_SIZE, \
.rxds_max = HW_ATL_A0_MAX_RXD, \
.rxds_min = HW_ATL_A0_MIN_RXD, \
.txd_alignment = 1U, \
.txd_size = HW_ATL_A0_TXD_SIZE, \
.txds_max = HW_ATL_A0_MAX_TXD, \
.txds_min = HW_ATL_A0_MIN_RXD, \
.txhwb_alignment = 4096U, \
.tx_rings = HW_ATL_A0_TX_RINGS, \
.rx_rings = HW_ATL_A0_RX_RINGS, \
.hw_features = NETIF_F_HW_CSUM | \
NETIF_F_RXHASH | \
NETIF_F_RXCSUM | \
NETIF_F_SG | \
NETIF_F_TSO | \
NETIF_F_NTUPLE | \
NETIF_F_HW_VLAN_CTAG_FILTER, \
.hw_priv_flags = IFF_UNICAST_FLT, \
.flow_control = true, \
.mtu = HW_ATL_A0_MTU_JUMBO, \
.mac_regs_count = 88, \
.hw_alive_check_addr = 0x10U
const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_FIBRE,
.link_speed_msk = AQ_NIC_RATE_5G |
AQ_NIC_RATE_2G5 |
AQ_NIC_RATE_1G |
AQ_NIC_RATE_100M,
};
const struct aq_hw_caps_s hw_atl_a0_caps_aqc107 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
.link_speed_msk = AQ_NIC_RATE_10G |
AQ_NIC_RATE_5G |
AQ_NIC_RATE_2G5 |
AQ_NIC_RATE_1G |
AQ_NIC_RATE_100M,
};
const struct aq_hw_caps_s hw_atl_a0_caps_aqc108 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
.link_speed_msk = AQ_NIC_RATE_5G |
AQ_NIC_RATE_2G5 |
AQ_NIC_RATE_1G |
AQ_NIC_RATE_100M,
};
const struct aq_hw_caps_s hw_atl_a0_caps_aqc109 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
.link_speed_msk = AQ_NIC_RATE_2G5 |
AQ_NIC_RATE_1G |
AQ_NIC_RATE_100M,
};
static int hw_atl_a0_hw_reset(struct aq_hw_s *self)
{
int err = 0;
u32 val;
hw_atl_glb_glb_reg_res_dis_set(self, 1U);
hw_atl_pci_pci_reg_res_dis_set(self, 0U);
hw_atl_rx_rx_reg_res_dis_set(self, 0U);
hw_atl_tx_tx_reg_res_dis_set(self, 0U);
HW_ATL_FLUSH();
hw_atl_glb_soft_res_set(self, 1);
/* check 10 times by 1ms */
err = readx_poll_timeout_atomic(hw_atl_glb_soft_res_get,
self, val, val == 0,
1000U, 10000U);
if (err < 0)
goto err_exit;
hw_atl_itr_irq_reg_res_dis_set(self, 0U);
hw_atl_itr_res_irq_set(self, 1U);
/* check 10 times by 1ms */
err = readx_poll_timeout_atomic(hw_atl_itr_res_irq_get,
self, val, val == 0,
1000U, 10000U);
if (err < 0)
goto err_exit;
self->aq_fw_ops->set_state(self, MPI_RESET);
err = aq_hw_err_from_flags(self);
err_exit:
return err;
}
static int hw_atl_a0_hw_qos_set(struct aq_hw_s *self)
{
bool is_rx_flow_control = false;
unsigned int i_priority = 0U;
u32 buff_size = 0U;
u32 tc = 0U;
/* TPS Descriptor rate init */
hw_atl_tps_tx_pkt_shed_desc_rate_curr_time_res_set(self, 0x0U);
hw_atl_tps_tx_pkt_shed_desc_rate_lim_set(self, 0xA);
/* TPS VM init */
hw_atl_tps_tx_pkt_shed_desc_vm_arb_mode_set(self, 0U);
/* TPS TC credits init */
hw_atl_tps_tx_pkt_shed_desc_tc_arb_mode_set(self, 0U);
hw_atl_tps_tx_pkt_shed_data_arb_mode_set(self, 0U);
hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0U, 0xFFF);
hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, 0U, 0x64);
hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0U, 0x50);
hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, 0U, 0x1E);
/* Tx buf size */
buff_size = HW_ATL_A0_TXBUF_MAX;
hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, buff_size, tc);
hw_atl_tpb_tx_buff_hi_threshold_per_tc_set(self,
(buff_size *
(1024 / 32U) * 66U) /
100U, tc);
hw_atl_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->fc.req);
buff_size = HW_ATL_A0_RXBUF_MAX;
hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc);
hw_atl_rpb_rx_buff_hi_threshold_per_tc_set(self,
(buff_size *
(1024U / 32U) * 66U) /
100U, tc);
hw_atl_rpb_rx_buff_lo_threshold_per_tc_set(self,
(buff_size *
(1024U / 32U) * 50U) /
100U, tc);
hw_atl_rpb_rx_xoff_en_per_tc_set(self, is_rx_flow_control ? 1U : 0U, tc);
/* QoS 802.1p priority -> TC mapping */
for (i_priority = 8U; i_priority--;)
hw_atl_rpf_rpb_user_priority_tc_map_set(self, i_priority, 0U);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_rss_hash_set(struct aq_hw_s *self,
struct aq_rss_parameters *rss_params)
{
struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
unsigned int addr = 0U;
unsigned int i = 0U;
int err = 0;
u32 val;
for (i = 10, addr = 0U; i--; ++addr) {
u32 key_data = cfg->is_rss ?
__swab32(rss_params->hash_secret_key[i]) : 0U;
hw_atl_rpf_rss_key_wr_data_set(self, key_data);
hw_atl_rpf_rss_key_addr_set(self, addr);
hw_atl_rpf_rss_key_wr_en_set(self, 1U);
err = readx_poll_timeout_atomic(hw_atl_rpf_rss_key_wr_en_get,
self, val, val == 0,
1000U, 10000U);
if (err < 0)
goto err_exit;
}
err = aq_hw_err_from_flags(self);
err_exit:
return err;
}
static int hw_atl_a0_hw_rss_set(struct aq_hw_s *self,
struct aq_rss_parameters *rss_params)
{
u32 num_rss_queues = max(1U, self->aq_nic_cfg->num_rss_queues);
u8 *indirection_table = rss_params->indirection_table;
u16 bitary[1 + (HW_ATL_A0_RSS_REDIRECTION_MAX *
HW_ATL_A0_RSS_REDIRECTION_BITS / 16U)];
int err = 0;
u32 i = 0U;
u32 val;
memset(bitary, 0, sizeof(bitary));
for (i = HW_ATL_A0_RSS_REDIRECTION_MAX; i--; ) {
(*(u32 *)(bitary + ((i * 3U) / 16U))) |=
((indirection_table[i] % num_rss_queues) <<
((i * 3U) & 0xFU));
}
for (i = ARRAY_SIZE(bitary); i--;) {
hw_atl_rpf_rss_redir_tbl_wr_data_set(self, bitary[i]);
hw_atl_rpf_rss_redir_tbl_addr_set(self, i);
hw_atl_rpf_rss_redir_wr_en_set(self, 1U);
err = readx_poll_timeout_atomic(hw_atl_rpf_rss_redir_wr_en_get,
self, val, val == 0,
1000U, 10000U);
if (err < 0)
goto err_exit;
}
err = aq_hw_err_from_flags(self);
err_exit:
return err;
}
static int hw_atl_a0_hw_offload_set(struct aq_hw_s *self,
struct aq_nic_cfg_s *aq_nic_cfg)
{
/* TX checksums offloads*/
hw_atl_tpo_ipv4header_crc_offload_en_set(self, 1);
hw_atl_tpo_tcp_udp_crc_offload_en_set(self, 1);
/* RX checksums offloads*/
hw_atl_rpo_ipv4header_crc_offload_en_set(self, 1);
hw_atl_rpo_tcp_udp_crc_offload_en_set(self, 1);
/* LSO offloads*/
hw_atl_tdm_large_send_offload_en_set(self, 0xFFFFFFFFU);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_init_tx_path(struct aq_hw_s *self)
{
hw_atl_thm_lso_tcp_flag_of_first_pkt_set(self, 0x0FF6U);
hw_atl_thm_lso_tcp_flag_of_middle_pkt_set(self, 0x0FF6U);
hw_atl_thm_lso_tcp_flag_of_last_pkt_set(self, 0x0F7FU);
/* Tx interrupts */
hw_atl_tdm_tx_desc_wr_wb_irq_en_set(self, 1U);
/* misc */
aq_hw_write_reg(self, 0x00007040U, 0x00000000U);
hw_atl_tdm_tx_dca_en_set(self, 0U);
hw_atl_tdm_tx_dca_mode_set(self, 0U);
hw_atl_tpb_tx_path_scp_ins_en_set(self, 1U);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_init_rx_path(struct aq_hw_s *self)
{
struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
int i;
/* Rx TC/RSS number config */
hw_atl_rpb_rpf_rx_traf_class_mode_set(self, 1U);
/* Rx flow control */
hw_atl_rpb_rx_flow_ctl_mode_set(self, 1U);
/* RSS Ring selection */
hw_atl_reg_rx_flr_rss_control1set(self, cfg->is_rss ?
0xB3333333U : 0x00000000U);
/* Multicast filters */
for (i = HW_ATL_A0_MAC_MAX; i--;) {
hw_atl_rpfl2_uc_flr_en_set(self, (i == 0U) ? 1U : 0U, i);
hw_atl_rpfl2unicast_flr_act_set(self, 1U, i);
}
hw_atl_reg_rx_flr_mcst_flr_msk_set(self, 0x00000000U);
hw_atl_reg_rx_flr_mcst_flr_set(self, 0x00010FFFU, 0U);
/* Vlan filters */
hw_atl_rpf_vlan_outer_etht_set(self, 0x88A8U);
hw_atl_rpf_vlan_inner_etht_set(self, 0x8100U);
hw_atl_rpf_vlan_prom_mode_en_set(self, 1);
/* Rx Interrupts */
hw_atl_rdm_rx_desc_wr_wb_irq_en_set(self, 1U);
/* misc */
hw_atl_rpfl2broadcast_flr_act_set(self, 1U);
hw_atl_rpfl2broadcast_count_threshold_set(self, 0xFFFFU & (~0U / 256U));
hw_atl_rdm_rx_dca_en_set(self, 0U);
hw_atl_rdm_rx_dca_mode_set(self, 0U);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_mac_addr_set(struct aq_hw_s *self, const u8 *mac_addr)
{
unsigned int h = 0U;
unsigned int l = 0U;
int err = 0;
if (!mac_addr) {
err = -EINVAL;
goto err_exit;
}
h = (mac_addr[0] << 8) | (mac_addr[1]);
l = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
(mac_addr[4] << 8) | mac_addr[5];
hw_atl_rpfl2_uc_flr_en_set(self, 0U, HW_ATL_A0_MAC);
hw_atl_rpfl2unicast_dest_addresslsw_set(self, l, HW_ATL_A0_MAC);
hw_atl_rpfl2unicast_dest_addressmsw_set(self, h, HW_ATL_A0_MAC);
hw_atl_rpfl2_uc_flr_en_set(self, 1U, HW_ATL_A0_MAC);
err = aq_hw_err_from_flags(self);
err_exit:
return err;
}
static int hw_atl_a0_hw_init(struct aq_hw_s *self, const u8 *mac_addr)
{
static u32 aq_hw_atl_igcr_table_[4][2] = {
[AQ_HW_IRQ_INVALID] = { 0x20000000U, 0x20000000U },
[AQ_HW_IRQ_INTX] = { 0x20000080U, 0x20000080U },
[AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U },
[AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U },
};
struct aq_nic_cfg_s *aq_nic_cfg = self->aq_nic_cfg;
int err = 0;
hw_atl_a0_hw_init_tx_path(self);
hw_atl_a0_hw_init_rx_path(self);
hw_atl_a0_hw_mac_addr_set(self, mac_addr);
self->aq_fw_ops->set_link_speed(self, aq_nic_cfg->link_speed_msk);
self->aq_fw_ops->set_state(self, MPI_INIT);
hw_atl_reg_tx_dma_debug_ctl_set(self, 0x800000b8U);
hw_atl_reg_tx_dma_debug_ctl_set(self, 0x000000b8U);
hw_atl_a0_hw_qos_set(self);
hw_atl_a0_hw_rss_set(self, &aq_nic_cfg->aq_rss);
hw_atl_a0_hw_rss_hash_set(self, &aq_nic_cfg->aq_rss);
/* Reset link status and read out initial hardware counters */
self->aq_link_status.mbps = 0;
self->aq_fw_ops->update_stats(self);
err = aq_hw_err_from_flags(self);
if (err < 0)
goto err_exit;
/* Interrupts */
hw_atl_reg_irq_glb_ctl_set(self,
aq_hw_atl_igcr_table_[aq_nic_cfg->irq_type]
[(aq_nic_cfg->vecs > 1U) ? 1 : 0]);
hw_atl_itr_irq_auto_masklsw_set(self, aq_nic_cfg->aq_hw_caps->irq_mask);
/* Interrupts */
hw_atl_reg_gen_irq_map_set(self,
((HW_ATL_A0_ERR_INT << 0x18) | (1U << 0x1F)) |
((HW_ATL_A0_ERR_INT << 0x10) | (1U << 0x17)) |
((HW_ATL_A0_ERR_INT << 8) | (1U << 0xF)) |
((HW_ATL_A0_ERR_INT) | (1U << 0x7)), 0U);
hw_atl_a0_hw_offload_set(self, aq_nic_cfg);
err_exit:
return err;
}
static int hw_atl_a0_hw_ring_tx_start(struct aq_hw_s *self,
struct aq_ring_s *ring)
{
hw_atl_tdm_tx_desc_en_set(self, 1, ring->idx);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_ring_rx_start(struct aq_hw_s *self,
struct aq_ring_s *ring)
{
hw_atl_rdm_rx_desc_en_set(self, 1, ring->idx);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_start(struct aq_hw_s *self)
{
hw_atl_tpb_tx_buff_en_set(self, 1);
hw_atl_rpb_rx_buff_en_set(self, 1);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_tx_ring_tail_update(struct aq_hw_s *self,
struct aq_ring_s *ring)
{
hw_atl_reg_tx_dma_desc_tail_ptr_set(self, ring->sw_tail, ring->idx);
return 0;
}
static int hw_atl_a0_hw_ring_tx_xmit(struct aq_hw_s *self,
struct aq_ring_s *ring,
unsigned int frags)
{
struct aq_ring_buff_s *buff = NULL;
struct hw_atl_txd_s *txd = NULL;
unsigned int buff_pa_len = 0U;
unsigned int frag_count = 0U;
unsigned int pkt_len = 0U;
bool is_gso = false;
buff = &ring->buff_ring[ring->sw_tail];
pkt_len = (buff->is_eop && buff->is_sop) ? buff->len : buff->len_pkt;
for (frag_count = 0; frag_count < frags; frag_count++) {
txd = (struct hw_atl_txd_s *)&ring->dx_ring[ring->sw_tail *
HW_ATL_A0_TXD_SIZE];
txd->ctl = 0;
txd->ctl2 = 0;
txd->buf_addr = 0;
buff = &ring->buff_ring[ring->sw_tail];
if (buff->is_gso_tcp) {
txd->ctl |= (buff->len_l3 << 31) |
(buff->len_l2 << 24) |
HW_ATL_A0_TXD_CTL_CMD_TCP |
HW_ATL_A0_TXD_CTL_DESC_TYPE_TXC;
txd->ctl2 |= (buff->mss << 16) |
(buff->len_l4 << 8) |
(buff->len_l3 >> 1);
pkt_len -= (buff->len_l4 +
buff->len_l3 +
buff->len_l2);
is_gso = true;
if (buff->is_ipv6)
txd->ctl |= HW_ATL_A0_TXD_CTL_CMD_IPV6;
} else {
buff_pa_len = buff->len;
txd->buf_addr = buff->pa;
txd->ctl |= (HW_ATL_A0_TXD_CTL_BLEN &
((u32)buff_pa_len << 4));
txd->ctl |= HW_ATL_A0_TXD_CTL_DESC_TYPE_TXD;
/* PAY_LEN */
txd->ctl2 |= HW_ATL_A0_TXD_CTL2_LEN & (pkt_len << 14);
if (is_gso) {
txd->ctl |= HW_ATL_A0_TXD_CTL_CMD_LSO;
txd->ctl2 |= HW_ATL_A0_TXD_CTL2_CTX_EN;
}
/* Tx checksum offloads */
if (buff->is_ip_cso)
txd->ctl |= HW_ATL_A0_TXD_CTL_CMD_IPCSO;
if (buff->is_udp_cso || buff->is_tcp_cso)
txd->ctl |= HW_ATL_A0_TXD_CTL_CMD_TUCSO;
if (unlikely(buff->is_eop)) {
txd->ctl |= HW_ATL_A0_TXD_CTL_EOP;
txd->ctl |= HW_ATL_A0_TXD_CTL_CMD_WB;
is_gso = false;
}
}
ring->sw_tail = aq_ring_next_dx(ring, ring->sw_tail);
}
hw_atl_a0_hw_tx_ring_tail_update(self, ring);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_ring_rx_init(struct aq_hw_s *self,
struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param)
{
u32 dma_desc_addr_msw = (u32)(((u64)aq_ring->dx_ring_pa) >> 32);
u32 dma_desc_addr_lsw = (u32)aq_ring->dx_ring_pa;
hw_atl_rdm_rx_desc_en_set(self, false, aq_ring->idx);
hw_atl_rdm_rx_desc_head_splitting_set(self, 0U, aq_ring->idx);
hw_atl_reg_rx_dma_desc_base_addresslswset(self, dma_desc_addr_lsw,
aq_ring->idx);
hw_atl_reg_rx_dma_desc_base_addressmswset(self,
dma_desc_addr_msw,
aq_ring->idx);
hw_atl_rdm_rx_desc_len_set(self, aq_ring->size / 8U, aq_ring->idx);
hw_atl_rdm_rx_desc_data_buff_size_set(self,
aq_ring->frame_max / 1024U,
aq_ring->idx);
hw_atl_rdm_rx_desc_head_buff_size_set(self, 0U, aq_ring->idx);
hw_atl_rdm_rx_desc_head_splitting_set(self, 0U, aq_ring->idx);
hw_atl_rpo_rx_desc_vlan_stripping_set(self, 0U, aq_ring->idx);
/* Rx ring set mode */
/* Mapping interrupt vector */
hw_atl_itr_irq_map_rx_set(self, aq_ring_param->vec_idx, aq_ring->idx);
hw_atl_itr_irq_map_en_rx_set(self, true, aq_ring->idx);
hw_atl_rdm_cpu_id_set(self, aq_ring_param->cpu, aq_ring->idx);
hw_atl_rdm_rx_desc_dca_en_set(self, 0U, aq_ring->idx);
hw_atl_rdm_rx_head_dca_en_set(self, 0U, aq_ring->idx);
hw_atl_rdm_rx_pld_dca_en_set(self, 0U, aq_ring->idx);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_ring_tx_init(struct aq_hw_s *self,
struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param)
{
u32 dma_desc_msw_addr = (u32)(((u64)aq_ring->dx_ring_pa) >> 32);
u32 dma_desc_lsw_addr = (u32)aq_ring->dx_ring_pa;
hw_atl_reg_tx_dma_desc_base_addresslswset(self, dma_desc_lsw_addr,
aq_ring->idx);
hw_atl_reg_tx_dma_desc_base_addressmswset(self, dma_desc_msw_addr,
aq_ring->idx);
hw_atl_tdm_tx_desc_len_set(self, aq_ring->size / 8U, aq_ring->idx);
hw_atl_a0_hw_tx_ring_tail_update(self, aq_ring);
/* Set Tx threshold */
hw_atl_tdm_tx_desc_wr_wb_threshold_set(self, 0U, aq_ring->idx);
/* Mapping interrupt vector */
hw_atl_itr_irq_map_tx_set(self, aq_ring_param->vec_idx, aq_ring->idx);
hw_atl_itr_irq_map_en_tx_set(self, true, aq_ring->idx);
hw_atl_tdm_cpu_id_set(self, aq_ring_param->cpu, aq_ring->idx);
hw_atl_tdm_tx_desc_dca_en_set(self, 0U, aq_ring->idx);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_ring_rx_fill(struct aq_hw_s *self,
struct aq_ring_s *ring,
unsigned int sw_tail_old)
{
for (; sw_tail_old != ring->sw_tail;
sw_tail_old = aq_ring_next_dx(ring, sw_tail_old)) {
struct hw_atl_rxd_s *rxd =
(struct hw_atl_rxd_s *)&ring->dx_ring[sw_tail_old *
HW_ATL_A0_RXD_SIZE];
struct aq_ring_buff_s *buff = &ring->buff_ring[sw_tail_old];
rxd->buf_addr = buff->pa;
rxd->hdr_addr = 0U;
}
hw_atl_reg_rx_dma_desc_tail_ptr_set(self, sw_tail_old, ring->idx);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_ring_tx_head_update(struct aq_hw_s *self,
struct aq_ring_s *ring)
{
unsigned int hw_head = hw_atl_tdm_tx_desc_head_ptr_get(self, ring->idx);
int err = 0;
if (aq_utils_obj_test(&self->flags, AQ_HW_FLAG_ERR_UNPLUG)) {
err = -ENXIO;
goto err_exit;
}
ring->hw_head = hw_head;
err = aq_hw_err_from_flags(self);
err_exit:
return err;
}
static int hw_atl_a0_hw_ring_rx_receive(struct aq_hw_s *self,
struct aq_ring_s *ring)
{
for (; ring->hw_head != ring->sw_tail;
ring->hw_head = aq_ring_next_dx(ring, ring->hw_head)) {
struct aq_ring_buff_s *buff = NULL;
struct hw_atl_rxd_wb_s *rxd_wb = (struct hw_atl_rxd_wb_s *)
&ring->dx_ring[ring->hw_head * HW_ATL_A0_RXD_SIZE];
unsigned int is_err = 1U;
unsigned int is_rx_check_sum_enabled = 0U;
unsigned int pkt_type = 0U;
if (!(rxd_wb->status & 0x5U)) { /* RxD is not done */
if ((1U << 4) &
hw_atl_reg_rx_dma_desc_status_get(self, ring->idx)) {
hw_atl_rdm_rx_desc_en_set(self, false, ring->idx);
hw_atl_rdm_rx_desc_res_set(self, true, ring->idx);
hw_atl_rdm_rx_desc_res_set(self, false, ring->idx);
hw_atl_rdm_rx_desc_en_set(self, true, ring->idx);
}
if (ring->hw_head ||
(hw_atl_rdm_rx_desc_head_ptr_get(self,
ring->idx) < 2U)) {
break;
} else if (!(rxd_wb->status & 0x1U)) {
struct hw_atl_rxd_wb_s *rxd_wb1 =
(struct hw_atl_rxd_wb_s *)
(&ring->dx_ring[(1U) *
HW_ATL_A0_RXD_SIZE]);
if ((rxd_wb1->status & 0x1U)) {
rxd_wb->pkt_len = 1514U;
rxd_wb->status = 3U;
} else {
break;
}
}
}
buff = &ring->buff_ring[ring->hw_head];
if (0x3U != (rxd_wb->status & 0x3U))
rxd_wb->status |= 4;
is_err = (0x0000001CU & rxd_wb->status);
is_rx_check_sum_enabled = (rxd_wb->type) & (0x3U << 19);
pkt_type = 0xFFU & (rxd_wb->type >> 4);
if (is_rx_check_sum_enabled) {
if (0x0U == (pkt_type & 0x3U))
buff->is_ip_cso = (is_err & 0x08U) ? 0 : 1;
if (0x4U == (pkt_type & 0x1CU))
buff->is_udp_cso = (is_err & 0x10U) ? 0 : 1;
else if (0x0U == (pkt_type & 0x1CU))
buff->is_tcp_cso = (is_err & 0x10U) ? 0 : 1;
/* Checksum offload workaround for small packets */
if (rxd_wb->pkt_len <= 60) {
buff->is_ip_cso = 0U;
buff->is_cso_err = 0U;
}
}
is_err &= ~0x18U;
is_err &= ~0x04U;
if (is_err || rxd_wb->type & 0x1000U) {
/* status error or DMA error */
buff->is_error = 1U;
} else {
if (self->aq_nic_cfg->is_rss) {
/* last 4 byte */
u16 rss_type = rxd_wb->type & 0xFU;
if (rss_type && rss_type < 0x8U) {
buff->is_hash_l4 = (rss_type == 0x4 ||
rss_type == 0x5);
buff->rss_hash = rxd_wb->rss_hash;
}
}
if (HW_ATL_A0_RXD_WB_STAT2_EOP & rxd_wb->status) {
buff->len = rxd_wb->pkt_len %
ring->frame_max;
buff->len = buff->len ?
buff->len : ring->frame_max;
buff->next = 0U;
buff->is_eop = 1U;
} else {
/* jumbo */
buff->next = aq_ring_next_dx(ring,
ring->hw_head);
++ring->stats.rx.jumbo_packets;
}
}
}
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_irq_enable(struct aq_hw_s *self, u64 mask)
{
hw_atl_itr_irq_msk_setlsw_set(self, LODWORD(mask) |
(1U << HW_ATL_A0_ERR_INT));
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_irq_disable(struct aq_hw_s *self, u64 mask)
{
hw_atl_itr_irq_msk_clearlsw_set(self, LODWORD(mask));
hw_atl_itr_irq_status_clearlsw_set(self, LODWORD(mask));
if ((1U << 16) & hw_atl_reg_gen_irq_status_get(self))
atomic_inc(&self->dpc);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_irq_read(struct aq_hw_s *self, u64 *mask)
{
*mask = hw_atl_itr_irq_statuslsw_get(self);
return aq_hw_err_from_flags(self);
}
#define IS_FILTER_ENABLED(_F_) ((packet_filter & (_F_)) ? 1U : 0U)
static int hw_atl_a0_hw_packet_filter_set(struct aq_hw_s *self,
unsigned int packet_filter)
{
struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
unsigned int i = 0U;
hw_atl_rpfl2promiscuous_mode_en_set(self,
IS_FILTER_ENABLED(IFF_PROMISC));
hw_atl_rpfl2multicast_flr_en_set(self,
IS_FILTER_ENABLED(IFF_MULTICAST), 0);
hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST));
cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST);
for (i = HW_ATL_A0_MAC_MIN; i < HW_ATL_A0_MAC_MAX; ++i)
hw_atl_rpfl2_uc_flr_en_set(self,
(cfg->is_mc_list_enabled &&
(i <= cfg->mc_list_count)) ? 1U : 0U,
i);
return aq_hw_err_from_flags(self);
}
#undef IS_FILTER_ENABLED
static int hw_atl_a0_hw_multicast_list_set(struct aq_hw_s *self,
u8 ar_mac
[AQ_HW_MULTICAST_ADDRESS_MAX]
[ETH_ALEN],
u32 count)
{
struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
int err = 0;
if (count > (HW_ATL_A0_MAC_MAX - HW_ATL_A0_MAC_MIN)) {
err = -EBADRQC;
goto err_exit;
}
for (cfg->mc_list_count = 0U; cfg->mc_list_count < count; ++cfg->mc_list_count) {
u32 i = cfg->mc_list_count;
u32 h = (ar_mac[i][0] << 8) | (ar_mac[i][1]);
u32 l = (ar_mac[i][2] << 24) | (ar_mac[i][3] << 16) |
(ar_mac[i][4] << 8) | ar_mac[i][5];
hw_atl_rpfl2_uc_flr_en_set(self, 0U, HW_ATL_A0_MAC_MIN + i);
hw_atl_rpfl2unicast_dest_addresslsw_set(self,
l,
HW_ATL_A0_MAC_MIN + i);
hw_atl_rpfl2unicast_dest_addressmsw_set(self,
h,
HW_ATL_A0_MAC_MIN + i);
hw_atl_rpfl2_uc_flr_en_set(self,
(cfg->is_mc_list_enabled),
HW_ATL_A0_MAC_MIN + i);
}
err = aq_hw_err_from_flags(self);
err_exit:
return err;
}
static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self)
{
unsigned int i = 0U;
u32 itr_rx;
if (self->aq_nic_cfg->itr) {
if (self->aq_nic_cfg->itr != AQ_CFG_INTERRUPT_MODERATION_AUTO) {
u32 itr_ = (self->aq_nic_cfg->itr >> 1);
itr_ = min(AQ_CFG_IRQ_MASK, itr_);
itr_rx = 0x80000000U | (itr_ << 0x10);
} else {
u32 n = 0xFFFFU & aq_hw_read_reg(self, 0x00002A00U);
if (n < self->aq_link_status.mbps) {
itr_rx = 0U;
} else {
static unsigned int hw_timers_tbl_[] = {
0x01CU, /* 10Gbit */
0x039U, /* 5Gbit */
0x039U, /* 5Gbit 5GS */
0x073U, /* 2.5Gbit */
0x120U, /* 1Gbit */
0x1FFU, /* 100Mbit */
};
unsigned int speed_index =
hw_atl_utils_mbps_2_speed_index(
self->aq_link_status.mbps);
itr_rx = 0x80000000U |
(hw_timers_tbl_[speed_index] << 0x10U);
}
aq_hw_write_reg(self, 0x00002A00U, 0x40000000U);
aq_hw_write_reg(self, 0x00002A00U, 0x8D000000U);
}
} else {
itr_rx = 0U;
}
for (i = HW_ATL_A0_RINGS_MAX; i--;)
hw_atl_reg_irq_thr_set(self, itr_rx, i);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_stop(struct aq_hw_s *self)
{
hw_atl_a0_hw_irq_disable(self, HW_ATL_A0_INT_MASK);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_ring_tx_stop(struct aq_hw_s *self,
struct aq_ring_s *ring)
{
hw_atl_tdm_tx_desc_en_set(self, 0U, ring->idx);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self,
struct aq_ring_s *ring)
{
hw_atl_rdm_rx_desc_en_set(self, 0U, ring->idx);
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_fl3l4_clear(struct aq_hw_s *self,
struct aq_rx_filter_l3l4 *data)
{
u8 location = data->location;
if (!data->is_ipv6) {
hw_atl_rpfl3l4_cmd_clear(self, location);
hw_atl_rpf_l4_spd_set(self, 0U, location);
hw_atl_rpf_l4_dpd_set(self, 0U, location);
hw_atl_rpfl3l4_ipv4_src_addr_clear(self, location);
hw_atl_rpfl3l4_ipv4_dest_addr_clear(self, location);
} else {
int i;
for (i = 0; i < HW_ATL_RX_CNT_REG_ADDR_IPV6; ++i) {
hw_atl_rpfl3l4_cmd_clear(self, location + i);
hw_atl_rpf_l4_spd_set(self, 0U, location + i);
hw_atl_rpf_l4_dpd_set(self, 0U, location + i);
}
hw_atl_rpfl3l4_ipv6_src_addr_clear(self, location);
hw_atl_rpfl3l4_ipv6_dest_addr_clear(self, location);
}
return aq_hw_err_from_flags(self);
}
static int hw_atl_a0_hw_fl3l4_set(struct aq_hw_s *self,
struct aq_rx_filter_l3l4 *data)
{
u8 location = data->location;
hw_atl_a0_hw_fl3l4_clear(self, data);
if (data->cmd) {
if (!data->is_ipv6) {
hw_atl_rpfl3l4_ipv4_dest_addr_set(self,
location,
data->ip_dst[0]);
hw_atl_rpfl3l4_ipv4_src_addr_set(self,
location,
data->ip_src[0]);
} else {
hw_atl_rpfl3l4_ipv6_dest_addr_set(self,
location,
data->ip_dst);
hw_atl_rpfl3l4_ipv6_src_addr_set(self,
location,
data->ip_src);
}
}
hw_atl_rpf_l4_dpd_set(self, data->p_dst, location);
hw_atl_rpf_l4_spd_set(self, data->p_src, location);
hw_atl_rpfl3l4_cmd_set(self, location, data->cmd);
return aq_hw_err_from_flags(self);
}
const struct aq_hw_ops hw_atl_ops_a0 = {
.hw_soft_reset = hw_atl_utils_soft_reset,
.hw_prepare = hw_atl_utils_initfw,
.hw_set_mac_address = hw_atl_a0_hw_mac_addr_set,
.hw_init = hw_atl_a0_hw_init,
.hw_reset = hw_atl_a0_hw_reset,
.hw_start = hw_atl_a0_hw_start,
.hw_ring_tx_start = hw_atl_a0_hw_ring_tx_start,
.hw_ring_tx_stop = hw_atl_a0_hw_ring_tx_stop,
.hw_ring_rx_start = hw_atl_a0_hw_ring_rx_start,
.hw_ring_rx_stop = hw_atl_a0_hw_ring_rx_stop,
.hw_stop = hw_atl_a0_hw_stop,
.hw_ring_tx_xmit = hw_atl_a0_hw_ring_tx_xmit,
.hw_ring_tx_head_update = hw_atl_a0_hw_ring_tx_head_update,
.hw_ring_rx_receive = hw_atl_a0_hw_ring_rx_receive,
.hw_ring_rx_fill = hw_atl_a0_hw_ring_rx_fill,
.hw_irq_enable = hw_atl_a0_hw_irq_enable,
.hw_irq_disable = hw_atl_a0_hw_irq_disable,
.hw_irq_read = hw_atl_a0_hw_irq_read,
.hw_ring_rx_init = hw_atl_a0_hw_ring_rx_init,
.hw_ring_tx_init = hw_atl_a0_hw_ring_tx_init,
.hw_packet_filter_set = hw_atl_a0_hw_packet_filter_set,
.hw_filter_l3l4_set = hw_atl_a0_hw_fl3l4_set,
.hw_multicast_list_set = hw_atl_a0_hw_multicast_list_set,
.hw_interrupt_moderation_set = hw_atl_a0_hw_interrupt_moderation_set,
.hw_rss_set = hw_atl_a0_hw_rss_set,
.hw_rss_hash_set = hw_atl_a0_hw_rss_hash_set,
.hw_get_regs = hw_atl_utils_hw_get_regs,
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version = hw_atl_utils_get_fw_version,
};
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_a0.h: Declaration of abstract interface for Atlantic hardware
* specific functions.
*/
#ifndef HW_ATL_A0_H
#define HW_ATL_A0_H
#include "../aq_common.h"
extern const struct aq_hw_caps_s hw_atl_a0_caps_aqc100;
extern const struct aq_hw_caps_s hw_atl_a0_caps_aqc107;
extern const struct aq_hw_caps_s hw_atl_a0_caps_aqc108;
extern const struct aq_hw_caps_s hw_atl_a0_caps_aqc109;
extern const struct aq_hw_ops hw_atl_ops_a0;
#endif /* HW_ATL_A0_H */
@@ -0,0 +1,90 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_a0_internal.h: Definition of Atlantic A0 chip specific
* constants.
*/
#ifndef HW_ATL_A0_INTERNAL_H
#define HW_ATL_A0_INTERNAL_H
#include "../aq_common.h"
#define HW_ATL_A0_MTU_JUMBO 9014U
#define HW_ATL_A0_TX_RINGS 4U
#define HW_ATL_A0_RX_RINGS 4U
#define HW_ATL_A0_RINGS_MAX 32U
#define HW_ATL_A0_TXD_SIZE 16U
#define HW_ATL_A0_RXD_SIZE 16U
#define HW_ATL_A0_MAC 0U
#define HW_ATL_A0_MAC_MIN 1U
#define HW_ATL_A0_MAC_MAX 33U
/* interrupts */
#define HW_ATL_A0_ERR_INT 8U
#define HW_ATL_A0_INT_MASK 0xFFFFFFFFU
#define HW_ATL_A0_TXD_CTL2_LEN 0xFFFFC000U
#define HW_ATL_A0_TXD_CTL2_CTX_EN 0x00002000U
#define HW_ATL_A0_TXD_CTL2_CTX_IDX 0x00001000U
#define HW_ATL_A0_TXD_CTL_DESC_TYPE_TXD 0x00000001U
#define HW_ATL_A0_TXD_CTL_DESC_TYPE_TXC 0x00000002U
#define HW_ATL_A0_TXD_CTL_BLEN 0x000FFFF0U
#define HW_ATL_A0_TXD_CTL_DD 0x00100000U
#define HW_ATL_A0_TXD_CTL_EOP 0x00200000U
#define HW_ATL_A0_TXD_CTL_CMD_X 0x3FC00000U
#define HW_ATL_A0_TXD_CTL_CMD_VLAN BIT(22)
#define HW_ATL_A0_TXD_CTL_CMD_FCS BIT(23)
#define HW_ATL_A0_TXD_CTL_CMD_IPCSO BIT(24)
#define HW_ATL_A0_TXD_CTL_CMD_TUCSO BIT(25)
#define HW_ATL_A0_TXD_CTL_CMD_LSO BIT(26)
#define HW_ATL_A0_TXD_CTL_CMD_WB BIT(27)
#define HW_ATL_A0_TXD_CTL_CMD_VXLAN BIT(28)
#define HW_ATL_A0_TXD_CTL_CMD_IPV6 BIT(21)
#define HW_ATL_A0_TXD_CTL_CMD_TCP BIT(22)
#define HW_ATL_A0_MPI_CONTROL_ADR 0x0368U
#define HW_ATL_A0_MPI_STATE_ADR 0x036CU
#define HW_ATL_A0_MPI_SPEED_MSK 0xFFFFU
#define HW_ATL_A0_MPI_SPEED_SHIFT 16U
#define HW_ATL_A0_TXBUF_MAX 160U
#define HW_ATL_A0_RXBUF_MAX 320U
#define HW_ATL_A0_RSS_REDIRECTION_MAX 64U
#define HW_ATL_A0_RSS_REDIRECTION_BITS 3U
#define HW_ATL_A0_TC_MAX 1U
#define HW_ATL_A0_RSS_MAX 8U
#define HW_ATL_A0_FW_SEMA_RAM 0x2U
#define HW_ATL_A0_RXD_DD 0x1U
#define HW_ATL_A0_RXD_NCEA0 0x1U
#define HW_ATL_A0_RXD_WB_STAT2_EOP 0x0002U
#define HW_ATL_A0_UCP_0X370_REG 0x370U
#define HW_ATL_A0_FW_VER_EXPECTED 0x01050006U
#define HW_ATL_A0_MIN_RXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_RXD_MULTIPLE))
#define HW_ATL_A0_MIN_TXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_TXD_MULTIPLE))
#define HW_ATL_A0_MAX_RXD 8184U
#define HW_ATL_A0_MAX_TXD 8184U
#endif /* HW_ATL_A0_INTERNAL_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File hw_atl_b0.h: Declaration of abstract interface for Atlantic hardware
* specific functions.
*/
#ifndef HW_ATL_B0_H
#define HW_ATL_B0_H
#include "../aq_common.h"
extern const struct aq_hw_caps_s hw_atl_b0_caps_aqc100;
extern const struct aq_hw_caps_s hw_atl_b0_caps_aqc107;
extern const struct aq_hw_caps_s hw_atl_b0_caps_aqc108;
extern const struct aq_hw_caps_s hw_atl_b0_caps_aqc109;
extern const struct aq_hw_caps_s hw_atl_b0_caps_aqc111;
extern const struct aq_hw_caps_s hw_atl_b0_caps_aqc112;
#define hw_atl_b0_caps_aqc100s hw_atl_b0_caps_aqc100
#define hw_atl_b0_caps_aqc107s hw_atl_b0_caps_aqc107
#define hw_atl_b0_caps_aqc108s hw_atl_b0_caps_aqc108
#define hw_atl_b0_caps_aqc109s hw_atl_b0_caps_aqc109
#define hw_atl_b0_caps_aqc111s hw_atl_b0_caps_aqc111
#define hw_atl_b0_caps_aqc112s hw_atl_b0_caps_aqc112
extern const struct aq_hw_ops hw_atl_ops_b0;
#define hw_atl_ops_b1 hw_atl_ops_b0
int hw_atl_b0_hw_rss_hash_set(struct aq_hw_s *self,
struct aq_rss_parameters *rss_params);
int hw_atl_b0_hw_offload_set(struct aq_hw_s *self,
struct aq_nic_cfg_s *aq_nic_cfg);
int hw_atl_b0_hw_ring_tx_start(struct aq_hw_s *self, struct aq_ring_s *ring);
int hw_atl_b0_hw_ring_rx_start(struct aq_hw_s *self, struct aq_ring_s *ring);
int hw_atl_b0_hw_ring_rx_init(struct aq_hw_s *self, struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param);
int hw_atl_b0_hw_ring_rx_fill(struct aq_hw_s *self, struct aq_ring_s *ring,
unsigned int sw_tail_old);
int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self, struct aq_ring_s *ring);
int hw_atl_b0_hw_ring_tx_init(struct aq_hw_s *self, struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param);
int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self, struct aq_ring_s *ring,
unsigned int frags);
int hw_atl_b0_hw_ring_tx_head_update(struct aq_hw_s *self,
struct aq_ring_s *ring);
int hw_atl_b0_hw_ring_tx_stop(struct aq_hw_s *self, struct aq_ring_s *ring);
int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self, struct aq_ring_s *ring);
void hw_atl_b0_hw_init_rx_rss_ctrl1(struct aq_hw_s *self);
int hw_atl_b0_hw_mac_addr_set(struct aq_hw_s *self, const u8 *mac_addr);
int hw_atl_b0_set_fc(struct aq_hw_s *self, u32 fc, u32 tc);
int hw_atl_b0_set_loopback(struct aq_hw_s *self, u32 mode, bool enable);
int hw_atl_b0_hw_start(struct aq_hw_s *self);
int hw_atl_b0_hw_irq_enable(struct aq_hw_s *self, u64 mask);
int hw_atl_b0_hw_irq_disable(struct aq_hw_s *self, u64 mask);
int hw_atl_b0_hw_irq_read(struct aq_hw_s *self, u64 *mask);
int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
unsigned int packet_filter);
#endif /* HW_ATL_B0_H */
@@ -0,0 +1,160 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_b0_internal.h: Definition of Atlantic B0 chip specific
* constants.
*/
#ifndef HW_ATL_B0_INTERNAL_H
#define HW_ATL_B0_INTERNAL_H
#include "../aq_common.h"
#define HW_ATL_B0_MTU_JUMBO 16352U
#define HW_ATL_B0_MTU 1514U
#define HW_ATL_B0_TX_RINGS 4U
#define HW_ATL_B0_RX_RINGS 4U
#define HW_ATL_B0_RINGS_MAX 32U
#define HW_ATL_B0_TXD_SIZE (16U)
#define HW_ATL_B0_RXD_SIZE (16U)
#define HW_ATL_B0_MAC 0U
#define HW_ATL_B0_MAC_MIN 1U
#define HW_ATL_B0_MAC_MAX 33U
/* UCAST/MCAST filters */
#define HW_ATL_B0_UCAST_FILTERS_MAX 38
#define HW_ATL_B0_MCAST_FILTERS_MAX 8
/* interrupts */
#define HW_ATL_B0_ERR_INT 8U
#define HW_ATL_B0_INT_MASK (0xFFFFFFFFU)
#define HW_ATL_B0_TXD_CTL2_LEN (0xFFFFC000)
#define HW_ATL_B0_TXD_CTL2_CTX_EN (0x00002000)
#define HW_ATL_B0_TXD_CTL2_CTX_IDX (0x00001000)
#define HW_ATL_B0_TXD_CTL_DESC_TYPE_TXD (0x00000001)
#define HW_ATL_B0_TXD_CTL_DESC_TYPE_TXC (0x00000002)
#define HW_ATL_B0_TXD_CTL_BLEN (0x000FFFF0)
#define HW_ATL_B0_TXD_CTL_DD (0x00100000)
#define HW_ATL_B0_TXD_CTL_EOP (0x00200000)
#define HW_ATL_B0_TXD_CTL_CMD_X (0x3FC00000)
#define HW_ATL_B0_TXD_CTL_CMD_VLAN BIT(22)
#define HW_ATL_B0_TXD_CTL_CMD_FCS BIT(23)
#define HW_ATL_B0_TXD_CTL_CMD_IPCSO BIT(24)
#define HW_ATL_B0_TXD_CTL_CMD_TUCSO BIT(25)
#define HW_ATL_B0_TXD_CTL_CMD_LSO BIT(26)
#define HW_ATL_B0_TXD_CTL_CMD_WB BIT(27)
#define HW_ATL_B0_TXD_CTL_CMD_VXLAN BIT(28)
#define HW_ATL_B0_TXD_CTL_CMD_IPV6 BIT(21)
#define HW_ATL_B0_TXD_CTL_CMD_TCP BIT(22)
#define HW_ATL_B0_MPI_CONTROL_ADR 0x0368U
#define HW_ATL_B0_MPI_STATE_ADR 0x036CU
#define HW_ATL_B0_MPI_SPEED_MSK 0xFFFFU
#define HW_ATL_B0_MPI_SPEED_SHIFT 16U
#define HW_ATL_B0_TXBUF_MAX 160U
#define HW_ATL_B0_PTP_TXBUF_SIZE 8U
#define HW_ATL_B0_RXBUF_MAX 320U
#define HW_ATL_B0_PTP_RXBUF_SIZE 16U
#define HW_ATL_B0_RSS_REDIRECTION_MAX 64U
#define HW_ATL_B0_RSS_REDIRECTION_BITS 3U
#define HW_ATL_B0_RSS_HASHKEY_BITS 320U
#define HW_ATL_B0_TCRSS_4_8 1
#define HW_ATL_B0_TC_MAX 8U
#define HW_ATL_B0_RSS_MAX 8U
#define HW_ATL_B0_LRO_RXD_MAX 16U
#define HW_ATL_B0_RS_SLIP_ENABLED 0U
/* (256k -1(max pay_len) - 54(header)) */
#define HAL_ATL_B0_LSO_MAX_SEGMENT_SIZE 262089U
/* (256k -1(max pay_len) - 74(header)) */
#define HAL_ATL_B0_LSO_IPV6_MAX_SEGMENT_SIZE 262069U
#define HW_ATL_B0_CHIP_REVISION_B0 0xA0U
#define HW_ATL_B0_CHIP_REVISION_UNKNOWN 0xFFU
#define HW_ATL_B0_FW_SEMA_RAM 0x2U
#define HW_ATL_B0_TXC_LEN_TUNLEN (0x0000FF00)
#define HW_ATL_B0_TXC_LEN_OUTLEN (0xFFFF0000)
#define HW_ATL_B0_TXC_CTL_DESC_TYPE (0x00000007)
#define HW_ATL_B0_TXC_CTL_CTX_ID (0x00000008)
#define HW_ATL_B0_TXC_CTL_VLAN (0x000FFFF0)
#define HW_ATL_B0_TXC_CTL_CMD (0x00F00000)
#define HW_ATL_B0_TXC_CTL_L2LEN (0x7F000000)
#define HW_ATL_B0_TXC_CTL_L3LEN (0x80000000) /* L3LEN lsb */
#define HW_ATL_B0_TXC_LEN2_L3LEN (0x000000FF) /* L3LE upper bits */
#define HW_ATL_B0_TXC_LEN2_L4LEN (0x0000FF00)
#define HW_ATL_B0_TXC_LEN2_MSSLEN (0xFFFF0000)
#define HW_ATL_B0_RXD_DD (0x1)
#define HW_ATL_B0_RXD_NCEA0 (0x1)
#define HW_ATL_B0_RXD_WB_STAT_RSSTYPE (0x0000000F)
#define HW_ATL_B0_RXD_WB_STAT_RSSTYPE_SHIFT (0x0)
#define HW_ATL_B0_RXD_WB_STAT_PKTTYPE (0x00000FF0)
#define HW_ATL_B0_RXD_WB_STAT_PKTTYPE_SHIFT (0x4)
#define HW_ATL_B0_RXD_WB_STAT_RXCTRL (0x00180000)
#define HW_ATL_B0_RXD_WB_STAT_RXCTRL_SHIFT (0x13)
#define HW_ATL_B0_RXD_WB_STAT_SPLHDR (0x00200000)
#define HW_ATL_B0_RXD_WB_STAT_HDRLEN (0xFFC00000)
#define HW_ATL_B0_RXD_WB_STAT_HDRLEN_SHIFT (0x16)
#define HW_ATL_B0_RXD_WB_PKTTYPE_VLAN BIT(5)
#define HW_ATL_B0_RXD_WB_PKTTYPE_VLAN_DOUBLE BIT(6)
#define HW_ATL_B0_RXD_WB_STAT2_DD (0x0001)
#define HW_ATL_B0_RXD_WB_STAT2_EOP (0x0002)
#define HW_ATL_B0_RXD_WB_STAT2_RXSTAT (0x003C)
#define HW_ATL_B0_RXD_WB_STAT2_MACERR (0x0004)
#define HW_ATL_B0_RXD_WB_STAT2_IP4ERR (0x0008)
#define HW_ATL_B0_RXD_WB_STAT2_TCPUPDERR (0x0010)
#define HW_ATL_B0_RXD_WB_STAT2_RXESTAT (0x0FC0)
#define HW_ATL_B0_RXD_WB_STAT2_RSCCNT (0xF000)
#define L2_FILTER_ACTION_DISCARD (0x0)
#define L2_FILTER_ACTION_HOST (0x1)
#define HW_ATL_B0_UCP_0X370_REG (0x370)
#define HW_ATL_B0_FLUSH() AQ_HW_READ_REG(self, 0x10)
#define HW_ATL_B0_FW_VER_EXPECTED 0x01050006U
#define HW_ATL_INTR_MODER_MAX 0x1FF
#define HW_ATL_INTR_MODER_MIN 0xFF
#define HW_ATL_B0_MIN_RXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_RXD_MULTIPLE))
#define HW_ATL_B0_MIN_TXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_TXD_MULTIPLE))
#define HW_ATL_B0_MAX_RXD 8184U
#define HW_ATL_B0_MAX_TXD 8184U
#define HW_ATL_RSS_DISABLED 0x00000000U
#define HW_ATL_RSS_ENABLED_8TCS_2INDEX_BITS 0xA2222222U
#define HW_ATL_RSS_ENABLED_4TCS_3INDEX_BITS 0x80003333U
/* HW layer capabilities */
#endif /* HW_ATL_B0_INTERNAL_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,893 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File hw_atl_llh.h: Declarations of bitfield and register access functions for
* Atlantic registers.
*/
#ifndef HW_ATL_LLH_H
#define HW_ATL_LLH_H
#include <linux/types.h>
struct aq_hw_s;
/* set temperature sense reset */
void hw_atl_ts_reset_set(struct aq_hw_s *aq_hw, u32 val);
/* set temperature sense power down */
void hw_atl_ts_power_down_set(struct aq_hw_s *aq_hw, u32 val);
/* get temperature sense power down */
u32 hw_atl_ts_power_down_get(struct aq_hw_s *aq_hw);
/* get temperature sense ready */
u32 hw_atl_ts_ready_get(struct aq_hw_s *aq_hw);
/* get temperature sense ready latch high */
u32 hw_atl_ts_ready_latch_high_get(struct aq_hw_s *aq_hw);
/* get temperature sense data */
u32 hw_atl_ts_data_get(struct aq_hw_s *aq_hw);
/* SMBUS0 bus busy */
u32 hw_atl_smb0_bus_busy_get(struct aq_hw_s *aq_hw);
/* SMBUS0 byte transfer complete */
u32 hw_atl_smb0_byte_transfer_complete_get(struct aq_hw_s *aq_hw);
/* SMBUS0 receive acknowledged */
u32 hw_atl_smb0_receive_acknowledged_get(struct aq_hw_s *aq_hw);
/* SMBUS0 set transmitted data (only leftmost byte of data valid) */
void hw_atl_smb0_tx_data_set(struct aq_hw_s *aq_hw, u32 data);
/* SMBUS0 provisioning2 command register */
void hw_atl_smb0_provisioning2_set(struct aq_hw_s *aq_hw, u32 data);
/* SMBUS0 repeated start detect */
u32 hw_atl_smb0_repeated_start_detect_get(struct aq_hw_s *aq_hw);
/* SMBUS0 received data register */
u32 hw_atl_smb0_rx_data_get(struct aq_hw_s *aq_hw);
/* global */
/* set global microprocessor semaphore */
void hw_atl_reg_glb_cpu_sem_set(struct aq_hw_s *aq_hw, u32 glb_cpu_sem,
u32 semaphore);
/* get global microprocessor semaphore */
u32 hw_atl_reg_glb_cpu_sem_get(struct aq_hw_s *aq_hw, u32 semaphore);
/* set global register reset disable */
void hw_atl_glb_glb_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 glb_reg_res_dis);
/* set soft reset */
void hw_atl_glb_soft_res_set(struct aq_hw_s *aq_hw, u32 soft_res);
/* get soft reset */
u32 hw_atl_glb_soft_res_get(struct aq_hw_s *aq_hw);
/* stats */
u32 hw_atl_rpb_rx_dma_drop_pkt_cnt_get(struct aq_hw_s *aq_hw);
/* get rx dma good octet counter */
u64 hw_atl_stats_rx_dma_good_octet_counter_get(struct aq_hw_s *aq_hw);
/* get rx dma good packet counter */
u64 hw_atl_stats_rx_dma_good_pkt_counter_get(struct aq_hw_s *aq_hw);
/* get tx dma good octet counter */
u64 hw_atl_stats_tx_dma_good_octet_counter_get(struct aq_hw_s *aq_hw);
/* get tx dma good packet counter */
u64 hw_atl_stats_tx_dma_good_pkt_counter_get(struct aq_hw_s *aq_hw);
/* get msm rx errors counter register */
u32 hw_atl_reg_mac_msm_rx_errs_cnt_get(struct aq_hw_s *aq_hw);
/* get msm rx unicast frames counter register */
u32 hw_atl_reg_mac_msm_rx_ucst_frm_cnt_get(struct aq_hw_s *aq_hw);
/* get msm rx multicast frames counter register */
u32 hw_atl_reg_mac_msm_rx_mcst_frm_cnt_get(struct aq_hw_s *aq_hw);
/* get msm rx broadcast frames counter register */
u32 hw_atl_reg_mac_msm_rx_bcst_frm_cnt_get(struct aq_hw_s *aq_hw);
/* get msm rx broadcast octets counter register 1 */
u32 hw_atl_reg_mac_msm_rx_bcst_octets_counter1get(struct aq_hw_s *aq_hw);
/* get msm rx unicast octets counter register 0 */
u32 hw_atl_reg_mac_msm_rx_ucst_octets_counter0get(struct aq_hw_s *aq_hw);
/* get msm tx errors counter register */
u32 hw_atl_reg_mac_msm_tx_errs_cnt_get(struct aq_hw_s *aq_hw);
/* get msm tx unicast frames counter register */
u32 hw_atl_reg_mac_msm_tx_ucst_frm_cnt_get(struct aq_hw_s *aq_hw);
/* get msm tx multicast frames counter register */
u32 hw_atl_reg_mac_msm_tx_mcst_frm_cnt_get(struct aq_hw_s *aq_hw);
/* get msm tx broadcast frames counter register */
u32 hw_atl_reg_mac_msm_tx_bcst_frm_cnt_get(struct aq_hw_s *aq_hw);
/* get msm tx multicast octets counter register 1 */
u32 hw_atl_reg_mac_msm_tx_mcst_octets_counter1get(struct aq_hw_s *aq_hw);
/* get msm tx broadcast octets counter register 1 */
u32 hw_atl_reg_mac_msm_tx_bcst_octets_counter1get(struct aq_hw_s *aq_hw);
/* get msm tx unicast octets counter register 0 */
u32 hw_atl_reg_mac_msm_tx_ucst_octets_counter0get(struct aq_hw_s *aq_hw);
/* get global mif identification */
u32 hw_atl_reg_glb_mif_id_get(struct aq_hw_s *aq_hw);
/* interrupt */
/* set interrupt auto mask lsw */
void hw_atl_itr_irq_auto_masklsw_set(struct aq_hw_s *aq_hw,
u32 irq_auto_masklsw);
/* set interrupt mapping enable rx */
void hw_atl_itr_irq_map_en_rx_set(struct aq_hw_s *aq_hw, u32 irq_map_en_rx,
u32 rx);
/* set interrupt mapping enable tx */
void hw_atl_itr_irq_map_en_tx_set(struct aq_hw_s *aq_hw, u32 irq_map_en_tx,
u32 tx);
/* set interrupt mapping rx */
void hw_atl_itr_irq_map_rx_set(struct aq_hw_s *aq_hw, u32 irq_map_rx, u32 rx);
/* set interrupt mapping tx */
void hw_atl_itr_irq_map_tx_set(struct aq_hw_s *aq_hw, u32 irq_map_tx, u32 tx);
/* set interrupt mask clear lsw */
void hw_atl_itr_irq_msk_clearlsw_set(struct aq_hw_s *aq_hw,
u32 irq_msk_clearlsw);
/* set interrupt mask set lsw */
void hw_atl_itr_irq_msk_setlsw_set(struct aq_hw_s *aq_hw, u32 irq_msk_setlsw);
/* set interrupt register reset disable */
void hw_atl_itr_irq_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 irq_reg_res_dis);
/* set interrupt status clear lsw */
void hw_atl_itr_irq_status_clearlsw_set(struct aq_hw_s *aq_hw,
u32 irq_status_clearlsw);
/* get interrupt status lsw */
u32 hw_atl_itr_irq_statuslsw_get(struct aq_hw_s *aq_hw);
/* get reset interrupt */
u32 hw_atl_itr_res_irq_get(struct aq_hw_s *aq_hw);
/* set reset interrupt */
void hw_atl_itr_res_irq_set(struct aq_hw_s *aq_hw, u32 res_irq);
/* set RSC interrupt */
void hw_atl_itr_rsc_en_set(struct aq_hw_s *aq_hw, u32 enable);
/* set RSC delay */
void hw_atl_itr_rsc_delay_set(struct aq_hw_s *aq_hw, u32 delay);
/* rdm */
/* set cpu id */
void hw_atl_rdm_cpu_id_set(struct aq_hw_s *aq_hw, u32 cpuid, u32 dca);
/* set rx dca enable */
void hw_atl_rdm_rx_dca_en_set(struct aq_hw_s *aq_hw, u32 rx_dca_en);
/* set rx dca mode */
void hw_atl_rdm_rx_dca_mode_set(struct aq_hw_s *aq_hw, u32 rx_dca_mode);
/* set rx descriptor data buffer size */
void hw_atl_rdm_rx_desc_data_buff_size_set(struct aq_hw_s *aq_hw,
u32 rx_desc_data_buff_size,
u32 descriptor);
/* set rx descriptor dca enable */
void hw_atl_rdm_rx_desc_dca_en_set(struct aq_hw_s *aq_hw, u32 rx_desc_dca_en,
u32 dca);
/* set rx descriptor enable */
void hw_atl_rdm_rx_desc_en_set(struct aq_hw_s *aq_hw, u32 rx_desc_en,
u32 descriptor);
/* set rx descriptor header splitting */
void hw_atl_rdm_rx_desc_head_splitting_set(struct aq_hw_s *aq_hw,
u32 rx_desc_head_splitting,
u32 descriptor);
/* get rx descriptor head pointer */
u32 hw_atl_rdm_rx_desc_head_ptr_get(struct aq_hw_s *aq_hw, u32 descriptor);
/* set rx descriptor length */
void hw_atl_rdm_rx_desc_len_set(struct aq_hw_s *aq_hw, u32 rx_desc_len,
u32 descriptor);
/* set rx descriptor write-back interrupt enable */
void hw_atl_rdm_rx_desc_wr_wb_irq_en_set(struct aq_hw_s *aq_hw,
u32 rx_desc_wr_wb_irq_en);
/* set rx header dca enable */
void hw_atl_rdm_rx_head_dca_en_set(struct aq_hw_s *aq_hw, u32 rx_head_dca_en,
u32 dca);
/* set rx payload dca enable */
void hw_atl_rdm_rx_pld_dca_en_set(struct aq_hw_s *aq_hw, u32 rx_pld_dca_en,
u32 dca);
/* set rx descriptor header buffer size */
void hw_atl_rdm_rx_desc_head_buff_size_set(struct aq_hw_s *aq_hw,
u32 rx_desc_head_buff_size,
u32 descriptor);
/* set rx descriptor reset */
void hw_atl_rdm_rx_desc_res_set(struct aq_hw_s *aq_hw, u32 rx_desc_res,
u32 descriptor);
/* Set RDM Interrupt Moderation Enable */
void hw_atl_rdm_rdm_intr_moder_en_set(struct aq_hw_s *aq_hw,
u32 rdm_intr_moder_en);
/* reg */
/* set general interrupt mapping register */
void hw_atl_reg_gen_irq_map_set(struct aq_hw_s *aq_hw, u32 gen_intr_map,
u32 regidx);
/* get general interrupt status register */
u32 hw_atl_reg_gen_irq_status_get(struct aq_hw_s *aq_hw);
/* set interrupt global control register */
void hw_atl_reg_irq_glb_ctl_set(struct aq_hw_s *aq_hw, u32 intr_glb_ctl);
/* set interrupt throttle register */
void hw_atl_reg_irq_thr_set(struct aq_hw_s *aq_hw, u32 intr_thr, u32 throttle);
/* set rx dma descriptor base address lsw */
void hw_atl_reg_rx_dma_desc_base_addresslswset(struct aq_hw_s *aq_hw,
u32 rx_dma_desc_base_addrlsw,
u32 descriptor);
/* set rx dma descriptor base address msw */
void hw_atl_reg_rx_dma_desc_base_addressmswset(struct aq_hw_s *aq_hw,
u32 rx_dma_desc_base_addrmsw,
u32 descriptor);
/* get rx dma descriptor status register */
u32 hw_atl_reg_rx_dma_desc_status_get(struct aq_hw_s *aq_hw, u32 descriptor);
/* set rx dma descriptor tail pointer register */
void hw_atl_reg_rx_dma_desc_tail_ptr_set(struct aq_hw_s *aq_hw,
u32 rx_dma_desc_tail_ptr,
u32 descriptor);
/* set rx filter multicast filter mask register */
void hw_atl_reg_rx_flr_mcst_flr_msk_set(struct aq_hw_s *aq_hw,
u32 rx_flr_mcst_flr_msk);
/* set rx filter multicast filter register */
void hw_atl_reg_rx_flr_mcst_flr_set(struct aq_hw_s *aq_hw, u32 rx_flr_mcst_flr,
u32 filter);
/* set rx filter rss control register 1 */
void hw_atl_reg_rx_flr_rss_control1set(struct aq_hw_s *aq_hw,
u32 rx_flr_rss_control1);
/* Set RX Filter Control Register 2 */
void hw_atl_reg_rx_flr_control2_set(struct aq_hw_s *aq_hw, u32 rx_flr_control2);
/* Set RX Interrupt Moderation Control Register */
void hw_atl_reg_rx_intr_moder_ctrl_set(struct aq_hw_s *aq_hw,
u32 rx_intr_moderation_ctl,
u32 queue);
/* set tx dma debug control */
void hw_atl_reg_tx_dma_debug_ctl_set(struct aq_hw_s *aq_hw,
u32 tx_dma_debug_ctl);
/* set tx dma descriptor base address lsw */
void hw_atl_reg_tx_dma_desc_base_addresslswset(struct aq_hw_s *aq_hw,
u32 tx_dma_desc_base_addrlsw,
u32 descriptor);
/* set tx dma descriptor base address msw */
void hw_atl_reg_tx_dma_desc_base_addressmswset(struct aq_hw_s *aq_hw,
u32 tx_dma_desc_base_addrmsw,
u32 descriptor);
/* set tx dma descriptor tail pointer register */
void hw_atl_reg_tx_dma_desc_tail_ptr_set(struct aq_hw_s *aq_hw,
u32 tx_dma_desc_tail_ptr,
u32 descriptor);
/* Set TX Interrupt Moderation Control Register */
void hw_atl_reg_tx_intr_moder_ctrl_set(struct aq_hw_s *aq_hw,
u32 tx_intr_moderation_ctl,
u32 queue);
/* set global microprocessor scratch pad */
void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw,
u32 glb_cpu_scratch_scp,
u32 scratch_scp);
/* rpb */
/* set dma system loopback */
void hw_atl_rpb_dma_sys_lbk_set(struct aq_hw_s *aq_hw, u32 dma_sys_lbk);
/* set dma network loopback */
void hw_atl_rpb_dma_net_lbk_set(struct aq_hw_s *aq_hw, u32 dma_net_lbk);
/* set rx traffic class mode */
void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw,
u32 rx_traf_class_mode);
/* get rx traffic class mode */
u32 hw_atl_rpb_rpf_rx_traf_class_mode_get(struct aq_hw_s *aq_hw);
/* set rx buffer enable */
void hw_atl_rpb_rx_buff_en_set(struct aq_hw_s *aq_hw, u32 rx_buff_en);
/* set rx buffer high threshold (per tc) */
void hw_atl_rpb_rx_buff_hi_threshold_per_tc_set(struct aq_hw_s *aq_hw,
u32 rx_buff_hi_threshold_per_tc,
u32 buffer);
/* set rx buffer low threshold (per tc) */
void hw_atl_rpb_rx_buff_lo_threshold_per_tc_set(struct aq_hw_s *aq_hw,
u32 rx_buff_lo_threshold_per_tc,
u32 buffer);
/* set rx flow control mode */
void hw_atl_rpb_rx_flow_ctl_mode_set(struct aq_hw_s *aq_hw,
u32 rx_flow_ctl_mode);
/* set rx packet buffer size (per tc) */
void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw,
u32 rx_pkt_buff_size_per_tc,
u32 buffer);
/* toggle rdm rx dma descriptor cache init */
void hw_atl_rdm_rx_dma_desc_cache_init_tgl(struct aq_hw_s *aq_hw);
/* get rdm rx dma descriptor cache init done */
u32 hw_atl_rdm_rx_dma_desc_cache_init_done_get(struct aq_hw_s *aq_hw);
/* set rx xoff enable (per tc) */
void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw,
u32 rx_xoff_en_per_tc,
u32 buffer);
/* rpf */
/* set l2 broadcast count threshold */
void hw_atl_rpfl2broadcast_count_threshold_set(struct aq_hw_s *aq_hw,
u32 l2broadcast_count_threshold);
/* set l2 broadcast enable */
void hw_atl_rpfl2broadcast_en_set(struct aq_hw_s *aq_hw, u32 l2broadcast_en);
/* set l2 broadcast filter action */
void hw_atl_rpfl2broadcast_flr_act_set(struct aq_hw_s *aq_hw,
u32 l2broadcast_flr_act);
/* set l2 multicast filter enable */
void hw_atl_rpfl2multicast_flr_en_set(struct aq_hw_s *aq_hw,
u32 l2multicast_flr_en,
u32 filter);
/* get l2 promiscuous mode enable */
u32 hw_atl_rpfl2promiscuous_mode_en_get(struct aq_hw_s *aq_hw);
/* set l2 promiscuous mode enable */
void hw_atl_rpfl2promiscuous_mode_en_set(struct aq_hw_s *aq_hw,
u32 l2promiscuous_mode_en);
/* set l2 unicast filter action */
void hw_atl_rpfl2unicast_flr_act_set(struct aq_hw_s *aq_hw,
u32 l2unicast_flr_act,
u32 filter);
/* set l2 unicast filter enable */
void hw_atl_rpfl2_uc_flr_en_set(struct aq_hw_s *aq_hw, u32 l2unicast_flr_en,
u32 filter);
/* set l2 unicast destination address lsw */
void hw_atl_rpfl2unicast_dest_addresslsw_set(struct aq_hw_s *aq_hw,
u32 l2unicast_dest_addresslsw,
u32 filter);
/* set l2 unicast destination address msw */
void hw_atl_rpfl2unicast_dest_addressmsw_set(struct aq_hw_s *aq_hw,
u32 l2unicast_dest_addressmsw,
u32 filter);
/* Set L2 Accept all Multicast packets */
void hw_atl_rpfl2_accept_all_mc_packets_set(struct aq_hw_s *aq_hw,
u32 l2_accept_all_mc_packets);
/* set user-priority tc mapping */
void hw_atl_rpf_rpb_user_priority_tc_map_set(struct aq_hw_s *aq_hw,
u32 user_priority_tc_map, u32 tc);
/* set rss key address */
void hw_atl_rpf_rss_key_addr_set(struct aq_hw_s *aq_hw, u32 rss_key_addr);
/* set rss key write data */
void hw_atl_rpf_rss_key_wr_data_set(struct aq_hw_s *aq_hw, u32 rss_key_wr_data);
/* get rss key write enable */
u32 hw_atl_rpf_rss_key_wr_en_get(struct aq_hw_s *aq_hw);
/* set rss key write enable */
void hw_atl_rpf_rss_key_wr_en_set(struct aq_hw_s *aq_hw, u32 rss_key_wr_en);
/* set rss redirection table address */
void hw_atl_rpf_rss_redir_tbl_addr_set(struct aq_hw_s *aq_hw,
u32 rss_redir_tbl_addr);
/* set rss redirection table write data */
void hw_atl_rpf_rss_redir_tbl_wr_data_set(struct aq_hw_s *aq_hw,
u32 rss_redir_tbl_wr_data);
/* get rss redirection write enable */
u32 hw_atl_rpf_rss_redir_wr_en_get(struct aq_hw_s *aq_hw);
/* set rss redirection write enable */
void hw_atl_rpf_rss_redir_wr_en_set(struct aq_hw_s *aq_hw, u32 rss_redir_wr_en);
/* set tpo to rpf system loopback */
void hw_atl_rpf_tpo_to_rpf_sys_lbk_set(struct aq_hw_s *aq_hw,
u32 tpo_to_rpf_sys_lbk);
/* set vlan inner ethertype */
void hw_atl_rpf_vlan_inner_etht_set(struct aq_hw_s *aq_hw, u32 vlan_inner_etht);
/* set vlan outer ethertype */
void hw_atl_rpf_vlan_outer_etht_set(struct aq_hw_s *aq_hw, u32 vlan_outer_etht);
/* set vlan promiscuous mode enable */
void hw_atl_rpf_vlan_prom_mode_en_set(struct aq_hw_s *aq_hw,
u32 vlan_prom_mode_en);
/* Get VLAN promiscuous mode enable */
u32 hw_atl_rpf_vlan_prom_mode_en_get(struct aq_hw_s *aq_hw);
/* Set VLAN untagged action */
void hw_atl_rpf_vlan_untagged_act_set(struct aq_hw_s *aq_hw,
u32 vlan_untagged_act);
/* Set VLAN accept untagged packets */
void hw_atl_rpf_vlan_accept_untagged_packets_set(struct aq_hw_s *aq_hw,
u32 vlan_acc_untagged_packets);
/* Set VLAN filter enable */
void hw_atl_rpf_vlan_flr_en_set(struct aq_hw_s *aq_hw, u32 vlan_flr_en,
u32 filter);
/* Set VLAN Filter Action */
void hw_atl_rpf_vlan_flr_act_set(struct aq_hw_s *aq_hw, u32 vlan_filter_act,
u32 filter);
/* Set VLAN ID Filter */
void hw_atl_rpf_vlan_id_flr_set(struct aq_hw_s *aq_hw, u32 vlan_id_flr,
u32 filter);
/* Set VLAN RX queue assignment enable */
void hw_atl_rpf_vlan_rxq_en_flr_set(struct aq_hw_s *aq_hw, u32 vlan_rxq_en,
u32 filter);
/* Set VLAN RX queue */
void hw_atl_rpf_vlan_rxq_flr_set(struct aq_hw_s *aq_hw, u32 vlan_rxq,
u32 filter);
/* set ethertype filter enable */
void hw_atl_rpf_etht_flr_en_set(struct aq_hw_s *aq_hw, u32 etht_flr_en,
u32 filter);
/* set ethertype user-priority enable */
void hw_atl_rpf_etht_user_priority_en_set(struct aq_hw_s *aq_hw,
u32 etht_user_priority_en,
u32 filter);
/* set ethertype rx queue enable */
void hw_atl_rpf_etht_rx_queue_en_set(struct aq_hw_s *aq_hw,
u32 etht_rx_queue_en,
u32 filter);
/* set ethertype rx queue */
void hw_atl_rpf_etht_rx_queue_set(struct aq_hw_s *aq_hw, u32 etht_rx_queue,
u32 filter);
/* set ethertype user-priority */
void hw_atl_rpf_etht_user_priority_set(struct aq_hw_s *aq_hw,
u32 etht_user_priority,
u32 filter);
/* set ethertype management queue */
void hw_atl_rpf_etht_mgt_queue_set(struct aq_hw_s *aq_hw, u32 etht_mgt_queue,
u32 filter);
/* set ethertype filter action */
void hw_atl_rpf_etht_flr_act_set(struct aq_hw_s *aq_hw, u32 etht_flr_act,
u32 filter);
/* set ethertype filter */
void hw_atl_rpf_etht_flr_set(struct aq_hw_s *aq_hw, u32 etht_flr, u32 filter);
/* set L4 source port */
void hw_atl_rpf_l4_spd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter);
/* set L4 destination port */
void hw_atl_rpf_l4_dpd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter);
/* rpo */
/* set ipv4 header checksum offload enable */
void hw_atl_rpo_ipv4header_crc_offload_en_set(struct aq_hw_s *aq_hw,
u32 ipv4header_crc_offload_en);
/* set rx descriptor vlan stripping */
void hw_atl_rpo_rx_desc_vlan_stripping_set(struct aq_hw_s *aq_hw,
u32 rx_desc_vlan_stripping,
u32 descriptor);
void hw_atl_rpo_outer_vlan_tag_mode_set(void *context,
u32 outervlantagmode);
u32 hw_atl_rpo_outer_vlan_tag_mode_get(void *context);
/* set tcp/udp checksum offload enable */
void hw_atl_rpo_tcp_udp_crc_offload_en_set(struct aq_hw_s *aq_hw,
u32 tcp_udp_crc_offload_en);
/* Set LRO Patch Optimization Enable. */
void hw_atl_rpo_lro_patch_optimization_en_set(struct aq_hw_s *aq_hw,
u32 lro_patch_optimization_en);
/* Set Large Receive Offload Enable */
void hw_atl_rpo_lro_en_set(struct aq_hw_s *aq_hw, u32 lro_en);
/* Set LRO Q Sessions Limit */
void hw_atl_rpo_lro_qsessions_lim_set(struct aq_hw_s *aq_hw,
u32 lro_qsessions_lim);
/* Set LRO Total Descriptor Limit */
void hw_atl_rpo_lro_total_desc_lim_set(struct aq_hw_s *aq_hw,
u32 lro_total_desc_lim);
/* Set LRO Min Payload of First Packet */
void hw_atl_rpo_lro_min_pay_of_first_pkt_set(struct aq_hw_s *aq_hw,
u32 lro_min_pld_of_first_pkt);
/* Set LRO Packet Limit */
void hw_atl_rpo_lro_pkt_lim_set(struct aq_hw_s *aq_hw, u32 lro_packet_lim);
/* Set LRO Max Number of Descriptors */
void hw_atl_rpo_lro_max_num_of_descriptors_set(struct aq_hw_s *aq_hw,
u32 lro_max_desc_num, u32 lro);
/* Set LRO Time Base Divider */
void hw_atl_rpo_lro_time_base_divider_set(struct aq_hw_s *aq_hw,
u32 lro_time_base_divider);
/*Set LRO Inactive Interval */
void hw_atl_rpo_lro_inactive_interval_set(struct aq_hw_s *aq_hw,
u32 lro_inactive_interval);
/*Set LRO Max Coalescing Interval */
void hw_atl_rpo_lro_max_coalescing_interval_set(struct aq_hw_s *aq_hw,
u32 lro_max_coal_interval);
/* rx */
/* set rx register reset disable */
void hw_atl_rx_rx_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 rx_reg_res_dis);
/* tdm */
/* set cpu id */
void hw_atl_tdm_cpu_id_set(struct aq_hw_s *aq_hw, u32 cpuid, u32 dca);
/* set large send offload enable */
void hw_atl_tdm_large_send_offload_en_set(struct aq_hw_s *aq_hw,
u32 large_send_offload_en);
/* set tx descriptor enable */
void hw_atl_tdm_tx_desc_en_set(struct aq_hw_s *aq_hw, u32 tx_desc_en,
u32 descriptor);
/* set tx dca enable */
void hw_atl_tdm_tx_dca_en_set(struct aq_hw_s *aq_hw, u32 tx_dca_en);
/* set tx dca mode */
void hw_atl_tdm_tx_dca_mode_set(struct aq_hw_s *aq_hw, u32 tx_dca_mode);
/* set tx descriptor dca enable */
void hw_atl_tdm_tx_desc_dca_en_set(struct aq_hw_s *aq_hw, u32 tx_desc_dca_en,
u32 dca);
/* get tx descriptor head pointer */
u32 hw_atl_tdm_tx_desc_head_ptr_get(struct aq_hw_s *aq_hw, u32 descriptor);
/* set tx descriptor length */
void hw_atl_tdm_tx_desc_len_set(struct aq_hw_s *aq_hw, u32 tx_desc_len,
u32 descriptor);
/* set tx descriptor write-back interrupt enable */
void hw_atl_tdm_tx_desc_wr_wb_irq_en_set(struct aq_hw_s *aq_hw,
u32 tx_desc_wr_wb_irq_en);
/* set tx descriptor write-back threshold */
void hw_atl_tdm_tx_desc_wr_wb_threshold_set(struct aq_hw_s *aq_hw,
u32 tx_desc_wr_wb_threshold,
u32 descriptor);
/* Set TDM Interrupt Moderation Enable */
void hw_atl_tdm_tdm_intr_moder_en_set(struct aq_hw_s *aq_hw,
u32 tdm_irq_moderation_en);
/* thm */
/* set lso tcp flag of first packet */
void hw_atl_thm_lso_tcp_flag_of_first_pkt_set(struct aq_hw_s *aq_hw,
u32 lso_tcp_flag_of_first_pkt);
/* set lso tcp flag of last packet */
void hw_atl_thm_lso_tcp_flag_of_last_pkt_set(struct aq_hw_s *aq_hw,
u32 lso_tcp_flag_of_last_pkt);
/* set lso tcp flag of middle packet */
void hw_atl_thm_lso_tcp_flag_of_middle_pkt_set(struct aq_hw_s *aq_hw,
u32 lso_tcp_flag_of_middle_pkt);
/* tpb */
/* set TX Traffic Class Mode */
void hw_atl_tpb_tps_tx_tc_mode_set(struct aq_hw_s *aq_hw,
u32 tx_traf_class_mode);
/* get TX Traffic Class Mode */
u32 hw_atl_tpb_tps_tx_tc_mode_get(struct aq_hw_s *aq_hw);
/* set tx buffer enable */
void hw_atl_tpb_tx_buff_en_set(struct aq_hw_s *aq_hw, u32 tx_buff_en);
/* set tx buffer high threshold (per tc) */
void hw_atl_tpb_tx_buff_hi_threshold_per_tc_set(struct aq_hw_s *aq_hw,
u32 tx_buff_hi_threshold_per_tc,
u32 buffer);
/* set tx buffer low threshold (per tc) */
void hw_atl_tpb_tx_buff_lo_threshold_per_tc_set(struct aq_hw_s *aq_hw,
u32 tx_buff_lo_threshold_per_tc,
u32 buffer);
/* set tx dma system loopback enable */
void hw_atl_tpb_tx_dma_sys_lbk_en_set(struct aq_hw_s *aq_hw, u32 tx_dma_sys_lbk_en);
/* set tx dma network loopback enable */
void hw_atl_tpb_tx_dma_net_lbk_en_set(struct aq_hw_s *aq_hw,
u32 tx_dma_net_lbk_en);
/* set tx clock gating enable */
void hw_atl_tpb_tx_tx_clk_gate_en_set(struct aq_hw_s *aq_hw,
u32 tx_clk_gate_en);
/* set tx packet buffer size (per tc) */
void hw_atl_tpb_tx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw,
u32 tx_pkt_buff_size_per_tc,
u32 buffer);
/* set tx path pad insert enable */
void hw_atl_tpb_tx_path_scp_ins_en_set(struct aq_hw_s *aq_hw, u32 tx_path_scp_ins_en);
/* tpo */
/* set ipv4 header checksum offload enable */
void hw_atl_tpo_ipv4header_crc_offload_en_set(struct aq_hw_s *aq_hw,
u32 ipv4header_crc_offload_en);
/* set tcp/udp checksum offload enable */
void hw_atl_tpo_tcp_udp_crc_offload_en_set(struct aq_hw_s *aq_hw,
u32 tcp_udp_crc_offload_en);
/* set tx pkt system loopback enable */
void hw_atl_tpo_tx_pkt_sys_lbk_en_set(struct aq_hw_s *aq_hw,
u32 tx_pkt_sys_lbk_en);
/* tps */
/* set tx packet scheduler data arbitration mode */
void hw_atl_tps_tx_pkt_shed_data_arb_mode_set(struct aq_hw_s *aq_hw,
u32 tx_pkt_shed_data_arb_mode);
/* set tx packet scheduler descriptor rate current time reset */
void hw_atl_tps_tx_pkt_shed_desc_rate_curr_time_res_set(struct aq_hw_s *aq_hw,
u32 curr_time_res);
/* set tx packet scheduler descriptor rate limit */
void hw_atl_tps_tx_pkt_shed_desc_rate_lim_set(struct aq_hw_s *aq_hw,
u32 tx_pkt_shed_desc_rate_lim);
/* set tx packet scheduler descriptor tc arbitration mode */
void hw_atl_tps_tx_pkt_shed_desc_tc_arb_mode_set(struct aq_hw_s *aq_hw,
u32 arb_mode);
/* set tx packet scheduler descriptor tc max credit */
void hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(struct aq_hw_s *aq_hw,
const u32 tc,
const u32 max_credit);
/* set tx packet scheduler descriptor tc weight */
void hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(struct aq_hw_s *aq_hw,
const u32 tc,
const u32 weight);
/* set tx packet scheduler descriptor vm arbitration mode */
void hw_atl_tps_tx_pkt_shed_desc_vm_arb_mode_set(struct aq_hw_s *aq_hw,
u32 arb_mode);
/* set tx packet scheduler tc data max credit */
void hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(struct aq_hw_s *aq_hw,
const u32 tc,
const u32 max_credit);
/* set tx packet scheduler tc data weight */
void hw_atl_tps_tx_pkt_shed_tc_data_weight_set(struct aq_hw_s *aq_hw,
const u32 tc,
const u32 weight);
/* set tx descriptor rate mode */
void hw_atl_tps_tx_desc_rate_mode_set(struct aq_hw_s *aq_hw,
const u32 rate_mode);
/* set tx packet scheduler descriptor rate enable */
void hw_atl_tps_tx_desc_rate_en_set(struct aq_hw_s *aq_hw, const u32 desc,
const u32 enable);
/* set tx packet scheduler descriptor rate integral value */
void hw_atl_tps_tx_desc_rate_x_set(struct aq_hw_s *aq_hw, const u32 desc,
const u32 rate_int);
/* set tx packet scheduler descriptor rate fractional value */
void hw_atl_tps_tx_desc_rate_y_set(struct aq_hw_s *aq_hw, const u32 desc,
const u32 rate_frac);
/* tx */
/* set tx register reset disable */
void hw_atl_tx_tx_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 tx_reg_res_dis);
/* msm */
/* get register access status */
u32 hw_atl_msm_reg_access_status_get(struct aq_hw_s *aq_hw);
/* set register address for indirect address */
void hw_atl_msm_reg_addr_for_indirect_addr_set(struct aq_hw_s *aq_hw,
u32 reg_addr_for_indirect_addr);
/* set register read strobe */
void hw_atl_msm_reg_rd_strobe_set(struct aq_hw_s *aq_hw, u32 reg_rd_strobe);
/* get register read data */
u32 hw_atl_msm_reg_rd_data_get(struct aq_hw_s *aq_hw);
/* set register write data */
void hw_atl_msm_reg_wr_data_set(struct aq_hw_s *aq_hw, u32 reg_wr_data);
/* set register write strobe */
void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, u32 reg_wr_strobe);
/* pci */
/* set pci register reset disable */
void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 pci_reg_res_dis);
/* pcs */
void hw_atl_pcs_ptp_clock_read_enable(struct aq_hw_s *aq_hw,
u32 ptp_clock_read_enable);
u32 hw_atl_pcs_ptp_clock_get(struct aq_hw_s *aq_hw, u32 index);
/* set uP Force Interrupt */
void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr);
/* clear ipv4 filter destination address */
void hw_atl_rpfl3l4_ipv4_dest_addr_clear(struct aq_hw_s *aq_hw, u8 location);
/* clear ipv4 filter source address */
void hw_atl_rpfl3l4_ipv4_src_addr_clear(struct aq_hw_s *aq_hw, u8 location);
/* clear command for filter l3-l4 */
void hw_atl_rpfl3l4_cmd_clear(struct aq_hw_s *aq_hw, u8 location);
/* clear ipv6 filter destination address */
void hw_atl_rpfl3l4_ipv6_dest_addr_clear(struct aq_hw_s *aq_hw, u8 location);
/* clear ipv6 filter source address */
void hw_atl_rpfl3l4_ipv6_src_addr_clear(struct aq_hw_s *aq_hw, u8 location);
/* set ipv4 filter destination address */
void hw_atl_rpfl3l4_ipv4_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
u32 ipv4_dest);
/* set ipv4 filter source address */
void hw_atl_rpfl3l4_ipv4_src_addr_set(struct aq_hw_s *aq_hw, u8 location,
u32 ipv4_src);
/* set command for filter l3-l4 */
void hw_atl_rpfl3l4_cmd_set(struct aq_hw_s *aq_hw, u8 location, u32 cmd);
/* set ipv6 filter source address */
void hw_atl_rpfl3l4_ipv6_src_addr_set(struct aq_hw_s *aq_hw, u8 location,
u32 *ipv6_src);
/* set ipv6 filter destination address */
void hw_atl_rpfl3l4_ipv6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
u32 *ipv6_dest);
/* set Global MDIO Interface 1 */
void hw_atl_glb_mdio_iface1_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 1 */
u32 hw_atl_glb_mdio_iface1_get(struct aq_hw_s *hw);
/* set Global MDIO Interface 2 */
void hw_atl_glb_mdio_iface2_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 2 */
u32 hw_atl_glb_mdio_iface2_get(struct aq_hw_s *hw);
/* set Global MDIO Interface 3 */
void hw_atl_glb_mdio_iface3_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 3 */
u32 hw_atl_glb_mdio_iface3_get(struct aq_hw_s *hw);
/* set Global MDIO Interface 4 */
void hw_atl_glb_mdio_iface4_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 4 */
u32 hw_atl_glb_mdio_iface4_get(struct aq_hw_s *hw);
/* set Global MDIO Interface 5 */
void hw_atl_glb_mdio_iface5_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 5 */
u32 hw_atl_glb_mdio_iface5_get(struct aq_hw_s *hw);
u32 hw_atl_mdio_busy_get(struct aq_hw_s *aq_hw);
/* get global microprocessor ram semaphore */
u32 hw_atl_sem_ram_get(struct aq_hw_s *self);
/* get global microprocessor mdio semaphore */
u32 hw_atl_sem_mdio_get(struct aq_hw_s *self);
u32 hw_atl_sem_reset1_get(struct aq_hw_s *self);
u32 hw_atl_sem_reset2_get(struct aq_hw_s *self);
/* get global microprocessor scratch pad register */
u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp);
/* get global microprocessor scratch pad 12 register */
u32 hw_atl_scrpad12_get(struct aq_hw_s *self);
/* get global microprocessor scratch pad 25 register */
u32 hw_atl_scrpad25_get(struct aq_hw_s *self);
#endif /* HW_ATL_LLH_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,649 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File hw_atl_utils.h: Declaration of common functions for Atlantic hardware
* abstraction layer.
*/
#ifndef HW_ATL_UTILS_H
#define HW_ATL_UTILS_H
#define HW_ATL_FLUSH() { (void)aq_hw_read_reg(self, 0x10); }
/* Hardware tx descriptor */
struct __packed hw_atl_txd_s {
u64 buf_addr;
u32 ctl;
u32 ctl2; /* 63..46 - payload length, 45 - ctx enable, 44 - ctx index */
};
/* Hardware tx context descriptor */
struct __packed hw_atl_txc_s {
u32 rsvd;
u32 len;
u32 ctl;
u32 len2;
};
/* Hardware rx descriptor */
struct __packed hw_atl_rxd_s {
u64 buf_addr;
u64 hdr_addr;
};
/* Hardware rx descriptor writeback */
struct __packed hw_atl_rxd_wb_s {
u32 type;
u32 rss_hash;
u16 status;
u16 pkt_len;
u16 next_desc_ptr;
__le16 vlan;
};
/* Hardware rx HW TIMESTAMP writeback */
struct __packed hw_atl_rxd_hwts_wb_s {
u32 sec_hw;
u32 ns;
u32 sec_lw0;
u32 sec_lw1;
};
struct __packed hw_atl_stats_s {
u32 uprc;
u32 mprc;
u32 bprc;
u32 erpt;
u32 uptc;
u32 mptc;
u32 bptc;
u32 erpr;
u32 mbtc;
u32 bbtc;
u32 mbrc;
u32 bbrc;
u32 ubrc;
u32 ubtc;
u32 dpc;
};
struct __packed drv_msg_enable_wakeup {
union {
u32 pattern_mask;
struct {
u32 reason_arp_v4_pkt : 1;
u32 reason_ipv4_ping_pkt : 1;
u32 reason_ipv6_ns_pkt : 1;
u32 reason_ipv6_ping_pkt : 1;
u32 reason_link_up : 1;
u32 reason_link_down : 1;
u32 reason_maximum : 1;
};
};
union {
u32 offload_mask;
};
};
struct __packed magic_packet_pattern_s {
u8 mac_addr[ETH_ALEN];
};
struct __packed drv_msg_wol_add {
u32 priority;
u32 packet_type;
u32 pattern_id;
u32 next_pattern_offset;
struct magic_packet_pattern_s magic_packet_pattern;
};
struct __packed drv_msg_wol_remove {
u32 id;
};
struct __packed hw_atl_utils_mbox_header {
u32 version;
u32 transaction_id;
u32 error;
};
struct __packed hw_atl_ptp_offset {
u16 ingress_100;
u16 egress_100;
u16 ingress_1000;
u16 egress_1000;
u16 ingress_2500;
u16 egress_2500;
u16 ingress_5000;
u16 egress_5000;
u16 ingress_10000;
u16 egress_10000;
};
struct __packed hw_atl_cable_diag {
u8 fault;
u8 distance;
u8 far_distance;
u8 reserved;
};
enum gpio_pin_function {
GPIO_PIN_FUNCTION_NC,
GPIO_PIN_FUNCTION_VAUX_ENABLE,
GPIO_PIN_FUNCTION_EFUSE_BURN_ENABLE,
GPIO_PIN_FUNCTION_SFP_PLUS_DETECT,
GPIO_PIN_FUNCTION_TX_DISABLE,
GPIO_PIN_FUNCTION_RATE_SEL_0,
GPIO_PIN_FUNCTION_RATE_SEL_1,
GPIO_PIN_FUNCTION_TX_FAULT,
GPIO_PIN_FUNCTION_PTP0,
GPIO_PIN_FUNCTION_PTP1,
GPIO_PIN_FUNCTION_PTP2,
GPIO_PIN_FUNCTION_SIZE
};
struct __packed hw_atl_info {
u8 reserved[6];
u16 phy_fault_code;
u16 phy_temperature;
u8 cable_len;
u8 reserved1;
struct hw_atl_cable_diag cable_diag_data[4];
struct hw_atl_ptp_offset ptp_offset;
u8 reserved2[12];
u32 caps_lo;
u32 caps_hi;
u32 reserved_datapath;
u32 reserved3[7];
u32 reserved_simpleresp[3];
u32 reserved_linkstat[7];
u32 reserved_wakes_count;
u32 reserved_eee_stat[12];
u32 tx_stuck_cnt;
u32 setting_address;
u32 setting_length;
u32 caps_ex;
enum gpio_pin_function gpio_pin[3];
u32 pcie_aer_dump[18];
u16 snr_margin[4];
};
struct __packed hw_atl_utils_mbox {
struct hw_atl_utils_mbox_header header;
struct hw_atl_stats_s stats;
struct hw_atl_info info;
};
struct __packed offload_ip_info {
u8 v4_local_addr_count;
u8 v4_addr_count;
u8 v6_local_addr_count;
u8 v6_addr_count;
u32 v4_addr;
u32 v4_prefix;
u32 v6_addr;
u32 v6_prefix;
};
struct __packed offload_port_info {
u16 udp_port_count;
u16 tcp_port_count;
u32 udp_port;
u32 tcp_port;
};
struct __packed offload_ka_info {
u16 v4_ka_count;
u16 v6_ka_count;
u32 retry_count;
u32 retry_interval;
u32 v4_ka;
u32 v6_ka;
};
struct __packed offload_rr_info {
u32 rr_count;
u32 rr_buf_len;
u32 rr_id_x;
u32 rr_buf;
};
struct __packed offload_info {
u32 version;
u32 len;
u8 mac_addr[ETH_ALEN];
u8 reserved[2];
struct offload_ip_info ips;
struct offload_port_info ports;
struct offload_ka_info kas;
struct offload_rr_info rrs;
};
struct __packed hw_atl_utils_fw_rpc {
u32 msg_id;
union {
/* fw1x structures */
struct drv_msg_wol_add msg_wol_add;
struct drv_msg_wol_remove msg_wol_remove;
struct drv_msg_enable_wakeup msg_enable_wakeup;
/* fw2x structures */
struct offload_info fw2x_offloads;
};
};
/* Mailbox FW Request interface */
struct __packed hw_fw_request_ptp_gpio_ctrl {
u32 index;
u32 period;
u64 start;
};
struct __packed hw_fw_request_ptp_adj_freq {
u32 ns_mac;
u32 fns_mac;
u32 ns_phy;
u32 fns_phy;
u32 mac_ns_adj;
u32 mac_fns_adj;
};
struct __packed hw_fw_request_ptp_adj_clock {
u32 ns;
u32 sec;
int sign;
};
#define HW_AQ_FW_REQUEST_PTP_GPIO_CTRL 0x11
#define HW_AQ_FW_REQUEST_PTP_ADJ_FREQ 0x12
#define HW_AQ_FW_REQUEST_PTP_ADJ_CLOCK 0x13
struct __packed hw_fw_request_iface {
u32 msg_id;
union {
/* PTP FW Request */
struct hw_fw_request_ptp_gpio_ctrl ptp_gpio_ctrl;
struct hw_fw_request_ptp_adj_freq ptp_adj_freq;
struct hw_fw_request_ptp_adj_clock ptp_adj_clock;
};
};
struct __packed hw_atl_utils_settings {
u32 mtu;
u32 downshift_retry_count;
u32 link_pause_frame_quanta_100m;
u32 link_pause_frame_threshold_100m;
u32 link_pause_frame_quanta_1g;
u32 link_pause_frame_threshold_1g;
u32 link_pause_frame_quanta_2p5g;
u32 link_pause_frame_threshold_2p5g;
u32 link_pause_frame_quanta_5g;
u32 link_pause_frame_threshold_5g;
u32 link_pause_frame_quanta_10g;
u32 link_pause_frame_threshold_10g;
u32 pfc_quanta_class_0;
u32 pfc_threshold_class_0;
u32 pfc_quanta_class_1;
u32 pfc_threshold_class_1;
u32 pfc_quanta_class_2;
u32 pfc_threshold_class_2;
u32 pfc_quanta_class_3;
u32 pfc_threshold_class_3;
u32 pfc_quanta_class_4;
u32 pfc_threshold_class_4;
u32 pfc_quanta_class_5;
u32 pfc_threshold_class_5;
u32 pfc_quanta_class_6;
u32 pfc_threshold_class_6;
u32 pfc_quanta_class_7;
u32 pfc_threshold_class_7;
u32 eee_link_down_timeout;
u32 eee_link_up_timeout;
u32 eee_max_link_drops;
u32 eee_rates_mask;
u32 wake_timer;
u32 thermal_shutdown_off_temp;
u32 thermal_shutdown_warning_temp;
u32 thermal_shutdown_cold_temp;
u32 msm_options;
u32 dac_cable_serdes_modes;
u32 media_detect;
};
struct __packed smbus_request {
u32 msg_id;
u32 device_id;
u32 address;
u32 length;
};
enum macsec_msg_type {
macsec_cfg_msg = 0,
macsec_add_rx_sc_msg,
macsec_add_tx_sc_msg,
macsec_add_rx_sa_msg,
macsec_add_tx_sa_msg,
macsec_get_stats_msg,
};
struct __packed macsec_cfg_request {
u32 enabled;
u32 egress_threshold;
u32 ingress_threshold;
u32 interrupts_enabled;
};
struct __packed macsec_msg_fw_request {
u32 msg_id; /* not used */
u32 msg_type;
struct macsec_cfg_request cfg;
};
struct __packed macsec_msg_fw_response {
u32 result;
};
enum hw_atl_rx_action_with_traffic {
HW_ATL_RX_DISCARD,
HW_ATL_RX_HOST,
HW_ATL_RX_MNGMNT,
HW_ATL_RX_HOST_AND_MNGMNT,
HW_ATL_RX_WOL
};
struct aq_rx_filter_vlan {
u8 enable;
u8 location;
u16 vlan_id;
u8 queue;
};
#define HW_ATL_VLAN_MAX_FILTERS 16U
struct aq_rx_filter_l2 {
s8 queue;
u8 location;
u8 user_priority_en;
u8 user_priority;
u16 ethertype;
};
struct aq_rx_filter_l3l4 {
u32 cmd;
u8 location;
u32 ip_dst[4];
u32 ip_src[4];
u16 p_dst;
u16 p_src;
u8 is_ipv6;
};
enum hw_atl_rx_protocol_value_l3l4 {
HW_ATL_RX_TCP,
HW_ATL_RX_UDP,
HW_ATL_RX_SCTP,
HW_ATL_RX_ICMP
};
enum hw_atl_rx_ctrl_registers_l3l4 {
HW_ATL_RX_ENABLE_MNGMNT_QUEUE_L3L4 = BIT(22),
HW_ATL_RX_ENABLE_QUEUE_L3L4 = BIT(23),
HW_ATL_RX_ENABLE_ARP_FLTR_L3 = BIT(24),
HW_ATL_RX_ENABLE_CMP_PROT_L4 = BIT(25),
HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4 = BIT(26),
HW_ATL_RX_ENABLE_CMP_SRC_PORT_L4 = BIT(27),
HW_ATL_RX_ENABLE_CMP_DEST_ADDR_L3 = BIT(28),
HW_ATL_RX_ENABLE_CMP_SRC_ADDR_L3 = BIT(29),
HW_ATL_RX_ENABLE_L3_IPV6 = BIT(30),
HW_ATL_RX_ENABLE_FLTR_L3L4 = BIT(31)
};
#define HW_ATL_RX_QUEUE_FL3L4_SHIFT 8U
#define HW_ATL_RX_ACTION_FL3F4_SHIFT 16U
#define HW_ATL_RX_CNT_REG_ADDR_IPV6 4U
#define HW_ATL_GET_REG_LOCATION_FL3L4(location) \
((location) - AQ_RX_FIRST_LOC_FL3L4)
enum hal_atl_utils_fw_state_e {
MPI_DEINIT = 0,
MPI_RESET = 1,
MPI_INIT = 2,
MPI_POWER = 4,
};
#define HAL_ATLANTIC_RATE_10G BIT(0)
#define HAL_ATLANTIC_RATE_5G BIT(1)
#define HAL_ATLANTIC_RATE_5GSR BIT(2)
#define HAL_ATLANTIC_RATE_2G5 BIT(3)
#define HAL_ATLANTIC_RATE_1G BIT(4)
#define HAL_ATLANTIC_RATE_100M BIT(5)
#define HAL_ATLANTIC_RATE_INVALID BIT(6)
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD 0x4U
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR 0x10000000U
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN 0x1U
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT 0x2U
#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL 0x5U
#define HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP 0x6U
enum hw_atl_fw2x_rate {
FW2X_RATE_100M = 0x20,
FW2X_RATE_1G = 0x100,
FW2X_RATE_2G5 = 0x200,
FW2X_RATE_5G = 0x400,
FW2X_RATE_10G = 0x800,
};
/* 0x370
* Link capabilities resolution register
*/
enum hw_atl_fw2x_caps_lo {
CAPS_LO_10BASET_HD = 0,
CAPS_LO_10BASET_FD,
CAPS_LO_100BASETX_HD,
CAPS_LO_100BASET4_HD,
CAPS_LO_100BASET2_HD,
CAPS_LO_100BASETX_FD = 5,
CAPS_LO_100BASET2_FD,
CAPS_LO_1000BASET_HD,
CAPS_LO_1000BASET_FD,
CAPS_LO_2P5GBASET_FD,
CAPS_LO_5GBASET_FD = 10,
CAPS_LO_10GBASET_FD,
CAPS_LO_AUTONEG,
CAPS_LO_SMBUS_READ,
CAPS_LO_SMBUS_WRITE,
CAPS_LO_MACSEC = 15,
CAPS_LO_RESERVED1,
CAPS_LO_WAKE_ON_LINK_FORCED,
CAPS_LO_HIGH_TEMP_WARNING = 29,
CAPS_LO_DRIVER_SCRATCHPAD = 30,
CAPS_LO_GLOBAL_FAULT = 31
};
/* 0x374
* Status register
*/
enum hw_atl_fw2x_caps_hi {
CAPS_HI_TPO2EN = 0,
CAPS_HI_10BASET_EEE,
CAPS_HI_RESERVED2,
CAPS_HI_PAUSE,
CAPS_HI_ASYMMETRIC_PAUSE,
CAPS_HI_100BASETX_EEE = 5,
CAPS_HI_PHY_BUF_SEND,
CAPS_HI_PHY_BUF_RECV,
CAPS_HI_1000BASET_FD_EEE,
CAPS_HI_2P5GBASET_FD_EEE,
CAPS_HI_5GBASET_FD_EEE = 10,
CAPS_HI_10GBASET_FD_EEE,
CAPS_HI_FW_REQUEST,
CAPS_HI_PHY_LOG,
CAPS_HI_EEE_AUTO_DISABLE_SETTINGS,
CAPS_HI_PFC = 15,
CAPS_HI_WAKE_ON_LINK,
CAPS_HI_CABLE_DIAG,
CAPS_HI_TEMPERATURE,
CAPS_HI_DOWNSHIFT,
CAPS_HI_PTP_AVB_EN_FW2X = 20,
CAPS_HI_THERMAL_SHUTDOWN,
CAPS_HI_LINK_DROP,
CAPS_HI_SLEEP_PROXY,
CAPS_HI_WOL,
CAPS_HI_MAC_STOP = 25,
CAPS_HI_EXT_LOOPBACK,
CAPS_HI_INT_LOOPBACK,
CAPS_HI_EFUSE_AGENT,
CAPS_HI_WOL_TIMER,
CAPS_HI_STATISTICS = 30,
CAPS_HI_TRANSACTION_ID,
};
/* 0x36C
* Control register
*/
enum hw_atl_fw2x_ctrl {
CTRL_RESERVED1 = 0,
CTRL_RESERVED2,
CTRL_RESERVED3,
CTRL_PAUSE,
CTRL_ASYMMETRIC_PAUSE,
CTRL_RESERVED4 = 5,
CTRL_RESERVED5,
CTRL_RESERVED6,
CTRL_1GBASET_FD_EEE,
CTRL_2P5GBASET_FD_EEE,
CTRL_5GBASET_FD_EEE = 10,
CTRL_10GBASET_FD_EEE,
CTRL_THERMAL_SHUTDOWN,
CTRL_PHY_LOGS,
CTRL_EEE_AUTO_DISABLE,
CTRL_PFC = 15,
CTRL_WAKE_ON_LINK,
CTRL_CABLE_DIAG,
CTRL_TEMPERATURE,
CTRL_DOWNSHIFT,
CTRL_PTP_AVB = 20,
CTRL_RESERVED7,
CTRL_LINK_DROP,
CTRL_SLEEP_PROXY,
CTRL_WOL,
CTRL_MAC_STOP = 25,
CTRL_EXT_LOOPBACK,
CTRL_INT_LOOPBACK,
CTRL_RESERVED8,
CTRL_WOL_TIMER,
CTRL_STATISTICS = 30,
CTRL_FORCE_RECONNECT,
};
enum hw_atl_caps_ex {
CAPS_EX_LED_CONTROL = 0,
CAPS_EX_LED0_MODE_LO,
CAPS_EX_LED0_MODE_HI,
CAPS_EX_LED1_MODE_LO,
CAPS_EX_LED1_MODE_HI,
CAPS_EX_LED2_MODE_LO = 5,
CAPS_EX_LED2_MODE_HI,
CAPS_EX_RESERVED07,
CAPS_EX_RESERVED08,
CAPS_EX_RESERVED09,
CAPS_EX_RESERVED10 = 10,
CAPS_EX_RESERVED11,
CAPS_EX_RESERVED12,
CAPS_EX_RESERVED13,
CAPS_EX_RESERVED14,
CAPS_EX_RESERVED15 = 15,
CAPS_EX_PHY_PTP_EN,
CAPS_EX_MAC_PTP_EN,
CAPS_EX_EXT_CLK_EN,
CAPS_EX_SCHED_DMA_EN,
CAPS_EX_PTP_GPIO_EN = 20,
CAPS_EX_UPDATE_SETTINGS,
CAPS_EX_PHY_CTRL_TS_PIN,
CAPS_EX_SNR_OPERATING_MARGIN,
CAPS_EX_RESERVED24,
CAPS_EX_RESERVED25 = 25,
CAPS_EX_RESERVED26,
CAPS_EX_RESERVED27,
CAPS_EX_RESERVED28,
CAPS_EX_RESERVED29,
CAPS_EX_RESERVED30 = 30,
CAPS_EX_RESERVED31
};
struct aq_hw_s;
struct aq_fw_ops;
struct aq_hw_caps_s;
struct aq_hw_link_status_s;
int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops);
int hw_atl_utils_soft_reset(struct aq_hw_s *self);
void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p);
int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
struct hw_atl_utils_mbox_header *pmbox);
void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
struct hw_atl_utils_mbox *pmbox);
void hw_atl_utils_mpi_set(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state,
u32 speed);
int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self);
int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
u8 *mac);
unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps);
int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
const struct aq_hw_caps_s *aq_hw_caps,
u32 *regs_buff);
int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
unsigned int power_state);
int hw_atl_utils_hw_deinit(struct aq_hw_s *self);
u32 hw_atl_utils_get_fw_version(struct aq_hw_s *self);
int hw_atl_utils_update_stats(struct aq_hw_s *self);
struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self);
int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
u32 *p, u32 cnt);
int hw_atl_write_fwcfg_dwords(struct aq_hw_s *self, u32 *p, u32 cnt);
int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p,
u32 cnt);
int hw_atl_utils_fw_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac);
int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size);
int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
struct hw_atl_utils_fw_rpc **rpc);
bool hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
extern const struct aq_fw_ops aq_fw_1x_ops;
extern const struct aq_fw_ops aq_fw_2x_ops;
#endif /* HW_ATL_UTILS_H */
@@ -0,0 +1,812 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
* Atlantic hardware abstraction layer.
*/
#include "../aq_hw.h"
#include "../aq_hw_utils.h"
#include "../aq_pci_func.h"
#include "../aq_ring.h"
#include "../aq_vec.h"
#include "../aq_nic.h"
#include "hw_atl_utils.h"
#include "hw_atl_llh.h"
#define HW_ATL_FW2X_MPI_LED_ADDR 0x31c
#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334
#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360
#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364
#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368
#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C
#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370
#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374
#define HW_ATL_FW3X_EXT_CONTROL_ADDR 0x378
#define HW_ATL_FW3X_EXT_STATE_ADDR 0x37c
#define HW_ATL_FW3X_PTP_ADJ_LSW_ADDR 0x50a0
#define HW_ATL_FW3X_PTP_ADJ_MSW_ADDR 0x50a4
#define HW_ATL_FW2X_CAP_PAUSE BIT(CAPS_HI_PAUSE)
#define HW_ATL_FW2X_CAP_ASYM_PAUSE BIT(CAPS_HI_ASYMMETRIC_PAUSE)
#define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY)
#define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL)
#define HW_ATL_FW2X_CTRL_WAKE_ON_LINK BIT(CTRL_WAKE_ON_LINK)
#define HW_ATL_FW2X_CTRL_SLEEP_PROXY BIT(CTRL_SLEEP_PROXY)
#define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL)
#define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP)
#define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE)
#define HW_ATL_FW2X_CTRL_TEMPERATURE BIT(CTRL_TEMPERATURE)
#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
#define HW_ATL_FW2X_CTRL_INT_LOOPBACK BIT(CTRL_INT_LOOPBACK)
#define HW_ATL_FW2X_CTRL_EXT_LOOPBACK BIT(CTRL_EXT_LOOPBACK)
#define HW_ATL_FW2X_CTRL_DOWNSHIFT BIT(CTRL_DOWNSHIFT)
#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT)
#define HW_ATL_FW2X_CAP_EEE_1G_MASK BIT(CAPS_HI_1000BASET_FD_EEE)
#define HW_ATL_FW2X_CAP_EEE_2G5_MASK BIT(CAPS_HI_2P5GBASET_FD_EEE)
#define HW_ATL_FW2X_CAP_EEE_5G_MASK BIT(CAPS_HI_5GBASET_FD_EEE)
#define HW_ATL_FW2X_CAP_EEE_10G_MASK BIT(CAPS_HI_10GBASET_FD_EEE)
#define HW_ATL_FW2X_CAP_MACSEC BIT(CAPS_LO_MACSEC)
#define HAL_ATLANTIC_WOL_FILTERS_COUNT 8
#define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E
#define HW_ATL_FW_VER_LED 0x03010026U
#define HW_ATL_FW_VER_MEDIA_CONTROL 0x0301005aU
struct __packed fw2x_msg_wol_pattern {
u8 mask[16];
u32 crc;
};
struct __packed fw2x_msg_wol {
u32 msg_id;
u8 hw_addr[ETH_ALEN];
u8 magic_packet_enabled;
u8 filter_count;
struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
u8 link_up_enabled;
u8 link_down_enabled;
u16 reserved;
u32 link_up_timeout;
u32 link_down_timeout;
};
static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
static int aq_fw2x_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state);
static u32 aq_fw2x_mbox_get(struct aq_hw_s *self);
static u32 aq_fw2x_rpc_get(struct aq_hw_s *self);
static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr);
static u32 aq_fw2x_state_get(struct aq_hw_s *self);
static u32 aq_fw2x_state2_get(struct aq_hw_s *self);
static int aq_fw2x_init(struct aq_hw_s *self)
{
int err = 0;
/* check 10 times by 1ms */
err = readx_poll_timeout_atomic(aq_fw2x_mbox_get,
self, self->mbox_addr,
self->mbox_addr != 0U,
1000U, 10000U);
err = readx_poll_timeout_atomic(aq_fw2x_rpc_get,
self, self->rpc_addr,
self->rpc_addr != 0U,
1000U, 100000U);
err = aq_fw2x_settings_get(self, &self->settings_addr);
return err;
}
static int aq_fw2x_deinit(struct aq_hw_s *self)
{
int err = aq_fw2x_set_link_speed(self, 0);
if (!err)
err = aq_fw2x_set_state(self, MPI_DEINIT);
return err;
}
static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
{
enum hw_atl_fw2x_rate rate = 0;
if (speed & AQ_NIC_RATE_10G)
rate |= FW2X_RATE_10G;
if (speed & AQ_NIC_RATE_5G)
rate |= FW2X_RATE_5G;
if (speed & AQ_NIC_RATE_2G5)
rate |= FW2X_RATE_2G5;
if (speed & AQ_NIC_RATE_1G)
rate |= FW2X_RATE_1G;
if (speed & AQ_NIC_RATE_100M)
rate |= FW2X_RATE_100M;
return rate;
}
static u32 fw2x_to_eee_mask(u32 speed)
{
u32 rate = 0;
if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
rate |= AQ_NIC_RATE_EEE_10G;
if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
rate |= AQ_NIC_RATE_EEE_5G;
if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
rate |= AQ_NIC_RATE_EEE_2G5;
if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
rate |= AQ_NIC_RATE_EEE_1G;
return rate;
}
static u32 eee_mask_to_fw2x(u32 speed)
{
u32 rate = 0;
if (speed & AQ_NIC_RATE_EEE_10G)
rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
if (speed & AQ_NIC_RATE_EEE_5G)
rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
if (speed & AQ_NIC_RATE_EEE_2G5)
rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
if (speed & AQ_NIC_RATE_EEE_1G)
rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
return rate;
}
static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
{
u32 val = link_speed_mask_2fw2x_ratemask(speed);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
return 0;
}
static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self,
u32 *mpi_state, u32 fc)
{
*mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE |
HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE);
switch (fc) {
/* There is not explicit mode of RX only pause frames,
* thus, we join this mode with FC full.
* FC full is either Rx, either Tx, or both.
*/
case AQ_NIC_FC_FULL:
case AQ_NIC_FC_RX:
*mpi_state |= HW_ATL_FW2X_CTRL_PAUSE |
HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
break;
case AQ_NIC_FC_TX:
*mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
break;
}
}
static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
u32 eee_speeds)
{
*mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
HW_ATL_FW2X_CAP_EEE_2G5_MASK |
HW_ATL_FW2X_CAP_EEE_5G_MASK |
HW_ATL_FW2X_CAP_EEE_10G_MASK);
*mpi_opts |= eee_mask_to_fw2x(eee_speeds);
}
static int aq_fw2x_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state)
{
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
switch (state) {
case MPI_INIT:
mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
aq_fw2x_upd_flow_control_bits(self, &mpi_state,
self->aq_nic_cfg->fc.req);
break;
case MPI_DEINIT:
mpi_state |= BIT(CAPS_HI_LINK_DROP);
break;
case MPI_RESET:
case MPI_POWER:
/* No actions */
break;
}
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
return 0;
}
static int aq_fw2x_update_link_status(struct aq_hw_s *self)
{
struct aq_hw_link_status_s *link_status = &self->aq_link_status;
u32 mpi_state;
u32 speed;
mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
FW2X_RATE_2G5 | FW2X_RATE_5G |
FW2X_RATE_10G);
if (speed) {
if (speed & FW2X_RATE_10G)
link_status->mbps = 10000;
else if (speed & FW2X_RATE_5G)
link_status->mbps = 5000;
else if (speed & FW2X_RATE_2G5)
link_status->mbps = 2500;
else if (speed & FW2X_RATE_1G)
link_status->mbps = 1000;
else if (speed & FW2X_RATE_100M)
link_status->mbps = 100;
else
link_status->mbps = 10000;
} else {
link_status->mbps = 0;
}
link_status->full_duplex = true;
return 0;
}
static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
{
u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
u32 mac_addr[2] = { 0 };
int err = 0;
if (efuse_addr != 0) {
err = hw_atl_utils_fw_downld_dwords(self,
efuse_addr + (40U * 4U),
mac_addr,
ARRAY_SIZE(mac_addr));
if (err)
return err;
mac_addr[0] = __swab32(mac_addr[0]);
mac_addr[1] = __swab32(mac_addr[1]);
}
ether_addr_copy(mac, (u8 *)mac_addr);
return err;
}
static int aq_fw2x_update_stats(struct aq_hw_s *self)
{
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
u32 stats_val;
int err = 0;
/* Toggle statistics bit for FW to update */
mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
/* Wait FW to report back */
err = readx_poll_timeout_atomic(aq_fw2x_state2_get,
self, stats_val,
orig_stats_val != (stats_val &
BIT(CAPS_HI_STATISTICS)),
1U, 10000U);
if (err)
return err;
return hw_atl_utils_update_stats(self);
}
static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp)
{
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
u32 temp_val = mpi_opts & HW_ATL_FW2X_CTRL_TEMPERATURE;
u32 phy_temp_offset;
u32 temp_res;
int err = 0;
u32 val;
phy_temp_offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
info.phy_temperature);
/* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */
mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
/* Wait FW to report back */
err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
temp_val !=
(val & HW_ATL_FW2X_CTRL_TEMPERATURE),
1U, 10000U);
err = hw_atl_utils_fw_downld_dwords(self, phy_temp_offset,
&temp_res, 1);
if (err)
return err;
/* Convert PHY temperature from 1/256 degree Celsius
* to 1/1000 degree Celsius.
*/
*temp = (int16_t)(temp_res & 0xFFFF) * 1000 / 256;
return 0;
}
static int aq_fw2x_set_wol(struct aq_hw_s *self, const u8 *mac)
{
struct hw_atl_utils_fw_rpc *rpc = NULL;
struct offload_info *info = NULL;
u32 wol_bits = 0;
u32 rpc_size;
int err = 0;
u32 val;
if (self->aq_nic_cfg->wol & WAKE_PHY) {
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR,
HW_ATL_FW2X_CTRL_LINK_DROP);
readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
(val &
HW_ATL_FW2X_CTRL_LINK_DROP) != 0,
1000, 100000);
wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK;
}
if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY |
HW_ATL_FW2X_CTRL_WOL;
err = hw_atl_utils_fw_rpc_wait(self, &rpc);
if (err < 0)
goto err_exit;
rpc_size = sizeof(*info) +
offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads);
memset(rpc, 0, rpc_size);
info = &rpc->fw2x_offloads;
memcpy(info->mac_addr, mac, ETH_ALEN);
info->len = sizeof(*info);
err = hw_atl_utils_fw_rpc_call(self, rpc_size);
if (err < 0)
goto err_exit;
}
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits);
err_exit:
return err;
}
static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
const u8 *mac)
{
int err = 0;
if (self->aq_nic_cfg->wol)
err = aq_fw2x_set_wol(self, mac);
return err;
}
static int aq_fw2x_send_fw_request(struct aq_hw_s *self,
const struct hw_fw_request_iface *fw_req,
size_t size)
{
u32 ctrl2, orig_ctrl2;
u32 dword_cnt;
int err = 0;
u32 val;
/* Write data to drvIface Mailbox */
dword_cnt = size / sizeof(u32);
if (size % sizeof(u32))
dword_cnt++;
err = hw_atl_write_fwcfg_dwords(self, (void *)fw_req, dword_cnt);
if (err < 0)
goto err_exit;
/* Toggle statistics bit for FW to update */
ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST);
ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2);
/* Wait FW to report back */
err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
orig_ctrl2 != (val &
BIT(CAPS_HI_FW_REQUEST)),
1U, 10000U);
err_exit:
return err;
}
static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable)
{
u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR);
u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) |
BIT(CAPS_EX_PTP_GPIO_EN);
if (enable)
ptp_opts |= all_ptp_features;
else
ptp_opts &= ~all_ptp_features;
aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts);
}
static void aq_fw3x_adjust_ptp(struct aq_hw_s *self, uint64_t adj)
{
aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_LSW_ADDR,
(adj >> 0) & 0xffffffff);
aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_MSW_ADDR,
(adj >> 32) & 0xffffffff);
}
static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode)
{
if (self->fw_ver_actual < HW_ATL_FW_VER_LED)
return -EOPNOTSUPP;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode);
return 0;
}
static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
{
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
return 0;
}
static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
u32 *supported_rates)
{
u32 mpi_state;
u32 caps_hi;
int err = 0;
u32 offset;
offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
info.caps_hi);
err = hw_atl_utils_fw_downld_dwords(self, offset, &caps_hi, 1);
if (err)
return err;
*supported_rates = fw2x_to_eee_mask(caps_hi);
mpi_state = aq_fw2x_state2_get(self);
*rate = fw2x_to_eee_mask(mpi_state);
return err;
}
static int aq_fw2x_renegotiate(struct aq_hw_s *self)
{
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
return 0;
}
static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
{
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
aq_fw2x_upd_flow_control_bits(self, &mpi_state,
self->aq_nic_cfg->fc.req);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
return 0;
}
static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
{
u32 mpi_state = aq_fw2x_state2_get(self);
*fcmode = 0;
if (mpi_state & HW_ATL_FW2X_CAP_PAUSE)
*fcmode |= AQ_NIC_FC_RX;
if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
*fcmode |= AQ_NIC_FC_TX;
return 0;
}
static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable)
{
u32 mpi_opts;
switch (mode) {
case AQ_HW_LOOPBACK_PHYINT_SYS:
mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
if (enable)
mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK;
else
mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
break;
case AQ_HW_LOOPBACK_PHYEXT_SYS:
mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
if (enable)
mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
else
mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
break;
default:
return -EINVAL;
}
return 0;
}
static u32 aq_fw2x_mbox_get(struct aq_hw_s *self)
{
return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR);
}
static u32 aq_fw2x_rpc_get(struct aq_hw_s *self)
{
return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR);
}
static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr)
{
int err = 0;
u32 offset;
offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
info.setting_address);
err = hw_atl_utils_fw_downld_dwords(self, offset, addr, 1);
return err;
}
static u32 aq_fw2x_state_get(struct aq_hw_s *self)
{
return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
}
static u32 aq_fw2x_state2_get(struct aq_hw_s *self)
{
return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
}
static int aq_fw2x_set_downshift(struct aq_hw_s *self, u32 counter)
{
int err = 0;
u32 mpi_opts;
u32 offset;
offset = offsetof(struct hw_atl_utils_settings, downshift_retry_count);
err = hw_atl_write_fwsettings_dwords(self, offset, &counter, 1);
if (err)
return err;
mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
if (counter)
mpi_opts |= HW_ATL_FW2X_CTRL_DOWNSHIFT;
else
mpi_opts &= ~HW_ATL_FW2X_CTRL_DOWNSHIFT;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
return err;
}
static int aq_fw2x_set_media_detect(struct aq_hw_s *self, bool on)
{
u32 enable;
u32 offset;
if (self->fw_ver_actual < HW_ATL_FW_VER_MEDIA_CONTROL)
return -EOPNOTSUPP;
offset = offsetof(struct hw_atl_utils_settings, media_detect);
enable = on;
return hw_atl_write_fwsettings_dwords(self, offset, &enable, 1);
}
static u32 aq_fw2x_get_link_capabilities(struct aq_hw_s *self)
{
int err = 0;
u32 offset;
u32 val;
offset = self->mbox_addr +
offsetof(struct hw_atl_utils_mbox, info.caps_lo);
err = hw_atl_utils_fw_downld_dwords(self, offset, &val, 1);
if (err)
return 0;
return val;
}
static int aq_fw2x_send_macsec_req(struct aq_hw_s *hw,
struct macsec_msg_fw_request *req,
struct macsec_msg_fw_response *response)
{
u32 low_status, low_req = 0;
u32 dword_cnt;
u32 caps_lo;
u32 offset;
int err;
if (!req || !response)
return -EINVAL;
caps_lo = aq_fw2x_get_link_capabilities(hw);
if (!(caps_lo & BIT(CAPS_LO_MACSEC)))
return -EOPNOTSUPP;
/* Write macsec request to cfg memory */
dword_cnt = (sizeof(*req) + sizeof(u32) - 1) / sizeof(u32);
err = hw_atl_write_fwcfg_dwords(hw, (void *)req, dword_cnt);
if (err < 0)
return err;
/* Toggle 0x368.CAPS_LO_MACSEC bit */
low_req = aq_hw_read_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR);
low_req ^= HW_ATL_FW2X_CAP_MACSEC;
aq_hw_write_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR, low_req);
/* Wait FW to report back */
err = readx_poll_timeout_atomic(aq_fw2x_state_get, hw, low_status,
low_req != (low_status & BIT(CAPS_LO_MACSEC)), 1U, 10000U);
if (err)
return -EIO;
/* Read status of write operation */
offset = hw->rpc_addr + sizeof(u32);
err = hw_atl_utils_fw_downld_dwords(hw, offset, (u32 *)(void *)response,
sizeof(*response) / sizeof(u32));
return err;
}
static int aq_fw2x_read_module_eeprom(struct aq_hw_s *self, u8 dev_addr,
u8 reg_start_addr, int len, u8 *data)
{
u32 low_status, orig_low_status, low_req = 0;
u32 res_bytes_remain_cnt = len % sizeof(u32);
u32 res_dword_cnt = len / sizeof(u32);
struct smbus_request request = { 0 };
u32 req_dword_cnt;
u32 result = 0;
u32 caps_lo;
u32 offset;
int err;
caps_lo = aq_fw2x_get_link_capabilities(self);
if (!(caps_lo & BIT(CAPS_LO_SMBUS_READ)))
return -EOPNOTSUPP;
request.msg_id = 0;
request.device_id = dev_addr;
request.address = reg_start_addr;
request.length = len;
/* Write SMBUS request to cfg memory */
req_dword_cnt = DIV_ROUND_UP(sizeof(request), sizeof(u32));
err = hw_atl_write_fwcfg_dwords(self, (void *)&request, req_dword_cnt);
if (err < 0)
return err;
/* Toggle 0x368.CAPS_LO_SMBUS_READ bit */
low_req = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR);
orig_low_status = low_req & BIT(CAPS_LO_SMBUS_READ);
low_req ^= BIT(CAPS_LO_SMBUS_READ);
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, low_req);
/* Wait FW to report back */
err = readx_poll_timeout_atomic(aq_fw2x_state_get, self, low_status,
orig_low_status != (low_status &
BIT(CAPS_LO_SMBUS_READ)),
10U, 100000U);
if (err)
return err;
/* Read status of read operation */
offset = self->rpc_addr + sizeof(u32);
err = hw_atl_utils_fw_downld_dwords(self, offset, &result,
sizeof(result) / sizeof(u32));
if (err < 0)
return err;
if (result)
return -EIO;
/* Read response full DWORD data */
if (res_dword_cnt) {
offset = self->rpc_addr + sizeof(u32) * 2;
err = hw_atl_utils_fw_downld_dwords(self, offset, (u32 *)data,
res_dword_cnt);
if (err < 0)
return err;
}
/* Read response trailing bytes data */
if (res_bytes_remain_cnt) {
u32 bytes_remain_val = 0;
offset = self->rpc_addr +
(sizeof(u32) * 2) +
(res_dword_cnt * sizeof(u32));
err = hw_atl_utils_fw_downld_dwords(self, offset,
&bytes_remain_val, 1);
if (err < 0)
return err;
memcpy(data + len - res_bytes_remain_cnt,
&bytes_remain_val, res_bytes_remain_cnt);
}
return 0;
}
const struct aq_fw_ops aq_fw_2x_ops = {
.init = aq_fw2x_init,
.deinit = aq_fw2x_deinit,
.reset = NULL,
.renegotiate = aq_fw2x_renegotiate,
.get_mac_permanent = aq_fw2x_get_mac_permanent,
.set_link_speed = aq_fw2x_set_link_speed,
.set_state = aq_fw2x_set_state,
.update_link_status = aq_fw2x_update_link_status,
.update_stats = aq_fw2x_update_stats,
.get_mac_temp = NULL,
.get_phy_temp = aq_fw2x_get_phy_temp,
.set_power = aq_fw2x_set_power,
.set_eee_rate = aq_fw2x_set_eee_rate,
.get_eee_rate = aq_fw2x_get_eee_rate,
.set_flow_control = aq_fw2x_set_flow_control,
.get_flow_control = aq_fw2x_get_flow_control,
.send_fw_request = aq_fw2x_send_fw_request,
.enable_ptp = aq_fw3x_enable_ptp,
.led_control = aq_fw2x_led_control,
.set_phyloopback = aq_fw2x_set_phyloopback,
.set_downshift = aq_fw2x_set_downshift,
.set_media_detect = aq_fw2x_set_media_detect,
.adjust_ptp = aq_fw3x_adjust_ptp,
.get_link_capabilities = aq_fw2x_get_link_capabilities,
.send_macsec_req = aq_fw2x_send_macsec_req,
.read_module_eeprom = aq_fw2x_read_module_eeprom,
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef HW_ATL2_H
#define HW_ATL2_H
#include "aq_common.h"
#define HW_ATL2_RX_TS_SIZE 8
#define HW_ATL2_PTP_OFFSET_INGRESS_100 768
#define HW_ATL2_PTP_OFFSET_EGRESS_100 336
#define HW_ATL2_PTP_OFFSET_INGRESS_1000 510
#define HW_ATL2_PTP_OFFSET_EGRESS_1000 105
#define HW_ATL2_PTP_OFFSET_INGRESS_2500 2447
#define HW_ATL2_PTP_OFFSET_EGRESS_2500 634
#define HW_ATL2_PTP_OFFSET_INGRESS_5000 1426
#define HW_ATL2_PTP_OFFSET_EGRESS_5000 361
#define HW_ATL2_PTP_OFFSET_INGRESS_10000 997
#define HW_ATL2_PTP_OFFSET_EGRESS_10000 203
extern const struct aq_hw_caps_s hw_atl2_caps_aqc113;
extern const struct aq_hw_caps_s hw_atl2_caps_aqc115c;
extern const struct aq_hw_caps_s hw_atl2_caps_aqc116c;
extern const struct aq_hw_ops hw_atl2_ops;
#endif /* HW_ATL2_H */
@@ -0,0 +1,195 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef HW_ATL2_INTERNAL_H
#define HW_ATL2_INTERNAL_H
#include "hw_atl2_utils.h"
#define HW_ATL2_MTU_JUMBO 16352U
#define HW_ATL2_MTU 1514U
#define HW_ATL2_TX_RINGS 4U
#define HW_ATL2_RX_RINGS 4U
#define HW_ATL2_RINGS_MAX 32U
#define HW_ATL2_TXD_SIZE (16U)
#define HW_ATL2_RXD_SIZE (16U)
#define HW_ATL2_MAC_UC 0U
#define HW_ATL2_MAC_MIN 1U
#define HW_ATL2_MAC_MAX 38U
/* interrupts */
#define HW_ATL2_ERR_INT 8U
#define HW_ATL2_INT_MASK (0xFFFFFFFFU)
#define HW_ATL2_TXBUF_MAX 128U
#define HW_ATL2_PTP_TXBUF_SIZE 8U
/* hw_atl2 on-chip RX packet buffer available for data TCs */
#define HW_ATL2_RXBUF_MAX 172U
#define HW_ATL2_PTP_RXBUF_SIZE 16U
#define HW_ATL2_RSS_REDIRECTION_MAX 64U
#define HW_ATL2_TC_MAX 8U
#define HW_ATL2_RSS_MAX 8U
#define HW_ATL2_INTR_MODER_MAX 0x1FF
#define HW_ATL2_INTR_MODER_MIN 0xFF
#define HW_ATL2_MIN_RXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_RXD_MULTIPLE))
#define HW_ATL2_MIN_TXD \
(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_TXD_MULTIPLE))
#define HW_ATL2_MAX_RXD 8184U
#define HW_ATL2_MAX_TXD 8184U
#define HW_ATL2_FW_SM_ACT_RSLVR 0x3U
#define HW_ATL2_RPF_TAG_UC_OFFSET 0x0
#define HW_ATL2_RPF_TAG_ALLMC_OFFSET 0x6
#define HW_ATL2_RPF_TAG_ET_OFFSET 0x7
#define HW_ATL2_RPF_TAG_VLAN_OFFSET 0xA
#define HW_ATL2_RPF_TAG_UNTAG_OFFSET 0xE
#define HW_ATL2_RPF_TAG_L3_V4_OFFSET 0xF
#define HW_ATL2_RPF_TAG_L3_V6_OFFSET 0x12
#define HW_ATL2_RPF_TAG_L4_OFFSET 0x15
#define HW_ATL2_RPF_TAG_L4_FLEX_OFFSET 0x18
#define HW_ATL2_RPF_TAG_FLEX_OFFSET 0x1B
#define HW_ATL2_RPF_TAG_PCP_OFFSET 0x1D
#define HW_ATL2_RPF_TAG_UC_MASK (0x0000003F << HW_ATL2_RPF_TAG_UC_OFFSET)
#define HW_ATL2_RPF_TAG_ALLMC_MASK (0x00000001 << HW_ATL2_RPF_TAG_ALLMC_OFFSET)
#define HW_ATL2_RPF_TAG_UNTAG_MASK (0x00000001 << HW_ATL2_RPF_TAG_UNTAG_OFFSET)
#define HW_ATL2_RPF_TAG_VLAN_MASK (0x0000000F << HW_ATL2_RPF_TAG_VLAN_OFFSET)
#define HW_ATL2_RPF_TAG_ET_MASK (0x00000007 << HW_ATL2_RPF_TAG_ET_OFFSET)
#define HW_ATL2_RPF_TAG_L3_V4_MASK (0x00000007 << HW_ATL2_RPF_TAG_L3_V4_OFFSET)
#define HW_ATL2_RPF_TAG_L3_V6_MASK (0x00000007 << HW_ATL2_RPF_TAG_L3_V6_OFFSET)
#define HW_ATL2_RPF_TAG_L4_MASK (0x00000007 << HW_ATL2_RPF_TAG_L4_OFFSET)
#define HW_ATL2_RPF_TAG_PCP_MASK (0x00000007 << HW_ATL2_RPF_TAG_PCP_OFFSET)
#define HW_ATL2_RPF_TAG_BASE_UC BIT(HW_ATL2_RPF_TAG_UC_OFFSET)
#define HW_ATL2_RPF_TAG_BASE_ALLMC BIT(HW_ATL2_RPF_TAG_ALLMC_OFFSET)
#define HW_ATL2_RPF_TAG_BASE_UNTAG BIT(HW_ATL2_RPF_TAG_UNTAG_OFFSET)
#define HW_ATL2_RPF_TAG_BASE_VLAN BIT(HW_ATL2_RPF_TAG_VLAN_OFFSET)
enum HW_ATL2_RPF_ART_INDEX {
HW_ATL2_RPF_L2_PROMISC_OFF_INDEX,
HW_ATL2_RPF_VLAN_PROMISC_OFF_INDEX,
HW_ATL2_RPF_L3L4_USER_INDEX = 8,
HW_ATL2_RPF_ET_PCP_USER_INDEX = HW_ATL2_RPF_L3L4_USER_INDEX + 16,
HW_ATL2_RPF_VLAN_USER_INDEX = HW_ATL2_RPF_ET_PCP_USER_INDEX + 16,
HW_ATL2_RPF_PCP_TO_TC_INDEX = HW_ATL2_RPF_VLAN_USER_INDEX +
HW_ATL_VLAN_MAX_FILTERS,
};
#define HW_ATL2_RPF_L3_CMD_EN BIT(0)
#define HW_ATL2_RPF_L3_CMD_SA_EN BIT(1)
#define HW_ATL2_RPF_L3_CMD_DA_EN BIT(2)
#define HW_ATL2_RPF_L3_CMD_PROTO_EN BIT(3)
#define HW_ATL2_RPF_L3_V6_CMD_EN BIT(0x10)
#define HW_ATL2_RPF_L3_V6_CMD_SA_EN BIT(0x11)
#define HW_ATL2_RPF_L3_V6_CMD_DA_EN BIT(0x12)
#define HW_ATL2_RPF_L3_V6_CMD_PROTO_EN BIT(0x13)
#define HW_ATL2_RPF_L4_CMD_EN BIT(0)
#define HW_ATL2_RPF_L4_CMD_DP_EN BIT(1)
#define HW_ATL2_RPF_L4_CMD_SP_EN BIT(2)
#define HW_ATL2_ART_TOTAL_ENTRIES 128
#define HW_ATL2_ACTION(ACTION, RSS, INDEX, VALID) \
((((ACTION) & 0x3U) << 8) | \
(((RSS) & 0x1U) << 7) | \
(((INDEX) & 0x3FU) << 2) | \
(((VALID) & 0x1U) << 0))
#define HW_ATL2_ACTION_DROP HW_ATL2_ACTION(0, 0, 0, 1)
#define HW_ATL2_ACTION_DISABLE HW_ATL2_ACTION(0, 0, 0, 0)
#define HW_ATL2_ACTION_ASSIGN_QUEUE(QUEUE) HW_ATL2_ACTION(1, 0, (QUEUE), 1)
#define HW_ATL2_ACTION_ASSIGN_TC(TC) HW_ATL2_ACTION(1, 1, (TC), 1)
#define HW_ATL2_RPF_L3L4_FILTERS 8
#define HW_ATL2_RPF_L3V4_FILTERS 8
#define HW_ATL2_RPF_L3V6_FILTERS 6
#define HW_ATL2_RPF_L4_FILTERS 8
#define HW_ATL2_RPF_VLAN_FILTERS 16
#define HW_ATL2_RPF_ETYPE_FILTERS 16
#define HW_ATL2_RPF_ETYPE_TAGS 7
enum HW_ATL2_RPF_RSS_HASH_TYPE {
HW_ATL2_RPF_RSS_HASH_TYPE_NONE = 0,
HW_ATL2_RPF_RSS_HASH_TYPE_IPV4 = BIT(0),
HW_ATL2_RPF_RSS_HASH_TYPE_IPV4_TCP = BIT(1),
HW_ATL2_RPF_RSS_HASH_TYPE_IPV4_UDP = BIT(2),
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6 = BIT(3),
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_TCP = BIT(4),
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_UDP = BIT(5),
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_EX = BIT(6),
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_EX_TCP = BIT(7),
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_EX_UDP = BIT(8),
HW_ATL2_RPF_RSS_HASH_TYPE_ALL = HW_ATL2_RPF_RSS_HASH_TYPE_IPV4 |
HW_ATL2_RPF_RSS_HASH_TYPE_IPV4_TCP |
HW_ATL2_RPF_RSS_HASH_TYPE_IPV4_UDP |
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6 |
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_TCP |
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_UDP |
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_EX |
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_EX_TCP |
HW_ATL2_RPF_RSS_HASH_TYPE_IPV6_EX_UDP,
};
#define HW_ATL_MCAST_FLT_ANY_TO_HOST 0x00010FFFU
struct hw_atl2_l3_filter {
u8 proto;
u8 usage;
u32 cmd;
u32 srcip[4];
u32 dstip[4];
};
struct hw_atl2_l4_filter {
u8 usage;
u32 cmd;
u16 sport;
u16 dport;
};
struct hw_atl2_l3l4_filter {
s8 l3_index;
s8 l4_index;
u8 ipv6;
};
struct hw_atl2_tag_policy {
u16 action;
u16 usage;
};
struct hw_atl2_priv {
struct hw_atl2_l3_filter l3_v4_filters[HW_ATL2_RPF_L3L4_FILTERS];
struct hw_atl2_l3_filter l3_v6_filters[HW_ATL2_RPF_L3L4_FILTERS];
struct hw_atl2_l4_filter l4_filters[HW_ATL2_RPF_L3L4_FILTERS];
struct hw_atl2_l3l4_filter l3l4_filters[HW_ATL2_RPF_L3L4_FILTERS];
struct hw_atl2_tag_policy etype_policy[HW_ATL2_RPF_ETYPE_FILTERS];
struct statistics_s last_stats;
unsigned int art_base_index;
unsigned int art_count;
unsigned int l2_filters_base_index;
unsigned int l2_filter_count;
unsigned int etype_filter_base_index;
unsigned int etype_filter_count;
unsigned int etype_filter_tag_top;
unsigned int vlan_filter_base_index;
unsigned int vlan_filter_count;
unsigned int l3_v4_filter_base_index;
unsigned int l3_v4_filter_count;
unsigned int l3_v6_filter_base_index;
unsigned int l3_v6_filter_count;
unsigned int l4_filter_base_index;
unsigned int l4_filter_count;
};
#endif /* HW_ATL2_INTERNAL_H */
@@ -0,0 +1,556 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#include "hw_atl2_llh.h"
#include "hw_atl2_llh_internal.h"
#include "aq_hw_utils.h"
u32 hw_atl2_phi_ext_tag_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg_bit(aq_hw, HW_ATL2_PHI_EXT_TAG_EN_ADR,
HW_ATL2_PHI_EXT_TAG_EN_MSK,
HW_ATL2_PHI_EXT_TAG_EN_SHIFT);
}
void hw_atl2_rpf_redirection_table2_select_set(struct aq_hw_s *aq_hw,
u32 select)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_PIF_RPF_REDIR2_ENI_ADR,
HW_ATL2_RPF_PIF_RPF_REDIR2_ENI_MSK,
HW_ATL2_RPF_PIF_RPF_REDIR2_ENI_SHIFT, select);
}
void hw_atl2_rpf_rss_hash_type_set(struct aq_hw_s *aq_hw, u32 rss_hash_type)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_PIF_RPF_RSS_HASH_TYPEI_ADR,
HW_ATL2_RPF_PIF_RPF_RSS_HASH_TYPEI_MSK,
HW_ATL2_RPF_PIF_RPF_RSS_HASH_TYPEI_SHIFT,
rss_hash_type);
}
/* rpf */
void hw_atl2_rpf_new_enable_set(struct aq_hw_s *aq_hw, u32 enable)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_NEW_EN_ADR,
HW_ATL2_RPF_NEW_EN_MSK,
HW_ATL2_RPF_NEW_EN_SHIFT,
enable);
}
void hw_atl2_rpfl2_uc_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPFL2UC_TAG_ADR(filter),
HW_ATL2_RPFL2UC_TAG_MSK,
HW_ATL2_RPFL2UC_TAG_SHIFT,
tag);
}
void hw_atl2_rpfl2_bc_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L2_BC_TAG_ADR,
HW_ATL2_RPF_L2_BC_TAG_MSK,
HW_ATL2_RPF_L2_BC_TAG_SHIFT,
tag);
}
void hw_atl2_new_rpf_rss_redir_set(struct aq_hw_s *aq_hw, u32 tc, u32 index,
u32 queue)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_RSS_REDIR_ADR(tc, index),
HW_ATL2_RPF_RSS_REDIR_MSK(tc),
HW_ATL2_RPF_RSS_REDIR_SHIFT(tc),
queue);
}
void hw_atl2_rpf_vlan_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_VL_TAG_ADR(filter),
HW_ATL2_RPF_VL_TAG_MSK,
HW_ATL2_RPF_VL_TAG_SHIFT,
tag);
}
void hw_atl2_rpf_etht_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_ET_TAG_ADR(filter),
HW_ATL2_RPF_ET_TAG_MSK,
HW_ATL2_RPF_ET_TAG_SHIFT, tag);
}
u32 hw_atl2_rpf_etht_flr_tag_get(struct aq_hw_s *aq_hw, u32 filter)
{
return aq_hw_read_reg_bit(aq_hw, HW_ATL2_RPF_ET_TAG_ADR(filter),
HW_ATL2_RPF_ET_TAG_MSK,
HW_ATL2_RPF_ET_TAG_SHIFT);
}
void hw_atl2_rpf_l3_v4_dest_addr_set(struct aq_hw_s *aq_hw, u32 filter, u32 val)
{
u32 addr_set = 6 + ((filter < 4) ? 0 : 1);
u32 dword = filter % 4;
aq_hw_write_reg(aq_hw, HW_ATL2_RPF_L3_DA_DW_ADR(addr_set, dword), val);
}
void hw_atl2_rpf_l3_v4_src_addr_set(struct aq_hw_s *aq_hw, u32 filter, u32 val)
{
u32 addr_set = 6 + ((filter < 4) ? 0 : 1);
u32 dword = filter % 4;
aq_hw_write_reg(aq_hw, HW_ATL2_RPF_L3_SA_DW_ADR(addr_set, dword), val);
}
void hw_atl2_rpf_l3_v6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
u32 *ipv6_dst)
{
int i;
for (i = 0; i < 4; ++i)
aq_hw_write_reg(aq_hw,
HW_ATL2_RPF_L3_DA_DW_ADR(location, 3 - i),
ipv6_dst[i]);
}
void hw_atl2_rpf_l3_v6_src_addr_set(struct aq_hw_s *aq_hw, u8 location,
u32 *ipv6_src)
{
int i;
for (i = 0; i < 4; ++i)
aq_hw_write_reg(aq_hw,
HW_ATL2_RPF_L3_SA_DW_ADR(location, 3 - i),
ipv6_src[i]);
}
void hw_atl2_rpf_l3_v4_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V4_CMD_ADR(filter),
HW_ATL2_RPF_L3_V4_CMD_MSK,
HW_ATL2_RPF_L3_V4_CMD_SHIFT, val);
}
void hw_atl2_rpf_l3_v6_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V6_CMD_ADR(filter),
HW_ATL2_RPF_L3_V6_CMD_MSK,
HW_ATL2_RPF_L3_V6_CMD_SHIFT, val);
}
void hw_atl2_rpf_l3_v6_v4_select_set(struct aq_hw_s *aq_hw, u32 val)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V6_V4_SELECT_ADR,
HW_ATL2_RPF_L3_V6_V4_SELECT_MSK,
HW_ATL2_RPF_L3_V6_V4_SELECT_SHIFT, val);
}
void hw_atl2_rpf_l3_v4_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V4_TAG_ADR(filter),
HW_ATL2_RPF_L3_V4_TAG_MSK,
HW_ATL2_RPF_L3_V4_TAG_SHIFT, val);
}
void hw_atl2_rpf_l3_v6_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V6_TAG_ADR(filter),
HW_ATL2_RPF_L3_V6_TAG_MSK,
HW_ATL2_RPF_L3_V6_TAG_SHIFT, val);
}
void hw_atl2_rpf_l4_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L4_TAG_ADR(filter),
HW_ATL2_RPF_L4_TAG_MSK,
HW_ATL2_RPF_L4_TAG_SHIFT, val);
}
void hw_atl2_rpf_l4_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L4_CMD_ADR(filter),
HW_ATL2_RPF_L4_CMD_MSK,
HW_ATL2_RPF_L4_CMD_SHIFT, val);
}
/* tsg */
static void hw_atl2_clock_modif_value_set(struct aq_hw_s *aq_hw,
u32 clock_sel, u64 ns)
{
aq_hw_write_reg64(aq_hw,
HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_MODIF_VAL_LSW),
ns);
}
void hw_atl2_tsg_clock_en(struct aq_hw_s *aq_hw,
u32 clock_sel, u32 clock_enable)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_CFG),
HW_ATL2_TSG_CLOCK_EN_MSK,
HW_ATL2_TSG_CLOCK_EN_SHIFT,
clock_enable);
}
void hw_atl2_tsg_clock_reset(struct aq_hw_s *aq_hw, u32 clock_sel)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_CFG),
HW_ATL2_TSG_SYNC_RESET_MSK,
HW_ATL2_TSG_SYNC_RESET_SHIFT, 1);
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_CFG),
HW_ATL2_TSG_SYNC_RESET_MSK,
HW_ATL2_TSG_SYNC_RESET_SHIFT, 0);
}
u64 hw_atl2_tsg_clock_read(struct aq_hw_s *aq_hw, u32 clock_sel)
{
return aq_hw_read_reg64(aq_hw,
HW_ATL2_TSG_REG_ADR(clock_sel,
READ_CUR_NS_LSW));
}
void hw_atl2_tsg_clock_add(struct aq_hw_s *aq_hw, u32 clock_sel, u64 ns)
{
hw_atl2_clock_modif_value_set(aq_hw, clock_sel, ns);
aq_hw_write_reg(aq_hw,
HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_MODIF_CTRL),
HW_ATL2_TSG_ADD_COUNTER_MSK);
}
void hw_atl2_tsg_clock_sub(struct aq_hw_s *aq_hw, u32 clock_sel, u64 ns)
{
hw_atl2_clock_modif_value_set(aq_hw, clock_sel, ns);
aq_hw_write_reg(aq_hw,
HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_MODIF_CTRL),
HW_ATL2_TSG_SUBTRACT_COUNTER_MSK);
}
void hw_atl2_tsg_clock_increment_set(struct aq_hw_s *aq_hw,
u32 clock_sel, u32 ns, u32 fns)
{
u32 nsfns = (ns & 0xff) | (fns & 0xffffff00);
aq_hw_write_reg(aq_hw,
HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_INC_CFG),
nsfns);
aq_hw_write_reg(aq_hw,
HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_MODIF_CTRL),
HW_ATL2_TSG_LOAD_INC_CFG_MSK);
}
void hw_atl2_tpb_tps_highest_priority_tc_enable_set(struct aq_hw_s *aq_hw,
u32 tps_highest_prio_tc_en)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_ADR,
HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_MSK,
HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_SHIFT,
tps_highest_prio_tc_en);
}
void hw_atl2_tpb_tps_highest_priority_tc_set(struct aq_hw_s *aq_hw,
u32 tps_highest_prio_tc)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TPB_HIGHEST_PRIO_TC_ADR,
HW_ATL2_TPB_HIGHEST_PRIO_TC_MSK,
HW_ATL2_TPB_HIGHEST_PRIO_TC_SHIFT,
tps_highest_prio_tc);
}
void hw_atl2_tsg_gpio_isr_to_host_set(struct aq_hw_s *aq_hw,
int on, u32 clock_sel)
{
aq_hw_write_reg_bit(aq_hw,
HW_ATL2_GLOBAL_HIGH_PRIO_INTERRUPT_1_MASK_ADR,
clock_sel == 1 ? HW_ATL2_TSG_TSG1_GPIO_INTERRUPT_MSK :
HW_ATL2_TSG_TSG0_GPIO_INTERRUPT_MSK,
clock_sel == 1 ? HW_ATL2_TSG_TSG1_GPIO_INTERRUPT_SHIFT :
HW_ATL2_TSG_TSG0_GPIO_INTERRUPT_SHIFT,
!!on);
}
void hw_atl2_tsg_gpio_clear_status(struct aq_hw_s *aq_hw)
{
aq_hw_read_reg(aq_hw, HW_ATL2_GLOBAL_INTERNAL_ALARMS_1_ADR);
}
void hw_atl2_tsg_gpio_input_event_info_get(struct aq_hw_s *aq_hw,
u32 clock_sel,
u32 *event_count,
u64 *event_ts)
{
if (event_count)
*event_count = aq_hw_read_reg(aq_hw,
HW_ATL2_TSG_REG_ADR(clock_sel,
EXT_CLK_COUNT));
if (event_ts)
*event_ts = aq_hw_read_reg64(aq_hw,
HW_ATL2_TSG_REG_ADR(clock_sel,
GPIO_EVENT_TS_LSW));
}
void hw_atl2_tsg_ptp_gpio_gen_pulse(struct aq_hw_s *aq_hw, u32 clk_sel,
u64 ts, u32 period, u32 hightime)
{
u32 val = (HW_ATL2_TSG_GPIO_EVENT_MODE_SET_ON_TIME <<
(HW_ATL2_TSG_GPIO_EVENT_MODE_SHIFT -
HW_ATL2_TSG_GPIO_OUTPUT_EN_SHIFT)) |
(HW_ATL2_TSG_GPIO_GEN_OUTPUT_EN_MSK) |
(HW_ATL2_TSG_GPIO_OUTPUT_EN_MSK);
if (ts != 0) {
aq_hw_write_reg64(aq_hw,
HW_ATL2_TSG_REG_ADR(clk_sel,
GPIO_EVENT_GEN_TS_LSW),
ts);
aq_hw_write_reg64(aq_hw,
HW_ATL2_TSG_REG_ADR(clk_sel,
GPIO_EVENT_HIGH_TIME_LSW),
hightime);
aq_hw_write_reg64(aq_hw,
HW_ATL2_TSG_REG_ADR(clk_sel,
GPIO_EVENT_LOW_TIME_LSW),
(period - hightime));
}
aq_hw_write_reg_bit(aq_hw,
HW_ATL2_TSG_REG_ADR(clk_sel, GPIO_EVENT_GEN_CFG),
HW_ATL2_TSG_GPIO_EVENT_MODE_MSK |
HW_ATL2_TSG_GPIO_OUTPUT_EN_MSK |
HW_ATL2_TSG_GPIO_GEN_OUTPUT_EN_MSK,
HW_ATL2_TSG_GPIO_OUTPUT_EN_SHIFT,
(!ts ? 0 : val));
}
void hw_atl2_rpf_rx_desc_timestamp_req_set(struct aq_hw_s *aq_hw, u32 request,
u32 descriptor)
{
aq_hw_write_reg_bit(aq_hw,
HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_ADR(descriptor),
HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_MSK,
HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_SHIFT, request);
}
/* TX */
void hw_atl2_tpb_tx_tc_q_rand_map_en_set(struct aq_hw_s *aq_hw,
const u32 tc_q_rand_map_en)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TPB_TX_TC_Q_RAND_MAP_EN_ADR,
HW_ATL2_TPB_TX_TC_Q_RAND_MAP_EN_MSK,
HW_ATL2_TPB_TX_TC_Q_RAND_MAP_EN_SHIFT,
tc_q_rand_map_en);
}
void hw_atl2_tpb_tx_buf_clk_gate_en_set(struct aq_hw_s *aq_hw, u32 clk_gate_en)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TPB_TX_BUF_CLK_GATE_EN_ADR,
HW_ATL2_TPB_TX_BUF_CLK_GATE_EN_MSK,
HW_ATL2_TPB_TX_BUF_CLK_GATE_EN_SHIFT,
clk_gate_en);
}
void hw_atl2_reg_tx_intr_moder_ctrl_set(struct aq_hw_s *aq_hw,
u32 tx_intr_moderation_ctl,
u32 queue)
{
aq_hw_write_reg(aq_hw, HW_ATL2_TX_INTR_MODERATION_CTL_ADR(queue),
tx_intr_moderation_ctl);
}
void hw_atl2_tdm_tx_desc_timestamp_writeback_en_set(struct aq_hw_s *aq_hw,
u32 enable, u32 descriptor)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_DESCD_TS_WRB_EN_ADR(descriptor),
HW_ATL2_TDM_DESCD_TS_WRB_EN_MSK,
HW_ATL2_TDM_DESCD_TS_WRB_EN_SHIFT, enable);
}
void hw_atl2_tdm_tx_desc_timestamp_en_set(struct aq_hw_s *aq_hw, u32 enable,
u32 descriptor)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_DESCD_TS_EN_ADR(descriptor),
HW_ATL2_TDM_DESCD_TS_EN_MSK,
HW_ATL2_TDM_DESCD_TS_EN_SHIFT, enable);
}
void hw_atl2_tdm_tx_desc_avb_en_set(struct aq_hw_s *aq_hw, u32 enable,
u32 descriptor)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_DESCD_AVB_EN_ADR(descriptor),
HW_ATL2_TDM_DESCD_AVB_EN_MSK,
HW_ATL2_TDM_DESCD_AVB_EN_SHIFT, enable);
}
void hw_atl2_tps_tx_pkt_shed_data_arb_mode_set(struct aq_hw_s *aq_hw,
const u32 data_arb_mode)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TPS_DATA_TC_ARB_MODE_ADR,
HW_ATL2_TPS_DATA_TC_ARB_MODE_MSK,
HW_ATL2_TPS_DATA_TC_ARB_MODE_SHIFT,
data_arb_mode);
}
void hw_atl2_tps_tx_pkt_shed_tc_data_max_credit_set(struct aq_hw_s *aq_hw,
const u32 tc,
const u32 max_credit)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TPS_DATA_TCTCREDIT_MAX_ADR(tc),
HW_ATL2_TPS_DATA_TCTCREDIT_MAX_MSK,
HW_ATL2_TPS_DATA_TCTCREDIT_MAX_SHIFT,
max_credit);
}
void hw_atl2_tps_tx_pkt_shed_tc_data_weight_set(struct aq_hw_s *aq_hw,
const u32 tc,
const u32 weight)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TPS_DATA_TCTWEIGHT_ADR(tc),
HW_ATL2_TPS_DATA_TCTWEIGHT_MSK,
HW_ATL2_TPS_DATA_TCTWEIGHT_SHIFT,
weight);
}
void hw_atl2_tdm_tx_data_read_req_limit_set(struct aq_hw_s *aq_hw, u32 limit)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_ADR,
HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_MSK,
HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_SHIFT, limit);
}
void hw_atl2_tdm_tx_desc_read_req_limit_set(struct aq_hw_s *aq_hw, u32 limit)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_ADR,
HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_MSK,
HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_SHIFT, limit);
}
u32 hw_atl2_get_hw_version(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL2_FPGA_VER_ADR);
}
void hw_atl2_init_launchtime(struct aq_hw_s *aq_hw)
{
u32 hw_ver = hw_atl2_get_hw_version(aq_hw);
aq_hw_write_reg_bit(aq_hw, HW_ATL2_LT_CTRL_ADR,
HW_ATL2_LT_CTRL_CLK_RATIO_MSK,
HW_ATL2_LT_CTRL_CLK_RATIO_SHIFT,
hw_ver < HW_ATL2_FPGA_VER_U32(1, 0, 0, 0) ?
HW_ATL2_LT_CTRL_CLK_RATIO_FULL_SPEED :
hw_ver >= HW_ATL2_FPGA_VER_U32(1, 0, 85, 2) ?
HW_ATL2_LT_CTRL_CLK_RATIO_HALF_SPEED :
HW_ATL2_LT_CTRL_CLK_RATIO_QUATER_SPEED);
}
/* set action resolver record */
void hw_atl2_rpf_act_rslvr_record_set(struct aq_hw_s *aq_hw, u8 location,
u32 tag, u32 mask, u32 action)
{
aq_hw_write_reg(aq_hw,
HW_ATL2_RPF_ACT_RSLVR_REQ_TAG_ADR(location),
tag);
aq_hw_write_reg(aq_hw,
HW_ATL2_RPF_ACT_RSLVR_TAG_MASK_ADR(location),
mask);
aq_hw_write_reg(aq_hw,
HW_ATL2_RPF_ACT_RSLVR_ACTN_ADR(location),
action);
}
void hw_atl2_rpf_act_rslvr_section_en_set(struct aq_hw_s *aq_hw, u32 sections)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_REC_TAB_EN_ADR,
HW_ATL2_RPF_REC_TAB_EN_MSK,
HW_ATL2_RPF_REC_TAB_EN_SHIFT,
sections);
}
u32 hw_atl2_rpf_act_rslvr_section_en_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg_bit(aq_hw, HW_ATL2_RPF_REC_TAB_EN_ADR,
HW_ATL2_RPF_REC_TAB_EN_MSK,
HW_ATL2_RPF_REC_TAB_EN_SHIFT);
}
void hw_atl2_mif_shared_buf_get(struct aq_hw_s *aq_hw, int offset, u32 *data,
int len)
{
int j = 0;
int i;
for (i = offset; i < offset + len; i++, j++)
data[j] = aq_hw_read_reg(aq_hw,
HW_ATL2_MIF_SHARED_BUFFER_IN_ADR(i));
}
void hw_atl2_mif_shared_buf_write(struct aq_hw_s *aq_hw, int offset, u32 *data,
int len)
{
int j = 0;
int i;
for (i = offset; i < offset + len; i++, j++)
aq_hw_write_reg(aq_hw, HW_ATL2_MIF_SHARED_BUFFER_IN_ADR(i),
data[j]);
}
void hw_atl2_mif_shared_buf_read(struct aq_hw_s *aq_hw, int offset, u32 *data,
int len)
{
int j = 0;
int i;
for (i = offset; i < offset + len; i++, j++)
data[j] = aq_hw_read_reg(aq_hw,
HW_ATL2_MIF_SHARED_BUFFER_OUT_ADR(i));
}
void hw_atl2_mif_host_finished_write_set(struct aq_hw_s *aq_hw, u32 finish)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_MIF_HOST_FINISHED_WRITE_ADR,
HW_ATL2_MIF_HOST_FINISHED_WRITE_MSK,
HW_ATL2_MIF_HOST_FINISHED_WRITE_SHIFT,
finish);
}
u32 hw_atl2_mif_mcp_finished_read_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg_bit(aq_hw, HW_ATL2_MIF_MCP_FINISHED_READ_ADR,
HW_ATL2_MIF_MCP_FINISHED_READ_MSK,
HW_ATL2_MIF_MCP_FINISHED_READ_SHIFT);
}
u32 hw_atl2_mif_mcp_boot_reg_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL2_MIF_BOOT_REG_ADR);
}
void hw_atl2_mif_mcp_boot_reg_set(struct aq_hw_s *aq_hw, u32 val)
{
return aq_hw_write_reg(aq_hw, HW_ATL2_MIF_BOOT_REG_ADR, val);
}
u32 hw_atl2_mif_host_req_int_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL2_MCP_HOST_REQ_INT_ADR);
}
void hw_atl2_mif_host_req_int_clr(struct aq_hw_s *aq_hw, u32 val)
{
return aq_hw_write_reg(aq_hw, HW_ATL2_MCP_HOST_REQ_INT_CLR_ADR,
val);
}
void hw_atl2_gpio_special_mode_set(struct aq_hw_s *aq_hw,
u32 gpio_special_mode,
u32 pin)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL2_GPIO_PIN_SPEC_MODE_ADR(pin),
HW_ATL2_GPIO_PIN_SPEC_MODE_MSK,
HW_ATL2_GPIO_PIN_SPEC_MODE_SHIFT,
gpio_special_mode);
}
@@ -0,0 +1,197 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef HW_ATL2_LLH_H
#define HW_ATL2_LLH_H
#include <linux/types.h>
struct aq_hw_s;
/* Get Enable usage of extended tags from 32-255. */
u32 hw_atl2_phi_ext_tag_get(struct aq_hw_s *aq_hw);
/* Set TX Interrupt Moderation Control Register */
void hw_atl2_reg_tx_intr_moder_ctrl_set(struct aq_hw_s *aq_hw,
u32 tx_intr_moderation_ctl,
u32 queue);
/* Set Redirection Table 2 Select */
void hw_atl2_rpf_redirection_table2_select_set(struct aq_hw_s *aq_hw,
u32 select);
/* Set RSS HASH type */
void hw_atl2_rpf_rss_hash_type_set(struct aq_hw_s *aq_hw, u32 rss_hash_type);
/* set new RPF enable */
void hw_atl2_rpf_new_enable_set(struct aq_hw_s *aq_hw, u32 enable);
/* set l2 unicast filter tag */
void hw_atl2_rpfl2_uc_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter);
/* set l2 broadcast filter tag */
void hw_atl2_rpfl2_bc_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag);
/* set new rss redirection table */
void hw_atl2_new_rpf_rss_redir_set(struct aq_hw_s *aq_hw, u32 tc, u32 index,
u32 queue);
/* Set VLAN filter tag */
void hw_atl2_rpf_vlan_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter);
/* set ethertype filter tag */
void hw_atl2_rpf_etht_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter);
/* get ethertype filter tag */
u32 hw_atl2_rpf_etht_flr_tag_get(struct aq_hw_s *aq_hw, u32 filter);
/* set L3 v4 dest address */
void hw_atl2_rpf_l3_v4_dest_addr_set(struct aq_hw_s *aq_hw,
u32 filter, u32 val);
/* set L3 v4 src address */
void hw_atl2_rpf_l3_v4_src_addr_set(struct aq_hw_s *aq_hw, u32 filter, u32 val);
/* set L3 v4 cmd */
void hw_atl2_rpf_l3_v4_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter);
/* set L3 v6 cmd */
void hw_atl2_rpf_l3_v6_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter);
/* set L3 v6 dest address */
void hw_atl2_rpf_l3_v6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
u32 *ipv6_dst);
/* set L3 v6 src address */
void hw_atl2_rpf_l3_v6_src_addr_set(struct aq_hw_s *aq_hw, u8 location,
u32 *ipv6_src);
/* set L3 v6 v4 select */
void hw_atl2_rpf_l3_v6_v4_select_set(struct aq_hw_s *aq_hw, u32 val);
/* set L3 v4 tag */
void hw_atl2_rpf_l3_v4_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter);
/* set L3 v6 tag */
void hw_atl2_rpf_l3_v6_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter);
/* set L4 cmd */
void hw_atl2_rpf_l4_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter);
/* set L4 tag */
void hw_atl2_rpf_l4_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter);
/* set tx random TC-queue mapping enable bit */
void hw_atl2_tpb_tx_tc_q_rand_map_en_set(struct aq_hw_s *aq_hw,
const u32 tc_q_rand_map_en);
void hw_atl2_tpb_tps_highest_priority_tc_enable_set(struct aq_hw_s *aq_hw,
u32 tps_highest_prio_tc_en);
void hw_atl2_tpb_tps_highest_priority_tc_set(struct aq_hw_s *aq_hw,
u32 tps_highest_prio_tc);
/* set tx buffer clock gate enable */
void hw_atl2_tpb_tx_buf_clk_gate_en_set(struct aq_hw_s *aq_hw, u32 clk_gate_en);
/* tsg */
void hw_atl2_tsg_clock_en(struct aq_hw_s *aq_hw, u32 clock_sel,
u32 clock_enable);
void hw_atl2_tsg_clock_reset(struct aq_hw_s *aq_hw, u32 clock_sel);
u64 hw_atl2_tsg_clock_read(struct aq_hw_s *aq_hw, u32 clock_sel);
void hw_atl2_tsg_clock_add(struct aq_hw_s *aq_hw, u32 clock_sel,
u64 ns);
void hw_atl2_tsg_clock_sub(struct aq_hw_s *aq_hw, u32 clock_sel,
u64 ns);
void hw_atl2_tsg_clock_increment_set(struct aq_hw_s *aq_hw, u32 clock_sel,
u32 ns, u32 fns);
void hw_atl2_tsg_gpio_isr_to_host_set(struct aq_hw_s *aq_hw, int on,
u32 clock_sel);
void hw_atl2_tsg_gpio_clear_status(struct aq_hw_s *aq_hw);
void hw_atl2_tsg_gpio_input_event_info_get(struct aq_hw_s *aq_hw,
u32 clock_sel,
u32 *event_count,
u64 *event_ts);
/* Set Rx Descriptor0 Timestamp request */
void hw_atl2_rpf_rx_desc_timestamp_req_set(struct aq_hw_s *aq_hw, u32 request,
u32 descriptor);
/* Set Tx Descriptor Timestamp writeback Enable */
void hw_atl2_tdm_tx_desc_timestamp_writeback_en_set(struct aq_hw_s *aq_hw,
u32 enable,
u32 descriptor);
/* Set Tx Descriptor Timestamp enable */
void hw_atl2_tdm_tx_desc_timestamp_en_set(struct aq_hw_s *aq_hw, u32 enable,
u32 descriptor);
void hw_atl2_tps_tx_pkt_shed_data_arb_mode_set(struct aq_hw_s *aq_hw,
const u32 data_arb_mode);
/* set tx packet scheduler tc data max credit */
void hw_atl2_tps_tx_pkt_shed_tc_data_max_credit_set(struct aq_hw_s *aq_hw,
const u32 tc,
const u32 max_credit);
/* set tx packet scheduler tc data weight */
void hw_atl2_tps_tx_pkt_shed_tc_data_weight_set(struct aq_hw_s *aq_hw,
const u32 tc,
const u32 weight);
/* Set Tx Descriptor AVB enable */
void hw_atl2_tdm_tx_desc_avb_en_set(struct aq_hw_s *aq_hw, u32 enable,
u32 descriptor);
void hw_atl2_tsg_ptp_gpio_gen_pulse(struct aq_hw_s *aq_hw, u32 clk_sel,
u64 ts, u32 period, u32 hightime);
void hw_atl2_tdm_tx_data_read_req_limit_set(struct aq_hw_s *aq_hw, u32 limit);
void hw_atl2_tdm_tx_desc_read_req_limit_set(struct aq_hw_s *aq_hw, u32 limit);
u32 hw_atl2_get_hw_version(struct aq_hw_s *aq_hw);
void hw_atl2_init_launchtime(struct aq_hw_s *aq_hw);
/* set action resolver record */
void hw_atl2_rpf_act_rslvr_record_set(struct aq_hw_s *aq_hw, u8 location,
u32 tag, u32 mask, u32 action);
/* set enable action resolver section */
void hw_atl2_rpf_act_rslvr_section_en_set(struct aq_hw_s *aq_hw, u32 sections);
/* get enable action resolver section */
u32 hw_atl2_rpf_act_rslvr_section_en_get(struct aq_hw_s *aq_hw);
/* get data from firmware shared input buffer */
void hw_atl2_mif_shared_buf_get(struct aq_hw_s *aq_hw, int offset, u32 *data,
int len);
/* set data into firmware shared input buffer */
void hw_atl2_mif_shared_buf_write(struct aq_hw_s *aq_hw, int offset, u32 *data,
int len);
/* get data from firmware shared output buffer */
void hw_atl2_mif_shared_buf_read(struct aq_hw_s *aq_hw, int offset, u32 *data,
int len);
/* set host finished write shared buffer indication */
void hw_atl2_mif_host_finished_write_set(struct aq_hw_s *aq_hw, u32 finish);
/* get mcp finished read shared buffer indication */
u32 hw_atl2_mif_mcp_finished_read_get(struct aq_hw_s *aq_hw);
/* get mcp boot register */
u32 hw_atl2_mif_mcp_boot_reg_get(struct aq_hw_s *aq_hw);
/* set mcp boot register */
void hw_atl2_mif_mcp_boot_reg_set(struct aq_hw_s *aq_hw, u32 val);
/* get host interrupt request */
u32 hw_atl2_mif_host_req_int_get(struct aq_hw_s *aq_hw);
/* clear host interrupt request */
void hw_atl2_mif_host_req_int_clr(struct aq_hw_s *aq_hw, u32 val);
/* Set GPIO Special Mode */
void hw_atl2_gpio_special_mode_set(struct aq_hw_s *aq_hw,
u32 gpio_special_mode, u32 pin);
#endif /* HW_ATL2_LLH_H */
@@ -0,0 +1,585 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef HW_ATL2_LLH_INTERNAL_H
#define HW_ATL2_LLH_INTERNAL_H
/* RX timestamp_req_desc{D} [1:0] Bitfield Definitions
*/
#define HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_ADR(descr) (0x00005B08 + (descr) * 0x20)
#define HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_MSK 0x00030000
#define HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_SHIFT 16
/* RX pif_rpf_redir_2_en_i Bitfield Definitions
* PORT="pif_rpf_redir_2_en_i"
*/
#define HW_ATL2_RPF_PIF_RPF_REDIR2_ENI_ADR 0x000054C8
#define HW_ATL2_RPF_PIF_RPF_REDIR2_ENI_MSK 0x00001000
#define HW_ATL2_RPF_PIF_RPF_REDIR2_ENI_MSKN 0xFFFFEFFF
#define HW_ATL2_RPF_PIF_RPF_REDIR2_ENI_SHIFT 12
#define HW_ATL2_RPF_PIF_RPF_REDIR2_ENI_WIDTH 1
#define HW_ATL2_RPF_PIF_RPF_REDIR2_ENI_DEFAULT 0x0
/* RX pif_rpf_rss_hash_type_i Bitfield Definitions
*/
#define HW_ATL2_RPF_PIF_RPF_RSS_HASH_TYPEI_ADR 0x000054C8
#define HW_ATL2_RPF_PIF_RPF_RSS_HASH_TYPEI_MSK 0x000001FF
#define HW_ATL2_RPF_PIF_RPF_RSS_HASH_TYPEI_MSKN 0xFFFFFE00
#define HW_ATL2_RPF_PIF_RPF_RSS_HASH_TYPEI_SHIFT 0
#define HW_ATL2_RPF_PIF_RPF_RSS_HASH_TYPEI_WIDTH 9
/* rx rpf_new_rpf_en bitfield definitions
* preprocessor definitions for the bitfield "rpf_new_rpf_en_i".
* port="pif_rpf_new_rpf_en_i
*/
/* register address for bitfield rpf_new_rpf_en */
#define HW_ATL2_RPF_NEW_EN_ADR 0x00005104
/* bitmask for bitfield rpf_new_rpf_en */
#define HW_ATL2_RPF_NEW_EN_MSK 0x00000800
/* inverted bitmask for bitfield rpf_new_rpf_en */
#define HW_ATL2_RPF_NEW_EN_MSKN 0xfffff7ff
/* lower bit position of bitfield rpf_new_rpf_en */
#define HW_ATL2_RPF_NEW_EN_SHIFT 11
/* width of bitfield rpf_new_rpf_en */
#define HW_ATL2_RPF_NEW_EN_WIDTH 1
/* default value of bitfield rpf_new_rpf_en */
#define HW_ATL2_RPF_NEW_EN_DEFAULT 0x0
/* rx l2_uc_req_tag0{f}[5:0] bitfield definitions
* preprocessor definitions for the bitfield "l2_uc_req_tag0{f}[7:0]".
* parameter: filter {f} | stride size 0x8 | range [0, 37]
* port="pif_rpf_l2_uc_req_tag0[5:0]"
*/
/* register address for bitfield l2_uc_req_tag0{f}[2:0] */
#define HW_ATL2_RPFL2UC_TAG_ADR(filter) (0x00005114 + (filter) * 0x8)
/* bitmask for bitfield l2_uc_req_tag0{f}[2:0] */
#define HW_ATL2_RPFL2UC_TAG_MSK 0x0FC00000
/* inverted bitmask for bitfield l2_uc_req_tag0{f}[2:0] */
#define HW_ATL2_RPFL2UC_TAG_MSKN 0xF03FFFFF
/* lower bit position of bitfield l2_uc_req_tag0{f}[2:0] */
#define HW_ATL2_RPFL2UC_TAG_SHIFT 22
/* width of bitfield l2_uc_req_tag0{f}[2:0] */
#define HW_ATL2_RPFL2UC_TAG_WIDTH 6
/* default value of bitfield l2_uc_req_tag0{f}[2:0] */
#define HW_ATL2_RPFL2UC_TAG_DEFAULT 0x0
/* rpf_l2_bc_req_tag[5:0] bitfield definitions
* preprocessor definitions for the bitfield "rpf_l2_bc_req_tag[5:0]".
* port="pifrpf_l2_bc_req_tag_i[5:0]"
*/
/* register address for bitfield rpf_l2_bc_req_tag */
#define HW_ATL2_RPF_L2_BC_TAG_ADR 0x000050F0
/* bitmask for bitfield rpf_l2_bc_req_tag */
#define HW_ATL2_RPF_L2_BC_TAG_MSK 0x0000003F
/* inverted bitmask for bitfield rpf_l2_bc_req_tag */
#define HW_ATL2_RPF_L2_BC_TAG_MSKN 0xffffffc0
/* lower bit position of bitfield rpf_l2_bc_req_tag */
#define HW_ATL2_RPF_L2_BC_TAG_SHIFT 0
/* width of bitfield rpf_l2_bc_req_tag */
#define HW_ATL2_RPF_L2_BC_TAG_WIDTH 6
/* default value of bitfield rpf_l2_bc_req_tag */
#define HW_ATL2_RPF_L2_BC_TAG_DEFAULT 0x0
/* rx rpf_rss_red1_data_[4:0] bitfield definitions
* preprocessor definitions for the bitfield "rpf_rss_red1_data[4:0]".
* port="pif_rpf_rss_red1_data_i[4:0]"
*/
/* register address for bitfield rpf_rss_red1_data[4:0] */
#define HW_ATL2_RPF_RSS_REDIR_ADR(TC, INDEX) (0x00006200 + \
(0x100 * !!((TC) > 3)) + (INDEX) * 4)
/* bitmask for bitfield rpf_rss_red1_data[4:0] */
#define HW_ATL2_RPF_RSS_REDIR_MSK(TC) (0x00000001F << (5 * ((TC) % 4)))
/* lower bit position of bitfield rpf_rss_red1_data[4:0] */
#define HW_ATL2_RPF_RSS_REDIR_SHIFT(TC) (5 * ((TC) % 4))
/* width of bitfield rpf_rss_red1_data[4:0] */
#define HW_ATL2_RPF_RSS_REDIR_WIDTH 5
/* default value of bitfield rpf_rss_red1_data[4:0] */
#define HW_ATL2_RPF_RSS_REDIR_DEFAULT 0x0
/* rx vlan_req_tag0{f}[3:0] bitfield definitions
* preprocessor definitions for the bitfield "vlan_req_tag0{f}[3:0]".
* parameter: filter {f} | stride size 0x4 | range [0, 15]
* port="pif_rpf_vlan_req_tag0[3:0]"
*/
/* register address for bitfield vlan_req_tag0{f}[3:0] */
#define HW_ATL2_RPF_VL_TAG_ADR(filter) (0x00005290 + (filter) * 0x4)
/* bitmask for bitfield vlan_req_tag0{f}[3:0] */
#define HW_ATL2_RPF_VL_TAG_MSK 0x0000F000
/* inverted bitmask for bitfield vlan_req_tag0{f}[3:0] */
#define HW_ATL2_RPF_VL_TAG_MSKN 0xFFFF0FFF
/* lower bit position of bitfield vlan_req_tag0{f}[3:0] */
#define HW_ATL2_RPF_VL_TAG_SHIFT 12
/* width of bitfield vlan_req_tag0{f}[3:0] */
#define HW_ATL2_RPF_VL_TAG_WIDTH 4
/* default value of bitfield vlan_req_tag0{f}[3:0] */
#define HW_ATL2_RPF_VL_TAG_DEFAULT 0x0
/* register address for bitfield etype_req_tag0{f}[2:0] */
#define HW_ATL2_RPF_ET_TAG_ADR(filter) (0x00005340 + (filter) * 0x4)
/* bitmask for bitfield etype_req_tag0{f}[2:0] */
#define HW_ATL2_RPF_ET_TAG_MSK 0x00000007
/* lower bit position of bitfield etype_req_tag0{f}[2:0] */
#define HW_ATL2_RPF_ET_TAG_SHIFT 0
/* Lower bit position of bitfield l3_l4_act{F}[2:0] */
#define HW_ATL2_RPF_L3_L4_ACTF_SHIFT 16
/* Bitmask for bitfield l3_l4_rxq{F}[4:0] */
#define HW_ATL2_RPF_L3_L4_RXQF_MSK 0x00001F00u
/* Lower bit position of bitfield l3_l4_rxq{F}[4:0] */
#define HW_ATL2_RPF_L3_L4_RXQF_SHIFT 8
/* Register address for bitfield rpf_l3_v6_sa{F}_dw{D}[1F:0] */
#define HW_ATL2_RPF_L3_SA_DW_ADR(filter, dword) \
(0x00006400u + (filter) * 0x10 + (dword) * 0x4)
/* Register address for bitfield rpf_l3_v6_da{F}_dw{D}[1F:0] */
#define HW_ATL2_RPF_L3_DA_DW_ADR(filter, dword) \
(0x00006480u + (filter) * 0x10 + (dword) * 0x4)
/* Register address for bitfield rpf_l3_cmd{F}[1F:0] */
#define HW_ATL2_RPF_L3_V4_CMD_ADR(filter) (0x00006500u + (filter) * 0x4)
/* Bitmask for bitfield rpf_l3_cmd{F}[F:0] */
#define HW_ATL2_RPF_L3_V4_CMD_MSK 0x0000FFFFu
/* Lower bit position of bitfield rpf_l3_cmd{F}[1F:0] */
#define HW_ATL2_RPF_L3_V4_CMD_SHIFT 0
/* Register address for bitfield rpf_l3_v6_cmd{F}[1F:0] */
#define HW_ATL2_RPF_L3_V6_CMD_ADR(filter) (0x00006500u + (filter) * 0x4)
/* Bitmask for bitfield rpf_l3_v6_cmd{F}[F:0] */
#define HW_ATL2_RPF_L3_V6_CMD_MSK 0xFF7F0000u
/* Lower bit position of bitfield rpf_l3_v6_cmd{F}[1F:0] */
#define HW_ATL2_RPF_L3_V6_CMD_SHIFT 0
/* Register address for bitfield rpf_l3_v6_cmd{F}[F:0] */
#define HW_ATL2_RPF_L3_V6_V4_SELECT_ADR 0x00006500u
/* Bitmask for bitfield pif_rpf_l3_v6_v4_select*/
#define HW_ATL2_RPF_L3_V6_V4_SELECT_MSK 0x00800000u
/* Lower bit position of bitfield pif_rpf_l3_v6_v4_select */
#define HW_ATL2_RPF_L3_V6_V4_SELECT_SHIFT 23
/* Register address for bitfield rpf_l3_v4_req_tag{F}[2:0] */
#define HW_ATL2_RPF_L3_V4_TAG_ADR(filter) (0x00006500u + (filter) * 0x4)
/* Bitmask for bitfield rpf_l3_v4_req_tag{F}[2:0] */
#define HW_ATL2_RPF_L3_V4_TAG_MSK 0x00000070u
/* Lower bit position of bitfield rpf_l3_v4_req_tag{F}[2:0] */
#define HW_ATL2_RPF_L3_V4_TAG_SHIFT 4
/* Register address for bitfield rpf_l3_v6_req_tag{F}[2:0] */
#define HW_ATL2_RPF_L3_V6_TAG_ADR(filter) (0x00006500u + (filter) * 0x4)
/* Bitmask for bitfield rpf_l3_v6_req_tag{F}[2:0] */
#define HW_ATL2_RPF_L3_V6_TAG_MSK 0x00700000
/* Lower bit position of bitfield rpf_l3_v6_req_tag{F}[2:0] */
#define HW_ATL2_RPF_L3_V6_TAG_SHIFT 20
/* Register address for bitfield rpf_l4_cmd{F}[2:0] */
#define HW_ATL2_RPF_L4_CMD_ADR(filter) (0x00006520u + (filter) * 0x4)
/* Bitmask for bitfield rpf_l4_cmd{F}[2:0] */
#define HW_ATL2_RPF_L4_CMD_MSK 0x00000007u
/* Lower bit position of bitfield rpf_l4_cmd{F}[2:0] */
#define HW_ATL2_RPF_L4_CMD_SHIFT 0
/* Register address for bitfield rpf_l4_tag{F}[2:0] */
#define HW_ATL2_RPF_L4_TAG_ADR(filter) (0x00006520u + (filter) * 0x4)
/* Bitmask for bitfield rpf_l4_tag{F}[2:0] */
#define HW_ATL2_RPF_L4_TAG_MSK 0x00000070u
/* Lower bit position of bitfield rpf_l4_tag{F}[2:0] */
#define HW_ATL2_RPF_L4_TAG_SHIFT 4
/* RX rx_q{Q}_tc_map[2:0] Bitfield Definitions
* Preprocessor definitions for the bitfield "rx_q{Q}_tc_map[2:0]".
* Parameter: Queue {Q} | bit-level stride | range [0, 31]
* PORT="pif_rx_q0_tc_map_i[2:0]"
*/
/* Register address for bitfield rx_q{Q}_tc_map[2:0] */
#define HW_ATL2_RX_Q_TC_MAP_ADR(queue) \
(((queue) < 32) ? 0x00005900 + ((queue) / 8) * 4 : 0)
/* Lower bit position of bitfield rx_q{Q}_tc_map[2:0] */
#define HW_ATL2_RX_Q_TC_MAP_SHIFT(queue) \
(((queue) < 32) ? ((queue) * 4) % 32 : 0)
/* Width of bitfield rx_q{Q}_tc_map[2:0] */
#define HW_ATL2_RX_Q_TC_MAP_WIDTH 3
/* Default value of bitfield rx_q{Q}_tc_map[2:0] */
#define HW_ATL2_RX_Q_TC_MAP_DEFAULT 0x0
/* TX desc{D}_ts_wrb_en Bitfield Definitions
*/
#define HW_ATL2_TDM_DESCD_TS_WRB_EN_ADR(descriptor) \
(0x00007C08 + (descriptor) * 0x40)
#define HW_ATL2_TDM_DESCD_TS_WRB_EN_MSK 0x00040000
#define HW_ATL2_TDM_DESCD_TS_WRB_EN_SHIFT 18
/* TX desc{D}_ts_en Bitfield Definitions
*/
#define HW_ATL2_TDM_DESCD_TS_EN_ADR(descriptor) \
(0x00007C08 + (descriptor) * 0x40)
#define HW_ATL2_TDM_DESCD_TS_EN_MSK 0x00020000
#define HW_ATL2_TDM_DESCD_TS_EN_SHIFT 17
/* TX desc{D}_avb_en Bitfield Definitions
*/
#define HW_ATL2_TDM_DESCD_AVB_EN_ADR(descriptor) \
(0x00007C08 + (descriptor) * 0x40)
#define HW_ATL2_TDM_DESCD_AVB_EN_MSK 0x00010000
#define HW_ATL2_TDM_DESCD_AVB_EN_SHIFT 16
/* tx tx_tc_q_rand_map_en bitfield definitions
* preprocessor definitions for the bitfield "tx_tc_q_rand_map_en".
* port="pif_tpb_tx_tc_q_rand_map_en_i"
*/
/* register address for bitfield tx_tc_q_rand_map_en */
#define HW_ATL2_TPB_TX_TC_Q_RAND_MAP_EN_ADR 0x00007900
/* bitmask for bitfield tx_tc_q_rand_map_en */
#define HW_ATL2_TPB_TX_TC_Q_RAND_MAP_EN_MSK 0x00000200
/* inverted bitmask for bitfield tx_tc_q_rand_map_en */
#define HW_ATL2_TPB_TX_TC_Q_RAND_MAP_EN_MSKN 0xFFFFFDFF
/* lower bit position of bitfield tx_tc_q_rand_map_en */
#define HW_ATL2_TPB_TX_TC_Q_RAND_MAP_EN_SHIFT 9
/* width of bitfield tx_tc_q_rand_map_en */
#define HW_ATL2_TPB_TX_TC_Q_RAND_MAP_EN_WIDTH 1
/* default value of bitfield tx_tc_q_rand_map_en */
#define HW_ATL2_TPB_TX_TC_Q_RAND_MAP_EN_DEFAULT 0x0
/* tx tx_buffer_clk_gate_en bitfield definitions
* preprocessor definitions for the bitfield "tx_buffer_clk_gate_en".
* port="pif_tpb_tx_buffer_clk_gate_en_i"
*/
/* register address for bitfield tx_buffer_clk_gate_en */
#define HW_ATL2_TPB_TX_BUF_CLK_GATE_EN_ADR 0x00007900
/* bitmask for bitfield tx_buffer_clk_gate_en */
#define HW_ATL2_TPB_TX_BUF_CLK_GATE_EN_MSK 0x00000020
/* inverted bitmask for bitfield tx_buffer_clk_gate_en */
#define HW_ATL2_TPB_TX_BUF_CLK_GATE_EN_MSKN 0xffffffdf
/* lower bit position of bitfield tx_buffer_clk_gate_en */
#define HW_ATL2_TPB_TX_BUF_CLK_GATE_EN_SHIFT 5
/* width of bitfield tx_buffer_clk_gate_en */
#define HW_ATL2_TPB_TX_BUF_CLK_GATE_EN_WIDTH 1
/* default value of bitfield tx_buffer_clk_gate_en */
#define HW_ATL2_TPB_TX_BUF_CLK_GATE_EN_DEFAULT 0x0
/* tx tx_q_tc_map{q} bitfield definitions
* preprocessor definitions for the bitfield "tx_q_tc_map{q}".
* parameter: queue {q} | bit-level stride | range [0, 31]
* port="pif_tpb_tx_q_tc_map0_i[2:0]"
*/
/* register address for bitfield tx_q_tc_map{q} */
#define HW_ATL2_TX_Q_TC_MAP_ADR(queue) \
(((queue) < 32) ? 0x0000799C + ((queue) / 4) * 4 : 0)
/* lower bit position of bitfield tx_q_tc_map{q} */
#define HW_ATL2_TX_Q_TC_MAP_SHIFT(queue) \
(((queue) < 32) ? ((queue) * 8) % 32 : 0)
/* width of bitfield tx_q_tc_map{q} */
#define HW_ATL2_TX_Q_TC_MAP_WIDTH 3
/* default value of bitfield tx_q_tc_map{q} */
#define HW_ATL2_TX_Q_TC_MAP_DEFAULT 0x0
/* tx data_tc_arb_mode bitfield definitions
* preprocessor definitions for the bitfield "data_tc_arb_mode".
* port="pif_tps_data_tc_arb_mode_i"
*/
/* register address for bitfield data_tc_arb_mode */
#define HW_ATL2_TPS_DATA_TC_ARB_MODE_ADR 0x00007100
/* bitmask for bitfield data_tc_arb_mode */
#define HW_ATL2_TPS_DATA_TC_ARB_MODE_MSK 0x00000003
/* inverted bitmask for bitfield data_tc_arb_mode */
#define HW_ATL2_TPS_DATA_TC_ARB_MODE_MSKN 0xfffffffc
/* lower bit position of bitfield data_tc_arb_mode */
#define HW_ATL2_TPS_DATA_TC_ARB_MODE_SHIFT 0
/* width of bitfield data_tc_arb_mode */
#define HW_ATL2_TPS_DATA_TC_ARB_MODE_WIDTH 2
/* default value of bitfield data_tc_arb_mode */
#define HW_ATL2_TPS_DATA_TC_ARB_MODE_DEFAULT 0x0
/* tx data_tc{t}_credit_max[f:0] bitfield definitions
* preprocessor definitions for the bitfield "data_tc{t}_credit_max[f:0]".
* parameter: tc {t} | stride size 0x4 | range [0, 7]
* port="pif_tps_data_tc0_credit_max_i[15:0]"
*/
/* register address for bitfield data_tc{t}_credit_max[f:0] */
#define HW_ATL2_TPS_DATA_TCTCREDIT_MAX_ADR(tc) (0x00007110 + (tc) * 0x4)
/* bitmask for bitfield data_tc{t}_credit_max[f:0] */
#define HW_ATL2_TPS_DATA_TCTCREDIT_MAX_MSK 0xffff0000
/* inverted bitmask for bitfield data_tc{t}_credit_max[f:0] */
#define HW_ATL2_TPS_DATA_TCTCREDIT_MAX_MSKN 0x0000ffff
/* lower bit position of bitfield data_tc{t}_credit_max[f:0] */
#define HW_ATL2_TPS_DATA_TCTCREDIT_MAX_SHIFT 16
/* width of bitfield data_tc{t}_credit_max[f:0] */
#define HW_ATL2_TPS_DATA_TCTCREDIT_MAX_WIDTH 16
/* default value of bitfield data_tc{t}_credit_max[f:0] */
#define HW_ATL2_TPS_DATA_TCTCREDIT_MAX_DEFAULT 0x0
/* register address for bitfield pif_tpb_highest_prio_tc_en */
#define HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_ADR 0x00007180
/* bitmask for bitfield pif_tpb_highest_prio_tc_en */
#define HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_MSK 0x00000100
/* lower bit position of bitfield pif_tpb_highest_prio_tc_en */
#define HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_SHIFT 8
/* register address for bitfield pif_tpb_highest_prio_tc */
#define HW_ATL2_TPB_HIGHEST_PRIO_TC_ADR 0x00007180
/* bitmask for bitfield pif_tpb_highest_prio_tc */
#define HW_ATL2_TPB_HIGHEST_PRIO_TC_MSK 0x00000007
/* lower bit position of bitfield pif_tpb_highest_prio_tc */
#define HW_ATL2_TPB_HIGHEST_PRIO_TC_SHIFT 0
/* tx data_tc{t}_weight[e:0] bitfield definitions
* preprocessor definitions for the bitfield "data_tc{t}_weight[e:0]".
* parameter: tc {t} | stride size 0x4 | range [0, 7]
* port="pif_tps_data_tc0_weight_i[14:0]"
*/
/* register address for bitfield data_tc{t}_weight[e:0] */
#define HW_ATL2_TPS_DATA_TCTWEIGHT_ADR(tc) (0x00007110 + (tc) * 0x4)
/* bitmask for bitfield data_tc{t}_weight[e:0] */
#define HW_ATL2_TPS_DATA_TCTWEIGHT_MSK 0x00007fff
/* inverted bitmask for bitfield data_tc{t}_weight[e:0] */
#define HW_ATL2_TPS_DATA_TCTWEIGHT_MSKN 0xffff8000
/* lower bit position of bitfield data_tc{t}_weight[e:0] */
#define HW_ATL2_TPS_DATA_TCTWEIGHT_SHIFT 0
/* width of bitfield data_tc{t}_weight[e:0] */
#define HW_ATL2_TPS_DATA_TCTWEIGHT_WIDTH 15
/* default value of bitfield data_tc{t}_weight[e:0] */
#define HW_ATL2_TPS_DATA_TCTWEIGHT_DEFAULT 0x0
/* tx interrupt moderation control register definitions
* Preprocessor definitions for TX Interrupt Moderation Control Register
* Base Address: 0x00007c28
* Parameter: queue {Q} | stride size 0x4 | range [0, 31]
*/
#define HW_ATL2_TX_INTR_MODERATION_CTL_ADR(queue) (0x00007c28u + (queue) * 0x40)
/* TX tx_data_rd_req_limit[7:0] Bitfield Definitions
*/
#define HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_ADR 0x00007B04
#define HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_MSK 0x0000FF00
#define HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_SHIFT 8
/* TX tx_desc_rd_req_limit[4:0] Bitfield Definitions
*/
#define HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_ADR 0x00007B04
#define HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_MSK 0x0000001F
#define HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_SHIFT 0
/* register address for bitfield uP Force Interrupt */
#define HW_ATL2_GLB_CONTROL_2_ADR 0x00000404
#define HW_ATL2_MIF_INTERRUPT_2_TO_ITR_MSK 0x00000100
/* lower bit position of bitfield MIF Interrupt to ITR */
#define HW_ATL2_MIF_INTERRUPT_TO_ITR_SHIFT 6
#define HW_ATL2_EN_INTERRUPT_MIF2_TO_ITR_MSK 0x00001000
/* lower bit position of bitfield Enable MIF Interrupt to ITR */
#define HW_ATL2_EN_INTERRUPT_TO_ITR_SHIFT 0xA
#define HW_ATL2_GLOBAL_INTERNAL_ALARMS_1_ADR 0x00000924
#define HW_ATL2_GLOBAL_HIGH_PRIO_INTERRUPT_1_MASK_ADR 0x00000964
/* bitmask for bitfield TSG PTM GPIO interrupt */
#define HW_ATL2_TSG_TSG1_GPIO_INTERRUPT_MSK 0x00000200
/* lower bit position of bitfield TSG PTM GPIO interrupt */
#define HW_ATL2_TSG_TSG1_GPIO_INTERRUPT_SHIFT 9
/* bitmask for bitfield TSG0 GPIO interrupt */
#define HW_ATL2_TSG_TSG0_GPIO_INTERRUPT_MSK 0x00000020
/* lower bit position of bitfield TSG0 GPIO interrupt */
#define HW_ATL2_TSG_TSG0_GPIO_INTERRUPT_SHIFT 5
/* TSG registers */
#define HW_ATL2_TSG_REG_ADR(clk, reg_name) \
((clk) == 0 ? HW_ATL2_CLK0_##reg_name##_ADR :\
HW_ATL2_CLK1_##reg_name##_ADR)
#define HW_ATL2_CLK0_CLOCK_CFG_ADR 0x00000CA0u
#define HW_ATL2_CLK1_CLOCK_CFG_ADR 0x00000D50u
#define HW_ATL2_TSG_SYNC_RESET_MSK 0x00000001
#define HW_ATL2_TSG_SYNC_RESET_SHIFT 0x00000000
#define HW_ATL2_TSG_CLOCK_EN_MSK 0x00000002
#define HW_ATL2_TSG_CLOCK_EN_SHIFT 0x00000001
#define HW_ATL2_CLK0_CLOCK_MODIF_CTRL_ADR 0x00000CA4u
#define HW_ATL2_CLK1_CLOCK_MODIF_CTRL_ADR 0x00000D54u
#define HW_ATL2_TSG_SUBTRACT_COUNTER_MSK 0x00000002
#define HW_ATL2_TSG_ADD_COUNTER_MSK 0x00000004
#define HW_ATL2_TSG_LOAD_INC_CFG_MSK 0x00000008
#define HW_ATL2_CLK0_CLOCK_MODIF_VAL_LSW_ADR 0x00000CA8u
#define HW_ATL2_CLK1_CLOCK_MODIF_VAL_LSW_ADR 0x00000D58u
#define HW_ATL2_CLK0_CLOCK_INC_CFG_ADR 0x00000CB0u
#define HW_ATL2_CLK1_CLOCK_INC_CFG_ADR 0x00000D60u
#define HW_ATL2_CLK0_READ_CUR_NS_LSW_ADR 0x00000CB8u
#define HW_ATL2_CLK1_READ_CUR_NS_LSW_ADR 0x00000D68u
#define HW_ATL2_CLK0_GPIO_CFG_ADR 0x00000CC4u
#define HW_ATL2_CLK1_GPIO_CFG_ADR 0x00000D74u
#define HW_ATL2_TSG_GPIO_IN_MONITOR_EN_SHIFT 0x00000000
#define HW_ATL2_TSG_GPIO_IN_MONITOR_EN_MSK 0x00000001
#define HW_ATL2_TSG_GPIO_IN_MODE_SHIFT 0x00000001
#define HW_ATL2_TSG_GPIO_IN_MODE_MSK 0x00000006
#define HW_ATL2_TSG_GPIO_IN_MODE_POSEDGE 0x00000000
#define HW_ATL2_CLK0_EXT_CLK_COUNT_ADR 0x00000CCCu
#define HW_ATL2_CLK1_EXT_CLK_COUNT_ADR 0x00000D7Cu
#define HW_ATL2_CLK0_GPIO_EVENT_TS_LSW_ADR 0x00000CD0u
#define HW_ATL2_CLK1_GPIO_EVENT_TS_LSW_ADR 0x00000D80u
#define HW_ATL2_CLK0_GPIO_EVENT_GEN_TS_LSW_ADR 0x00000CE0u
#define HW_ATL2_CLK1_GPIO_EVENT_GEN_TS_LSW_ADR 0x00000D90u
#define HW_ATL2_CLK0_GPIO_EVENT_GEN_CFG_ADR 0x00000CE8u
#define HW_ATL2_CLK1_GPIO_EVENT_GEN_CFG_ADR 0x00000D98u
#define HW_ATL2_TSG_GPIO_OUTPUT_EN_SHIFT 0x00000000
#define HW_ATL2_TSG_GPIO_OUTPUT_EN_MSK 0x00000001
#define HW_ATL2_TSG_GPIO_EVENT_MODE_SHIFT 0x00000001
#define HW_ATL2_TSG_GPIO_EVENT_MODE_MSK 0x00000006
#define HW_ATL2_TSG_GPIO_EVENT_MODE_SET_ON_TIME 0x00000003
#define HW_ATL2_TSG_GPIO_GEN_OUTPUT_EN_MSK 0x00000008
#define HW_ATL2_CLK0_GPIO_EVENT_HIGH_TIME_LSW_ADR 0x00000CF0u
#define HW_ATL2_CLK1_GPIO_EVENT_HIGH_TIME_LSW_ADR 0x00000DA0u
#define HW_ATL2_CLK0_GPIO_EVENT_LOW_TIME_LSW_ADR 0x00000CF8u
#define HW_ATL2_CLK1_GPIO_EVENT_LOW_TIME_LSW_ADR 0x00000DA8u
/* PCIE Extended tag enable Bitfield Definitions
*/
#define HW_ATL2_PHI_EXT_TAG_EN_ADR 0x00001000
#define HW_ATL2_PHI_EXT_TAG_EN_MSK 0x00000020
#define HW_ATL2_PHI_EXT_TAG_EN_SHIFT 5
/* Launch time control register */
#define HW_ATL2_LT_CTRL_ADR 0x00007a1c
#define HW_ATL2_LT_CTRL_AVB_LEN_CMP_TRSHLD_MSK 0xFFFF0000
#define HW_ATL2_LT_CTRL_AVB_LEN_CMP_TRSHLD_SHIFT 16
#define HW_ATL2_LT_CTRL_CLK_RATIO_MSK 0x0000FF00
#define HW_ATL2_LT_CTRL_CLK_RATIO_SHIFT 8
#define HW_ATL2_LT_CTRL_CLK_RATIO_QUATER_SPEED 4
#define HW_ATL2_LT_CTRL_CLK_RATIO_HALF_SPEED 2
#define HW_ATL2_LT_CTRL_CLK_RATIO_FULL_SPEED 1
#define HW_ATL2_LT_CTRL_25G_MODE_SUPPORT_MSK 0x00000008
#define HW_ATL2_LT_CTRL_25G_MODE_SUPPORT_SHIFT 3
#define HW_ATL2_LT_CTRL_LINK_SPEED_MSK 0x00000007
#define HW_ATL2_LT_CTRL_LINK_SPEED_SHIFT 0
/* FPGA VER register */
#define HW_ATL2_FPGA_VER_ADR 0x000000f4
#define HW_ATL2_FPGA_VER_U32(mj, mi, bl, rv) \
((((mj) & 0xff) << 24) | \
(((mi) & 0xff) << 16) | \
(((bl) & 0xff) << 8) | \
(((rv) & 0xff) << 0))
/* ahb_mem_addr{f}[31:0] Bitfield Definitions
* Preprocessor definitions for the bitfield "ahb_mem_addr{f}[31:0]".
* Parameter: filter {f} | stride size 0x10 | range [0, 127]
* PORT="ahb_mem_addr{f}[31:0]"
*/
/* Register address for bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_REQ_TAG_ADR(filter) \
(0x00014000u + (filter) * 0x10)
/* Bitmask for bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_REQ_TAG_MSK 0xFFFFFFFFu
/* Inverted bitmask for bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_REQ_TAG_MSKN 0x00000000u
/* Lower bit position of bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_REQ_TAG_SHIFT 0
/* Width of bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_REQ_TAG_WIDTH 31
/* Default value of bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_REQ_TAG_DEFAULT 0x0
/* Register address for bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_TAG_MASK_ADR(filter) \
(0x00014004u + (filter) * 0x10)
/* Bitmask for bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_TAG_MASK_MSK 0xFFFFFFFFu
/* Inverted bitmask for bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_TAG_MASK_MSKN 0x00000000u
/* Lower bit position of bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_TAG_MASK_SHIFT 0
/* Width of bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_TAG_MASK_WIDTH 31
/* Default value of bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_TAG_MASK_DEFAULT 0x0
/* Register address for bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_ACTN_ADR(filter) \
(0x00014008u + (filter) * 0x10)
/* Bitmask for bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_ACTN_MSK 0x000007FFu
/* Inverted bitmask for bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_ACTN_MSKN 0xFFFFF800u
/* Lower bit position of bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_ACTN_SHIFT 0
/* Width of bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_ACTN_WIDTH 10
/* Default value of bitfield ahb_mem_addr{f}[31:0] */
#define HW_ATL2_RPF_ACT_RSLVR_ACTN_DEFAULT 0x0
/* rpf_rec_tab_en[15:0] Bitfield Definitions
* Preprocessor definitions for the bitfield "rpf_rec_tab_en[15:0]".
* PORT="pif_rpf_rec_tab_en[15:0]"
*/
/* Register address for bitfield rpf_rec_tab_en[15:0] */
#define HW_ATL2_RPF_REC_TAB_EN_ADR 0x00006ff0u
/* Bitmask for bitfield rpf_rec_tab_en[15:0] */
#define HW_ATL2_RPF_REC_TAB_EN_MSK 0x0000FFFFu
/* Inverted bitmask for bitfield rpf_rec_tab_en[15:0] */
#define HW_ATL2_RPF_REC_TAB_EN_MSKN 0xFFFF0000u
/* Lower bit position of bitfield rpf_rec_tab_en[15:0] */
#define HW_ATL2_RPF_REC_TAB_EN_SHIFT 0
/* Width of bitfield rpf_rec_tab_en[15:0] */
#define HW_ATL2_RPF_REC_TAB_EN_WIDTH 16
/* Default value of bitfield rpf_rec_tab_en[15:0] */
#define HW_ATL2_RPF_REC_TAB_EN_DEFAULT 0x0
/* Register address for firmware shared input buffer */
#define HW_ATL2_MIF_SHARED_BUFFER_IN_ADR(dword) (0x00012000U + (dword) * 0x4U)
/* Register address for firmware shared output buffer */
#define HW_ATL2_MIF_SHARED_BUFFER_OUT_ADR(dword) (0x00013000U + (dword) * 0x4U)
/* pif_host_finished_buf_wr_i Bitfield Definitions
* Preprocessor definitions for the bitfield "pif_host_finished_buf_wr_i".
* PORT="pif_host_finished_buf_wr_i"
*/
/* Register address for bitfield rpif_host_finished_buf_wr_i */
#define HW_ATL2_MIF_HOST_FINISHED_WRITE_ADR 0x00000e00u
/* Bitmask for bitfield pif_host_finished_buf_wr_i */
#define HW_ATL2_MIF_HOST_FINISHED_WRITE_MSK 0x00000001u
/* Inverted bitmask for bitfield pif_host_finished_buf_wr_i */
#define HW_ATL2_MIF_HOST_FINISHED_WRITE_MSKN 0xFFFFFFFEu
/* Lower bit position of bitfield pif_host_finished_buf_wr_i */
#define HW_ATL2_MIF_HOST_FINISHED_WRITE_SHIFT 0
/* Width of bitfield pif_host_finished_buf_wr_i */
#define HW_ATL2_MIF_HOST_FINISHED_WRITE_WIDTH 1
/* Default value of bitfield pif_host_finished_buf_wr_i */
#define HW_ATL2_MIF_HOST_FINISHED_WRITE_DEFAULT 0x0
/* pif_mcp_finished_buf_rd_i Bitfield Definitions
* Preprocessor definitions for the bitfield "pif_mcp_finished_buf_rd_i".
* PORT="pif_mcp_finished_buf_rd_i"
*/
/* Register address for bitfield pif_mcp_finished_buf_rd_i */
#define HW_ATL2_MIF_MCP_FINISHED_READ_ADR 0x00000e04u
/* Bitmask for bitfield pif_mcp_finished_buf_rd_i */
#define HW_ATL2_MIF_MCP_FINISHED_READ_MSK 0x00000001u
/* Inverted bitmask for bitfield pif_mcp_finished_buf_rd_i */
#define HW_ATL2_MIF_MCP_FINISHED_READ_MSKN 0xFFFFFFFEu
/* Lower bit position of bitfield pif_mcp_finished_buf_rd_i */
#define HW_ATL2_MIF_MCP_FINISHED_READ_SHIFT 0
/* Width of bitfield pif_mcp_finished_buf_rd_i */
#define HW_ATL2_MIF_MCP_FINISHED_READ_WIDTH 1
/* Default value of bitfield pif_mcp_finished_buf_rd_i */
#define HW_ATL2_MIF_MCP_FINISHED_READ_DEFAULT 0x0
/* Register address for bitfield pif_mcp_boot_reg */
#define HW_ATL2_MIF_BOOT_REG_ADR 0x00003040u
#define HW_ATL2_MCP_HOST_REQ_INT_READY BIT(0)
#define HW_ATL2_MCP_HOST_REQ_INT_ADR 0x00000F00u
#define HW_ATL2_MCP_HOST_REQ_INT_SET_ADR 0x00000F04u
#define HW_ATL2_MCP_HOST_REQ_INT_CLR_ADR 0x00000F08u
/* Register address for bitfield PTP EXT GPIO TS SEL */
#define HW_ATL2_TSG0_EXT_GPIO_TS_INPUT_SEL_ADR 0x00003664
/* Bitmask for bitfield PTP EXT GPIO TS SEL */
#define HW_ATL2_TSG0_EXT_GPIO_TS_INPUT_SEL_MSK 0x00001F00
/* Lower bit position of bitfield PTP EXT GPIO TS SEL */
#define HW_ATL2_TSG0_EXT_GPIO_TS_INPUT_SEL_SHIFT 8
/* Register address for bitfield TSG EXT GPIO TS SEL */
#define HW_ATL2_TSG1_EXT_GPIO_TS_INPUT_SEL_ADR 0x00003660
/* Bitmask for bitfield TSG EXT GPIO TS SEL */
#define HW_ATL2_TSG1_EXT_GPIO_TS_INPUT_SEL_MSK 0x00001F00
/* Lower bit position of bitfield TSG EXT GPIO TS SEL */
#define HW_ATL2_TSG1_EXT_GPIO_TS_INPUT_SEL_SHIFT 8
/* Register address for bitfield GPIO{P} Special Mode */
#define HW_ATL2_GPIO_PIN_SPEC_MODE_ADR(pin) (0x00003698 + (pin) * 0x4)
/* Bitmask for bitfield GPIO{P} Special Mode */
#define HW_ATL2_GPIO_PIN_SPEC_MODE_MSK 0x0000000C
/* Lower bit position of bitfield GPIO{P} Special Mode */
#define HW_ATL2_GPIO_PIN_SPEC_MODE_SHIFT 2
#define HW_ATL2_GPIO_PIN_SPEC_MODE_TSG1_EVENT_OUTPUT 0
#define HW_ATL2_GPIO_PIN_SPEC_MODE_TSG0_EVENT_OUTPUT 2
#define HW_ATL2_GPIO_PIN_SPEC_MODE_GPIO 3
#endif /* HW_ATL2_LLH_INTERNAL_H */
@@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#include <linux/iopoll.h>
#include "aq_hw_utils.h"
#include "hw_atl/hw_atl_utils.h"
#include "hw_atl2_utils.h"
#include "hw_atl2_llh.h"
#include "hw_atl2_llh_internal.h"
#define HW_ATL2_FW_VER_1X 0x01000000U
#define AQ_A2_BOOT_STARTED BIT(0x18)
#define AQ_A2_CRASH_INIT BIT(0x1B)
#define AQ_A2_BOOT_CODE_FAILED BIT(0x1C)
#define AQ_A2_FW_INIT_FAILED BIT(0x1D)
#define AQ_A2_FW_INIT_COMP_SUCCESS BIT(0x1F)
#define AQ_A2_FW_BOOT_FAILED_MASK (AQ_A2_CRASH_INIT | \
AQ_A2_BOOT_CODE_FAILED | \
AQ_A2_FW_INIT_FAILED)
#define AQ_A2_FW_BOOT_COMPLETE_MASK (AQ_A2_FW_BOOT_FAILED_MASK | \
AQ_A2_FW_INIT_COMP_SUCCESS)
#define AQ_A2_FW_BOOT_REQ_REBOOT BIT(0x0)
#define AQ_A2_FW_BOOT_REQ_HOST_BOOT BIT(0x8)
#define AQ_A2_FW_BOOT_REQ_MAC_FAST_BOOT BIT(0xA)
#define AQ_A2_FW_BOOT_REQ_PHY_FAST_BOOT BIT(0xB)
int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
{
int err;
self->fw_ver_actual = hw_atl2_utils_get_fw_version(self);
if (hw_atl_utils_ver_match(HW_ATL2_FW_VER_1X, self->fw_ver_actual)) {
*fw_ops = &aq_a2_fw_ops;
} else {
aq_pr_err("Bad FW version detected: %x, but continue\n",
self->fw_ver_actual);
*fw_ops = &aq_a2_fw_ops;
}
aq_pr_trace("Detect ATL2FW %x\n", self->fw_ver_actual);
self->aq_fw_ops = *fw_ops;
err = self->aq_fw_ops->init(self);
self->chip_features |= ATL_HW_CHIP_ANTIGUA;
return err;
}
static bool hw_atl2_mcp_boot_complete(struct aq_hw_s *self)
{
u32 rbl_status;
rbl_status = hw_atl2_mif_mcp_boot_reg_get(self);
if (rbl_status & AQ_A2_FW_BOOT_COMPLETE_MASK)
return true;
/* Host boot requested */
if (hw_atl2_mif_host_req_int_get(self) & HW_ATL2_MCP_HOST_REQ_INT_READY)
return true;
return false;
}
int hw_atl2_utils_soft_reset(struct aq_hw_s *self)
{
bool rbl_complete = false;
u32 rbl_status = 0;
u32 rbl_request;
int err;
hw_atl2_mif_host_req_int_clr(self, 0x01);
rbl_request = AQ_A2_FW_BOOT_REQ_REBOOT;
#ifdef AQ_CFG_FAST_START
rbl_request |= AQ_A2_FW_BOOT_REQ_MAC_FAST_BOOT;
#endif
hw_atl2_mif_mcp_boot_reg_set(self, rbl_request);
/* Wait for RBL boot */
err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_boot_reg_get, self,
rbl_status,
((rbl_status & AQ_A2_BOOT_STARTED) &&
(rbl_status != 0xFFFFFFFFu)),
10, 200000);
if (err) {
aq_pr_err("Boot code hanged");
goto err_exit;
}
err = readx_poll_timeout_atomic(hw_atl2_mcp_boot_complete, self,
rbl_complete,
rbl_complete,
10, 2000000);
if (err) {
aq_pr_err("FW Restart timed out");
goto err_exit;
}
rbl_status = hw_atl2_mif_mcp_boot_reg_get(self);
if (rbl_status & AQ_A2_FW_BOOT_FAILED_MASK) {
err = -EIO;
aq_pr_err("FW Restart failed");
goto err_exit;
}
if (hw_atl2_mif_host_req_int_get(self) &
HW_ATL2_MCP_HOST_REQ_INT_READY) {
err = -EIO;
aq_pr_err("No FW detected. Dynamic FW load not implemented");
goto err_exit;
}
if (self->aq_fw_ops) {
err = self->aq_fw_ops->init(self);
if (err) {
aq_pr_err("FW Init failed");
goto err_exit;
}
}
err_exit:
return err;
}
static const u32 hw_atl2_utils_hw_mac_regs[] = {
0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
};
int hw_atl2_utils_hw_get_regs(struct aq_hw_s *self,
const struct aq_hw_caps_s *aq_hw_caps,
u32 *regs_buff)
{
unsigned int i;
for (i = 0; i < min_t(u32, aq_hw_caps->mac_regs_count,
ARRAY_SIZE(hw_atl2_utils_hw_mac_regs)); i++)
regs_buff[i] = aq_hw_read_reg(self,
hw_atl2_utils_hw_mac_regs[i]);
return 0;
}
@@ -0,0 +1,649 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef HW_ATL2_UTILS_H
#define HW_ATL2_UTILS_H
#include "aq_hw.h"
/* Hardware tx launch time descriptor */
struct hw_atl2_txts_s {
__le64 ts;
__le32 ctrl;
u32 reserved;
};
#define HW_ATL2_TXTS_DD BIT(3)
#define HW_ATL2_TXTS_TS_VALID BIT(20)
/* F W A P I */
struct link_options_s {
u8 link_up:1;
u8 link_renegotiate:1;
u8 minimal_link_speed:1;
u8 internal_loopback:1;
u8 external_loopback:1;
u8 rate_10M_hd:1;
u8 rate_100M_hd:1;
u8 rate_1G_hd:1;
u8 rate_10M:1;
u8 rate_100M:1;
u8 rate_1G:1;
u8 rate_2P5G:1;
u8 rate_N2P5G:1;
u8 rate_5G:1;
u8 rate_N5G:1;
u8 rate_10G:1;
u8 eee_100M:1;
u8 eee_1G:1;
u8 eee_2P5G:1;
u8 eee_5G:1;
u8 eee_10G:1;
u8 rsvd3:3;
u8 pause_rx:1;
u8 pause_tx:1;
u8 rsvd4:1;
u8 downshift:1;
u8 downshift_retry:4;
};
struct link_control_s {
u8 mode:4;
u8 disable_crc_corruption:1;
u8 discard_short_frames:1;
u8 flow_control_mode:1;
u8 disable_length_check:1;
u8 discard_errored_frames:1;
u8 control_frame_enable:1;
u8 enable_tx_padding:1;
u8 enable_crc_forwarding:1;
u8 enable_frame_padding_removal_rx: 1;
u8 promiscuous_mode: 1;
u8 rsvd:2;
u16 rsvd2;
};
struct thermal_shutdown_s {
u8 enable:1;
u8 warning_enable:1;
u8 rsvd:6;
u8 shutdown_temperature;
u8 cold_temperature;
u8 warning_temperature;
};
struct mac_address_s {
u8 mac_address[6];
};
struct mac_address_aligned_s {
struct mac_address_s aligned;
u16 rsvd;
};
struct sleep_proxy_s {
struct wake_on_lan_s {
u8 wake_on_magic_packet:1;
u8 wake_on_pattern:1;
u8 wake_on_link_up:1;
u8 wake_on_link_down:1;
u8 wake_on_ping:1;
u8 wake_on_timer:1;
u8 rsvd:2;
u8 rsvd2;
u16 rsvd3;
u32 link_up_timeout;
u32 link_down_timeout;
u32 timer;
} wake_on_lan;
struct {
u32 mask[4];
u32 crc32;
} wake_up_pattern[8];
struct __packed {
u8 arp_responder:1;
u8 echo_responder:1;
u8 igmp_client:1;
u8 echo_truncate:1;
u8 address_guard:1;
u8 ignore_fragmented:1;
u8 rsvd:2;
u16 echo_max_len;
u8 rsvd2;
} ipv4_offload;
u32 ipv4_offload_addr[8];
u32 reserved[8];
struct __packed {
u8 ns_responder:1;
u8 echo_responder:1;
u8 mld_client:1;
u8 echo_truncate:1;
u8 address_guard:1;
u8 rsvd:3;
u16 echo_max_len;
u8 rsvd2;
} ipv6_offload;
u32 ipv6_offload_addr[16][4];
struct {
u16 port[16];
} tcp_port_offload;
struct {
u16 port[16];
} udp_port_offload;
struct {
u32 retry_count;
u32 retry_interval;
} ka4_offload;
struct {
u32 timeout;
u16 local_port;
u16 remote_port;
u8 remote_mac_addr[6];
u16 rsvd;
u32 rsvd2;
u32 rsvd3;
u16 rsvd4;
u16 win_size;
u32 seq_num;
u32 ack_num;
u32 local_ip;
u32 remote_ip;
} ka4_connection[16];
struct {
u32 retry_count;
u32 retry_interval;
} ka6_offload;
struct {
u32 timeout;
u16 local_port;
u16 remote_port;
u8 remote_mac_addr[6];
u16 rsvd;
u32 rsvd2;
u32 rsvd3;
u16 rsvd4;
u16 win_size;
u32 seq_num;
u32 ack_num;
u32 local_ip[4];
u32 remote_ip[4];
} ka6_connection[16];
struct {
u32 rr_count;
u32 rr_buf_len;
u32 idx_offset;
u32 rr__offset;
} mdns_offload;
};
struct pause_quanta_s {
u16 quanta_10M;
u16 threshold_10M;
u16 quanta_100M;
u16 threshold_100M;
u16 quanta_1G;
u16 threshold_1G;
u16 quanta_2P5G;
u16 threshold_2P5G;
u16 quanta_5G;
u16 threshold_5G;
u16 quanta_10G;
u16 threshold_10G;
};
struct data_buffer_status_s {
u32 data_offset;
u32 data_length;
};
struct device_caps_s {
u8 finite_flashless:1;
u8 cable_diag:1;
u8 ncsi:1;
u8 avb:1;
u8 rsvd:4;
u8 rsvd2;
u16 rsvd3;
u32 rsvd4;
};
struct version_s {
struct bundle_version_t {
u8 major;
u8 minor;
u16 build;
} bundle;
struct mac_version_t {
u8 major;
u8 minor;
u16 build;
} mac;
struct phy_version_t {
u8 major;
u8 minor;
u16 build;
} phy;
u32 drv_iface_ver:4;
u32 rsvd:28;
};
struct link_status_s {
u8 link_state:4;
u8 link_rate:4;
u8 pause_tx:1;
u8 pause_rx:1;
u8 eee:1;
u8 duplex:1;
u8 rsvd:4;
u16 rsvd2;
};
struct wol_status_s {
u8 wake_count;
u8 wake_reason;
u16 wake_up_packet_length :12;
u16 wake_up_pattern_number :3;
u16 rsvd:1;
u32 wake_up_packet[379];
};
struct mac_health_monitor_s {
u8 mac_ready:1;
u8 mac_fault:1;
u8 mac_flashless_finished:1;
u8 rsvd:5;
u8 mac_temperature;
u16 mac_heart_beat;
u16 mac_fault_code;
u16 rsvd2;
};
struct phy_health_monitor_s {
u8 phy_ready:1;
u8 phy_fault:1;
u8 phy_hot_warning:1;
u8 rsvd:5;
u8 phy_temperature;
u16 phy_heart_beat;
u16 phy_fault_code;
u16 rsvd2;
};
struct device_link_caps_s {
u8 rsvd:3;
u8 internal_loopback:1;
u8 external_loopback:1;
u8 rate_10M_hd:1;
u8 rate_100M_hd:1;
u8 rate_1G_hd:1;
u8 rate_10M:1;
u8 rate_100M:1;
u8 rate_1G:1;
u8 rate_2P5G:1;
u8 rate_N2P5G:1;
u8 rate_5G:1;
u8 rate_N5G:1;
u8 rate_10G:1;
u8 rsvd3:1;
u8 eee_100M:1;
u8 eee_1G:1;
u8 eee_2P5G:1;
u8 rsvd4:1;
u8 eee_5G:1;
u8 rsvd5:1;
u8 eee_10G:1;
u8 pause_rx:1;
u8 pause_tx:1;
u8 pfc:1;
u8 downshift:1;
u8 downshift_retry:4;
};
struct sleep_proxy_caps_s {
u8 ipv4_offload:1;
u8 ipv6_offload:1;
u8 tcp_port_offload:1;
u8 udp_port_offload:1;
u8 ka4_offload:1;
u8 ka6_offload:1;
u8 mdns_offload:1;
u8 wake_on_ping:1;
u8 wake_on_magic_packet:1;
u8 wake_on_pattern:1;
u8 wake_on_timer:1;
u8 wake_on_link:1;
u8 wake_patterns_count:4;
u8 ipv4_count;
u8 ipv6_count;
u8 tcp_port_offload_count;
u8 udp_port_offload_count;
u8 tcp4_ka_count;
u8 tcp6_ka_count;
u8 igmp_offload:1;
u8 mld_offload:1;
u8 rsvd:6;
u8 rsvd2;
u16 rsvd3;
};
struct lkp_link_caps_s {
u8 rsvd:5;
u8 rate_10M_hd:1;
u8 rate_100M_hd:1;
u8 rate_1G_hd:1;
u8 rate_10M:1;
u8 rate_100M:1;
u8 rate_1G:1;
u8 rate_2P5G:1;
u8 rate_N2P5G:1;
u8 rate_5G:1;
u8 rate_N5G:1;
u8 rate_10G:1;
u8 rsvd2:1;
u8 eee_100M:1;
u8 eee_1G:1;
u8 eee_2P5G:1;
u8 rsvd3:1;
u8 eee_5G:1;
u8 rsvd4:1;
u8 eee_10G:1;
u8 pause_rx:1;
u8 pause_tx:1;
u8 rsvd5:6;
};
struct core_dump_s {
u32 reg0;
u32 reg1;
u32 reg2;
u32 hi;
u32 lo;
u32 regs[32];
};
struct trace_s {
u32 sync_counter;
u32 mem_buffer[0x1ff];
};
struct cable_diag_control_s {
u8 toggle :1;
u8 rsvd:7;
u8 wait_timeout_sec;
u16 rsvd2;
};
struct cable_diag_lane_data_s {
u8 result_code;
u8 dist;
u8 far_dist;
u8 rsvd;
};
struct cable_diag_status_s {
struct cable_diag_lane_data_s lane_data[4];
u8 transact_id;
u8 status:4;
u8 rsvd:4;
u16 rsvd2;
};
struct statistics_a0_s {
struct {
u32 link_up;
u32 link_down;
} link;
struct {
u64 tx_unicast_octets;
u64 tx_multicast_octets;
u64 tx_broadcast_octets;
u64 rx_unicast_octets;
u64 rx_multicast_octets;
u64 rx_broadcast_octets;
u32 tx_unicast_frames;
u32 tx_multicast_frames;
u32 tx_broadcast_frames;
u32 tx_errors;
u32 rx_unicast_frames;
u32 rx_multicast_frames;
u32 rx_broadcast_frames;
u32 rx_dropped_frames;
u32 rx_error_frames;
u32 tx_good_frames;
u32 rx_good_frames;
u32 reserve_fw_gap;
} msm;
u32 main_loop_cycles;
u32 reserve_fw_gap;
};
struct __packed statistics_b0_s {
u64 rx_good_octets;
u64 rx_pause_frames;
u64 rx_good_frames;
u64 rx_errors;
u64 rx_unicast_frames;
u64 rx_multicast_frames;
u64 rx_broadcast_frames;
u64 tx_good_octets;
u64 tx_pause_frames;
u64 tx_good_frames;
u64 tx_errors;
u64 tx_unicast_frames;
u64 tx_multicast_frames;
u64 tx_broadcast_frames;
u32 main_loop_cycles;
};
struct __packed statistics_s {
union __packed {
struct statistics_a0_s a0;
struct statistics_b0_s b0;
};
};
struct filter_caps_s {
u8 l2_filters_base_index:6;
u8 flexible_filter_mask:2;
u8 l2_filter_count;
u8 ethertype_filter_base_index;
u8 ethertype_filter_count;
u8 vlan_filter_base_index;
u8 vlan_filter_count;
u8 l3_ip4_filter_base_index:4;
u8 l3_ip4_filter_count:4;
u8 l3_ip6_filter_base_index:4;
u8 l3_ip6_filter_count:4;
u8 l4_filter_base_index:4;
u8 l4_filter_count:4;
u8 l4_flex_filter_base_index:4;
u8 l4_flex_filter_count:4;
u8 rslv_tbl_base_index;
u8 rslv_tbl_count;
};
struct request_policy_s {
struct {
u8 all:1;
u8 mcast:1;
u8 rx_queue_tc_index:5;
u8 queue_or_tc:1;
} promisc;
struct {
u8 accept:1;
u8 rsvd:1;
u8 rx_queue_tc_index:5;
u8 queue_or_tc:1;
} bcast;
struct {
u8 accept:1;
u8 rsvd:1;
u8 rx_queue_tc_index:5;
u8 queue_or_tc:1;
} mcast;
u8 rsvd:8;
};
struct fw_interface_in {
u32 mtu;
u32 rsvd1;
struct mac_address_aligned_s mac_address;
struct link_control_s link_control;
u32 rsvd2;
struct link_options_s link_options;
u32 rsvd3;
struct thermal_shutdown_s thermal_shutdown;
u32 rsvd4;
struct sleep_proxy_s sleep_proxy;
u32 rsvd5;
struct pause_quanta_s pause_quanta[8];
struct cable_diag_control_s cable_diag_control;
u32 rsvd6;
struct data_buffer_status_s data_buffer_status;
u32 rsvd7;
struct request_policy_s request_policy;
};
struct transaction_counter_s {
u16 transaction_cnt_a;
u16 transaction_cnt_b;
};
struct management_status_s {
struct mac_address_s mac_address;
u16 vlan;
struct{
u32 enable : 1;
u32 rsvd:31;
} flags;
u32 rsvd1;
u32 rsvd2;
u32 rsvd3;
u32 rsvd4;
u32 rsvd5;
};
struct __packed fw_interface_out {
struct transaction_counter_s transaction_id;
struct version_s version;
struct link_status_s link_status;
struct wol_status_s wol_status;
u32 rsvd;
u32 rsvd2;
struct mac_health_monitor_s mac_health_monitor;
u32 rsvd3;
u32 rsvd4;
struct phy_health_monitor_s phy_health_monitor;
u32 rsvd5;
u32 rsvd6;
struct cable_diag_status_s cable_diag_status;
u32 rsvd7;
struct device_link_caps_s device_link_caps;
u32 rsvd8;
struct sleep_proxy_caps_s sleep_proxy_caps;
u32 rsvd9;
struct lkp_link_caps_s lkp_link_caps;
u32 rsvd10;
struct core_dump_s core_dump;
u32 rsvd11;
struct statistics_s stats;
struct filter_caps_s filter_caps;
struct device_caps_s device_caps;
u32 rsvd13;
struct management_status_s management_status;
u32 reserve[21];
struct trace_s trace;
};
#define AQ_A2_FW_LINK_RATE_INVALID 0
#define AQ_A2_FW_LINK_RATE_10M 1
#define AQ_A2_FW_LINK_RATE_100M 2
#define AQ_A2_FW_LINK_RATE_1G 3
#define AQ_A2_FW_LINK_RATE_2G5 4
#define AQ_A2_FW_LINK_RATE_5G 5
#define AQ_A2_FW_LINK_RATE_10G 6
#define AQ_HOST_MODE_INVALID 0U
#define AQ_HOST_MODE_ACTIVE 1U
#define AQ_HOST_MODE_SLEEP_PROXY 2U
#define AQ_HOST_MODE_LOW_POWER 3U
#define AQ_HOST_MODE_SHUTDOWN 4U
#define AQ_A2_FW_INTERFACE_A0 0
#define AQ_A2_FW_INTERFACE_B0 1
int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops);
int hw_atl2_utils_soft_reset(struct aq_hw_s *self);
int hw_atl2_utils_hw_get_regs(struct aq_hw_s *self,
const struct aq_hw_caps_s *aq_hw_caps,
u32 *regs_buff);
u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self);
int hw_atl2_utils_get_filter_caps(struct aq_hw_s *self);
extern const struct aq_fw_ops aq_a2_fw_ops;
#endif /* HW_ATL2_UTILS_H */
@@ -0,0 +1,718 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#include <linux/iopoll.h>
#include "aq_hw.h"
#include "aq_hw_utils.h"
#include "aq_nic.h"
#include "hw_atl/hw_atl_llh.h"
#include "hw_atl2_utils.h"
#include "hw_atl2_llh.h"
#include "hw_atl2_internal.h"
#define AQ_A2_FW_READ_TRY_MAX 1000
#define hw_atl2_shared_buffer_write(HW, ITEM, VARIABLE) \
{\
BUILD_BUG_ON_MSG((offsetof(struct fw_interface_in, ITEM) % \
sizeof(u32)) != 0,\
"Unaligned write " # ITEM);\
BUILD_BUG_ON_MSG((sizeof(VARIABLE) % sizeof(u32)) != 0,\
"Unaligned write length " # ITEM);\
hw_atl2_mif_shared_buf_write(HW,\
(offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\
(u32 *)&(VARIABLE), sizeof(VARIABLE) / sizeof(u32));\
}
#define hw_atl2_shared_buffer_get(HW, ITEM, VARIABLE) \
{\
BUILD_BUG_ON_MSG((offsetof(struct fw_interface_in, ITEM) % \
sizeof(u32)) != 0,\
"Unaligned get " # ITEM);\
BUILD_BUG_ON_MSG((sizeof(VARIABLE) % sizeof(u32)) != 0,\
"Unaligned get length " # ITEM);\
hw_atl2_mif_shared_buf_get(HW, \
(offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\
(u32 *)&(VARIABLE), \
sizeof(VARIABLE) / sizeof(u32));\
}
/* This should never be used on non atomic fields,
* treat any > u32 read as non atomic.
*/
#define hw_atl2_shared_buffer_read(HW, ITEM, VARIABLE) \
{\
BUILD_BUG_ON_MSG((offsetof(struct fw_interface_out, ITEM) % \
sizeof(u32)) != 0,\
"Unaligned read " # ITEM);\
BUILD_BUG_ON_MSG((sizeof(VARIABLE) % sizeof(u32)) != 0,\
"Unaligned read length " # ITEM);\
BUILD_BUG_ON_MSG(sizeof(VARIABLE) > sizeof(u32),\
"Non atomic read " # ITEM);\
hw_atl2_mif_shared_buf_read(HW, \
(offsetof(struct fw_interface_out, ITEM) / sizeof(u32)),\
(u32 *)&(VARIABLE), sizeof(VARIABLE) / sizeof(u32));\
}
#define hw_atl2_shared_buffer_read_safe(HW, ITEM, DATA) \
({\
BUILD_BUG_ON_MSG((offsetof(struct fw_interface_out, ITEM) % \
sizeof(u32)) != 0,\
"Unaligned read_safe " # ITEM);\
BUILD_BUG_ON_MSG((sizeof(((struct fw_interface_out *)0)->ITEM) % \
sizeof(u32)) != 0,\
"Unaligned read_safe length " # ITEM);\
hw_atl2_shared_buffer_read_block((HW), \
(offsetof(struct fw_interface_out, ITEM) / sizeof(u32)),\
sizeof(((struct fw_interface_out *)0)->ITEM) / sizeof(u32),\
(DATA));\
})
static int hw_atl2_shared_buffer_read_block(struct aq_hw_s *self,
u32 offset, u32 dwords, void *data)
{
struct transaction_counter_s tid1, tid2;
int cnt = 0;
do {
do {
hw_atl2_shared_buffer_read(self, transaction_id, tid1);
cnt++;
if (cnt > AQ_A2_FW_READ_TRY_MAX)
return -ETIME;
if (tid1.transaction_cnt_a != tid1.transaction_cnt_b)
mdelay(1);
} while (tid1.transaction_cnt_a != tid1.transaction_cnt_b);
hw_atl2_mif_shared_buf_read(self, offset, (u32 *)data, dwords);
hw_atl2_shared_buffer_read(self, transaction_id, tid2);
cnt++;
if (cnt > AQ_A2_FW_READ_TRY_MAX)
return -ETIME;
} while (tid2.transaction_cnt_a != tid2.transaction_cnt_b ||
tid1.transaction_cnt_a != tid2.transaction_cnt_a);
return 0;
}
static inline int hw_atl2_shared_buffer_finish_ack(struct aq_hw_s *self)
{
u32 val;
int err;
hw_atl2_mif_host_finished_write_set(self, 1U);
err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_finished_read_get,
self, val, val == 0U,
100, 100000U);
WARN(err, "hw_atl2_shared_buffer_finish_ack");
return err;
}
static int aq_a2_fw_init(struct aq_hw_s *self)
{
struct link_control_s link_control;
u32 mtu;
u32 val;
int err;
err = hw_atl2_utils_get_filter_caps(self);
if (err)
return err;
hw_atl2_shared_buffer_get(self, link_control, link_control);
link_control.mode = AQ_HOST_MODE_ACTIVE;
hw_atl2_shared_buffer_write(self, link_control, link_control);
hw_atl2_shared_buffer_get(self, mtu, mtu);
mtu = HW_ATL2_MTU_JUMBO;
hw_atl2_shared_buffer_write(self, mtu, mtu);
hw_atl2_mif_host_finished_write_set(self, 1U);
err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_finished_read_get,
self, val, val == 0U,
100, 5000000U);
WARN(err, "hw_atl2_shared_buffer_finish_ack");
return err;
}
static int aq_a2_fw_deinit(struct aq_hw_s *self)
{
struct link_control_s link_control;
hw_atl2_shared_buffer_get(self, link_control, link_control);
link_control.mode = AQ_HOST_MODE_SHUTDOWN;
hw_atl2_shared_buffer_write(self, link_control, link_control);
return hw_atl2_shared_buffer_finish_ack(self);
}
static void a2_link_speed_mask2fw(u32 speed,
struct link_options_s *link_options)
{
link_options->rate_10G = !!(speed & AQ_NIC_RATE_10G);
link_options->rate_5G = !!(speed & AQ_NIC_RATE_5G);
link_options->rate_N5G = link_options->rate_5G;
link_options->rate_2P5G = !!(speed & AQ_NIC_RATE_2G5);
link_options->rate_N2P5G = link_options->rate_2P5G;
link_options->rate_1G = !!(speed & AQ_NIC_RATE_1G);
link_options->rate_100M = !!(speed & AQ_NIC_RATE_100M);
link_options->rate_10M = !!(speed & AQ_NIC_RATE_10M);
link_options->rate_1G_hd = !!(speed & AQ_NIC_RATE_1G_HALF);
link_options->rate_100M_hd = !!(speed & AQ_NIC_RATE_100M_HALF);
link_options->rate_10M_hd = !!(speed & AQ_NIC_RATE_10M_HALF);
}
static u32 a2_fw_dev_to_eee_mask(struct device_link_caps_s *device_link_caps)
{
u32 rate = 0;
if (device_link_caps->eee_10G)
rate |= AQ_NIC_RATE_EEE_10G;
if (device_link_caps->eee_5G)
rate |= AQ_NIC_RATE_EEE_5G;
if (device_link_caps->eee_2P5G)
rate |= AQ_NIC_RATE_EEE_2G5;
if (device_link_caps->eee_1G)
rate |= AQ_NIC_RATE_EEE_1G;
if (device_link_caps->eee_100M)
rate |= AQ_NIC_RATE_EEE_100M;
return rate;
}
static u32 a2_fw_lkp_to_mask(struct lkp_link_caps_s *lkp_link_caps)
{
u32 rate = 0;
if (lkp_link_caps->rate_10G)
rate |= AQ_NIC_RATE_10G;
if (lkp_link_caps->rate_5G)
rate |= AQ_NIC_RATE_5G;
if (lkp_link_caps->rate_2P5G)
rate |= AQ_NIC_RATE_2G5;
if (lkp_link_caps->rate_1G)
rate |= AQ_NIC_RATE_1G;
if (lkp_link_caps->rate_1G_hd)
rate |= AQ_NIC_RATE_1G_HALF;
if (lkp_link_caps->rate_100M)
rate |= AQ_NIC_RATE_100M;
if (lkp_link_caps->rate_100M_hd)
rate |= AQ_NIC_RATE_100M_HALF;
if (lkp_link_caps->rate_10M)
rate |= AQ_NIC_RATE_10M;
if (lkp_link_caps->rate_10M_hd)
rate |= AQ_NIC_RATE_10M_HALF;
if (lkp_link_caps->eee_10G)
rate |= AQ_NIC_RATE_EEE_10G;
if (lkp_link_caps->eee_5G)
rate |= AQ_NIC_RATE_EEE_5G;
if (lkp_link_caps->eee_2P5G)
rate |= AQ_NIC_RATE_EEE_2G5;
if (lkp_link_caps->eee_1G)
rate |= AQ_NIC_RATE_EEE_1G;
if (lkp_link_caps->eee_100M)
rate |= AQ_NIC_RATE_EEE_100M;
return rate;
}
static int aq_a2_fw_set_link_speed(struct aq_hw_s *self, u32 speed)
{
struct link_options_s link_options;
hw_atl2_shared_buffer_get(self, link_options, link_options);
link_options.link_up = 1U;
a2_link_speed_mask2fw(speed, &link_options);
hw_atl2_shared_buffer_write(self, link_options, link_options);
return hw_atl2_shared_buffer_finish_ack(self);
}
static void aq_a2_fw_set_mpi_flow_control(struct aq_hw_s *self,
struct link_options_s *link_options)
{
u32 flow_control = self->aq_nic_cfg->fc.req;
link_options->pause_rx = !!(flow_control & AQ_NIC_FC_RX);
link_options->pause_tx = !!(flow_control & AQ_NIC_FC_TX);
}
static void aq_a2_fw_upd_eee_rate_bits(struct aq_hw_s *self,
struct link_options_s *link_options,
u32 eee_speeds)
{
link_options->eee_10G = !!(eee_speeds & AQ_NIC_RATE_EEE_10G);
link_options->eee_5G = !!(eee_speeds & AQ_NIC_RATE_EEE_5G);
link_options->eee_2P5G = !!(eee_speeds & AQ_NIC_RATE_EEE_2G5);
link_options->eee_1G = !!(eee_speeds & AQ_NIC_RATE_EEE_1G);
link_options->eee_100M = !!(eee_speeds & AQ_NIC_RATE_EEE_100M);
}
static int aq_a2_fw_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state)
{
struct link_options_s link_options;
hw_atl2_shared_buffer_get(self, link_options, link_options);
switch (state) {
case MPI_INIT:
link_options.link_up = 1U;
aq_a2_fw_upd_eee_rate_bits(self, &link_options,
self->aq_nic_cfg->eee_speeds);
aq_a2_fw_set_mpi_flow_control(self, &link_options);
break;
case MPI_DEINIT:
link_options.link_up = 0U;
break;
case MPI_RESET:
case MPI_POWER:
/* No actions */
break;
}
hw_atl2_shared_buffer_write(self, link_options, link_options);
return hw_atl2_shared_buffer_finish_ack(self);
}
static int aq_a2_fw_update_link_status(struct aq_hw_s *self)
{
struct lkp_link_caps_s lkp_link_caps;
struct link_status_s link_status;
hw_atl2_shared_buffer_read(self, link_status, link_status);
switch (link_status.link_rate) {
case AQ_A2_FW_LINK_RATE_10G:
self->aq_link_status.mbps = 10000;
break;
case AQ_A2_FW_LINK_RATE_5G:
self->aq_link_status.mbps = 5000;
break;
case AQ_A2_FW_LINK_RATE_2G5:
self->aq_link_status.mbps = 2500;
break;
case AQ_A2_FW_LINK_RATE_1G:
self->aq_link_status.mbps = 1000;
break;
case AQ_A2_FW_LINK_RATE_100M:
self->aq_link_status.mbps = 100;
break;
case AQ_A2_FW_LINK_RATE_10M:
self->aq_link_status.mbps = 10;
break;
default:
self->aq_link_status.mbps = 0;
}
self->aq_link_status.full_duplex = link_status.duplex;
hw_atl2_shared_buffer_read(self, lkp_link_caps, lkp_link_caps);
self->aq_link_status.lp_link_speed_msk =
a2_fw_lkp_to_mask(&lkp_link_caps);
self->aq_link_status.lp_flow_control =
((lkp_link_caps.pause_rx) ? AQ_NIC_FC_RX : 0) |
((lkp_link_caps.pause_tx) ? AQ_NIC_FC_TX : 0);
return 0;
}
static int aq_a2_fw_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
{
struct mac_address_aligned_s mac_address;
hw_atl2_shared_buffer_get(self, mac_address, mac_address);
ether_addr_copy(mac, (u8 *)mac_address.aligned.mac_address);
return 0;
}
static void aq_a2_fill_a0_stats(struct aq_hw_s *self,
struct statistics_s *stats)
{
struct hw_atl2_priv *priv = self->priv;
struct aq_stats_s *cs = &self->curr_stats;
struct aq_stats_s curr_stats = *cs;
bool corrupted_stats = false;
#define AQ_SDELTA(_N, _F) \
do { \
if (!corrupted_stats && \
((s64)(stats->a0.msm._F - priv->last_stats.a0.msm._F)) >= 0) \
curr_stats._N += stats->a0.msm._F - priv->last_stats.a0.msm._F;\
else \
corrupted_stats = true; \
} while (0)
if (self->aq_link_status.mbps) {
AQ_SDELTA(uprc, rx_unicast_frames);
AQ_SDELTA(mprc, rx_multicast_frames);
AQ_SDELTA(bprc, rx_broadcast_frames);
AQ_SDELTA(erpr, rx_error_frames);
AQ_SDELTA(uptc, tx_unicast_frames);
AQ_SDELTA(mptc, tx_multicast_frames);
AQ_SDELTA(bptc, tx_broadcast_frames);
AQ_SDELTA(erpt, tx_errors);
AQ_SDELTA(ubrc, rx_unicast_octets);
AQ_SDELTA(ubtc, tx_unicast_octets);
AQ_SDELTA(mbrc, rx_multicast_octets);
AQ_SDELTA(mbtc, tx_multicast_octets);
AQ_SDELTA(bbrc, rx_broadcast_octets);
AQ_SDELTA(bbtc, tx_broadcast_octets);
if (!corrupted_stats)
*cs = curr_stats;
}
#undef AQ_SDELTA
}
static void aq_a2_fill_b0_stats(struct aq_hw_s *self,
struct statistics_s *stats)
{
struct hw_atl2_priv *priv = self->priv;
struct aq_stats_s *cs = &self->curr_stats;
struct aq_stats_s curr_stats = *cs;
bool corrupted_stats = false;
#define AQ_SDELTA(_N, _F) \
do { \
if (!corrupted_stats && \
((s64)(stats->b0._F - priv->last_stats.b0._F)) >= 0) \
curr_stats._N += stats->b0._F - priv->last_stats.b0._F; \
else \
corrupted_stats = true; \
} while (0)
if (self->aq_link_status.mbps) {
AQ_SDELTA(uprc, rx_unicast_frames);
AQ_SDELTA(mprc, rx_multicast_frames);
AQ_SDELTA(bprc, rx_broadcast_frames);
AQ_SDELTA(erpr, rx_errors);
AQ_SDELTA(brc, rx_good_octets);
AQ_SDELTA(uptc, tx_unicast_frames);
AQ_SDELTA(mptc, tx_multicast_frames);
AQ_SDELTA(bptc, tx_broadcast_frames);
AQ_SDELTA(erpt, tx_errors);
AQ_SDELTA(btc, tx_good_octets);
if (!corrupted_stats)
*cs = curr_stats;
}
#undef AQ_SDELTA
}
static int aq_a2_fw_update_stats(struct aq_hw_s *self)
{
struct aq_stats_s *cs = &self->curr_stats;
struct hw_atl2_priv *priv = self->priv;
struct statistics_s stats;
struct version_s version;
int err;
err = hw_atl2_shared_buffer_read_safe(self, version, &version);
if (err)
return err;
err = hw_atl2_shared_buffer_read_safe(self, stats, &stats);
if (err)
return err;
if (version.drv_iface_ver == AQ_A2_FW_INTERFACE_A0)
aq_a2_fill_a0_stats(self, &stats);
else
aq_a2_fill_b0_stats(self, &stats);
cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self);
cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self);
cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self);
cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self);
cs->dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
memcpy(&priv->last_stats, &stats, sizeof(stats));
return 0;
}
static int aq_a2_fw_get_phy_temp(struct aq_hw_s *self, int *temp)
{
struct phy_health_monitor_s phy_health_monitor;
hw_atl2_shared_buffer_read_safe(self, phy_health_monitor,
&phy_health_monitor);
*temp = (int8_t)phy_health_monitor.phy_temperature * 1000;
return 0;
}
static int aq_a2_fw_get_mac_temp(struct aq_hw_s *self, int *temp)
{
/* There's only one temperature sensor on A2, use it for
* both MAC and PHY.
*/
return aq_a2_fw_get_phy_temp(self, temp);
}
static int aq_a2_fw_set_wol_params(struct aq_hw_s *self, const u8 *mac, u32 wol)
{
struct mac_address_aligned_s mac_address;
struct link_control_s link_control;
struct wake_on_lan_s wake_on_lan;
memcpy(mac_address.aligned.mac_address, mac, ETH_ALEN);
hw_atl2_shared_buffer_write(self, mac_address, mac_address);
memset(&wake_on_lan, 0, sizeof(wake_on_lan));
if (wol & WAKE_MAGIC)
wake_on_lan.wake_on_magic_packet = 1U;
if (wol & (WAKE_PHY | AQ_FW_WAKE_ON_LINK_RTPM))
wake_on_lan.wake_on_link_up = 1U;
hw_atl2_shared_buffer_write(self, sleep_proxy, wake_on_lan);
hw_atl2_shared_buffer_get(self, link_control, link_control);
link_control.mode = AQ_HOST_MODE_SLEEP_PROXY;
hw_atl2_shared_buffer_write(self, link_control, link_control);
return hw_atl2_shared_buffer_finish_ack(self);
}
static int aq_a2_fw_set_power(struct aq_hw_s *self, unsigned int power_state,
const u8 *mac)
{
u32 wol = self->aq_nic_cfg->wol;
int err = 0;
if (wol)
err = aq_a2_fw_set_wol_params(self, mac, wol);
return err;
}
static int aq_a2_fw_set_eee_rate(struct aq_hw_s *self, u32 speed)
{
struct link_options_s link_options;
hw_atl2_shared_buffer_get(self, link_options, link_options);
aq_a2_fw_upd_eee_rate_bits(self, &link_options, speed);
hw_atl2_shared_buffer_write(self, link_options, link_options);
return hw_atl2_shared_buffer_finish_ack(self);
}
static int aq_a2_fw_get_eee_rate(struct aq_hw_s *self, u32 *rate,
u32 *supported_rates)
{
struct device_link_caps_s device_link_caps;
struct lkp_link_caps_s lkp_link_caps;
hw_atl2_shared_buffer_read(self, device_link_caps, device_link_caps);
hw_atl2_shared_buffer_read(self, lkp_link_caps, lkp_link_caps);
*supported_rates = a2_fw_dev_to_eee_mask(&device_link_caps);
*rate = a2_fw_lkp_to_mask(&lkp_link_caps);
return 0;
}
static int aq_a2_fw_renegotiate(struct aq_hw_s *self)
{
struct link_options_s link_options;
int err;
hw_atl2_shared_buffer_get(self, link_options, link_options);
link_options.link_renegotiate = 1U;
hw_atl2_shared_buffer_write(self, link_options, link_options);
err = hw_atl2_shared_buffer_finish_ack(self);
/* We should put renegotiate status back to zero
* after command completes
*/
link_options.link_renegotiate = 0U;
hw_atl2_shared_buffer_write(self, link_options, link_options);
return err;
}
static int aq_a2_fw_set_flow_control(struct aq_hw_s *self)
{
struct link_options_s link_options;
hw_atl2_shared_buffer_get(self, link_options, link_options);
aq_a2_fw_set_mpi_flow_control(self, &link_options);
hw_atl2_shared_buffer_write(self, link_options, link_options);
return hw_atl2_shared_buffer_finish_ack(self);
}
static u32 aq_a2_fw_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
{
struct link_status_s link_status;
hw_atl2_shared_buffer_read(self, link_status, link_status);
*fcmode = ((link_status.pause_rx) ? AQ_NIC_FC_RX : 0) |
((link_status.pause_tx) ? AQ_NIC_FC_TX : 0);
return 0;
}
static int aq_a2_fw_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable)
{
struct link_options_s link_options;
hw_atl2_shared_buffer_get(self, link_options, link_options);
switch (mode) {
case AQ_HW_LOOPBACK_PHYINT_SYS:
link_options.internal_loopback = enable;
break;
case AQ_HW_LOOPBACK_PHYEXT_SYS:
link_options.external_loopback = enable;
break;
default:
return -EINVAL;
}
hw_atl2_shared_buffer_write(self, link_options, link_options);
return hw_atl2_shared_buffer_finish_ack(self);
}
u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self)
{
struct version_s version;
hw_atl2_shared_buffer_read_safe(self, version, &version);
/* A2 FW version is stored in reverse order */
return version.bundle.major << 24 |
version.bundle.minor << 16 |
version.bundle.build;
}
int hw_atl2_utils_get_filter_caps(struct aq_hw_s *self)
{
struct hw_atl2_priv *priv = self->priv;
struct filter_caps_s filter_caps;
u32 tag_top;
int err;
err = hw_atl2_shared_buffer_read_safe(self, filter_caps, &filter_caps);
if (err)
return err;
priv->art_base_index = filter_caps.rslv_tbl_base_index * 8;
priv->art_count = filter_caps.rslv_tbl_count * 8;
if (priv->art_count == 0)
priv->art_count = HW_ATL2_ART_TOTAL_ENTRIES;
priv->l2_filters_base_index = filter_caps.l2_filters_base_index;
if (priv->l2_filters_base_index >= HW_ATL2_MAC_MAX)
priv->l2_filters_base_index = HW_ATL2_MAC_UC;
priv->l2_filter_count = filter_caps.l2_filter_count;
priv->etype_filter_base_index = filter_caps.ethertype_filter_base_index;
priv->etype_filter_count = filter_caps.ethertype_filter_count;
priv->etype_filter_tag_top =
(priv->etype_filter_count >= HW_ATL2_RPF_ETYPE_TAGS) ?
(HW_ATL2_RPF_ETYPE_TAGS) : (HW_ATL2_RPF_ETYPE_TAGS >> 1);
priv->vlan_filter_base_index = filter_caps.vlan_filter_base_index;
/* 0 - no tag, 1 - reserved for vlan-filter-offload filters */
tag_top =
(filter_caps.vlan_filter_count == HW_ATL2_RPF_VLAN_FILTERS) ?
(HW_ATL2_RPF_VLAN_FILTERS - 2) :
(HW_ATL2_RPF_VLAN_FILTERS / 2 - 2);
if (filter_caps.vlan_filter_count > 2) {
priv->vlan_filter_count = min_t(u32,
filter_caps.vlan_filter_count - 2,
tag_top);
} else {
pr_debug("atlantic: FW vlan_filter_count=%u <= 2, no usable VLAN filters\n",
filter_caps.vlan_filter_count);
priv->vlan_filter_count = 0;
}
priv->l3_v4_filter_base_index = filter_caps.l3_ip4_filter_base_index;
if (priv->l3_v4_filter_base_index >= HW_ATL2_RPF_L3V4_FILTERS) {
priv->l3_v4_filter_base_index = 0;
priv->l3_v4_filter_count = 0;
} else {
priv->l3_v4_filter_count = min_t(u32,
filter_caps.l3_ip4_filter_count,
HW_ATL2_RPF_L3V4_FILTERS - 1);
}
priv->l3_v6_filter_base_index = filter_caps.l3_ip6_filter_base_index;
if (priv->l3_v6_filter_base_index >= HW_ATL2_RPF_L3V6_FILTERS) {
priv->l3_v6_filter_base_index = 0;
priv->l3_v6_filter_count = 0;
} else {
priv->l3_v6_filter_count = min_t(u32,
filter_caps.l3_ip6_filter_count,
HW_ATL2_RPF_L3V6_FILTERS - 1);
}
priv->l4_filter_base_index = filter_caps.l4_filter_base_index;
if (priv->l4_filter_base_index >= HW_ATL2_RPF_L4_FILTERS) {
priv->l4_filter_base_index = 0;
priv->l4_filter_count = 0;
} else {
priv->l4_filter_count = min_t(u32,
filter_caps.l4_filter_count,
HW_ATL2_RPF_L4_FILTERS - 1);
}
return 0;
}
static int aq_a2_fw_set_downshift(struct aq_hw_s *self, u32 counter)
{
struct link_options_s link_options;
hw_atl2_shared_buffer_get(self, link_options, link_options);
link_options.downshift = !!counter;
link_options.downshift_retry = counter;
hw_atl2_shared_buffer_write(self, link_options, link_options);
return hw_atl2_shared_buffer_finish_ack(self);
}
const struct aq_fw_ops aq_a2_fw_ops = {
.init = aq_a2_fw_init,
.deinit = aq_a2_fw_deinit,
.reset = NULL,
.renegotiate = aq_a2_fw_renegotiate,
.get_mac_permanent = aq_a2_fw_get_mac_permanent,
.set_link_speed = aq_a2_fw_set_link_speed,
.set_state = aq_a2_fw_set_state,
.update_link_status = aq_a2_fw_update_link_status,
.update_stats = aq_a2_fw_update_stats,
.set_power = aq_a2_fw_set_power,
.get_mac_temp = aq_a2_fw_get_mac_temp,
.get_phy_temp = aq_a2_fw_get_phy_temp,
.set_eee_rate = aq_a2_fw_set_eee_rate,
.get_eee_rate = aq_a2_fw_get_eee_rate,
.set_flow_control = aq_a2_fw_set_flow_control,
.get_flow_control = aq_a2_fw_get_flow_control,
.set_phyloopback = aq_a2_fw_set_phyloopback,
.set_downshift = aq_a2_fw_set_downshift,
};
@@ -0,0 +1,73 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef MSS_EGRESS_REGS_HEADER
#define MSS_EGRESS_REGS_HEADER
#define MSS_EGRESS_CTL_REGISTER_ADDR 0x00005002
#define MSS_EGRESS_SA_EXPIRED_STATUS_REGISTER_ADDR 0x00005060
#define MSS_EGRESS_SA_THRESHOLD_EXPIRED_STATUS_REGISTER_ADDR 0x00005062
#define MSS_EGRESS_LUT_ADDR_CTL_REGISTER_ADDR 0x00005080
#define MSS_EGRESS_LUT_CTL_REGISTER_ADDR 0x00005081
#define MSS_EGRESS_LUT_DATA_CTL_REGISTER_ADDR 0x000050A0
struct mss_egress_ctl_register {
union {
struct {
unsigned int soft_reset : 1;
unsigned int drop_kay_packet : 1;
unsigned int drop_egprc_lut_miss : 1;
unsigned int gcm_start : 1;
unsigned int gcm_test_mode : 1;
unsigned int unmatched_use_sc_0 : 1;
unsigned int drop_invalid_sa_sc_packets : 1;
unsigned int reserved0 : 1;
/* Should always be set to 0. */
unsigned int external_classification_enable : 1;
unsigned int icv_lsb_8bytes_enable : 1;
unsigned int high_prio : 1;
unsigned int clear_counter : 1;
unsigned int clear_global_time : 1;
unsigned int ethertype_explicit_sectag_lsb : 3;
} bits_0;
unsigned short word_0;
};
union {
struct {
unsigned int ethertype_explicit_sectag_msb : 13;
unsigned int reserved0 : 3;
} bits_1;
unsigned short word_1;
};
};
struct mss_egress_lut_addr_ctl_register {
union {
struct {
unsigned int lut_addr : 9;
unsigned int reserved0 : 3;
/* 0x0 : Egress MAC Control FIlter (CTLF) LUT
* 0x1 : Egress Classification LUT
* 0x2 : Egress SC/SA LUT
* 0x3 : Egress SMIB
*/
unsigned int lut_select : 4;
} bits_0;
unsigned short word_0;
};
};
struct mss_egress_lut_ctl_register {
union {
struct {
unsigned int reserved0 : 14;
unsigned int lut_read : 1;
unsigned int lut_write : 1;
} bits_0;
unsigned short word_0;
};
};
#endif /* MSS_EGRESS_REGS_HEADER */
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef MSS_INGRESS_REGS_HEADER
#define MSS_INGRESS_REGS_HEADER
#define MSS_INGRESS_CTL_REGISTER_ADDR 0x0000800E
#define MSS_INGRESS_LUT_ADDR_CTL_REGISTER_ADDR 0x00008080
#define MSS_INGRESS_LUT_CTL_REGISTER_ADDR 0x00008081
#define MSS_INGRESS_LUT_DATA_CTL_REGISTER_ADDR 0x000080A0
struct mss_ingress_ctl_register {
union {
struct {
unsigned int soft_reset : 1;
unsigned int operation_point_to_point : 1;
unsigned int create_sci : 1;
/* Unused */
unsigned int mask_short_length_error : 1;
unsigned int drop_kay_packet : 1;
unsigned int drop_igprc_miss : 1;
/* Unused */
unsigned int check_icv : 1;
unsigned int clear_global_time : 1;
unsigned int clear_count : 1;
unsigned int high_prio : 1;
unsigned int remove_sectag : 1;
unsigned int global_validate_frames : 2;
unsigned int icv_lsb_8bytes_enabled : 1;
unsigned int reserved0 : 2;
} bits_0;
unsigned short word_0;
};
union {
struct {
unsigned int reserved0 : 16;
} bits_1;
unsigned short word_1;
};
};
struct mss_ingress_lut_addr_ctl_register {
union {
struct {
unsigned int lut_addr : 9;
unsigned int reserved0 : 3;
/* 0x0 : Ingress Pre-Security MAC Control FIlter
* (IGPRCTLF) LUT
* 0x1 : Ingress Pre-Security Classification LUT (IGPRC)
* 0x2 : Ingress Packet Format (IGPFMT) SAKey LUT
* 0x3 : Ingress Packet Format (IGPFMT) SC/SA LUT
* 0x4 : Ingress Post-Security Classification LUT
* (IGPOC)
* 0x5 : Ingress Post-Security MAC Control Filter
* (IGPOCTLF) LUT
* 0x6 : Ingress MIB (IGMIB)
*/
unsigned int lut_select : 4;
} bits_0;
unsigned short word_0;
};
};
struct mss_ingress_lut_ctl_register {
union {
struct {
unsigned int reserved0 : 14;
unsigned int lut_read : 1;
unsigned int lut_write : 1;
} bits_0;
unsigned short word_0;
};
};
#endif /* MSS_INGRESS_REGS_HEADER */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,323 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef __MACSEC_API_H__
#define __MACSEC_API_H__
#include "aq_hw.h"
#include "macsec_struct.h"
#define NUMROWS_INGRESSPRECTLFRECORD 24
#define ROWOFFSET_INGRESSPRECTLFRECORD 0
#define NUMROWS_INGRESSPRECLASSRECORD 48
#define ROWOFFSET_INGRESSPRECLASSRECORD 0
#define NUMROWS_INGRESSPOSTCLASSRECORD 48
#define ROWOFFSET_INGRESSPOSTCLASSRECORD 0
#define NUMROWS_INGRESSSCRECORD 32
#define ROWOFFSET_INGRESSSCRECORD 0
#define NUMROWS_INGRESSSARECORD 32
#define ROWOFFSET_INGRESSSARECORD 32
#define NUMROWS_INGRESSSAKEYRECORD 32
#define ROWOFFSET_INGRESSSAKEYRECORD 0
#define NUMROWS_INGRESSPOSTCTLFRECORD 24
#define ROWOFFSET_INGRESSPOSTCTLFRECORD 0
#define NUMROWS_EGRESSCTLFRECORD 24
#define ROWOFFSET_EGRESSCTLFRECORD 0
#define NUMROWS_EGRESSCLASSRECORD 48
#define ROWOFFSET_EGRESSCLASSRECORD 0
#define NUMROWS_EGRESSSCRECORD 32
#define ROWOFFSET_EGRESSSCRECORD 0
#define NUMROWS_EGRESSSARECORD 32
#define ROWOFFSET_EGRESSSARECORD 32
#define NUMROWS_EGRESSSAKEYRECORD 32
#define ROWOFFSET_EGRESSSAKEYRECORD 96
/*! Read the raw table data from the specified row of the Egress CTL
* Filter table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 23).
*/
int aq_mss_get_egress_ctlf_record(struct aq_hw_s *hw,
struct aq_mss_egress_ctlf_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Egress CTL Filter table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write(max 23).
*/
int aq_mss_set_egress_ctlf_record(struct aq_hw_s *hw,
const struct aq_mss_egress_ctlf_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Egress
* Packet Classifier table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 47).
*/
int aq_mss_get_egress_class_record(struct aq_hw_s *hw,
struct aq_mss_egress_class_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Egress Packet Classifier table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write (max 47).
*/
int aq_mss_set_egress_class_record(struct aq_hw_s *hw,
const struct aq_mss_egress_class_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Egress SC
* Lookup table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 31).
*/
int aq_mss_get_egress_sc_record(struct aq_hw_s *hw,
struct aq_mss_egress_sc_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Egress SC Lookup table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write (max 31).
*/
int aq_mss_set_egress_sc_record(struct aq_hw_s *hw,
const struct aq_mss_egress_sc_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Egress SA
* Lookup table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 31).
*/
int aq_mss_get_egress_sa_record(struct aq_hw_s *hw,
struct aq_mss_egress_sa_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Egress SA Lookup table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write (max 31).
*/
int aq_mss_set_egress_sa_record(struct aq_hw_s *hw,
const struct aq_mss_egress_sa_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Egress SA
* Key Lookup table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 31).
*/
int aq_mss_get_egress_sakey_record(struct aq_hw_s *hw,
struct aq_mss_egress_sakey_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Egress SA Key Lookup table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write (max 31).
*/
int aq_mss_set_egress_sakey_record(struct aq_hw_s *hw,
const struct aq_mss_egress_sakey_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Ingress
* Pre-MACSec CTL Filter table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 23).
*/
int aq_mss_get_ingress_prectlf_record(struct aq_hw_s *hw,
struct aq_mss_ingress_prectlf_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Ingress Pre-MACSec CTL Filter table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write(max 23).
*/
int aq_mss_set_ingress_prectlf_record(struct aq_hw_s *hw,
const struct aq_mss_ingress_prectlf_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Ingress
* Pre-MACSec Packet Classifier table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 47).
*/
int aq_mss_get_ingress_preclass_record(struct aq_hw_s *hw,
struct aq_mss_ingress_preclass_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Ingress Pre-MACSec Packet Classifier table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write(max 47).
*/
int aq_mss_set_ingress_preclass_record(struct aq_hw_s *hw,
const struct aq_mss_ingress_preclass_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Ingress SC
* Lookup table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 31).
*/
int aq_mss_get_ingress_sc_record(struct aq_hw_s *hw,
struct aq_mss_ingress_sc_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Ingress SC Lookup table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write(max 31).
*/
int aq_mss_set_ingress_sc_record(struct aq_hw_s *hw,
const struct aq_mss_ingress_sc_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Ingress SA
* Lookup table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 31).
*/
int aq_mss_get_ingress_sa_record(struct aq_hw_s *hw,
struct aq_mss_ingress_sa_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Ingress SA Lookup table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write(max 31).
*/
int aq_mss_set_ingress_sa_record(struct aq_hw_s *hw,
const struct aq_mss_ingress_sa_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Ingress SA
* Key Lookup table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 31).
*/
int aq_mss_get_ingress_sakey_record(struct aq_hw_s *hw,
struct aq_mss_ingress_sakey_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Ingress SA Key Lookup table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write(max 31).
*/
int aq_mss_set_ingress_sakey_record(struct aq_hw_s *hw,
const struct aq_mss_ingress_sakey_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Ingress
* Post-MACSec Packet Classifier table, and unpack it into the
* fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 48).
*/
int aq_mss_get_ingress_postclass_record(struct aq_hw_s *hw,
struct aq_mss_ingress_postclass_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Ingress Post-MACSec Packet Classifier table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write(max 48).
*/
int aq_mss_set_ingress_postclass_record(struct aq_hw_s *hw,
const struct aq_mss_ingress_postclass_record *rec,
u16 table_index);
/*! Read the raw table data from the specified row of the Ingress
* Post-MACSec CTL Filter table, and unpack it into the fields of rec.
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
* table_index - The table row to read (max 23).
*/
int aq_mss_get_ingress_postctlf_record(struct aq_hw_s *hw,
struct aq_mss_ingress_postctlf_record *rec,
u16 table_index);
/*! Pack the fields of rec, and write the packed data into the
* specified row of the Ingress Post-MACSec CTL Filter table.
* rec - [IN] The bitfield values to write to the table row.
* table_index - The table row to write(max 23).
*/
int aq_mss_set_ingress_postctlf_record(struct aq_hw_s *hw,
const struct aq_mss_ingress_postctlf_record *rec,
u16 table_index);
/*! Read the counters for the specified SC, and unpack them into the
* fields of counters.
* counters - [OUT] The raw table row data will be unpacked here.
* sc_index - The table row to read (max 31).
*/
int aq_mss_get_egress_sc_counters(struct aq_hw_s *hw,
struct aq_mss_egress_sc_counters *counters,
u16 sc_index);
/*! Read the counters for the specified SA, and unpack them into the
* fields of counters.
* counters - [OUT] The raw table row data will be unpacked here.
* sa_index - The table row to read (max 31).
*/
int aq_mss_get_egress_sa_counters(struct aq_hw_s *hw,
struct aq_mss_egress_sa_counters *counters,
u16 sa_index);
/*! Read the counters for the common egress counters, and unpack them
* into the fields of counters.
* counters - [OUT] The raw table row data will be unpacked here.
*/
int aq_mss_get_egress_common_counters(struct aq_hw_s *hw,
struct aq_mss_egress_common_counters *counters);
/*! Clear all Egress counters to 0.*/
int aq_mss_clear_egress_counters(struct aq_hw_s *hw);
/*! Read the counters for the specified SA, and unpack them into the
* fields of counters.
* counters - [OUT] The raw table row data will be unpacked here.
* sa_index - The table row to read (max 31).
*/
int aq_mss_get_ingress_sa_counters(struct aq_hw_s *hw,
struct aq_mss_ingress_sa_counters *counters,
u16 sa_index);
/*! Read the counters for the common ingress counters, and unpack them
* into the fields of counters.
* counters - [OUT] The raw table row data will be unpacked here.
*/
int aq_mss_get_ingress_common_counters(struct aq_hw_s *hw,
struct aq_mss_ingress_common_counters *counters);
/*! Clear all Ingress counters to 0. */
int aq_mss_clear_ingress_counters(struct aq_hw_s *hw);
/*! Get Egress SA expired. */
int aq_mss_get_egress_sa_expired(struct aq_hw_s *hw, u32 *expired);
/*! Get Egress SA threshold expired. */
int aq_mss_get_egress_sa_threshold_expired(struct aq_hw_s *hw,
u32 *expired);
/*! Set Egress SA expired. */
int aq_mss_set_egress_sa_expired(struct aq_hw_s *hw, u32 expired);
/*! Set Egress SA threshold expired. */
int aq_mss_set_egress_sa_threshold_expired(struct aq_hw_s *hw,
u32 expired);
#endif /* __MACSEC_API_H__ */
@@ -0,0 +1,914 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
* Copyright (C) 2020 Marvell International Ltd.
*/
#ifndef _MACSEC_STRUCT_H_
#define _MACSEC_STRUCT_H_
/*! Represents the bitfields of a single row in the Egress CTL Filter
* table.
*/
struct aq_mss_egress_ctlf_record {
/*! This is used to store the 48 bit value used to compare SA, DA or
* halfDA+half SA value.
*/
u32 sa_da[2];
/*! This is used to store the 16 bit ethertype value used for
* comparison.
*/
u32 eth_type;
/*! The match mask is per-nibble. 0 means don't care, i.e. every value
* will match successfully. The total data is 64 bit, i.e. 16 nibbles
* masks.
*/
u32 match_mask;
/*! 0: No compare, i.e. This entry is not used
* 1: compare DA only
* 2: compare SA only
* 3: compare half DA + half SA
* 4: compare ether type only
* 5: compare DA + ethertype
* 6: compare SA + ethertype
* 7: compare DA+ range.
*/
u32 match_type;
/*! 0: Bypass the remaining modules if matched.
* 1: Forward to next module for more classifications.
*/
u32 action;
};
/*! Represents the bitfields of a single row in the Egress Packet
* Classifier table.
*/
struct aq_mss_egress_class_record {
/*! VLAN ID field. */
u32 vlan_id;
/*! VLAN UP field. */
u32 vlan_up;
/*! VLAN Present in the Packet. */
u32 vlan_valid;
/*! The 8 bit value used to compare with extracted value for byte 3. */
u32 byte3;
/*! The 8 bit value used to compare with extracted value for byte 2. */
u32 byte2;
/*! The 8 bit value used to compare with extracted value for byte 1. */
u32 byte1;
/*! The 8 bit value used to compare with extracted value for byte 0. */
u32 byte0;
/*! The 8 bit TCI field used to compare with extracted value. */
u32 tci;
/*! The 64 bit SCI field in the SecTAG. */
u32 sci[2];
/*! The 16 bit Ethertype (in the clear) field used to compare with
* extracted value.
*/
u32 eth_type;
/*! This is to specify the 40bit SNAP header if the SNAP header's mask
* is enabled.
*/
u32 snap[2];
/*! This is to specify the 24bit LLC header if the LLC header's mask is
* enabled.
*/
u32 llc;
/*! The 48 bit MAC_SA field used to compare with extracted value. */
u32 mac_sa[2];
/*! The 48 bit MAC_DA field used to compare with extracted value. */
u32 mac_da[2];
/*! The 32 bit Packet number used to compare with extracted value. */
u32 pn;
/*! 0~63: byte location used extracted by packets comparator, which
* can be anything from the first 64 bytes of the MAC packets.
* This byte location counted from MAC' DA address. i.e. set to 0
* will point to byte 0 of DA address.
*/
u32 byte3_location;
/*! 0: don't care
* 1: enable comparison of extracted byte pointed by byte 3 location.
*/
u32 byte3_mask;
/*! 0~63: byte location used extracted by packets comparator, which
* can be anything from the first 64 bytes of the MAC packets.
* This byte location counted from MAC' DA address. i.e. set to 0
* will point to byte 0 of DA address.
*/
u32 byte2_location;
/*! 0: don't care
* 1: enable comparison of extracted byte pointed by byte 2 location.
*/
u32 byte2_mask;
/*! 0~63: byte location used extracted by packets comparator, which
* can be anything from the first 64 bytes of the MAC packets.
* This byte location counted from MAC' DA address. i.e. set to 0
* will point to byte 0 of DA address.
*/
u32 byte1_location;
/*! 0: don't care
* 1: enable comparison of extracted byte pointed by byte 1 location.
*/
u32 byte1_mask;
/*! 0~63: byte location used extracted by packets comparator, which
* can be anything from the first 64 bytes of the MAC packets.
* This byte location counted from MAC' DA address. i.e. set to 0
* will point to byte 0 of DA address.
*/
u32 byte0_location;
/*! 0: don't care
* 1: enable comparison of extracted byte pointed by byte 0 location.
*/
u32 byte0_mask;
/*! Mask is per-byte.
* 0: don't care
* 1: enable comparison of extracted VLAN ID field.
*/
u32 vlan_id_mask;
/*! 0: don't care
* 1: enable comparison of extracted VLAN UP field.
*/
u32 vlan_up_mask;
/*! 0: don't care
* 1: enable comparison of extracted VLAN Valid field.
*/
u32 vlan_valid_mask;
/*! This is bit mask to enable comparison the 8 bit TCI field,
* including the AN field.
* For explicit SECTAG, AN is hardware controlled. For sending
* packet w/ explicit SECTAG, rest of the TCI fields are directly
* from the SECTAG.
*/
u32 tci_mask;
/*! Mask is per-byte.
* 0: don't care
* 1: enable comparison of SCI
* Note: If this field is not 0, this means the input packet's
* SECTAG is explicitly tagged and MACSEC module will only update
* the MSDU.
* PN number is hardware controlled.
*/
u32 sci_mask;
/*! Mask is per-byte.
* 0: don't care
* 1: enable comparison of Ethertype.
*/
u32 eth_type_mask;
/*! Mask is per-byte.
* 0: don't care and no SNAP header exist.
* 1: compare the SNAP header.
* If this bit is set to 1, the extracted filed will assume the
* SNAP header exist as encapsulated in 802.3 (RFC 1042). I.E. the
* next 5 bytes after the LLC header is SNAP header.
*/
u32 snap_mask;
/*! 0: don't care and no LLC header exist.
* 1: compare the LLC header.
* If this bit is set to 1, the extracted filed will assume the
* LLC header exist as encapsulated in 802.3 (RFC 1042). I.E. the
* next three bytes after the 802.3MAC header is LLC header.
*/
u32 llc_mask;
/*! Mask is per-byte.
* 0: don't care
* 1: enable comparison of MAC_SA.
*/
u32 sa_mask;
/*! Mask is per-byte.
* 0: don't care
* 1: enable comparison of MAC_DA.
*/
u32 da_mask;
/*! Mask is per-byte. */
u32 pn_mask;
/*! Reserved. This bit should be always 0. */
u32 eight02dot2;
/*! 1: For explicit sectag case use TCI_SC from table
* 0: use TCI_SC from explicit sectag.
*/
u32 tci_sc;
/*! 1: For explicit sectag case,use TCI_V,ES,SCB,E,C from table
* 0: use TCI_V,ES,SCB,E,C from explicit sectag.
*/
u32 tci_87543;
/*! 1: indicates that incoming packet has explicit sectag. */
u32 exp_sectag_en;
/*! If packet matches and tagged as controlled-packet, this SC/SA
* index is used for later SC and SA table lookup.
*/
u32 sc_idx;
/*! This field is used to specify how many SA entries are
* associated with 1 SC entry.
* 2'b00: 1 SC has 4 SA.
* SC index is equivalent to {SC_Index[4:2], 1'b0}.
* SA index is equivalent to {SC_Index[4:2], SC entry's current AN[1:0]
* 2'b10: 1 SC has 2 SA.
* SC index is equivalent to SC_Index[4:1]
* SA index is equivalent to {SC_Index[4:1], SC entry's current AN[0]}
* 2'b11: 1 SC has 1 SA. No SC entry exists for the specific SA.
* SA index is equivalent to SC_Index[4:0]
* Note: if specified as 2'b11, hardware AN roll over is not
* supported.
*/
u32 sc_sa;
/*! 0: the packets will be sent to MAC FIFO
* 1: The packets will be sent to Debug/Loopback FIFO.
* If the above's action is drop, this bit has no meaning.
*/
u32 debug;
/*! 0: forward to remaining modules
* 1: bypass the next encryption modules. This packet is considered
* un-control packet.
* 2: drop
* 3: Reserved.
*/
u32 action;
/*! 0: Not valid entry. This entry is not used
* 1: valid entry.
*/
u32 valid;
};
/*! Represents the bitfields of a single row in the Egress SC Lookup table. */
struct aq_mss_egress_sc_record {
/*! This is to specify when the SC was first used. Set by HW. */
u32 start_time;
/*! This is to specify when the SC was last used. Set by HW. */
u32 stop_time;
/*! This is to specify which of the SA entries are used by current HW.
* Note: This value need to be set by SW after reset. It will be
* automatically updated by HW, if AN roll over is enabled.
*/
u32 curr_an;
/*! 0: Clear the SA Valid Bit after PN expiry.
* 1: Do not Clear the SA Valid bit after PN expiry of the current SA.
* When the Enable AN roll over is set, S/W does not need to
* program the new SA's and the H/W will automatically roll over
* between the SA's without session expiry.
* For normal operation, Enable AN Roll over will be set to '0'
* and in which case, the SW needs to program the new SA values
* after the current PN expires.
*/
u32 an_roll;
/*! This is the TCI field used if packet is not explicitly tagged. */
u32 tci;
/*! This value indicates the offset where the decryption will start.
* [[Values of 0, 4, 8-50].
*/
u32 enc_off;
/*! 0: Do not protect frames, all the packets will be forwarded
* unchanged. MIB counter (OutPktsUntagged) will be updated.
* 1: Protect.
*/
u32 protect;
/*! 0: when none of the SA related to SC has inUse set.
* 1: when either of the SA related to the SC has inUse set.
* This bit is set by HW.
*/
u32 recv;
/*! 0: H/W Clears this bit on the first use.
* 1: SW updates this entry, when programming the SC Table.
*/
u32 fresh;
/*! AES Key size
* 00 - 128bits
* 01 - 192bits
* 10 - 256bits
* 11 - Reserved.
*/
u32 sak_len;
/*! 0: Invalid SC
* 1: Valid SC.
*/
u32 valid;
};
/*! Represents the bitfields of a single row in the Egress SA Lookup table. */
struct aq_mss_egress_sa_record {
/*! This is to specify when the SC was first used. Set by HW. */
u32 start_time;
/*! This is to specify when the SC was last used. Set by HW. */
u32 stop_time;
/*! This is set by SW and updated by HW to store the Next PN number
* used for encryption.
*/
u32 next_pn;
/*! The Next_PN number is going to wrapped around from 0xFFFF_FFFF
* to 0. set by HW.
*/
u32 sat_pn;
/*! 0: This SA is in use.
* 1: This SA is Fresh and set by SW.
*/
u32 fresh;
/*! 0: Invalid SA
* 1: Valid SA.
*/
u32 valid;
};
/*! Represents the bitfields of a single row in the Egress SA Key
* Lookup table.
*/
struct aq_mss_egress_sakey_record {
/*! Key for AES-GCM processing. */
u32 key[8];
};
/*! Represents the bitfields of a single row in the Ingress Pre-MACSec
* CTL Filter table.
*/
struct aq_mss_ingress_prectlf_record {
/*! This is used to store the 48 bit value used to compare SA, DA
* or halfDA+half SA value.
*/
u32 sa_da[2];
/*! This is used to store the 16 bit ethertype value used for
* comparison.
*/
u32 eth_type;
/*! The match mask is per-nibble. 0 means don't care, i.e. every
* value will match successfully. The total data is 64 bit, i.e.
* 16 nibbles masks.
*/
u32 match_mask;
/*! 0: No compare, i.e. This entry is not used
* 1: compare DA only
* 2: compare SA only
* 3: compare half DA + half SA
* 4: compare ether type only
* 5: compare DA + ethertype
* 6: compare SA + ethertype
* 7: compare DA+ range.
*/
u32 match_type;
/*! 0: Bypass the remaining modules if matched.
* 1: Forward to next module for more classifications.
*/
u32 action;
};
/*! Represents the bitfields of a single row in the Ingress Pre-MACSec
* Packet Classifier table.
*/
struct aq_mss_ingress_preclass_record {
/*! The 64 bit SCI field used to compare with extracted value.
* Should have SCI value in case TCI[SCI_SEND] == 0. This will be
* used for ICV calculation.
*/
u32 sci[2];
/*! The 8 bit TCI field used to compare with extracted value. */
u32 tci;
/*! 8 bit encryption offset. */
u32 encr_offset;
/*! The 16 bit Ethertype (in the clear) field used to compare with
* extracted value.
*/
u32 eth_type;
/*! This is to specify the 40bit SNAP header if the SNAP header's
* mask is enabled.
*/
u32 snap[2];
/*! This is to specify the 24bit LLC header if the LLC header's
* mask is enabled.
*/
u32 llc;
/*! The 48 bit MAC_SA field used to compare with extracted value. */
u32 mac_sa[2];
/*! The 48 bit MAC_DA field used to compare with extracted value. */
u32 mac_da[2];
/*! 0: this is to compare with non-LPBK packet
* 1: this is to compare with LPBK packet.
* This value is used to compare with a controlled-tag which goes
* with the packet when looped back from Egress port.
*/
u32 lpbk_packet;
/*! The value of this bit mask will affects how the SC index and SA
* index created.
* 2'b00: 1 SC has 4 SA.
* SC index is equivalent to {SC_Index[4:2], 1'b0}.
* SA index is equivalent to {SC_Index[4:2], SECTAG's AN[1:0]}
* Here AN bits are not compared.
* 2'b10: 1 SC has 2 SA.
* SC index is equivalent to SC_Index[4:1]
* SA index is equivalent to {SC_Index[4:1], SECTAG's AN[0]}
* Compare AN[1] field only
* 2'b11: 1 SC has 1 SA. No SC entry exists for the specific SA.
* SA index is equivalent to SC_Index[4:0]
* AN[1:0] bits are compared.
* NOTE: This design is to supports different usage of AN. User
* can either ping-pong buffer 2 SA by using only the AN[0] bit.
* Or use 4 SA per SC by use AN[1:0] bits. Or even treat each SA
* as independent. i.e. AN[1:0] is just another matching pointer
* to select SA.
*/
u32 an_mask;
/*! This is bit mask to enable comparison the upper 6 bits TCI
* field, which does not include the AN field.
* 0: don't compare
* 1: enable comparison of the bits.
*/
u32 tci_mask;
/*! 0: don't care
* 1: enable comparison of SCI.
*/
u32 sci_mask;
/*! Mask is per-byte.
* 0: don't care
* 1: enable comparison of Ethertype.
*/
u32 eth_type_mask;
/*! Mask is per-byte.
* 0: don't care and no SNAP header exist.
* 1: compare the SNAP header.
* If this bit is set to 1, the extracted filed will assume the
* SNAP header exist as encapsulated in 802.3 (RFC 1042). I.E. the
* next 5 bytes after the LLC header is SNAP header.
*/
u32 snap_mask;
/*! Mask is per-byte.
* 0: don't care and no LLC header exist.
* 1: compare the LLC header.
* If this bit is set to 1, the extracted filed will assume the
* LLC header exist as encapsulated in 802.3 (RFC 1042). I.E. the
* next three bytes after the 802.3MAC header is LLC header.
*/
u32 llc_mask;
/*! Reserved. This bit should be always 0. */
u32 _802_2_encapsulate;
/*! Mask is per-byte.
* 0: don't care
* 1: enable comparison of MAC_SA.
*/
u32 sa_mask;
/*! Mask is per-byte.
* 0: don't care
* 1: enable comparison of MAC_DA.
*/
u32 da_mask;
/*! 0: don't care
* 1: enable checking if this is loopback packet or not.
*/
u32 lpbk_mask;
/*! If packet matches and tagged as controlled-packet. This SC/SA
* index is used for later SC and SA table lookup.
*/
u32 sc_idx;
/*! 0: the packets will be sent to MAC FIFO
* 1: The packets will be sent to Debug/Loopback FIFO.
* If the above's action is drop. This bit has no meaning.
*/
u32 proc_dest;
/*! 0: Process: Forward to next two modules for 802.1AE decryption.
* 1: Process but keep SECTAG: Forward to next two modules for
* 802.1AE decryption but keep the MACSEC header with added error
* code information. ICV will be stripped for all control packets.
* 2: Bypass: Bypass the next two decryption modules but processed
* by post-classification.
* 3: Drop: drop this packet and update counts accordingly.
*/
u32 action;
/*! 0: This is a controlled-port packet if matched.
* 1: This is an uncontrolled-port packet if matched.
*/
u32 ctrl_unctrl;
/*! Use the SCI value from the Table if 'SC' bit of the input
* packet is not present.
*/
u32 sci_from_table;
/*! Reserved. */
u32 reserved;
/*! 0: Not valid entry. This entry is not used
* 1: valid entry.
*/
u32 valid;
};
/*! Represents the bitfields of a single row in the Ingress SC Lookup table. */
struct aq_mss_ingress_sc_record {
/*! This is to specify when the SC was first used. Set by HW. */
u32 stop_time;
/*! This is to specify when the SC was first used. Set by HW. */
u32 start_time;
/*! 0: Strict
* 1: Check
* 2: Disabled.
*/
u32 validate_frames;
/*! 1: Replay control enabled.
* 0: replay control disabled.
*/
u32 replay_protect;
/*! This is to specify the window range for anti-replay. Default is 0.
* 0: is strict order enforcement.
*/
u32 anti_replay_window;
/*! 0: when none of the SA related to SC has inUse set.
* 1: when either of the SA related to the SC has inUse set.
* This bit is set by HW.
*/
u32 receiving;
/*! 0: when hardware processed the SC for the first time, it clears
* this bit
* 1: This bit is set by SW, when it sets up the SC.
*/
u32 fresh;
/*! 0: The AN number will not automatically roll over if Next_PN is
* saturated.
* 1: The AN number will automatically roll over if Next_PN is
* saturated.
* Rollover is valid only after expiry. Normal roll over between
* SA's should be normal process.
*/
u32 an_rol;
/*! Reserved. */
u32 reserved;
/*! 0: Invalid SC
* 1: Valid SC.
*/
u32 valid;
};
/*! Represents the bitfields of a single row in the Ingress SA Lookup table. */
struct aq_mss_ingress_sa_record {
/*! This is to specify when the SC was first used. Set by HW. */
u32 stop_time;
/*! This is to specify when the SC was first used. Set by HW. */
u32 start_time;
/*! This is updated by HW to store the expected NextPN number for
* anti-replay.
*/
u32 next_pn;
/*! The Next_PN number is going to wrapped around from 0XFFFF_FFFF
* to 0. set by HW.
*/
u32 sat_nextpn;
/*! 0: This SA is not yet used.
* 1: This SA is inUse.
*/
u32 in_use;
/*! 0: when hardware processed the SC for the first time, it clears
* this timer
* 1: This bit is set by SW, when it sets up the SC.
*/
u32 fresh;
/*! Reserved. */
u32 reserved;
/*! 0: Invalid SA.
* 1: Valid SA.
*/
u32 valid;
};
/*! Represents the bitfields of a single row in the Ingress SA Key
* Lookup table.
*/
struct aq_mss_ingress_sakey_record {
/*! Key for AES-GCM processing. */
u32 key[8];
/*! AES key size
* 00 - 128bits
* 01 - 192bits
* 10 - 256bits
* 11 - reserved.
*/
u32 key_len;
};
/*! Represents the bitfields of a single row in the Ingress Post-
* MACSec Packet Classifier table.
*/
struct aq_mss_ingress_postclass_record {
/*! The 8 bit value used to compare with extracted value for byte 0. */
u32 byte0;
/*! The 8 bit value used to compare with extracted value for byte 1. */
u32 byte1;
/*! The 8 bit value used to compare with extracted value for byte 2. */
u32 byte2;
/*! The 8 bit value used to compare with extracted value for byte 3. */
u32 byte3;
/*! Ethertype in the packet. */
u32 eth_type;
/*! Ether Type value > 1500 (0x5dc). */
u32 eth_type_valid;
/*! VLAN ID after parsing. */
u32 vlan_id;
/*! VLAN priority after parsing. */
u32 vlan_up;
/*! Valid VLAN coding. */
u32 vlan_valid;
/*! SA index. */
u32 sai;
/*! SAI hit, i.e. controlled packet. */
u32 sai_hit;
/*! Mask for payload ethertype field. */
u32 eth_type_mask;
/*! 0~63: byte location used extracted by packets comparator, which
* can be anything from the first 64 bytes of the MAC packets.
* This byte location counted from MAC' DA address. i.e. set to 0
* will point to byte 0 of DA address.
*/
u32 byte3_location;
/*! Mask for Byte Offset 3. */
u32 byte3_mask;
/*! 0~63: byte location used extracted by packets comparator, which
* can be anything from the first 64 bytes of the MAC packets.
* This byte location counted from MAC' DA address. i.e. set to 0
* will point to byte 0 of DA address.
*/
u32 byte2_location;
/*! Mask for Byte Offset 2. */
u32 byte2_mask;
/*! 0~63: byte location used extracted by packets comparator, which
* can be anything from the first 64 bytes of the MAC packets.
* This byte location counted from MAC' DA address. i.e. set to 0
* will point to byte 0 of DA address.
*/
u32 byte1_location;
/*! Mask for Byte Offset 1. */
u32 byte1_mask;
/*! 0~63: byte location used extracted by packets comparator, which
* can be anything from the first 64 bytes of the MAC packets.
* This byte location counted from MAC' DA address. i.e. set to 0
* will point to byte 0 of DA address.
*/
u32 byte0_location;
/*! Mask for Byte Offset 0. */
u32 byte0_mask;
/*! Mask for Ethertype valid field. Indicates 802.3 vs. Other. */
u32 eth_type_valid_mask;
/*! Mask for VLAN ID field. */
u32 vlan_id_mask;
/*! Mask for VLAN UP field. */
u32 vlan_up_mask;
/*! Mask for VLAN valid field. */
u32 vlan_valid_mask;
/*! Mask for SAI. */
u32 sai_mask;
/*! Mask for SAI_HIT. */
u32 sai_hit_mask;
/*! Action if only first level matches and second level does not.
* 0: pass
* 1: drop (fail).
*/
u32 firstlevel_actions;
/*! Action if both first and second level matched.
* 0: pass
* 1: drop (fail).
*/
u32 secondlevel_actions;
/*! Reserved. */
u32 reserved;
/*! 0: Not valid entry. This entry is not used
* 1: valid entry.
*/
u32 valid;
};
/*! Represents the bitfields of a single row in the Ingress Post-
* MACSec CTL Filter table.
*/
struct aq_mss_ingress_postctlf_record {
/*! This is used to store the 48 bit value used to compare SA, DA
* or halfDA+half SA value.
*/
u32 sa_da[2];
/*! This is used to store the 16 bit ethertype value used for
* comparison.
*/
u32 eth_type;
/*! The match mask is per-nibble. 0 means don't care, i.e. every
* value will match successfully. The total data is 64 bit, i.e.
* 16 nibbles masks.
*/
u32 match_mask;
/*! 0: No compare, i.e. This entry is not used
* 1: compare DA only
* 2: compare SA only
* 3: compare half DA + half SA
* 4: compare ether type only
* 5: compare DA + ethertype
* 6: compare SA + ethertype
* 7: compare DA+ range.
*/
u32 match_type;
/*! 0: Bypass the remaining modules if matched.
* 1: Forward to next module for more classifications.
*/
u32 action;
};
/*! Represents the Egress MIB counters for a single SC. Counters are
* 64 bits, lower 32 bits in field[0].
*/
struct aq_mss_egress_sc_counters {
/*! The number of integrity protected but not encrypted packets
* for this transmitting SC.
*/
u32 sc_protected_pkts[2];
/*! The number of integrity protected and encrypted packets for
* this transmitting SC.
*/
u32 sc_encrypted_pkts[2];
/*! The number of plain text octets that are integrity protected
* but not encrypted on the transmitting SC.
*/
u32 sc_protected_octets[2];
/*! The number of plain text octets that are integrity protected
* and encrypted on the transmitting SC.
*/
u32 sc_encrypted_octets[2];
};
/*! Represents the Egress MIB counters for a single SA. Counters are
* 64 bits, lower 32 bits in field[0].
*/
struct aq_mss_egress_sa_counters {
/*! The number of dropped packets for this transmitting SA. */
u32 sa_hit_drop_redirect[2];
/*! TODO */
u32 sa_protected2_pkts[2];
/*! The number of integrity protected but not encrypted packets
* for this transmitting SA.
*/
u32 sa_protected_pkts[2];
/*! The number of integrity protected and encrypted packets for
* this transmitting SA.
*/
u32 sa_encrypted_pkts[2];
};
/*! Represents the common Egress MIB counters; the counter not
* associated with a particular SC/SA. Counters are 64 bits, lower 32
* bits in field[0].
*/
struct aq_mss_egress_common_counters {
/*! The number of transmitted packets classified as MAC_CTL packets. */
u32 ctl_pkt[2];
/*! The number of transmitted packets that did not match any rows
* in the Egress Packet Classifier table.
*/
u32 unknown_sa_pkts[2];
/*! The number of transmitted packets where the SC table entry has
* protect=0 (so packets are forwarded unchanged).
*/
u32 untagged_pkts[2];
/*! The number of transmitted packets discarded because the packet
* length is greater than the ifMtu of the Common Port interface.
*/
u32 too_long[2];
/*! The number of transmitted packets for which table memory was
* affected by an ECC error during processing.
*/
u32 ecc_error_pkts[2];
/*! The number of transmitted packets for where the matched row in
* the Egress Packet Classifier table has action=drop.
*/
u32 unctrl_hit_drop_redir[2];
};
/*! Represents the Ingress MIB counters for a single SA. Counters are
* 64 bits, lower 32 bits in field[0].
*/
struct aq_mss_ingress_sa_counters {
/*! For this SA, the number of received packets without a SecTAG. */
u32 untagged_hit_pkts[2];
/*! For this SA, the number of received packets that were dropped. */
u32 ctrl_hit_drop_redir_pkts[2];
/*! For this SA which is not currently in use, the number of
* received packets that have been discarded, and have either the
* packets encrypted or the matched row in the Ingress SC Lookup
* table has validate_frames=Strict.
*/
u32 not_using_sa[2];
/*! For this SA which is not currently in use, the number of
* received, unencrypted, packets with the matched row in the
* Ingress SC Lookup table has validate_frames!=Strict.
*/
u32 unused_sa[2];
/*! For this SA, the number discarded packets with the condition
* that the packets are not valid and one of the following
* conditions are true: either the matched row in the Ingress SC
* Lookup table has validate_frames=Strict or the packets
* encrypted.
*/
u32 not_valid_pkts[2];
/*! For this SA, the number of packets with the condition that the
* packets are not valid and the matched row in the Ingress SC
* Lookup table has validate_frames=Check.
*/
u32 invalid_pkts[2];
/*! For this SA, the number of validated packets. */
u32 ok_pkts[2];
/*! For this SC, the number of received packets that have been
* discarded with the condition: the matched row in the Ingress
* SC Lookup table has replay_protect=1 and the PN of the packet
* is lower than the lower bound replay check PN.
*/
u32 late_pkts[2];
/*! For this SA, the number of packets with the condition that the
* PN of the packets is lower than the lower bound replay
* protection PN.
*/
u32 delayed_pkts[2];
/*! For this SC, the number of packets with the following condition:
* - the matched row in the Ingress SC Lookup table has
* replay_protect=0 or
* - the matched row in the Ingress SC Lookup table has
* replay_protect=1 and the packet is not encrypted and the
* integrity check has failed or
* - the matched row in the Ingress SC Lookup table has
* replay_protect=1 and the packet is encrypted and integrity
* check has failed.
*/
u32 unchecked_pkts[2];
/*! The number of octets of plaintext recovered from received
* packets that were integrity protected but not encrypted.
*/
u32 validated_octets[2];
/*! The number of octets of plaintext recovered from received
* packets that were integrity protected and encrypted.
*/
u32 decrypted_octets[2];
};
/*! Represents the common Ingress MIB counters; the counter not
* associated with a particular SA. Counters are 64 bits, lower 32
* bits in field[0].
*/
struct aq_mss_ingress_common_counters {
/*! The number of received packets classified as MAC_CTL packets. */
u32 ctl_pkts[2];
/*! The number of received packets with the MAC security tag
* (SecTAG), not matching any rows in the Ingress Pre-MACSec
* Packet Classifier table.
*/
u32 tagged_miss_pkts[2];
/*! The number of received packets without the MAC security tag
* (SecTAG), not matching any rows in the Ingress Pre-MACSec
* Packet Classifier table.
*/
u32 untagged_miss_pkts[2];
/*! The number of received packets discarded without the MAC
* security tag (SecTAG) and with the matched row in the Ingress
* SC Lookup table having validate_frames=Strict.
*/
u32 notag_pkts[2];
/*! The number of received packets without the MAC security tag
* (SecTAG) and with the matched row in the Ingress SC Lookup
* table having validate_frames!=Strict.
*/
u32 untagged_pkts[2];
/*! The number of received packets discarded with an invalid
* SecTAG or a zero value PN or an invalid ICV.
*/
u32 bad_tag_pkts[2];
/*! The number of received packets discarded with unknown SCI
* information with the condition:
* the matched row in the Ingress SC Lookup table has
* validate_frames=Strict or the C bit in the SecTAG is set.
*/
u32 no_sci_pkts[2];
/*! The number of received packets with unknown SCI with the condition:
* The matched row in the Ingress SC Lookup table has
* validate_frames!=Strict and the C bit in the SecTAG is not set.
*/
u32 unknown_sci_pkts[2];
/*! The number of received packets by the controlled port service
* that passed the Ingress Post-MACSec Packet Classifier table
* check.
*/
u32 ctrl_prt_pass_pkts[2];
/*! The number of received packets by the uncontrolled port
* service that passed the Ingress Post-MACSec Packet Classifier
* table check.
*/
u32 unctrl_prt_pass_pkts[2];
/*! The number of received packets by the controlled port service
* that failed the Ingress Post-MACSec Packet Classifier table
* check.
*/
u32 ctrl_prt_fail_pkts[2];
/*! The number of received packets by the uncontrolled port
* service that failed the Ingress Post-MACSec Packet Classifier
* table check.
*/
u32 unctrl_prt_fail_pkts[2];
/*! The number of received packets discarded because the packet
* length is greater than the ifMtu of the Common Port interface.
*/
u32 too_long_pkts[2];
/*! The number of received packets classified as MAC_CTL by the
* Ingress Post-MACSec CTL Filter table.
*/
u32 igpoc_ctl_pkts[2];
/*! The number of received packets for which table memory was
* affected by an ECC error during processing.
*/
u32 ecc_error_pkts[2];
/*! The number of received packets by the uncontrolled port
* service that were dropped.
*/
u32 unctrl_hit_drop_redir[2];
};
#endif