You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
446 lines
12 KiB
446 lines
12 KiB
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/* Atlantic Network Driver
|
|
*
|
|
* Copyright (C) 2017 aQuantia Corporation
|
|
* Copyright (C) 2019-2020 Marvell International Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#ifndef _ATL_COMMON_H_
|
|
#define _ATL_COMMON_H_
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/device.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/list.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/moduleparam.h>
|
|
|
|
#define ATL_VERSION "1.1.10"
|
|
|
|
struct atl_nic;
|
|
|
|
#include "atl_compat.h"
|
|
#include "atl_hw.h"
|
|
#include "atl_log.h"
|
|
#include "atl_ring_desc.h"
|
|
#include "atl_stats.h"
|
|
|
|
#define ATL_MAX_QUEUES 8
|
|
|
|
#include "atl_fwd.h"
|
|
|
|
struct atl_ptp;
|
|
|
|
enum {
|
|
ATL_RXF_VLAN_BASE = 0,
|
|
ATL_RXF_VLAN_MAX = ATL_VLAN_FLT_NUM,
|
|
ATL_RXF_ETYPE_BASE = ATL_RXF_VLAN_BASE + ATL_RXF_VLAN_MAX,
|
|
ATL_RXF_ETYPE_MAX = ATL_ETYPE_FLT_NUM,
|
|
ATL2_RPF_ETYPE_TAGS = 7,
|
|
ATL_RXF_NTUPLE_BASE = ATL_RXF_ETYPE_BASE + ATL_RXF_ETYPE_MAX,
|
|
ATL_RXF_NTUPLE_MAX = ATL_NTUPLE_FLT_NUM,
|
|
ATL_RXF_FLEX_BASE = ATL_RXF_NTUPLE_BASE + ATL_RXF_NTUPLE_MAX,
|
|
ATL_RXF_FLEX_MAX = 1,
|
|
};
|
|
|
|
enum atl_rxf_common_cmd {
|
|
ATL_RXF_EN = BIT(31),
|
|
ATL_RXF_RXQ_MSK = BIT(5) - 1,
|
|
ATL_RXF_ACT_SHIFT = 16,
|
|
ATL_RXF_ACT_MASK = BIT(3) - 1,
|
|
ATL_RXF_ACT_TOHOST = BIT(0) << ATL_RXF_ACT_SHIFT,
|
|
};
|
|
|
|
enum atl_ntuple_cmd {
|
|
ATL_NTC_EN = ATL_RXF_EN, /* Filter enabled */
|
|
ATL_NTC_V6 = BIT(30), /* IPv6 mode -- only valid in filters
|
|
* 0 and 4 */
|
|
ATL_NTC_SA = BIT(29), /* Match source address */
|
|
ATL_NTC_DA = BIT(28), /* Match destination address */
|
|
ATL_NTC_SP = BIT(27), /* Match source port */
|
|
ATL_NTC_DP = BIT(26), /* Match destination port */
|
|
ATL_NTC_PROTO = BIT(25), /* Match L4 proto */
|
|
ATL_NTC_ARP = BIT(24),
|
|
ATL_NTC_RXQ = BIT(23), /* Assign Rx queue */
|
|
ATL_NTC_ACT_SHIFT = ATL_RXF_ACT_SHIFT,
|
|
ATL_NTC_RXQ_SHIFT = 8,
|
|
ATL_NTC_RXQ_MASK = ATL_RXF_RXQ_MSK << ATL_NTC_RXQ_SHIFT,
|
|
ATL_NTC_L4_MASK = BIT(3) - 1,
|
|
ATL_NTC_L4_TCP = 0,
|
|
ATL_NTC_L4_UDP = 1,
|
|
ATL_NTC_L4_SCTP = 2,
|
|
ATL_NTC_L4_ICMP = 3,
|
|
};
|
|
|
|
enum atl2_ntuple_cmd {
|
|
ATL2_NTC_L3_IPV4_EN = BIT(0), /* Filter enabled */
|
|
ATL2_NTC_L3_IPV4_SA = BIT(1),
|
|
ATL2_NTC_L3_IPV4_DA = BIT(2),
|
|
ATL2_NTC_L3_IPV4_PROTO = BIT(3),
|
|
ATL2_NTC_L3_IPV4_TAG_SHIFT = 4,
|
|
ATL2_NTC_L3_IPV4_PROTO_SHIFT = 8,
|
|
|
|
ATL2_NTC_L3_IPV6_EN = BIT(0x10), /* Filter enabled */
|
|
ATL2_NTC_L3_IPV6_SA = BIT(0x11),
|
|
ATL2_NTC_L3_IPV6_DA = BIT(0x12),
|
|
ATL2_NTC_L3_IPV6_PROTO = BIT(0x13),
|
|
ATL2_NTC_L3_IPV6_TAG_SHIFT = 0x14,
|
|
ATL2_NTC_L3_IPV6_PROTO_SHIFT = 0x18,
|
|
|
|
ATL2_NTC_L4_EN = BIT(0), /* Filter enabled */
|
|
ATL2_NTC_L4_DP = BIT(1),
|
|
ATL2_NTC_L4_SP = BIT(2),
|
|
};
|
|
|
|
struct atl2_rxf_l3 {
|
|
union {
|
|
struct {
|
|
__be32 dst_ip4;
|
|
__be32 src_ip4;
|
|
};
|
|
struct {
|
|
__be32 dst_ip6[4];
|
|
__be32 src_ip6[4];
|
|
};
|
|
};
|
|
u16 proto;
|
|
u32 cmd;
|
|
u16 usage;
|
|
};
|
|
|
|
struct atl2_rxf_l4 {
|
|
__be16 dst_port;
|
|
__be16 src_port;
|
|
u32 cmd;
|
|
u16 usage;
|
|
};
|
|
|
|
struct atl_rxf_ntuple {
|
|
union {
|
|
struct {
|
|
__be32 dst_ip4[ATL_RXF_NTUPLE_MAX];
|
|
__be32 src_ip4[ATL_RXF_NTUPLE_MAX];
|
|
};
|
|
struct {
|
|
__be32 dst_ip6[ATL_RXF_NTUPLE_MAX][4];
|
|
__be32 src_ip6[ATL_RXF_NTUPLE_MAX][4];
|
|
};
|
|
};
|
|
__be16 dst_port[ATL_RXF_NTUPLE_MAX];
|
|
__be16 src_port[ATL_RXF_NTUPLE_MAX];
|
|
|
|
struct atl2_rxf_l3 l3v4[ATL_RXF_NTUPLE_MAX];
|
|
struct atl2_rxf_l3 l3v6[ATL_RXF_NTUPLE_MAX];
|
|
struct atl2_rxf_l4 l4[ATL_RXF_NTUPLE_MAX];
|
|
s8 l3_idx[ATL_RXF_NTUPLE_MAX];
|
|
bool is_ipv6[ATL_RXF_NTUPLE_MAX];
|
|
s8 l4_idx[ATL_RXF_NTUPLE_MAX];
|
|
uint32_t cmd[ATL_RXF_NTUPLE_MAX];
|
|
int count;
|
|
int l3_v4_base_index;
|
|
int l3_v4_available;
|
|
int l3_v6_base_index;
|
|
int l3_v6_available;
|
|
int l4_base_index;
|
|
int l4_available;
|
|
};
|
|
|
|
enum atl_vlan_cmd {
|
|
ATL_VLAN_EN = ATL_RXF_EN,
|
|
ATL_VLAN_RXQ = BIT(28),
|
|
ATL_VLAN_RXQ_SHIFT = 20,
|
|
ATL_VLAN_RXQ_MASK = ATL_RXF_RXQ_MSK << ATL_VLAN_RXQ_SHIFT,
|
|
ATL_VLAN_ACT_SHIFT = ATL_RXF_ACT_SHIFT,
|
|
ATL_VLAN_VID_MASK = BIT(12) - 1,
|
|
};
|
|
|
|
#define ATL_VID_MAP_LEN BITS_TO_LONGS(BIT(12))
|
|
|
|
struct atl_rxf_vlan {
|
|
uint32_t cmd[ATL_RXF_VLAN_MAX];
|
|
int count;
|
|
unsigned long map[ATL_VID_MAP_LEN];
|
|
int vlans_active;
|
|
int promisc_count;
|
|
int base_index;
|
|
int available;
|
|
};
|
|
|
|
enum atl_etype_cmd {
|
|
ATL_ETYPE_EN = ATL_RXF_EN,
|
|
ATL_ETYPE_RXQ = BIT(29),
|
|
ATL_ETYPE_RXQ_SHIFT = 20,
|
|
ATL_ETYPE_RXQ_MASK = ATL_RXF_RXQ_MSK << ATL_ETYPE_RXQ_SHIFT,
|
|
ATL_ETYPE_ACT_SHIFT = ATL_RXF_ACT_SHIFT,
|
|
ATL_ETYPE_VAL_MASK = BIT(16) - 1,
|
|
};
|
|
|
|
struct atl2_tag_policy {
|
|
u16 action;
|
|
u16 usage;
|
|
};
|
|
|
|
struct atl_rxf_etype {
|
|
uint32_t cmd[ATL_RXF_ETYPE_MAX];
|
|
int count;
|
|
struct atl2_tag_policy tags_policy[ATL_RXF_ETYPE_MAX];
|
|
int tag[ATL_RXF_ETYPE_MAX];
|
|
int base_index;
|
|
int available;
|
|
int tag_top;
|
|
};
|
|
|
|
struct atl_rxf_mac {
|
|
int base_index;
|
|
int available;
|
|
};
|
|
|
|
enum atl_flex_cmd {
|
|
ATL_FLEX_EN = ATL_RXF_EN,
|
|
ATL_FLEX_RXQ = BIT(30),
|
|
ATL_FLEX_RXQ_SHIFT = 20,
|
|
ATL_FLEX_RXQ_MASK = ATL_RXF_RXQ_MSK << ATL_FLEX_RXQ_SHIFT,
|
|
ATL_FLEX_ACT_SHIFT = ATL_RXF_ACT_SHIFT,
|
|
};
|
|
|
|
struct atl_rxf_flex {
|
|
uint32_t cmd[ATL_RXF_FLEX_MAX];
|
|
int count;
|
|
int base_index;
|
|
int available;
|
|
};
|
|
|
|
struct atl_queue_vec;
|
|
|
|
#define ATL_NUM_FWD_RINGS ATL_MAX_QUEUES
|
|
#define ATL_FWD_RING_BASE ATL_MAX_QUEUES /* Use TC 1 for offload
|
|
* engine rings */
|
|
#define ATL_NUM_MSI_VECS 32
|
|
enum {
|
|
ATL_IRQ_LINK = 0,
|
|
ATL_IRQ_PTP,
|
|
ATL_NUM_NON_RING_IRQS,
|
|
};
|
|
|
|
#define ATL_RXF_RING_ANY 32
|
|
|
|
#define ATL_FWD_MSI_BASE (ATL_MAX_QUEUES + ATL_NUM_NON_RING_IRQS)
|
|
|
|
enum atl_fwd_dir {
|
|
ATL_FWDIR_RX = 0,
|
|
ATL_FWDIR_TX = 1,
|
|
ATL_FWDIR_NUM,
|
|
};
|
|
|
|
struct atl_fwd {
|
|
unsigned long ring_map[ATL_FWDIR_NUM];
|
|
struct atl_fwd_ring *rings[ATL_FWDIR_NUM][ATL_NUM_FWD_RINGS];
|
|
unsigned long msi_map;
|
|
struct blocking_notifier_head nh_clients;
|
|
};
|
|
|
|
#if IS_ENABLED(CONFIG_ATLFWD_FWD_NETLINK)
|
|
struct atl_fwdnl {
|
|
struct atl_desc_ring ring_desc[ATL_NUM_FWD_RINGS * 2];
|
|
/* State of forced redirections */
|
|
int force_icmp_via;
|
|
int force_tx_via;
|
|
/* Deferred TX head cleanup */
|
|
struct delayed_work *tx_cleanup_wq;
|
|
u32 tx_bunch;
|
|
};
|
|
#endif /* CONFIG_ATLFWD_FWD_NETLINK */
|
|
|
|
struct atl_nic {
|
|
struct net_device *ndev;
|
|
|
|
struct atl_queue_vec *qvecs;
|
|
int nvecs;
|
|
struct atl_hw hw;
|
|
unsigned flags;
|
|
uint32_t priv_flags;
|
|
struct timer_list work_timer;
|
|
int max_mtu;
|
|
unsigned int requested_nvecs;
|
|
int requested_rx_size;
|
|
int requested_tx_size;
|
|
int rx_intr_delay;
|
|
int tx_intr_delay;
|
|
struct atl_global_stats stats;
|
|
spinlock_t stats_lock;
|
|
struct work_struct work;
|
|
|
|
#if IS_ENABLED(CONFIG_ATLFWD_FWD)
|
|
struct atl_fwd fwd;
|
|
#endif
|
|
#if IS_ENABLED(CONFIG_ATLFWD_FWD_NETLINK)
|
|
struct atl_fwdnl fwdnl;
|
|
#endif
|
|
|
|
struct atl_rxf_ntuple rxf_ntuple;
|
|
struct atl_rxf_vlan rxf_vlan;
|
|
struct atl_rxf_etype rxf_etype;
|
|
struct atl_rxf_mac rxf_mac;
|
|
struct atl_rxf_flex rxf_flex;
|
|
|
|
/* PTP support */
|
|
struct atl_ptp *ptp;
|
|
};
|
|
|
|
/* Flags only modified with RTNL lock held */
|
|
enum atl_nic_flags {
|
|
ATL_FL_MULTIPLE_VECTORS = BIT(0),
|
|
ATL_FL_WOL = BIT(1),
|
|
};
|
|
|
|
#define ATL_PF(_name) ATL_PF_ ## _name
|
|
#define ATL_PF_BIT(_name) ATL_PF_ ## _name ## _BIT
|
|
#define ATL_DEF_PF_BIT(_name) ATL_PF_BIT(_name) = BIT(ATL_PF(_name))
|
|
|
|
enum atl_priv_flags {
|
|
ATL_PF_LPB_SYS_PB,
|
|
ATL_PF_LPB_SYS_DMA,
|
|
ATL_PF_LPB_NET_DMA,
|
|
ATL_PF_LPB_INT_PHY,
|
|
ATL_PF_LPB_EXT_PHY,
|
|
ATL_PF_LPI_RX_MAC,
|
|
ATL_PF_LPI_TX_MAC,
|
|
ATL_PF_LPI_RX_PHY,
|
|
ATL_PF_LPI_TX_PHY,
|
|
ATL_PF_STATS_RESET,
|
|
ATL_PF_STRIP_PAD,
|
|
ATL_PF_MEDIA_DETECT,
|
|
};
|
|
|
|
enum atl_priv_flag_bits {
|
|
ATL_DEF_PF_BIT(LPB_SYS_PB),
|
|
ATL_DEF_PF_BIT(LPB_SYS_DMA),
|
|
ATL_DEF_PF_BIT(LPB_NET_DMA),
|
|
ATL_DEF_PF_BIT(LPB_INT_PHY),
|
|
ATL_DEF_PF_BIT(LPB_EXT_PHY),
|
|
|
|
ATL_PF_LPB_MASK = ATL_PF_BIT(LPB_SYS_DMA) | ATL_PF_BIT(LPB_SYS_PB) |
|
|
ATL_PF_BIT(LPB_NET_DMA) | ATL_PF_BIT(LPB_INT_PHY) |
|
|
ATL_PF_BIT(LPB_EXT_PHY),
|
|
|
|
ATL_DEF_PF_BIT(LPI_RX_MAC),
|
|
ATL_DEF_PF_BIT(LPI_TX_MAC),
|
|
ATL_DEF_PF_BIT(LPI_RX_PHY),
|
|
ATL_DEF_PF_BIT(LPI_TX_PHY),
|
|
ATL_PF_LPI_MASK = ATL_PF_BIT(LPI_RX_MAC) | ATL_PF_BIT(LPI_TX_MAC) |
|
|
ATL_PF_BIT(LPI_RX_PHY) | ATL_PF_BIT(LPI_TX_PHY),
|
|
|
|
ATL_DEF_PF_BIT(STATS_RESET),
|
|
|
|
ATL_DEF_PF_BIT(STRIP_PAD),
|
|
ATL_DEF_PF_BIT(MEDIA_DETECT),
|
|
|
|
ATL_PF_RW_MASK = ATL_PF_LPB_MASK | ATL_PF_BIT(STATS_RESET) |
|
|
ATL_PF_BIT(STRIP_PAD) | ATL_PF_BIT(MEDIA_DETECT),
|
|
ATL_PF_RO_MASK = ATL_PF_LPI_MASK,
|
|
};
|
|
|
|
#define ATL_MAX_MTU (16352 - ETH_FCS_LEN - ETH_HLEN)
|
|
|
|
#define ATL_MAX_RING_SIZE (8192 - 8)
|
|
#define ATL_RING_SIZE 4096
|
|
|
|
extern const char atl_driver_name[];
|
|
|
|
extern const struct ethtool_ops atl_ethtool_ops;
|
|
|
|
extern unsigned int atl_max_queues;
|
|
extern unsigned int atl_max_queues_non_msi;
|
|
extern unsigned atl_rx_linear;
|
|
extern unsigned atl_min_intr_delay;
|
|
extern bool atl_enable_msi;
|
|
extern bool atl_wq_non_msi;
|
|
extern unsigned int atl_tx_clean_budget;
|
|
extern unsigned int atl_tx_free_low;
|
|
extern unsigned int atl_tx_free_high;
|
|
|
|
#define atl_module_param(_name, _type, _mode) \
|
|
module_param_named(_name, atl_ ## _name, _type, _mode)
|
|
|
|
static inline void atl_intr_enable_non_ring(struct atl_nic *nic)
|
|
{
|
|
struct atl_hw *hw = &nic->hw;
|
|
|
|
atl_intr_enable(hw, hw->non_ring_intr_mask);
|
|
}
|
|
|
|
static inline void atl_intr_disable_non_ring(struct atl_nic *nic)
|
|
{
|
|
struct atl_hw *hw = &nic->hw;
|
|
|
|
atl_intr_disable(hw, hw->non_ring_intr_mask);
|
|
}
|
|
|
|
netdev_tx_t atl_start_xmit(struct sk_buff *skb, struct net_device *ndev);
|
|
int atl_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid);
|
|
int atl_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid);
|
|
void atl_set_rx_mode(struct net_device *ndev);
|
|
int atl_set_features(struct net_device *ndev, netdev_features_t features);
|
|
void atl_get_stats64(struct net_device *ndev,
|
|
struct rtnl_link_stats64 *stats);
|
|
int atl_setup_datapath(struct atl_nic *nic);
|
|
void atl_clear_datapath(struct atl_nic *nic);
|
|
int atl_start_rings(struct atl_nic *nic);
|
|
void atl_stop_rings(struct atl_nic *nic);
|
|
void atl_clear_rdm_cache(struct atl_nic *nic);
|
|
void atl_clear_tdm_cache(struct atl_nic *nic);
|
|
int atl_alloc_rings(struct atl_nic *nic);
|
|
void atl_free_rings(struct atl_nic *nic);
|
|
irqreturn_t atl_ring_irq(int irq, void *priv);
|
|
void atl_ring_work(struct work_struct *work);
|
|
void atl_start_hw_global(struct atl_nic *nic);
|
|
int atl_intr_init(struct atl_nic *nic);
|
|
void atl_intr_release(struct atl_nic *nic);
|
|
int atl_hw_reset(struct atl_hw *hw);
|
|
int atl_fw_init(struct atl_hw *hw);
|
|
int atl_fw_configure(struct atl_hw *hw);
|
|
int atl_reconfigure(struct atl_nic *nic);
|
|
void atl_reset_stats(struct atl_nic *nic);
|
|
void atl_update_global_stats(struct atl_nic *nic);
|
|
void atl_set_loopback(struct atl_nic *nic, int idx, bool on);
|
|
void atl_set_intr_mod(struct atl_nic *nic);
|
|
void atl_update_ntuple_flt(struct atl_nic *nic, int idx);
|
|
void atl_set_vlan_promisc(struct atl_hw *hw, int promisc);
|
|
int atl_hwsem_get(struct atl_hw *hw, int idx);
|
|
void atl_hwsem_put(struct atl_hw *hw, int idx);
|
|
int __atl_msm_read(struct atl_hw *hw, uint32_t addr, uint32_t *val);
|
|
int atl_msm_read(struct atl_hw *hw, uint32_t addr, uint32_t *val);
|
|
int __atl_msm_write(struct atl_hw *hw, uint32_t addr, uint32_t val);
|
|
int atl_msm_write(struct atl_hw *hw, uint32_t addr, uint32_t val);
|
|
int atl_update_eth_stats(struct atl_nic *nic);
|
|
void atl_adjust_eth_stats(struct atl_ether_stats *stats,
|
|
struct atl_ether_stats *base, bool add);
|
|
void atl_fwd_release_rings(struct atl_nic *nic);
|
|
#if IS_ENABLED(CONFIG_ATLFWD_FWD)
|
|
enum atl_fwd_notify;
|
|
int atl_fwd_suspend_rings(struct atl_nic *nic);
|
|
int atl_fwd_resume_rings(struct atl_nic *nic);
|
|
void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data);
|
|
#else
|
|
static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; }
|
|
static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; }
|
|
static inline void atl_fwd_notify(struct atl_nic *nic,
|
|
enum atl_fwd_notify notif, void *data) {}
|
|
#endif
|
|
int atl_get_lpi_timer(struct atl_nic *nic, uint32_t *lpi_delay);
|
|
void atl_refresh_rxfs(struct atl_nic *nic);
|
|
void atl_schedule_work(struct atl_nic *nic);
|
|
int atl_hwmon_init(struct atl_nic *nic);
|
|
void atl_thermal_check(struct atl_hw *hw, bool alarm);
|
|
int atl_update_thermal(struct atl_hw *hw);
|
|
int atl_update_thermal_flag(struct atl_hw *hw, int bit, bool val);
|
|
int atl_verify_thermal_limits(struct atl_hw *hw, struct atl_thermal *thermal);
|
|
int atl_do_reset(struct atl_nic *nic);
|
|
int atl_set_media_detect(struct atl_nic *nic, bool on);
|
|
|
|
#endif
|
|
|