linux/drivers/net/ethernet/cisco/enic/enic.h
Satish Kharat 4368f5fab4 enic: detect admin channel resources for SR-IOV
Check for the presence of admin channel BAR resources
(RES_TYPE_ADMIN_WQ, ADMIN_RQ, ADMIN_CQ, SRIOV_INTR) during resource
discovery. Set has_admin_channel when all four are available.

Use ARRAY_SIZE(enic->admin_cq) for the admin CQ count check since the
driver allocates two admin CQs (one for WQ completions, one for RQ
completions) and both must be backed by hardware resources.

Add admin WQ, RQ, CQ and INTR fields to struct enic for use by the
upcoming admin channel open/close paths.

Signed-off-by: Satish Kharat <satishkh@cisco.com>
Link: https://patch.msgid.link/20260401-enic-sriov-v2-prep-v4-6-d5834b2ef1b9@cisco.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-04-02 18:05:06 -07:00

425 lines
11 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*/
#ifndef _ENIC_H_
#define _ENIC_H_
#include "vnic_enet.h"
#include "vnic_dev.h"
#include "vnic_wq.h"
#include "vnic_rq.h"
#include "vnic_cq.h"
#include "vnic_intr.h"
#include "vnic_stats.h"
#include "vnic_nic.h"
#include "vnic_rss.h"
#include <linux/irq.h>
#include <net/page_pool/helpers.h>
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
#define PCI_SUBDEV_ID_CISCO_VIC_1225 0x085
#define PCI_SUBDEV_ID_CISCO_VIC_1225T 0x0CE
#define PCI_SUBDEV_ID_CISCO_VIC_1227 0x12E
#define PCI_SUBDEV_ID_CISCO_VIC_1227T 0x139
#define PCI_SUBDEV_ID_CISCO_VIC_1240 0x084
#define PCI_SUBDEV_ID_CISCO_VIC_1280 0x04F
#define PCI_SUBDEV_ID_CISCO_VIC_1285 0x0CD
#define PCI_SUBDEV_ID_CISCO_VIC_1340 0x12C
#define PCI_SUBDEV_ID_CISCO_VIC_1380 0x137
#define PCI_SUBDEV_ID_CISCO_VIC_1385 0x14D
#define PCI_SUBDEV_ID_CISCO_VIC_1387 0x15D
#define PCI_SUBDEV_ID_CISCO_VIC_1440 0x0215
#define PCI_SUBDEV_ID_CISCO_VIC_1455 0x0217
#define PCI_SUBDEV_ID_CISCO_VIC_1457 0x0218
#define PCI_SUBDEV_ID_CISCO_VIC_1467 0x02AF
#define PCI_SUBDEV_ID_CISCO_VIC_1477 0x2B0
#define PCI_SUBDEV_ID_CISCO_VIC_1480 0x0216
#define PCI_SUBDEV_ID_CISCO_VIC_1485 0x0219
#define PCI_SUBDEV_ID_CISCO_VIC_1487 0x021A
#define PCI_SUBDEV_ID_CISCO_VIC_1495 0x024A
#define PCI_SUBDEV_ID_CISCO_VIC_1497 0x024B
#define PCI_SUBDEV_ID_CISCO_VIC_14425 0x02CF
#define PCI_SUBDEV_ID_CISCO_VIC_14825 0x02D0
#define PCI_SUBDEV_ID_CISCO_VIC_15230 0x02DF
#define PCI_SUBDEV_ID_CISCO_VIC_15231 0x02DB
#define PCI_SUBDEV_ID_CISCO_VIC_15235 0x02E4
#define PCI_SUBDEV_ID_CISCO_VIC_15237 0x02F3
#define PCI_SUBDEV_ID_CISCO_VIC_15238 0x02E8
#define PCI_SUBDEV_ID_CISCO_VIC_15411 0x02DC
#define PCI_SUBDEV_ID_CISCO_VIC_15412 0x02E2
#define PCI_SUBDEV_ID_CISCO_VIC_15420 0x02DE
#define PCI_SUBDEV_ID_CISCO_VIC_15422 0x02E1
#define PCI_SUBDEV_ID_CISCO_VIC_15425 0x02F2
#define PCI_SUBDEV_ID_CISCO_VIC_15427 0x02E0
#define PCI_SUBDEV_ID_CISCO_VIC_15428 0x02DD
#define ENIC_BARS_MAX 6
#define ENIC_WQ_MAX 256
#define ENIC_RQ_MAX 256
#define ENIC_RQ_MIN_DEFAULT 8
#define ENIC_WQ_NAPI_BUDGET 256
#define ENIC_AIC_LARGE_PKT_DIFF 3
enum ext_cq {
ENIC_RQ_CQ_ENTRY_SIZE_16,
ENIC_RQ_CQ_ENTRY_SIZE_32,
ENIC_RQ_CQ_ENTRY_SIZE_64,
ENIC_RQ_CQ_ENTRY_SIZE_MAX,
};
struct enic_msix_entry {
int requested;
char devname[IFNAMSIZ + 8];
irqreturn_t (*isr)(int, void *);
void *devid;
cpumask_var_t affinity_mask;
};
/* Store only the lower range. Higher range is given by fw. */
struct enic_intr_mod_range {
u32 small_pkt_range_start;
u32 large_pkt_range_start;
};
struct enic_intr_mod_table {
u32 rx_rate;
u32 range_percent;
};
#define ENIC_MAX_LINK_SPEEDS 3
#define ENIC_LINK_SPEED_10G 10000
#define ENIC_LINK_SPEED_4G 4000
#define ENIC_LINK_40G_INDEX 2
#define ENIC_LINK_10G_INDEX 1
#define ENIC_LINK_4G_INDEX 0
#define ENIC_RX_COALESCE_RANGE_END 125
#define ENIC_AIC_TS_BREAK 100
struct enic_rx_coal {
u32 small_pkt_range_start;
u32 large_pkt_range_start;
u32 range_end;
u32 use_adaptive_rx_coalesce;
};
/* priv_flags */
#define ENIC_SRIOV_ENABLED (1 << 0)
/* enic port profile set flags */
#define ENIC_PORT_REQUEST_APPLIED (1 << 0)
#define ENIC_SET_REQUEST (1 << 1)
#define ENIC_SET_NAME (1 << 2)
#define ENIC_SET_INSTANCE (1 << 3)
#define ENIC_SET_HOST (1 << 4)
#define MAX_TSO BIT(16)
#define WQ_ENET_MAX_DESC_LEN BIT(WQ_ENET_LEN_BITS)
#define ENIC_DESC_MAX_SPLITS (MAX_TSO / WQ_ENET_MAX_DESC_LEN + 1)
struct enic_port_profile {
u32 set;
u8 request;
char name[PORT_PROFILE_MAX];
u8 instance_uuid[PORT_UUID_MAX];
u8 host_uuid[PORT_UUID_MAX];
u8 vf_mac[ETH_ALEN];
u8 mac_addr[ETH_ALEN];
};
/* enic_rfs_fltr_node - rfs filter node in hash table
* @@keys: IPv4 5 tuple
* @flow_id: flow_id of clsf filter provided by kernel
* @fltr_id: filter id of clsf filter returned by adaptor
* @rq_id: desired rq index
* @node: hlist_node
*/
struct enic_rfs_fltr_node {
struct flow_keys keys;
u32 flow_id;
u16 fltr_id;
u16 rq_id;
struct hlist_node node;
};
/* enic_rfs_flw_tbl - rfs flow table
* @max: Maximum number of filters vNIC supports
* @free: Number of free filters available
* @toclean: hash table index to clean next
* @ht_head: hash table list head
* @lock: spin lock
* @rfs_may_expire: timer function for enic_rps_may_expire_flow
*/
struct enic_rfs_flw_tbl {
u16 max;
int free;
#define ENIC_RFS_FLW_BITSHIFT (10)
#define ENIC_RFS_FLW_MASK ((1 << ENIC_RFS_FLW_BITSHIFT) - 1)
u16 toclean:ENIC_RFS_FLW_BITSHIFT;
struct hlist_head ht_head[1 << ENIC_RFS_FLW_BITSHIFT];
spinlock_t lock;
struct timer_list rfs_may_expire;
};
struct vxlan_offload {
u16 vxlan_udp_port_number;
u8 patch_level;
u8 flags;
};
struct enic_wq_stats {
u64 packets; /* pkts queued for Tx */
u64 stopped; /* Tx ring almost full, queue stopped */
u64 wake; /* Tx ring no longer full, queue woken up*/
u64 tso; /* non-encap tso pkt */
u64 encap_tso; /* encap tso pkt */
u64 encap_csum; /* encap HW csum */
u64 csum_partial; /* skb->ip_summed = CHECKSUM_PARTIAL */
u64 csum_none; /* HW csum not required */
u64 bytes; /* bytes queued for Tx */
u64 add_vlan; /* HW adds vlan tag */
u64 cq_work; /* Tx completions processed */
u64 cq_bytes; /* Tx bytes processed */
u64 null_pkt; /* skb length <= 0 */
u64 skb_linear_fail; /* linearize failures */
u64 desc_full_awake; /* TX ring full while queue awake */
};
struct enic_rq_stats {
u64 packets; /* pkts received */
u64 bytes; /* bytes received */
u64 l4_rss_hash; /* hashed on l4 */
u64 l3_rss_hash; /* hashed on l3 */
u64 csum_unnecessary; /* HW verified csum */
u64 csum_unnecessary_encap; /* HW verified csum on encap packet */
u64 vlan_stripped; /* HW stripped vlan */
u64 napi_complete; /* napi complete intr reenabled */
u64 napi_repoll; /* napi poll again */
u64 bad_fcs; /* bad pkts */
u64 pkt_truncated; /* truncated pkts */
u64 no_skb; /* out of skbs */
u64 desc_skip; /* Rx pkt went into later buffer */
u64 pp_alloc_fail; /* page pool alloc failure */
};
struct enic_wq {
spinlock_t lock; /* spinlock for wq */
struct vnic_wq vwq;
struct enic_wq_stats stats;
} ____cacheline_aligned;
struct enic_rq {
struct vnic_rq vrq;
struct enic_rq_stats stats;
struct page_pool *pool;
} ____cacheline_aligned;
enum enic_vf_type {
ENIC_VF_TYPE_NONE,
ENIC_VF_TYPE_V1,
ENIC_VF_TYPE_USNIC,
ENIC_VF_TYPE_V2,
};
/* Per-instance private data structure */
struct enic {
struct net_device *netdev;
struct pci_dev *pdev;
struct vnic_enet_config config;
struct vnic_dev_bar bar[ENIC_BARS_MAX];
struct vnic_dev *vdev;
struct timer_list notify_timer;
struct work_struct reset;
struct work_struct tx_hang_reset;
struct work_struct change_mtu_work;
struct msix_entry *msix_entry;
struct enic_msix_entry *msix;
u32 msg_enable;
spinlock_t devcmd_lock;
u8 mac_addr[ETH_ALEN];
unsigned int flags;
unsigned int priv_flags;
unsigned int mc_count;
unsigned int uc_count;
u32 port_mtu;
struct enic_rx_coal rx_coalesce_setting;
u32 rx_coalesce_usecs;
u32 tx_coalesce_usecs;
#ifdef CONFIG_PCI_IOV
u16 num_vfs;
#endif
enum enic_vf_type vf_type;
unsigned int enable_count;
spinlock_t enic_api_lock;
bool enic_api_busy;
struct enic_port_profile *pp;
struct enic_wq *wq;
unsigned int wq_avail;
unsigned int wq_count;
u16 loop_enable;
u16 loop_tag;
struct enic_rq *rq;
unsigned int rq_avail;
unsigned int rq_count;
struct vxlan_offload vxlan;
struct napi_struct *napi;
struct vnic_intr *intr;
unsigned int intr_avail;
unsigned int intr_count;
u32 __iomem *legacy_pba; /* memory-mapped */
struct vnic_cq *cq;
unsigned int cq_avail;
unsigned int cq_count;
struct enic_rfs_flw_tbl rfs_h;
u8 rss_key[ENIC_RSS_LEN];
struct vnic_gen_stats gen_stats;
enum ext_cq ext_cq;
/* Admin channel resources for SR-IOV MBOX */
bool has_admin_channel;
struct vnic_wq admin_wq;
struct vnic_rq admin_rq;
struct vnic_cq admin_cq[2];
struct vnic_intr admin_intr;
};
static inline struct net_device *vnic_get_netdev(struct vnic_dev *vdev)
{
struct enic *enic = vdev->priv;
return enic->netdev;
}
/* wrappers function for kernel log
*/
#define vdev_err(vdev, fmt, ...) \
dev_err(&(vdev)->pdev->dev, fmt, ##__VA_ARGS__)
#define vdev_warn(vdev, fmt, ...) \
dev_warn(&(vdev)->pdev->dev, fmt, ##__VA_ARGS__)
#define vdev_info(vdev, fmt, ...) \
dev_info(&(vdev)->pdev->dev, fmt, ##__VA_ARGS__)
#define vdev_dbg(vdev, fmt, ...) \
dev_dbg(&(vdev)->pdev->dev, fmt, ##__VA_ARGS__)
#define vdev_neterr(vdev, fmt, ...) \
netdev_err(vnic_get_netdev(vdev), fmt, ##__VA_ARGS__)
#define vdev_netwarn(vdev, fmt, ...) \
netdev_warn(vnic_get_netdev(vdev), fmt, ##__VA_ARGS__)
#define vdev_netinfo(vdev, fmt, ...) \
netdev_info(vnic_get_netdev(vdev), fmt, ##__VA_ARGS__)
static inline struct device *enic_get_dev(struct enic *enic)
{
return &(enic->pdev->dev);
}
static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq)
{
return rq;
}
static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq)
{
return enic->rq_count + wq;
}
static inline unsigned int enic_msix_rq_intr(struct enic *enic,
unsigned int rq)
{
return enic->cq[enic_cq_rq(enic, rq)].interrupt_offset;
}
static inline unsigned int enic_msix_wq_intr(struct enic *enic,
unsigned int wq)
{
return enic->cq[enic_cq_wq(enic, wq)].interrupt_offset;
}
/* MSIX interrupts are organized as the error interrupt, then the notify
* interrupt followed by all the I/O interrupts. The error interrupt needs
* to fit in 7 bits due to hardware constraints
*/
#define ENIC_MSIX_RESERVED_INTR 2
#define ENIC_MSIX_ERR_INTR 0
#define ENIC_MSIX_NOTIFY_INTR 1
#define ENIC_MSIX_IO_INTR_BASE ENIC_MSIX_RESERVED_INTR
#define ENIC_MSIX_MIN_INTR (ENIC_MSIX_RESERVED_INTR + 2)
#define ENIC_LEGACY_IO_INTR 0
#define ENIC_LEGACY_ERR_INTR 1
#define ENIC_LEGACY_NOTIFY_INTR 2
static inline unsigned int enic_msix_err_intr(struct enic *enic)
{
return ENIC_MSIX_ERR_INTR;
}
static inline unsigned int enic_msix_notify_intr(struct enic *enic)
{
return ENIC_MSIX_NOTIFY_INTR;
}
static inline bool enic_is_err_intr(struct enic *enic, int intr)
{
switch (vnic_dev_get_intr_mode(enic->vdev)) {
case VNIC_DEV_INTR_MODE_INTX:
return intr == ENIC_LEGACY_ERR_INTR;
case VNIC_DEV_INTR_MODE_MSIX:
return intr == enic_msix_err_intr(enic);
case VNIC_DEV_INTR_MODE_MSI:
default:
return false;
}
}
static inline bool enic_is_notify_intr(struct enic *enic, int intr)
{
switch (vnic_dev_get_intr_mode(enic->vdev)) {
case VNIC_DEV_INTR_MODE_INTX:
return intr == ENIC_LEGACY_NOTIFY_INTR;
case VNIC_DEV_INTR_MODE_MSIX:
return intr == enic_msix_notify_intr(enic);
case VNIC_DEV_INTR_MODE_MSI:
default:
return false;
}
}
static inline int enic_dma_map_check(struct enic *enic, dma_addr_t dma_addr)
{
if (unlikely(dma_mapping_error(&enic->pdev->dev, dma_addr))) {
net_warn_ratelimited("%s: PCI dma mapping failed!\n",
enic->netdev->name);
enic->gen_stats.dma_map_error++;
return -ENOMEM;
}
return 0;
}
void enic_reset_addr_lists(struct enic *enic);
int enic_sriov_enabled(struct enic *enic);
int enic_is_valid_vf(struct enic *enic, int vf);
int enic_is_dynamic(struct enic *enic);
void enic_set_ethtool_ops(struct net_device *netdev);
int __enic_set_rsskey(struct enic *enic);
void enic_ext_cq(struct enic *enic);
#endif /* _ENIC_H_ */