enic: Cisco VIC driver
This driver is based of the enic (Cisco VIC) DPDK driver. It provides basic ethernet functionality. Has been run with various VIC cards to do UEFI PXE boot with NFS root.
This commit is contained in:
@@ -143,6 +143,7 @@ MAN= aac.4 \
|
||||
em.4 \
|
||||
ena.4 \
|
||||
enc.4 \
|
||||
enic.4 \
|
||||
epair.4 \
|
||||
est.4 \
|
||||
et.4 \
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
.\" Copyright 2008-2017 Cisco Systems, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd Sept 7, 2022
|
||||
.Dt ENIC 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm enic
|
||||
.Nd "VIC Ethernet NIC driver"
|
||||
.Sh SYNOPSIS
|
||||
To compile this driver into the kernel,
|
||||
place the following lines in your
|
||||
kernel configuration file:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "device iflib"
|
||||
.Cd "device enic"
|
||||
.Ed
|
||||
.Pp
|
||||
To load the driver as a module at run-time,
|
||||
run the following command as root:
|
||||
.Bd -literal -offset indent
|
||||
kldload if_enic
|
||||
.Ed
|
||||
.Pp
|
||||
To load the driver as a
|
||||
module at boot time, place the following lines in
|
||||
.Xr loader.conf 5 :
|
||||
.Bd -literal -offset indent
|
||||
if_enic_load="YES"
|
||||
.Ed
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provides support for Cisco Virtual Interface Card. Support
|
||||
is limited to basic network connectivity. Media is controlled by the
|
||||
NIC itself since there can be multiple virtual PCI NIC devices exposed
|
||||
to the PCI bus.
|
||||
.Sh HARDWARE
|
||||
The
|
||||
.Nm
|
||||
driver should supports all known Cisco VIC cards.
|
||||
.Sh CONFIGURATION
|
||||
The
|
||||
.Nm
|
||||
network interface is configured using
|
||||
.Xr ifconfig 8
|
||||
and the
|
||||
.Xr sysctl 8
|
||||
tree at
|
||||
.Dv dev.enic.<N> .
|
||||
All configurable entries are also tunables, and can be put directly into the
|
||||
.Xr loader.conf 5
|
||||
for persistent configuration.
|
||||
.Sh SEE ALSO
|
||||
.Xr ifconfig 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
device driver first appeared in
|
||||
.Fx 14.0 .
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm
|
||||
driver was written by
|
||||
.An Cisco UCS team
|
||||
based of the DPDK driver.
|
||||
@@ -119,6 +119,14 @@ dev/axgbe/xgbe-txrx.c optional axp
|
||||
dev/axgbe/xgbe_osdep.c optional axp
|
||||
dev/axgbe/xgbe-i2c.c optional axp
|
||||
dev/axgbe/xgbe-phy-v2.c optional axp
|
||||
dev/enic/enic_res.c optional enic
|
||||
dev/enic/enic_txrx.c optional enic
|
||||
dev/enic/if_enic.c optional enic
|
||||
dev/enic/vnic_cq.c optional enic
|
||||
dev/enic/vnic_dev.c optional enic
|
||||
dev/enic/vnic_intr.c optional enic
|
||||
dev/enic/vnic_rq.c optional enic
|
||||
dev/enic/vnic_wq.c optional enic
|
||||
dev/hyperv/vmbus/amd64/hyperv_machdep.c optional hyperv
|
||||
dev/hyperv/vmbus/amd64/vmbus_vector.S optional hyperv
|
||||
dev/iavf/if_iavf_iflib.c optional iavf pci \
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CQ_DESC_H_
|
||||
#define _CQ_DESC_H_
|
||||
|
||||
/*
|
||||
* Completion queue descriptor types
|
||||
*/
|
||||
enum cq_desc_types {
|
||||
CQ_DESC_TYPE_WQ_ENET = 0,
|
||||
CQ_DESC_TYPE_DESC_COPY = 1,
|
||||
CQ_DESC_TYPE_WQ_EXCH = 2,
|
||||
CQ_DESC_TYPE_RQ_ENET = 3,
|
||||
CQ_DESC_TYPE_RQ_FCP = 4,
|
||||
CQ_DESC_TYPE_IOMMU_MISS = 5,
|
||||
CQ_DESC_TYPE_SGL = 6,
|
||||
CQ_DESC_TYPE_CLASSIFIER = 7,
|
||||
CQ_DESC_TYPE_TEST = 127,
|
||||
};
|
||||
|
||||
/* Completion queue descriptor: 16B
|
||||
*
|
||||
* All completion queues have this basic layout. The
|
||||
* type_specfic area is unique for each completion
|
||||
* queue type.
|
||||
*/
|
||||
struct cq_desc {
|
||||
__le16 completed_index;
|
||||
__le16 q_number;
|
||||
u8 type_specfic[11];
|
||||
u8 type_color;
|
||||
};
|
||||
|
||||
#define CQ_DESC_TYPE_BITS 4
|
||||
#define CQ_DESC_TYPE_MASK ((1 << CQ_DESC_TYPE_BITS) - 1)
|
||||
#define CQ_DESC_COLOR_MASK 1
|
||||
#define CQ_DESC_COLOR_SHIFT 7
|
||||
#define CQ_DESC_COLOR_MASK_NOSHIFT 0x80
|
||||
#define CQ_DESC_Q_NUM_BITS 10
|
||||
#define CQ_DESC_Q_NUM_MASK ((1 << CQ_DESC_Q_NUM_BITS) - 1)
|
||||
#define CQ_DESC_COMP_NDX_BITS 12
|
||||
#define CQ_DESC_COMP_NDX_MASK ((1 << CQ_DESC_COMP_NDX_BITS) - 1)
|
||||
|
||||
static inline void cq_color_enc(struct cq_desc *desc, const u8 color)
|
||||
{
|
||||
if (color)
|
||||
desc->type_color |= (1 << CQ_DESC_COLOR_SHIFT);
|
||||
else
|
||||
desc->type_color &= ~(1 << CQ_DESC_COLOR_SHIFT);
|
||||
}
|
||||
|
||||
static inline void cq_desc_enc(struct cq_desc *desc,
|
||||
const u8 type, const u8 color, const u16 q_number,
|
||||
const u16 completed_index)
|
||||
{
|
||||
desc->type_color = (type & CQ_DESC_TYPE_MASK) |
|
||||
((color & CQ_DESC_COLOR_MASK) << CQ_DESC_COLOR_SHIFT);
|
||||
desc->q_number = cpu_to_le16(q_number & CQ_DESC_Q_NUM_MASK);
|
||||
desc->completed_index = cpu_to_le16(completed_index &
|
||||
CQ_DESC_COMP_NDX_MASK);
|
||||
}
|
||||
|
||||
static inline void cq_desc_dec(const struct cq_desc *desc_arg,
|
||||
u8 *type, u8 *color, u16 *q_number, u16 *completed_index)
|
||||
{
|
||||
const struct cq_desc *desc = desc_arg;
|
||||
const u8 type_color = desc->type_color;
|
||||
|
||||
*color = (type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK;
|
||||
|
||||
/*
|
||||
* Make sure color bit is read from desc *before* other fields
|
||||
* are read from desc. Hardware guarantees color bit is last
|
||||
* bit (byte) written. Adding the rmb() prevents the compiler
|
||||
* and/or CPU from reordering the reads which would potentially
|
||||
* result in reading stale values.
|
||||
*/
|
||||
|
||||
rmb();
|
||||
|
||||
*type = type_color & CQ_DESC_TYPE_MASK;
|
||||
*q_number = le16_to_cpu(desc->q_number) & CQ_DESC_Q_NUM_MASK;
|
||||
*completed_index = le16_to_cpu(desc->completed_index) &
|
||||
CQ_DESC_COMP_NDX_MASK;
|
||||
}
|
||||
|
||||
static inline void cq_color_dec(const struct cq_desc *desc_arg, u8 *color)
|
||||
{
|
||||
volatile const struct cq_desc *desc = desc_arg;
|
||||
|
||||
*color = (desc->type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK;
|
||||
}
|
||||
|
||||
#endif /* _CQ_DESC_H_ */
|
||||
@@ -0,0 +1,244 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CQ_ENET_DESC_H_
|
||||
#define _CQ_ENET_DESC_H_
|
||||
|
||||
#include "cq_desc.h"
|
||||
|
||||
/* Ethernet completion queue descriptor: 16B */
|
||||
struct cq_enet_wq_desc {
|
||||
__le16 completed_index;
|
||||
__le16 q_number;
|
||||
u8 reserved[11];
|
||||
u8 type_color;
|
||||
};
|
||||
|
||||
static inline void cq_enet_wq_desc_enc(struct cq_enet_wq_desc *desc,
|
||||
u8 type, u8 color, u16 q_number, u16 completed_index)
|
||||
{
|
||||
cq_desc_enc((struct cq_desc *)desc, type,
|
||||
color, q_number, completed_index);
|
||||
}
|
||||
|
||||
static inline void cq_enet_wq_desc_dec(struct cq_enet_wq_desc *desc,
|
||||
u8 *type, u8 *color, u16 *q_number, u16 *completed_index)
|
||||
{
|
||||
cq_desc_dec((struct cq_desc *)desc, type,
|
||||
color, q_number, completed_index);
|
||||
}
|
||||
|
||||
/* Completion queue descriptor: Ethernet receive queue, 16B */
|
||||
struct cq_enet_rq_desc {
|
||||
__le16 completed_index_flags;
|
||||
__le16 q_number_rss_type_flags;
|
||||
__le32 rss_hash;
|
||||
__le16 bytes_written_flags;
|
||||
__le16 vlan;
|
||||
__le16 checksum_fcoe;
|
||||
u8 flags;
|
||||
u8 type_color;
|
||||
};
|
||||
|
||||
/* Completion queue descriptor: Ethernet receive queue, 16B */
|
||||
struct cq_enet_rq_clsf_desc {
|
||||
__le16 completed_index_flags;
|
||||
__le16 q_number_rss_type_flags;
|
||||
__le16 filter_id;
|
||||
__le16 lif;
|
||||
__le16 bytes_written_flags;
|
||||
__le16 vlan;
|
||||
__le16 checksum_fcoe;
|
||||
u8 flags;
|
||||
u8 type_color;
|
||||
};
|
||||
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT (0x1 << 12)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_FCOE (0x1 << 13)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_EOP (0x1 << 14)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_SOP (0x1 << 15)
|
||||
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_BITS 4
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_RSS_TYPE_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_NONE 0
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv4 1
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv4 2
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6 3
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6 4
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6_EX 5
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6_EX 6
|
||||
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC (0x1 << 14)
|
||||
|
||||
#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS 14
|
||||
#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_TRUNCATED (0x1 << 14)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED (0x1 << 15)
|
||||
|
||||
#define CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_BITS 12
|
||||
#define CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_VLAN_TCI_CFI_MASK (0x1 << 12)
|
||||
#define CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_BITS 3
|
||||
#define CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_SHIFT 13
|
||||
|
||||
#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS 8
|
||||
#define CQ_ENET_RQ_DESC_FCOE_SOF_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_FCOE_SOF_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_FCOE_EOF_BITS 8
|
||||
#define CQ_ENET_RQ_DESC_FCOE_EOF_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_FCOE_EOF_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT 8
|
||||
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK (0x1 << 0)
|
||||
#define CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK (0x1 << 0)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_UDP (0x1 << 1)
|
||||
#define CQ_ENET_RQ_DESC_FCOE_ENC_ERROR (0x1 << 1)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_TCP (0x1 << 2)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK (0x1 << 3)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_IPV6 (0x1 << 4)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_IPV4 (0x1 << 5)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT (0x1 << 6)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_FCS_OK (0x1 << 7)
|
||||
|
||||
static inline void cq_enet_rq_desc_enc(struct cq_enet_rq_desc *desc,
|
||||
u8 type, u8 color, u16 q_number, u16 completed_index,
|
||||
u8 ingress_port, u8 fcoe, u8 eop, u8 sop, u8 rss_type, u8 csum_not_calc,
|
||||
u32 rss_hash, u16 bytes_written, u8 packet_error, u8 vlan_stripped,
|
||||
u16 vlan, u16 checksum, u8 fcoe_sof, u8 fcoe_fc_crc_ok,
|
||||
u8 fcoe_enc_error, u8 fcoe_eof, u8 tcp_udp_csum_ok, u8 udp, u8 tcp,
|
||||
u8 ipv4_csum_ok, u8 ipv6, u8 ipv4, u8 ipv4_fragment, u8 fcs_ok)
|
||||
{
|
||||
cq_desc_enc((struct cq_desc *)desc, type,
|
||||
color, q_number, completed_index);
|
||||
|
||||
desc->completed_index_flags |= cpu_to_le16(
|
||||
(ingress_port ? CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT : 0) |
|
||||
(fcoe ? CQ_ENET_RQ_DESC_FLAGS_FCOE : 0) |
|
||||
(eop ? CQ_ENET_RQ_DESC_FLAGS_EOP : 0) |
|
||||
(sop ? CQ_ENET_RQ_DESC_FLAGS_SOP : 0));
|
||||
|
||||
desc->q_number_rss_type_flags |= cpu_to_le16(
|
||||
((rss_type & CQ_ENET_RQ_DESC_RSS_TYPE_MASK) <<
|
||||
CQ_DESC_Q_NUM_BITS) |
|
||||
(csum_not_calc ? CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC : 0));
|
||||
|
||||
desc->rss_hash = cpu_to_le32(rss_hash);
|
||||
|
||||
desc->bytes_written_flags = cpu_to_le16(
|
||||
(bytes_written & CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK) |
|
||||
(packet_error ? CQ_ENET_RQ_DESC_FLAGS_TRUNCATED : 0) |
|
||||
(vlan_stripped ? CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED : 0));
|
||||
|
||||
desc->vlan = cpu_to_le16(vlan);
|
||||
|
||||
if (fcoe) {
|
||||
desc->checksum_fcoe = cpu_to_le16(
|
||||
(fcoe_sof & CQ_ENET_RQ_DESC_FCOE_SOF_MASK) |
|
||||
((fcoe_eof & CQ_ENET_RQ_DESC_FCOE_EOF_MASK) <<
|
||||
CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT));
|
||||
} else {
|
||||
desc->checksum_fcoe = cpu_to_le16(checksum);
|
||||
}
|
||||
|
||||
desc->flags =
|
||||
(tcp_udp_csum_ok ? CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK : 0) |
|
||||
(udp ? CQ_ENET_RQ_DESC_FLAGS_UDP : 0) |
|
||||
(tcp ? CQ_ENET_RQ_DESC_FLAGS_TCP : 0) |
|
||||
(ipv4_csum_ok ? CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK : 0) |
|
||||
(ipv6 ? CQ_ENET_RQ_DESC_FLAGS_IPV6 : 0) |
|
||||
(ipv4 ? CQ_ENET_RQ_DESC_FLAGS_IPV4 : 0) |
|
||||
(ipv4_fragment ? CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT : 0) |
|
||||
(fcs_ok ? CQ_ENET_RQ_DESC_FLAGS_FCS_OK : 0) |
|
||||
(fcoe_fc_crc_ok ? CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK : 0) |
|
||||
(fcoe_enc_error ? CQ_ENET_RQ_DESC_FCOE_ENC_ERROR : 0);
|
||||
}
|
||||
|
||||
static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc,
|
||||
u8 *type, u8 *color, u16 *q_number, u16 *completed_index,
|
||||
u8 *ingress_port, u8 *fcoe, u8 *eop, u8 *sop, u8 *rss_type,
|
||||
u8 *csum_not_calc, u32 *rss_hash, u16 *bytes_written, u8 *packet_error,
|
||||
u8 *vlan_stripped, u16 *vlan_tci, u16 *checksum, u8 *fcoe_sof,
|
||||
u8 *fcoe_fc_crc_ok, u8 *fcoe_enc_error, u8 *fcoe_eof,
|
||||
u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok,
|
||||
u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok)
|
||||
{
|
||||
u16 completed_index_flags;
|
||||
u16 q_number_rss_type_flags;
|
||||
u16 bytes_written_flags;
|
||||
|
||||
cq_desc_dec((struct cq_desc *)desc, type,
|
||||
color, q_number, completed_index);
|
||||
|
||||
completed_index_flags = le16_to_cpu(desc->completed_index_flags);
|
||||
q_number_rss_type_flags =
|
||||
le16_to_cpu(desc->q_number_rss_type_flags);
|
||||
bytes_written_flags = le16_to_cpu(desc->bytes_written_flags);
|
||||
|
||||
*ingress_port = (completed_index_flags &
|
||||
CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT) ? 1 : 0;
|
||||
*fcoe = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_FCOE) ?
|
||||
1 : 0;
|
||||
*eop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_EOP) ?
|
||||
1 : 0;
|
||||
*sop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_SOP) ?
|
||||
1 : 0;
|
||||
|
||||
*rss_type = (u8)((q_number_rss_type_flags >> CQ_DESC_Q_NUM_BITS) &
|
||||
CQ_ENET_RQ_DESC_RSS_TYPE_MASK);
|
||||
*csum_not_calc = (q_number_rss_type_flags &
|
||||
CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC) ? 1 : 0;
|
||||
|
||||
*rss_hash = le32_to_cpu(desc->rss_hash);
|
||||
|
||||
*bytes_written = bytes_written_flags &
|
||||
CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK;
|
||||
*packet_error = (bytes_written_flags &
|
||||
CQ_ENET_RQ_DESC_FLAGS_TRUNCATED) ? 1 : 0;
|
||||
*vlan_stripped = (bytes_written_flags &
|
||||
CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Tag Control Information(16) = user_priority(3) + cfi(1) + vlan(12)
|
||||
*/
|
||||
*vlan_tci = le16_to_cpu(desc->vlan);
|
||||
|
||||
if (*fcoe) {
|
||||
*fcoe_sof = (u8)(le16_to_cpu(desc->checksum_fcoe) &
|
||||
CQ_ENET_RQ_DESC_FCOE_SOF_MASK);
|
||||
*fcoe_fc_crc_ok = (desc->flags &
|
||||
CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK) ? 1 : 0;
|
||||
*fcoe_enc_error = (desc->flags &
|
||||
CQ_ENET_RQ_DESC_FCOE_ENC_ERROR) ? 1 : 0;
|
||||
*fcoe_eof = (u8)((le16_to_cpu(desc->checksum_fcoe) >>
|
||||
CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT) &
|
||||
CQ_ENET_RQ_DESC_FCOE_EOF_MASK);
|
||||
*checksum = 0;
|
||||
} else {
|
||||
*fcoe_sof = 0;
|
||||
*fcoe_fc_crc_ok = 0;
|
||||
*fcoe_enc_error = 0;
|
||||
*fcoe_eof = 0;
|
||||
*checksum = le16_to_cpu(desc->checksum_fcoe);
|
||||
}
|
||||
|
||||
*tcp_udp_csum_ok =
|
||||
(desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK) ? 1 : 0;
|
||||
*udp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_UDP) ? 1 : 0;
|
||||
*tcp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP) ? 1 : 0;
|
||||
*ipv4_csum_ok =
|
||||
(desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK) ? 1 : 0;
|
||||
*ipv6 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV6) ? 1 : 0;
|
||||
*ipv4 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4) ? 1 : 0;
|
||||
*ipv4_fragment =
|
||||
(desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT) ? 1 : 0;
|
||||
*fcs_ok = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_FCS_OK) ? 1 : 0;
|
||||
}
|
||||
|
||||
#endif /* _CQ_ENET_DESC_H_ */
|
||||
@@ -0,0 +1,406 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: $");
|
||||
|
||||
#ifndef _ENIC_H
|
||||
#define _ENIC_H
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/iflib.h>
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
#define u64 uint64_t
|
||||
|
||||
struct enic_bar_info {
|
||||
struct resource *res;
|
||||
bus_space_tag_t tag;
|
||||
bus_space_handle_t handle;
|
||||
bus_size_t size;
|
||||
int rid;
|
||||
int offset;
|
||||
};
|
||||
|
||||
#define ENIC_BUS_WRITE_8(res, index, value) \
|
||||
bus_space_write_8(res->bar.tag, res->bar.handle, \
|
||||
res->bar.offset + (index), value)
|
||||
#define ENIC_BUS_WRITE_4(res, index, value) \
|
||||
bus_space_write_4(res->bar.tag, res->bar.handle, \
|
||||
res->bar.offset + (index), value)
|
||||
#define ENIC_BUS_WRITE_REGION_4(res, index, values, count) \
|
||||
bus_space_write_region_4(res->bar.tag, res->bar.handle, \
|
||||
res->bar.offset + (index), values, count);
|
||||
|
||||
#define ENIC_BUS_READ_8(res, index) \
|
||||
bus_space_read_8(res->bar.tag, res->bar.handle, \
|
||||
res->bar.offset + (index))
|
||||
#define ENIC_BUS_READ_4(res, index) \
|
||||
bus_space_read_4(res->bar.tag, res->bar.handle, \
|
||||
res->bar.offset + (index))
|
||||
#define ENIC_BUS_READ_REGION_4(res, type, index, values, count) \
|
||||
bus_space_read_region_4(res->type.tag, res->type.handle, \
|
||||
res->type.offset + (index), values, count);
|
||||
|
||||
struct vnic_res {
|
||||
unsigned int count;
|
||||
struct enic_bar_info bar;
|
||||
};
|
||||
|
||||
#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 "enic_res.h"
|
||||
#include "cq_enet_desc.h"
|
||||
|
||||
#define ENIC_LOCK(_softc) mtx_lock(&(_softc)->enic_lock)
|
||||
#define ENIC_UNLOCK(_softc) mtx_unlock(&(_softc)->enic_lock)
|
||||
|
||||
#define DRV_NAME "enic"
|
||||
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC"
|
||||
#define DRV_COPYRIGHT "Copyright 2008-2015 Cisco Systems, Inc"
|
||||
|
||||
#define ENIC_MAX_MAC_ADDR 64
|
||||
|
||||
#define VLAN_ETH_HLEN 18
|
||||
|
||||
#define ENICPMD_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0)
|
||||
|
||||
#define ENICPMD_BDF_LENGTH 13 /* 0000:00:00.0'\0' */
|
||||
#define ENIC_CALC_IP_CKSUM 1
|
||||
#define ENIC_CALC_TCP_UDP_CKSUM 2
|
||||
#define ENIC_MAX_MTU 9000
|
||||
#define ENIC_PAGE_SIZE 4096
|
||||
#define PAGE_ROUND_UP(x) \
|
||||
((((unsigned long)(x)) + ENIC_PAGE_SIZE-1) & (~(ENIC_PAGE_SIZE-1)))
|
||||
|
||||
/* must be >= VNIC_COUNTER_DMA_MIN_PERIOD */
|
||||
#define VNIC_FLOW_COUNTER_UPDATE_MSECS 500
|
||||
|
||||
/* PCI IDs */
|
||||
#define CISCO_VENDOR_ID 0x1137
|
||||
|
||||
#define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */
|
||||
#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */
|
||||
|
||||
/* Special Filter id for non-specific packet flagging. Don't change value */
|
||||
#define ENIC_MAGIC_FILTER_ID 0xffff
|
||||
|
||||
#define ENICPMD_FDIR_MAX 64
|
||||
|
||||
/* HW default VXLAN port */
|
||||
#define ENIC_DEFAULT_VXLAN_PORT 4789
|
||||
|
||||
/*
|
||||
* Interrupt 0: LSC and errors
|
||||
* Interrupt 1: rx queue 0
|
||||
* Interrupt 2: rx queue 1
|
||||
* ...
|
||||
*/
|
||||
#define ENICPMD_LSC_INTR_OFFSET 0
|
||||
#define ENICPMD_RXQ_INTR_OFFSET 1
|
||||
|
||||
#include "vnic_devcmd.h"
|
||||
|
||||
enum vnic_proxy_type {
|
||||
PROXY_NONE,
|
||||
PROXY_BY_BDF,
|
||||
PROXY_BY_INDEX,
|
||||
};
|
||||
|
||||
struct vnic_intr_coal_timer_info {
|
||||
u32 mul;
|
||||
u32 div;
|
||||
u32 max_usec;
|
||||
};
|
||||
|
||||
struct enic_softc;
|
||||
struct vnic_dev {
|
||||
void *priv;
|
||||
struct rte_pci_device *pdev;
|
||||
struct vnic_res res[RES_TYPE_MAX];
|
||||
enum vnic_dev_intr_mode intr_mode;
|
||||
struct vnic_res __iomem *devcmd;
|
||||
struct vnic_devcmd_notify *notify;
|
||||
struct vnic_devcmd_notify notify_copy;
|
||||
bus_addr_t notify_pa;
|
||||
struct iflib_dma_info notify_res;
|
||||
u32 notify_sz;
|
||||
struct iflib_dma_info linkstatus_res;
|
||||
struct vnic_stats *stats;
|
||||
struct iflib_dma_info stats_res;
|
||||
struct vnic_devcmd_fw_info *fw_info;
|
||||
struct iflib_dma_info fw_info_res;
|
||||
enum vnic_proxy_type proxy;
|
||||
u32 proxy_index;
|
||||
u64 args[VNIC_DEVCMD_NARGS];
|
||||
int in_reset;
|
||||
struct vnic_intr_coal_timer_info intr_coal_timer_info;
|
||||
void *(*alloc_consistent)(void *priv, size_t size,
|
||||
bus_addr_t *dma_handle, struct iflib_dma_info *res, u8 *name);
|
||||
void (*free_consistent)(void *priv, size_t size, void *vaddr,
|
||||
bus_addr_t dma_handle, struct iflib_dma_info *res);
|
||||
struct vnic_counter_counts *flow_counters;
|
||||
struct iflib_dma_info flow_counters_res;
|
||||
u8 flow_counters_dma_active;
|
||||
struct enic_softc *softc;
|
||||
};
|
||||
|
||||
struct enic_soft_stats {
|
||||
uint64_t rx_nombuf;
|
||||
uint64_t rx_packet_errors;
|
||||
uint64_t tx_oversized;
|
||||
};
|
||||
|
||||
struct intr_queue {
|
||||
struct if_irq intr_irq;
|
||||
struct resource *res;
|
||||
int rid;
|
||||
struct enic_softc *softc;
|
||||
};
|
||||
|
||||
struct enic {
|
||||
struct enic *next;
|
||||
struct rte_pci_device *pdev;
|
||||
struct vnic_enet_config config;
|
||||
struct vnic_dev_bar bar0;
|
||||
struct vnic_dev *vdev;
|
||||
|
||||
/*
|
||||
* mbuf_initializer contains 64 bits of mbuf rearm_data, used by
|
||||
* the avx2 handler at this time.
|
||||
*/
|
||||
uint64_t mbuf_initializer;
|
||||
unsigned int port_id;
|
||||
bool overlay_offload;
|
||||
char bdf_name[ENICPMD_BDF_LENGTH];
|
||||
int dev_fd;
|
||||
int iommu_group_fd;
|
||||
int iommu_groupid;
|
||||
int eventfd;
|
||||
uint8_t mac_addr[ETH_ALEN];
|
||||
pthread_t err_intr_thread;
|
||||
u8 ig_vlan_strip_en;
|
||||
int link_status;
|
||||
u8 hw_ip_checksum;
|
||||
u16 max_mtu;
|
||||
u8 adv_filters;
|
||||
u32 flow_filter_mode;
|
||||
u8 filter_actions; /* HW supported actions */
|
||||
bool vxlan;
|
||||
bool disable_overlay; /* devargs disable_overlay=1 */
|
||||
uint8_t enable_avx2_rx; /* devargs enable-avx2-rx=1 */
|
||||
bool nic_cfg_chk; /* NIC_CFG_CHK available */
|
||||
bool udp_rss_weak; /* Bodega style UDP RSS */
|
||||
uint8_t ig_vlan_rewrite_mode; /* devargs ig-vlan-rewrite */
|
||||
uint16_t vxlan_port; /* current vxlan port pushed to NIC */
|
||||
|
||||
unsigned int flags;
|
||||
unsigned int priv_flags;
|
||||
|
||||
/* work queue (len = conf_wq_count) */
|
||||
struct vnic_wq *wq;
|
||||
unsigned int wq_count; /* equals eth_dev nb_tx_queues */
|
||||
|
||||
/* receive queue (len = conf_rq_count) */
|
||||
struct vnic_rq *rq;
|
||||
unsigned int rq_count; /* equals eth_dev nb_rx_queues */
|
||||
|
||||
/* completion queue (len = conf_cq_count) */
|
||||
struct vnic_cq *cq;
|
||||
unsigned int cq_count; /* equals rq_count + wq_count */
|
||||
|
||||
/* interrupt vectors (len = conf_intr_count) */
|
||||
struct vnic_intr *intr;
|
||||
struct intr_queue *intr_queues;;
|
||||
unsigned int intr_count; /* equals enabled interrupts (lsc + rxqs) */
|
||||
|
||||
|
||||
/* software counters */
|
||||
struct enic_soft_stats soft_stats;
|
||||
|
||||
/* configured resources on vic */
|
||||
unsigned int conf_rq_count;
|
||||
unsigned int conf_wq_count;
|
||||
unsigned int conf_cq_count;
|
||||
unsigned int conf_intr_count;
|
||||
|
||||
/* linked list storing memory allocations */
|
||||
LIST_HEAD(enic_memzone_list, enic_memzone_entry) memzone_list;
|
||||
|
||||
LIST_HEAD(enic_flows, rte_flow) flows;
|
||||
int max_flow_counter;
|
||||
|
||||
/* RSS */
|
||||
uint16_t reta_size;
|
||||
uint8_t hash_key_size;
|
||||
uint64_t flow_type_rss_offloads; /* 0 indicates RSS not supported */
|
||||
/*
|
||||
* Keep a copy of current RSS config for queries, as we cannot retrieve
|
||||
* it from the NIC.
|
||||
*/
|
||||
uint8_t rss_hash_type; /* NIC_CFG_RSS_HASH_TYPE flags */
|
||||
uint8_t rss_enable;
|
||||
uint64_t rss_hf; /* ETH_RSS flags */
|
||||
union vnic_rss_key rss_key;
|
||||
union vnic_rss_cpu rss_cpu;
|
||||
|
||||
uint64_t rx_offload_capa; /* DEV_RX_OFFLOAD flags */
|
||||
uint64_t tx_offload_capa; /* DEV_TX_OFFLOAD flags */
|
||||
uint64_t tx_queue_offload_capa; /* DEV_TX_OFFLOAD flags */
|
||||
uint64_t tx_offload_mask; /* PKT_TX flags accepted */
|
||||
struct enic_softc *softc;
|
||||
int port_mtu;
|
||||
};
|
||||
|
||||
struct enic_softc {
|
||||
device_t dev;
|
||||
if_ctx_t ctx;
|
||||
if_softc_ctx_t scctx;
|
||||
if_shared_ctx_t sctx;
|
||||
struct ifmedia *media;
|
||||
struct ifnet *ifp;
|
||||
|
||||
struct mtx enic_lock;
|
||||
|
||||
struct enic_bar_info mem;
|
||||
struct enic_bar_info io;
|
||||
|
||||
struct vnic_dev vdev;
|
||||
struct enic enic;
|
||||
|
||||
int ntxqsets;
|
||||
int nrxqsets;
|
||||
|
||||
struct if_irq enic_event_intr_irq;
|
||||
struct if_irq enic_err_intr_irq;
|
||||
uint8_t lladdr[ETHER_ADDR_LEN];
|
||||
int link_active;
|
||||
int stopped;
|
||||
uint8_t mac_addr[ETHER_ADDR_LEN];
|
||||
|
||||
int directed;
|
||||
int multicast;
|
||||
int broadcast;
|
||||
int promisc;
|
||||
int allmulti;
|
||||
|
||||
u_int mc_count;
|
||||
uint8_t *mta;
|
||||
};
|
||||
|
||||
/* Per-instance private data structure */
|
||||
|
||||
static inline unsigned int enic_vnic_rq_count(struct enic *enic)
|
||||
{
|
||||
return enic->rq_count;
|
||||
}
|
||||
|
||||
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 uint32_t
|
||||
enic_ring_add(uint32_t n_descriptors, uint32_t i0, uint32_t i1)
|
||||
{
|
||||
uint32_t d = i0 + i1;
|
||||
d -= (d >= n_descriptors) ? n_descriptors : 0;
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
enic_ring_sub(uint32_t n_descriptors, uint32_t i0, uint32_t i1)
|
||||
{
|
||||
int32_t d = i1 - i0;
|
||||
return (uint32_t)((d < 0) ? ((int32_t)n_descriptors + d) : d);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
enic_ring_incr(uint32_t n_descriptors, uint32_t idx)
|
||||
{
|
||||
idx++;
|
||||
if (unlikely(idx == n_descriptors))
|
||||
idx = 0;
|
||||
return idx;
|
||||
}
|
||||
|
||||
void enic_free_wq(void *txq);
|
||||
int enic_alloc_intr_resources(struct enic *enic);
|
||||
int enic_setup_finish(struct enic *enic);
|
||||
int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
|
||||
unsigned int socket_id, uint16_t nb_desc);
|
||||
void enic_start_wq(struct enic *enic, uint16_t queue_idx);
|
||||
int enic_stop_wq(struct enic *enic, uint16_t queue_idx);
|
||||
void enic_start_rq(struct enic *enic, uint16_t queue_idx);
|
||||
void enic_free_rq(void *rxq);
|
||||
int enic_set_vnic_res(struct enic *enic);
|
||||
int enic_init_rss_nic_cfg(struct enic *enic);
|
||||
int enic_set_rss_reta(struct enic *enic, union vnic_rss_cpu *rss_cpu);
|
||||
int enic_set_vlan_strip(struct enic *enic);
|
||||
int enic_enable(struct enic *enic);
|
||||
int enic_disable(struct enic *enic);
|
||||
void enic_remove(struct enic *enic);
|
||||
int enic_get_link_status(struct enic *enic);
|
||||
void enic_dev_stats_clear(struct enic *enic);
|
||||
void enic_add_packet_filter(struct enic *enic);
|
||||
int enic_set_mac_address(struct enic *enic, uint8_t *mac_addr);
|
||||
int enic_del_mac_address(struct enic *enic, int mac_index);
|
||||
unsigned int enic_cleanup_wq(struct enic *enic, struct vnic_wq *wq);
|
||||
|
||||
void enic_post_wq_index(struct vnic_wq *wq);
|
||||
int enic_probe(struct enic *enic);
|
||||
int enic_clsf_init(struct enic *enic);
|
||||
void enic_clsf_destroy(struct enic *enic);
|
||||
int enic_set_mtu(struct enic *enic, uint16_t new_mtu);
|
||||
int enic_link_update(struct enic *enic);
|
||||
bool enic_use_vector_rx_handler(struct enic *enic);
|
||||
void enic_fdir_info(struct enic *enic);
|
||||
void enic_prep_wq_for_simple_tx(struct enic *, uint16_t);
|
||||
|
||||
struct enic_ring {
|
||||
uint64_t paddr;
|
||||
caddr_t vaddr;
|
||||
struct enic_softc *softc;
|
||||
uint32_t ring_size; /* Must be a power of two */
|
||||
uint16_t id; /* Logical ID */
|
||||
uint16_t phys_id;
|
||||
};
|
||||
|
||||
struct enic_cp_ring {
|
||||
struct enic_ring ring;
|
||||
struct if_irq irq;
|
||||
uint32_t cons;
|
||||
bool v_bit; /* Value of valid bit */
|
||||
struct ctx_hw_stats *stats;
|
||||
uint32_t stats_ctx_id;
|
||||
uint32_t last_idx; /* Used by RX rings only
|
||||
* set to the last read pidx
|
||||
*/
|
||||
};
|
||||
|
||||
#endif /* _ENIC_H_ */
|
||||
@@ -0,0 +1,65 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _ENIC_COMPAT_H_
|
||||
#define _ENIC_COMPAT_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/priv.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#define ETH_ALEN ETHER_ADDR_LEN
|
||||
|
||||
#define typeof __typeof__
|
||||
#define __iomem
|
||||
#define unlikely(x) __builtin_expect((x),0)
|
||||
|
||||
#define le16_to_cpu
|
||||
#define le32_to_cpu
|
||||
#define le64_to_cpu
|
||||
#define cpu_to_le16
|
||||
#define cpu_to_le32
|
||||
#define cpu_to_le64
|
||||
|
||||
#define pr_err(y, args...) dev_err(0, y, ##args)
|
||||
#define pr_warn(y, args...) dev_warning(0, y, ##args)
|
||||
#define BUG() pr_err("BUG at %s:%d", __func__, __LINE__)
|
||||
|
||||
#define VNIC_ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
|
||||
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
|
||||
#define udelay(t) DELAY(t)
|
||||
#define usleep(x) pause("ENIC usleep", ((x) * 1000000 / hz + 1))
|
||||
|
||||
#define dev_printk(level, fmt, args...) \
|
||||
printf(fmt, ## args)
|
||||
|
||||
#define dev_err(x, args...) dev_printk(ERR, args)
|
||||
/*#define dev_info(x, args...) dev_printk(INFO, args)*/
|
||||
#define dev_info(x, args...)
|
||||
|
||||
#define __le16 uint16_t
|
||||
#define __le32 uint32_t
|
||||
#define __le64 uint64_t
|
||||
|
||||
#define min_t(type, x, y) ({ \
|
||||
type __min1 = (x); \
|
||||
type __min2 = (y); \
|
||||
__min1 < __min2 ? __min1 : __min2; })
|
||||
|
||||
#define max_t(type, x, y) ({ \
|
||||
type __max1 = (x); \
|
||||
type __max2 = (y); \
|
||||
__max1 > __max2 ? __max1 : __max2; })
|
||||
|
||||
#endif /* _ENIC_COMPAT_H_ */
|
||||
@@ -0,0 +1,212 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "enic.h"
|
||||
#include "enic_compat.h"
|
||||
#include "wq_enet_desc.h"
|
||||
#include "rq_enet_desc.h"
|
||||
#include "cq_enet_desc.h"
|
||||
#include "vnic_resource.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 "enic_res.h"
|
||||
#include "enic.h"
|
||||
|
||||
int enic_get_vnic_config(struct enic *enic)
|
||||
{
|
||||
struct vnic_enet_config *c = &enic->config;
|
||||
int err;
|
||||
err = vnic_dev_get_mac_addr(enic->vdev, enic->mac_addr);
|
||||
if (err) {
|
||||
dev_err(enic_get_dev(enic),
|
||||
"Error getting MAC addr, %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#define GET_CONFIG(m) \
|
||||
do { \
|
||||
err = vnic_dev_spec(enic->vdev, \
|
||||
offsetof(struct vnic_enet_config, m), \
|
||||
sizeof(c->m), &c->m); \
|
||||
if (err) { \
|
||||
dev_err(enic_get_dev(enic), \
|
||||
"Error getting %s, %d\n", #m, err); \
|
||||
return err; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
GET_CONFIG(flags);
|
||||
GET_CONFIG(wq_desc_count);
|
||||
GET_CONFIG(rq_desc_count);
|
||||
GET_CONFIG(mtu);
|
||||
GET_CONFIG(intr_timer_type);
|
||||
GET_CONFIG(intr_mode);
|
||||
GET_CONFIG(intr_timer_usec);
|
||||
GET_CONFIG(loop_tag);
|
||||
GET_CONFIG(num_arfs);
|
||||
GET_CONFIG(max_pkt_size);
|
||||
|
||||
/* max packet size is only defined in newer VIC firmware
|
||||
* and will be 0 for legacy firmware and VICs
|
||||
*/
|
||||
if (c->max_pkt_size > ENIC_DEFAULT_RX_MAX_PKT_SIZE)
|
||||
enic->max_mtu = c->max_pkt_size - (ETHER_HDR_LEN + 4);
|
||||
else
|
||||
enic->max_mtu = ENIC_DEFAULT_RX_MAX_PKT_SIZE
|
||||
- (ETHER_HDR_LEN + 4);
|
||||
if (c->mtu == 0)
|
||||
c->mtu = 1500;
|
||||
|
||||
enic->adv_filters = vnic_dev_capable_adv_filters(enic->vdev);
|
||||
|
||||
err = vnic_dev_capable_filter_mode(enic->vdev, &enic->flow_filter_mode,
|
||||
&enic->filter_actions);
|
||||
if (err) {
|
||||
dev_err(enic_get_dev(enic),
|
||||
"Error getting filter modes, %d\n", err);
|
||||
return err;
|
||||
}
|
||||
vnic_dev_capable_udp_rss_weak(enic->vdev, &enic->nic_cfg_chk,
|
||||
&enic->udp_rss_weak);
|
||||
|
||||
c->wq_desc_count =
|
||||
min_t(u32, ENIC_MAX_WQ_DESCS,
|
||||
max_t(u32, ENIC_MIN_WQ_DESCS,
|
||||
c->wq_desc_count));
|
||||
c->wq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
|
||||
|
||||
c->rq_desc_count =
|
||||
min_t(u32, ENIC_MAX_RQ_DESCS,
|
||||
max_t(u32, ENIC_MIN_RQ_DESCS,
|
||||
c->rq_desc_count));
|
||||
c->rq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
|
||||
|
||||
c->intr_timer_usec = min_t(u32, c->intr_timer_usec,
|
||||
vnic_dev_get_intr_coal_timer_max(enic->vdev));
|
||||
|
||||
dev_info(enic_get_dev(enic),
|
||||
"vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x "
|
||||
"wq/rq %d/%d mtu d, max mtu:%d\n",
|
||||
enic->mac_addr[0], enic->mac_addr[1], enic->mac_addr[2],
|
||||
enic->mac_addr[3], enic->mac_addr[4], enic->mac_addr[5],
|
||||
c->wq_desc_count, c->rq_desc_count,
|
||||
/* enic->rte_dev->data->mtu, */ enic->max_mtu);
|
||||
dev_info(enic_get_dev(enic), "vNIC csum tx/rx %s/%s "
|
||||
"rss %s intr mode %s type %s timer %d usec "
|
||||
"loopback tag 0x%04x\n",
|
||||
ENIC_SETTING(enic, TXCSUM) ? "yes" : "no",
|
||||
ENIC_SETTING(enic, RXCSUM) ? "yes" : "no",
|
||||
ENIC_SETTING(enic, RSS) ?
|
||||
(ENIC_SETTING(enic, RSSHASH_UDPIPV4) ? "+UDP" :
|
||||
((enic->udp_rss_weak ? "+udp" :
|
||||
"yes"))) : "no",
|
||||
c->intr_mode == VENET_INTR_MODE_INTX ? "INTx" :
|
||||
c->intr_mode == VENET_INTR_MODE_MSI ? "MSI" :
|
||||
c->intr_mode == VENET_INTR_MODE_ANY ? "any" :
|
||||
"unknown",
|
||||
c->intr_timer_type == VENET_INTR_TYPE_MIN ? "min" :
|
||||
c->intr_timer_type == VENET_INTR_TYPE_IDLE ? "idle" :
|
||||
"unknown",
|
||||
c->intr_timer_usec,
|
||||
c->loop_tag);
|
||||
|
||||
/* RSS settings from vNIC */
|
||||
enic->reta_size = ENIC_RSS_RETA_SIZE;
|
||||
enic->hash_key_size = ENIC_RSS_HASH_KEY_SIZE;
|
||||
enic->flow_type_rss_offloads = 0;
|
||||
|
||||
/* Zero offloads if RSS is not enabled */
|
||||
if (!ENIC_SETTING(enic, RSS))
|
||||
enic->flow_type_rss_offloads = 0;
|
||||
|
||||
enic->vxlan = ENIC_SETTING(enic, VXLAN) &&
|
||||
vnic_dev_capable_vxlan(enic->vdev);
|
||||
/*
|
||||
* Default hardware capabilities. enic_dev_init() may add additional
|
||||
* flags if it enables overlay offloads.
|
||||
*/
|
||||
enic->tx_queue_offload_capa = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int enic_add_vlan(struct enic *enic, u16 vlanid)
|
||||
{
|
||||
u64 a0 = vlanid, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
|
||||
err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
|
||||
if (err)
|
||||
dev_err(enic_get_dev(enic), "Can't add vlan id, %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_del_vlan(struct enic *enic, u16 vlanid)
|
||||
{
|
||||
u64 a0 = vlanid, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
|
||||
err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
|
||||
if (err)
|
||||
dev_err(enic_get_dev(enic), "Can't delete vlan id, %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
|
||||
u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
|
||||
u8 ig_vlan_strip_en)
|
||||
{
|
||||
enum vnic_devcmd_cmd cmd;
|
||||
u64 a0, a1;
|
||||
u32 nic_cfg;
|
||||
int wait = 1000;
|
||||
|
||||
vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
|
||||
rss_hash_type, rss_hash_bits, rss_base_cpu,
|
||||
rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
|
||||
|
||||
a0 = nic_cfg;
|
||||
a1 = 0;
|
||||
cmd = enic->nic_cfg_chk ? CMD_NIC_CFG_CHK : CMD_NIC_CFG;
|
||||
return vnic_dev_cmd(enic->vdev, cmd, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
void enic_get_res_counts(struct enic *enic)
|
||||
{
|
||||
enic->conf_wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
|
||||
enic->conf_rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
|
||||
enic->conf_cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
|
||||
enic->conf_intr_count = vnic_dev_get_res_count(enic->vdev,
|
||||
RES_TYPE_INTR_CTRL);
|
||||
|
||||
dev_info(enic_get_dev(enic),
|
||||
"vNIC resources avail: wq %d rq %d cq %d intr %d\n",
|
||||
enic->conf_wq_count, enic->conf_rq_count,
|
||||
enic->conf_cq_count, enic->conf_intr_count);
|
||||
enic->conf_rq_count = min(enic->conf_rq_count, enic->conf_wq_count);
|
||||
enic->conf_wq_count = enic->conf_rq_count;
|
||||
enic->conf_cq_count = enic->conf_rq_count + enic->conf_wq_count;
|
||||
dev_info(enic_get_dev(enic),
|
||||
"vNIC resources iflib: wq %d rq %d cq %d intr %d\n",
|
||||
enic->conf_wq_count, enic->conf_rq_count,
|
||||
enic->conf_cq_count, enic->conf_intr_count);
|
||||
dev_info(enic_get_dev(enic),
|
||||
"vNIC resources avail: wq_desc %d rq_desc %d\n",
|
||||
enic->config.wq_desc_count, enic->config.rq_desc_count);
|
||||
|
||||
enic->wq_count = enic->conf_wq_count;
|
||||
enic->rq_count = enic->conf_rq_count;
|
||||
enic->cq_count = enic->conf_cq_count;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _ENIC_RES_H_
|
||||
#define _ENIC_RES_H_
|
||||
|
||||
#include "wq_enet_desc.h"
|
||||
#include "rq_enet_desc.h"
|
||||
#include "vnic_wq.h"
|
||||
#include "vnic_rq.h"
|
||||
|
||||
#define ENIC_MIN_WQ_DESCS 64
|
||||
#define ENIC_MAX_WQ_DESCS 4096
|
||||
#define ENIC_MIN_RQ_DESCS 64
|
||||
#define ENIC_MAX_RQ_DESCS 4096
|
||||
|
||||
#define ENIC_MAX_MULTICAST_ADDRESSES 32
|
||||
|
||||
/* A descriptor ring has a multiple of 32 descriptors */
|
||||
#define ENIC_ALIGN_DESCS 32
|
||||
#define ENIC_ALIGN_DESCS_MASK ~(ENIC_ALIGN_DESCS - 1)
|
||||
|
||||
/* Request a completion index every 32 buffers (roughly packets) */
|
||||
#define ENIC_WQ_CQ_THRESH 32
|
||||
|
||||
#define ENIC_MIN_MTU 68
|
||||
|
||||
/* Does not include (possible) inserted VLAN tag and FCS */
|
||||
#define ENIC_DEFAULT_RX_MAX_PKT_SIZE 9022
|
||||
|
||||
/* Does not include (possible) inserted VLAN tag and FCS */
|
||||
#define ENIC_TX_MAX_PKT_SIZE 9208
|
||||
|
||||
#define ENIC_MULTICAST_PERFECT_FILTERS 32
|
||||
#define ENIC_UNICAST_PERFECT_FILTERS 32
|
||||
|
||||
#define ENIC_NON_TSO_MAX_DESC 16
|
||||
#define ENIC_DEFAULT_RX_FREE_THRESH 32
|
||||
#define ENIC_TX_XMIT_MAX 64
|
||||
#define ENIC_RX_BURST_MAX 64
|
||||
|
||||
/* Defaults for dev_info.default_{rx,tx}portconf */
|
||||
#define ENIC_DEFAULT_RX_BURST 32
|
||||
#define ENIC_DEFAULT_RX_RINGS 1
|
||||
#define ENIC_DEFAULT_RX_RING_SIZE 512
|
||||
#define ENIC_DEFAULT_TX_BURST 32
|
||||
#define ENIC_DEFAULT_TX_RINGS 1
|
||||
#define ENIC_DEFAULT_TX_RING_SIZE 512
|
||||
|
||||
#define ENIC_RSS_DEFAULT_CPU 0
|
||||
#define ENIC_RSS_BASE_CPU 0
|
||||
#define ENIC_RSS_HASH_BITS 7
|
||||
#define ENIC_RSS_RETA_SIZE (1 << ENIC_RSS_HASH_BITS)
|
||||
#define ENIC_RSS_HASH_KEY_SIZE 40
|
||||
|
||||
#define ENIC_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0)
|
||||
|
||||
struct enic;
|
||||
|
||||
int enic_get_vnic_config(struct enic *);
|
||||
int enic_add_vlan(struct enic *enic, u16 vlanid);
|
||||
int enic_del_vlan(struct enic *enic, u16 vlanid);
|
||||
int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
|
||||
u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
|
||||
u8 ig_vlan_strip_en);
|
||||
void enic_get_res_counts(struct enic *enic);
|
||||
void enic_init_vnic_resources(struct enic *enic);
|
||||
int enic_alloc_vnic_resources(struct enic *);
|
||||
void enic_free_vnic_resources(struct enic *);
|
||||
|
||||
#endif /* _ENIC_RES_H_ */
|
||||
@@ -0,0 +1,485 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "opt_rss.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/smp.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if_vlan_var.h>
|
||||
#include <net/iflib.h>
|
||||
#ifdef RSS
|
||||
#include <net/rss_config.h>
|
||||
#endif
|
||||
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
#include "ifdi_if.h"
|
||||
#include "enic.h"
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
static int enic_isc_txd_encap(void *, if_pkt_info_t);
|
||||
static void enic_isc_txd_flush(void *, uint16_t, qidx_t);
|
||||
static int enic_isc_txd_credits_update(void *, uint16_t, bool);
|
||||
static int enic_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t);
|
||||
static int enic_isc_rxd_pkt_get(void *, if_rxd_info_t);
|
||||
static void enic_isc_rxd_refill(void *, if_rxd_update_t);
|
||||
static void enic_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t);
|
||||
static int enic_legacy_intr(void *);
|
||||
static void enic_initial_post_rx(struct enic *, struct vnic_rq *);
|
||||
static int enic_wq_service(struct vnic_dev *, struct cq_desc *, u8, u16, u16,
|
||||
void *);
|
||||
static int enic_rq_service(struct vnic_dev *, struct cq_desc *, u8, u16, u16,
|
||||
void *);
|
||||
|
||||
struct if_txrx enic_txrx = {
|
||||
.ift_txd_encap = enic_isc_txd_encap,
|
||||
.ift_txd_flush = enic_isc_txd_flush,
|
||||
.ift_txd_credits_update = enic_isc_txd_credits_update,
|
||||
.ift_rxd_available = enic_isc_rxd_available,
|
||||
.ift_rxd_pkt_get = enic_isc_rxd_pkt_get,
|
||||
.ift_rxd_refill = enic_isc_rxd_refill,
|
||||
.ift_rxd_flush = enic_isc_rxd_flush,
|
||||
.ift_legacy_intr = enic_legacy_intr
|
||||
};
|
||||
|
||||
static int
|
||||
enic_isc_txd_encap(void *vsc, if_pkt_info_t pi)
|
||||
{
|
||||
struct enic_softc *softc;
|
||||
struct enic *enic;
|
||||
struct vnic_wq *wq;
|
||||
int nsegs;
|
||||
int i;
|
||||
|
||||
struct wq_enet_desc *desc;
|
||||
uint64_t bus_addr;
|
||||
uint16_t mss = 7;
|
||||
uint16_t header_len = 0;
|
||||
uint8_t offload_mode = 0;
|
||||
uint8_t eop = 0, cq;
|
||||
uint8_t vlan_tag_insert = 0;
|
||||
unsigned short vlan_id = 0;
|
||||
|
||||
unsigned int wq_desc_avail;
|
||||
int head_idx;
|
||||
unsigned int desc_count, data_len;
|
||||
|
||||
softc = vsc;
|
||||
enic = &softc->enic;
|
||||
|
||||
wq = &enic->wq[pi->ipi_qsidx];
|
||||
nsegs = pi->ipi_nsegs;
|
||||
|
||||
ENIC_LOCK(softc);
|
||||
wq_desc_avail = vnic_wq_desc_avail(wq);
|
||||
head_idx = wq->head_idx;
|
||||
desc_count = wq->ring.desc_count;
|
||||
|
||||
for (i = 0; i < nsegs; i++) {
|
||||
eop = 0;
|
||||
cq = 0;
|
||||
wq->cq_pend++;
|
||||
if (i + 1 == nsegs) {
|
||||
eop = 1;
|
||||
cq = 1;
|
||||
wq->cq_pend = 0;
|
||||
}
|
||||
desc = wq->ring.descs;
|
||||
bus_addr = pi->ipi_segs[i].ds_addr;
|
||||
data_len = pi->ipi_segs[i].ds_len;
|
||||
|
||||
wq_enet_desc_enc(&desc[head_idx], bus_addr, data_len, mss,
|
||||
header_len, offload_mode, eop, cq, 0,
|
||||
vlan_tag_insert, vlan_id, 0);
|
||||
|
||||
head_idx = enic_ring_incr(desc_count, head_idx);
|
||||
wq_desc_avail--;
|
||||
}
|
||||
|
||||
wq->ring.desc_avail = wq_desc_avail;
|
||||
wq->head_idx = head_idx;
|
||||
|
||||
pi->ipi_new_pidx = head_idx;
|
||||
ENIC_UNLOCK(softc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
enic_isc_txd_flush(void *vsc, uint16_t txqid, qidx_t pidx)
|
||||
{
|
||||
struct enic_softc *softc;
|
||||
struct enic *enic;
|
||||
struct vnic_wq *wq;
|
||||
int head_idx;
|
||||
|
||||
softc = vsc;
|
||||
enic = &softc->enic;
|
||||
|
||||
ENIC_LOCK(softc);
|
||||
wq = &enic->wq[txqid];
|
||||
head_idx = wq->head_idx;
|
||||
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_POSTED_INDEX, head_idx);
|
||||
ENIC_UNLOCK(softc);
|
||||
}
|
||||
|
||||
static int
|
||||
enic_isc_txd_credits_update(void *vsc, uint16_t txqid, bool clear)
|
||||
{
|
||||
|
||||
struct enic_softc *softc;
|
||||
struct enic *enic;
|
||||
struct vnic_wq *wq;
|
||||
struct vnic_cq *cq;
|
||||
int processed;
|
||||
unsigned int cq_wq;
|
||||
unsigned int wq_work_to_do = 10;
|
||||
unsigned int wq_work_avail;
|
||||
|
||||
softc = vsc;
|
||||
enic = &softc->enic;
|
||||
wq = &softc->enic.wq[txqid];
|
||||
|
||||
cq_wq = enic_cq_wq(enic, txqid);
|
||||
cq = &enic->cq[cq_wq];
|
||||
|
||||
ENIC_LOCK(softc);
|
||||
wq_work_avail = vnic_cq_work(cq, wq_work_to_do);
|
||||
ENIC_UNLOCK(softc);
|
||||
|
||||
if (wq_work_avail == 0)
|
||||
return (0);
|
||||
|
||||
if (!clear)
|
||||
return (1);
|
||||
|
||||
ENIC_LOCK(softc);
|
||||
vnic_cq_service(cq, wq_work_to_do,
|
||||
enic_wq_service, NULL);
|
||||
|
||||
processed = wq->processed;
|
||||
wq->processed = 0;
|
||||
|
||||
ENIC_UNLOCK(softc);
|
||||
|
||||
return (processed);
|
||||
}
|
||||
|
||||
static int
|
||||
enic_isc_rxd_available(void *vsc, uint16_t rxqid, qidx_t idx, qidx_t budget)
|
||||
{
|
||||
struct enic_softc *softc;
|
||||
struct enic *enic;
|
||||
struct vnic_cq *cq;
|
||||
unsigned int rq_work_to_do = budget;
|
||||
unsigned int rq_work_avail = 0;
|
||||
unsigned int cq_rq;
|
||||
|
||||
softc = vsc;
|
||||
enic = &softc->enic;
|
||||
|
||||
cq_rq = enic_cq_rq(&softc->enic, rxqid);
|
||||
cq = &enic->cq[cq_rq];
|
||||
|
||||
rq_work_avail = vnic_cq_work(cq, rq_work_to_do);
|
||||
return rq_work_avail;
|
||||
}
|
||||
|
||||
static int
|
||||
enic_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
|
||||
{
|
||||
struct enic_softc *softc;
|
||||
struct enic *enic;
|
||||
struct vnic_cq *cq;
|
||||
unsigned int rq_work_to_do = 1;
|
||||
unsigned int rq_work_done = 0;
|
||||
unsigned int cq_rq;
|
||||
|
||||
softc = vsc;
|
||||
enic = &softc->enic;
|
||||
|
||||
cq_rq = enic_cq_rq(&softc->enic, ri->iri_qsidx);
|
||||
cq = &enic->cq[cq_rq];
|
||||
ENIC_LOCK(softc);
|
||||
rq_work_done = vnic_cq_service(cq, rq_work_to_do, enic_rq_service, ri);
|
||||
|
||||
if (rq_work_done != 0) {
|
||||
vnic_intr_return_credits(&enic->intr[cq_rq], rq_work_done, 0,
|
||||
1);
|
||||
ENIC_UNLOCK(softc);
|
||||
return (0);
|
||||
} else {
|
||||
ENIC_UNLOCK(softc);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
enic_isc_rxd_refill(void *vsc, if_rxd_update_t iru)
|
||||
{
|
||||
struct enic_softc *softc;
|
||||
struct vnic_rq *rq;
|
||||
struct rq_enet_desc *rqd;
|
||||
|
||||
uint64_t *paddrs;
|
||||
int count;
|
||||
uint32_t pidx;
|
||||
int len;
|
||||
int idx;
|
||||
int i;
|
||||
|
||||
count = iru->iru_count;
|
||||
len = iru->iru_buf_size;
|
||||
paddrs = iru->iru_paddrs;
|
||||
pidx = iru->iru_pidx;
|
||||
|
||||
softc = vsc;
|
||||
rq = &softc->enic.rq[iru->iru_qsidx];
|
||||
rqd = rq->ring.descs;
|
||||
|
||||
idx = pidx;
|
||||
for (i = 0; i < count; i++, idx++) {
|
||||
|
||||
if (idx == rq->ring.desc_count)
|
||||
idx = 0;
|
||||
rq_enet_desc_enc(&rqd[idx], paddrs[i],
|
||||
RQ_ENET_TYPE_ONLY_SOP,
|
||||
len);
|
||||
|
||||
}
|
||||
|
||||
rq->in_use = 1;
|
||||
|
||||
if (rq->need_initial_post) {
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_FETCH_INDEX, 0);
|
||||
}
|
||||
|
||||
enic_initial_post_rx(&softc->enic, rq);
|
||||
}
|
||||
|
||||
static void
|
||||
enic_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx)
|
||||
{
|
||||
|
||||
struct enic_softc *softc;
|
||||
struct vnic_rq *rq;
|
||||
|
||||
softc = vsc;
|
||||
rq = &softc->enic.rq[rxqid];
|
||||
|
||||
/*
|
||||
* pidx is the index of the last descriptor with a buffer the device
|
||||
* can use, and the device needs to be told which index is one past
|
||||
* that.
|
||||
*/
|
||||
|
||||
ENIC_LOCK(softc);
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_POSTED_INDEX, pidx);
|
||||
ENIC_UNLOCK(softc);
|
||||
}
|
||||
|
||||
static int
|
||||
enic_legacy_intr(void *xsc)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
vnic_wq_service(struct vnic_wq *wq, struct cq_desc *cq_desc,
|
||||
u16 completed_index, void (*buf_service) (struct vnic_wq *wq,
|
||||
struct cq_desc *cq_desc, /* struct vnic_wq_buf * *buf, */ void *opaque),
|
||||
void *opaque)
|
||||
{
|
||||
int processed;
|
||||
|
||||
processed = completed_index - wq->ring.last_count;
|
||||
if (processed < 0)
|
||||
processed += wq->ring.desc_count;
|
||||
if (processed == 0)
|
||||
processed++;
|
||||
|
||||
wq->ring.desc_avail += processed;
|
||||
wq->processed += processed;
|
||||
wq->ring.last_count = completed_index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Post the Rx buffers for the first time. enic_alloc_rx_queue_mbufs() has
|
||||
* allocated the buffers and filled the RQ descriptor ring. Just need to push
|
||||
* the post index to the NIC.
|
||||
*/
|
||||
static void
|
||||
enic_initial_post_rx(struct enic *enic, struct vnic_rq *rq)
|
||||
{
|
||||
struct enic_softc *softc = enic->softc;
|
||||
if (!rq->in_use || !rq->need_initial_post)
|
||||
return;
|
||||
|
||||
ENIC_LOCK(softc);
|
||||
/* make sure all prior writes are complete before doing the PIO write */
|
||||
/* Post all but the last buffer to VIC. */
|
||||
rq->posted_index = rq->ring.desc_count - 1;
|
||||
|
||||
rq->rx_nb_hold = 0;
|
||||
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_POSTED_INDEX, rq->posted_index);
|
||||
|
||||
rq->need_initial_post = false;
|
||||
ENIC_UNLOCK(softc);
|
||||
}
|
||||
|
||||
static int
|
||||
enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, u8 type,
|
||||
u16 q_number, u16 completed_index, void *opaque)
|
||||
{
|
||||
struct enic *enic = vnic_dev_priv(vdev);
|
||||
|
||||
vnic_wq_service(&enic->wq[q_number], cq_desc,
|
||||
completed_index, NULL, opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
vnic_rq_service(struct vnic_rq *rq, struct cq_desc *cq_desc,
|
||||
u16 in_completed_index, int desc_return,
|
||||
void(*buf_service)(struct vnic_rq *rq, struct cq_desc *cq_desc,
|
||||
/* struct vnic_rq_buf * *buf, */ int skipped, void *opaque), void *opaque)
|
||||
{
|
||||
|
||||
if_rxd_info_t ri = (if_rxd_info_t) opaque;
|
||||
u8 type, color, eop, sop, ingress_port, vlan_stripped;
|
||||
u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
|
||||
u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
|
||||
u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
|
||||
u8 packet_error;
|
||||
u16 q_number, completed_index, bytes_written, vlan_tci, checksum;
|
||||
u32 rss_hash;
|
||||
int cqidx;
|
||||
if_rxd_frag_t frag;
|
||||
|
||||
cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc,
|
||||
&type, &color, &q_number, &completed_index,
|
||||
&ingress_port, &fcoe, &eop, &sop, &rss_type,
|
||||
&csum_not_calc, &rss_hash, &bytes_written,
|
||||
&packet_error, &vlan_stripped, &vlan_tci, &checksum,
|
||||
&fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
|
||||
&fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
|
||||
&ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
|
||||
&fcs_ok);
|
||||
|
||||
cqidx = ri->iri_cidx;
|
||||
|
||||
frag = &ri->iri_frags[0];
|
||||
frag->irf_idx = cqidx;
|
||||
frag->irf_len = bytes_written;
|
||||
|
||||
if (++cqidx == rq->ring.desc_count) {
|
||||
cqidx = 0;
|
||||
}
|
||||
|
||||
ri->iri_cidx = cqidx;
|
||||
ri->iri_nfrags = 1;
|
||||
ri->iri_len = bytes_written;
|
||||
}
|
||||
|
||||
static int
|
||||
enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
|
||||
u8 type, u16 q_number, u16 completed_index, void *opaque)
|
||||
{
|
||||
struct enic *enic = vnic_dev_priv(vdev);
|
||||
if_rxd_info_t ri = (if_rxd_info_t) opaque;
|
||||
|
||||
vnic_rq_service(&enic->rq[ri->iri_qsidx], cq_desc, completed_index,
|
||||
VNIC_RQ_RETURN_DESC, NULL, /* enic_rq_indicate_buf, */ opaque);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
enic_prep_wq_for_simple_tx(struct enic *enic, uint16_t queue_idx)
|
||||
{
|
||||
struct wq_enet_desc *desc;
|
||||
struct vnic_wq *wq;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Fill WQ descriptor fields that never change. Every descriptor is
|
||||
* one packet, so set EOP. Also set CQ_ENTRY every ENIC_WQ_CQ_THRESH
|
||||
* descriptors (i.e. request one completion update every 32 packets).
|
||||
*/
|
||||
wq = &enic->wq[queue_idx];
|
||||
desc = (struct wq_enet_desc *)wq->ring.descs;
|
||||
for (i = 0; i < wq->ring.desc_count; i++, desc++) {
|
||||
desc->header_length_flags = 1 << WQ_ENET_FLAGS_EOP_SHIFT;
|
||||
if (i % ENIC_WQ_CQ_THRESH == ENIC_WQ_CQ_THRESH - 1)
|
||||
desc->header_length_flags |=
|
||||
(1 << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
enic_start_wq(struct enic *enic, uint16_t queue_idx)
|
||||
{
|
||||
vnic_wq_enable(&enic->wq[queue_idx]);
|
||||
}
|
||||
|
||||
int
|
||||
enic_stop_wq(struct enic *enic, uint16_t queue_idx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = vnic_wq_disable(&enic->wq[queue_idx]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
enic_start_rq(struct enic *enic, uint16_t queue_idx)
|
||||
{
|
||||
struct vnic_rq *rq;
|
||||
|
||||
rq = &enic->rq[queue_idx];
|
||||
vnic_rq_enable(rq);
|
||||
enic_initial_post_rx(enic, rq);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _RQ_ENET_DESC_H_
|
||||
#define _RQ_ENET_DESC_H_
|
||||
|
||||
/* Ethernet receive queue descriptor: 16B */
|
||||
struct rq_enet_desc {
|
||||
__le64 address;
|
||||
__le16 length_type;
|
||||
u8 reserved[6];
|
||||
};
|
||||
|
||||
enum rq_enet_type_types {
|
||||
RQ_ENET_TYPE_ONLY_SOP = 0,
|
||||
RQ_ENET_TYPE_NOT_SOP = 1,
|
||||
RQ_ENET_TYPE_RESV2 = 2,
|
||||
RQ_ENET_TYPE_RESV3 = 3,
|
||||
};
|
||||
|
||||
#define RQ_ENET_ADDR_BITS 64
|
||||
#define RQ_ENET_LEN_BITS 14
|
||||
#define RQ_ENET_LEN_MASK ((1 << RQ_ENET_LEN_BITS) - 1)
|
||||
#define RQ_ENET_TYPE_BITS 2
|
||||
#define RQ_ENET_TYPE_MASK ((1 << RQ_ENET_TYPE_BITS) - 1)
|
||||
|
||||
static inline void rq_enet_desc_enc(volatile struct rq_enet_desc *desc,
|
||||
u64 address, u8 type, u16 length)
|
||||
{
|
||||
desc->address = cpu_to_le64(address);
|
||||
desc->length_type = cpu_to_le16((length & RQ_ENET_LEN_MASK) |
|
||||
((type & RQ_ENET_TYPE_MASK) << RQ_ENET_LEN_BITS));
|
||||
}
|
||||
|
||||
static inline void rq_enet_desc_dec(struct rq_enet_desc *desc,
|
||||
u64 *address, u8 *type, u16 *length)
|
||||
{
|
||||
*address = le64_to_cpu(desc->address);
|
||||
*length = le16_to_cpu(desc->length_type) & RQ_ENET_LEN_MASK;
|
||||
*type = (u8)((le16_to_cpu(desc->length_type) >> RQ_ENET_LEN_BITS) &
|
||||
RQ_ENET_TYPE_MASK);
|
||||
}
|
||||
|
||||
#endif /* _RQ_ENET_DESC_H_ */
|
||||
@@ -0,0 +1,45 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "enic.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_cq.h"
|
||||
|
||||
void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable,
|
||||
unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail,
|
||||
unsigned int cq_tail_color, unsigned int interrupt_enable,
|
||||
unsigned int cq_entry_enable, unsigned int cq_message_enable,
|
||||
unsigned int interrupt_offset, u64 cq_message_addr)
|
||||
{
|
||||
u64 paddr;
|
||||
|
||||
paddr = (u64)cq->ring.base_addr | VNIC_PADDR_TARGET;
|
||||
ENIC_BUS_WRITE_8(cq->ctrl, CQ_RING_BASE, paddr);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_RING_SIZE, cq->ring.desc_count);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_FLOW_CONTROL_ENABLE, flow_control_enable);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_COLOR_ENABLE, color_enable);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_HEAD, cq_head);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_TAIL, cq_tail);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_TAIL_COLOR, cq_tail_color);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_INTR_ENABLE, interrupt_enable);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_ENTRY_ENABLE, cq_entry_enable);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_MESSAGE_ENABLE, cq_message_enable);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_INTR_OFFSET, interrupt_offset);
|
||||
ENIC_BUS_WRITE_8(cq->ctrl, CQ_MESSAGE_ADDR, cq_message_addr);
|
||||
|
||||
cq->interrupt_offset = interrupt_offset;
|
||||
}
|
||||
|
||||
void vnic_cq_clean(struct vnic_cq *cq)
|
||||
{
|
||||
cq->to_clean = 0;
|
||||
cq->last_color = 0;
|
||||
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_HEAD, 0);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_TAIL, 0);
|
||||
ENIC_BUS_WRITE_4(cq->ctrl, CQ_TAIL_COLOR, 1);
|
||||
|
||||
vnic_dev_clear_desc_ring(&cq->ring);
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_CQ_H_
|
||||
#define _VNIC_CQ_H_
|
||||
|
||||
#include "cq_desc.h"
|
||||
#include "vnic_dev.h"
|
||||
|
||||
/* Completion queue control */
|
||||
struct vnic_cq_ctrl {
|
||||
u64 ring_base; /* 0x00 */
|
||||
#define CQ_RING_BASE 0x00
|
||||
u32 ring_size; /* 0x08 */
|
||||
#define CQ_RING_SIZE 0x08
|
||||
u32 pad0;
|
||||
u32 flow_control_enable; /* 0x10 */
|
||||
#define CQ_FLOW_CONTROL_ENABLE 0x10
|
||||
u32 pad1;
|
||||
u32 color_enable; /* 0x18 */
|
||||
#define CQ_COLOR_ENABLE 0x18
|
||||
u32 pad2;
|
||||
u32 cq_head; /* 0x20 */
|
||||
#define CQ_HEAD 0x20
|
||||
u32 pad3;
|
||||
u32 cq_tail; /* 0x28 */
|
||||
#define CQ_TAIL 0x28
|
||||
u32 pad4;
|
||||
u32 cq_tail_color; /* 0x30 */
|
||||
#define CQ_TAIL_COLOR 0x30
|
||||
u32 pad5;
|
||||
u32 interrupt_enable; /* 0x38 */
|
||||
#define CQ_INTR_ENABLE 0x38
|
||||
u32 pad6;
|
||||
u32 cq_entry_enable; /* 0x40 */
|
||||
#define CQ_ENTRY_ENABLE 0x40
|
||||
u32 pad7;
|
||||
u32 cq_message_enable; /* 0x48 */
|
||||
#define CQ_MESSAGE_ENABLE 0x48
|
||||
u32 pad8;
|
||||
u32 interrupt_offset; /* 0x50 */
|
||||
#define CQ_INTR_OFFSET 0x50
|
||||
u32 pad9;
|
||||
u64 cq_message_addr; /* 0x58 */
|
||||
#define CQ_MESSAGE_ADDR 0x58
|
||||
u32 pad10;
|
||||
};
|
||||
|
||||
#ifdef ENIC_AIC
|
||||
struct vnic_rx_bytes_counter {
|
||||
unsigned int small_pkt_bytes_cnt;
|
||||
unsigned int large_pkt_bytes_cnt;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct vnic_cq {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_res *ctrl;
|
||||
struct vnic_dev_ring ring;
|
||||
unsigned int to_clean;
|
||||
unsigned int last_color;
|
||||
unsigned int interrupt_offset;
|
||||
#ifdef ENIC_AIC
|
||||
struct vnic_rx_bytes_counter pkt_size_counter;
|
||||
unsigned int cur_rx_coal_timeval;
|
||||
unsigned int tobe_rx_coal_timeval;
|
||||
ktime_t prev_ts;
|
||||
#endif
|
||||
int ntxqsets;
|
||||
int nrxqsets;
|
||||
int ntxqsets_start;
|
||||
int nrxqsets_start;
|
||||
};
|
||||
|
||||
void vnic_cq_free(struct vnic_cq *cq);
|
||||
void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable,
|
||||
unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail,
|
||||
unsigned int cq_tail_color, unsigned int interrupt_enable,
|
||||
unsigned int cq_entry_enable, unsigned int message_enable,
|
||||
unsigned int interrupt_offset, u64 message_addr);
|
||||
void vnic_cq_clean(struct vnic_cq *cq);
|
||||
int vnic_cq_mem_size(struct vnic_cq *cq, unsigned int desc_count,
|
||||
unsigned int desc_size);
|
||||
|
||||
static inline unsigned int vnic_cq_service(struct vnic_cq *cq,
|
||||
unsigned int work_to_do,
|
||||
int (*q_service)(struct vnic_dev *vdev, struct cq_desc *cq_desc,
|
||||
u8 type, u16 q_number, u16 completed_index, void *opaque),
|
||||
void *opaque)
|
||||
{
|
||||
struct cq_desc *cq_desc;
|
||||
unsigned int work_done = 0;
|
||||
u16 q_number, completed_index;
|
||||
u8 type, color;
|
||||
|
||||
cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
|
||||
cq->ring.desc_size * cq->to_clean);
|
||||
cq_desc_dec(cq_desc, &type, &color,
|
||||
&q_number, &completed_index);
|
||||
|
||||
while (color != cq->last_color) {
|
||||
if ((*q_service)(cq->vdev, cq_desc, type,
|
||||
q_number, completed_index, opaque))
|
||||
break;
|
||||
|
||||
cq->to_clean++;
|
||||
if (cq->to_clean == cq->ring.desc_count) {
|
||||
cq->to_clean = 0;
|
||||
cq->last_color = cq->last_color ? 0 : 1;
|
||||
}
|
||||
|
||||
cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
|
||||
cq->ring.desc_size * cq->to_clean);
|
||||
cq_desc_dec(cq_desc, &type, &color,
|
||||
&q_number, &completed_index);
|
||||
|
||||
work_done++;
|
||||
if (work_done >= work_to_do)
|
||||
break;
|
||||
}
|
||||
|
||||
return work_done;
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_cq_work(struct vnic_cq *cq,
|
||||
unsigned int work_to_do)
|
||||
{
|
||||
struct cq_desc *cq_desc;
|
||||
unsigned int work_avail = 0;
|
||||
u16 q_number, completed_index;
|
||||
u8 type, color;
|
||||
u32 to_clean, last_color;
|
||||
|
||||
to_clean = cq->to_clean;
|
||||
last_color = cq->last_color;
|
||||
cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
|
||||
cq->ring.desc_size * to_clean);
|
||||
cq_desc_dec(cq_desc, &type, &color,
|
||||
&q_number, &completed_index);
|
||||
|
||||
while (color != last_color) {
|
||||
to_clean++;
|
||||
if (to_clean == cq->ring.desc_count) {
|
||||
to_clean = 0;
|
||||
last_color = last_color ? 0 : 1;
|
||||
}
|
||||
|
||||
cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
|
||||
cq->ring.desc_size * to_clean);
|
||||
cq_desc_dec(cq_desc, &type, &color,
|
||||
&q_number, &completed_index);
|
||||
|
||||
work_avail++;
|
||||
if (work_avail >= work_to_do)
|
||||
break;
|
||||
}
|
||||
|
||||
return work_avail;
|
||||
}
|
||||
|
||||
#endif /* _VNIC_CQ_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,170 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_DEV_H_
|
||||
#define _VNIC_DEV_H_
|
||||
|
||||
#include "enic_compat.h"
|
||||
#include "vnic_resource.h"
|
||||
#include "vnic_devcmd.h"
|
||||
|
||||
#ifndef VNIC_PADDR_TARGET
|
||||
#define VNIC_PADDR_TARGET 0x0000000000000000ULL
|
||||
#endif
|
||||
|
||||
enum vnic_dev_intr_mode {
|
||||
VNIC_DEV_INTR_MODE_UNKNOWN,
|
||||
VNIC_DEV_INTR_MODE_INTX,
|
||||
VNIC_DEV_INTR_MODE_MSI,
|
||||
VNIC_DEV_INTR_MODE_MSIX,
|
||||
};
|
||||
|
||||
struct vnic_dev_bar {
|
||||
void __iomem *vaddr;
|
||||
unsigned long len;
|
||||
};
|
||||
|
||||
struct vnic_dev_ring {
|
||||
void *descs; /* vaddr */
|
||||
size_t size;
|
||||
bus_addr_t base_addr; /* paddr */
|
||||
size_t base_align;
|
||||
void *descs_unaligned;
|
||||
size_t size_unaligned;
|
||||
bus_addr_t base_addr_unaligned;
|
||||
unsigned int desc_size;
|
||||
unsigned int desc_count;
|
||||
unsigned int desc_avail;
|
||||
unsigned int last_count;
|
||||
};
|
||||
|
||||
struct vnic_dev_iomap_info {
|
||||
bus_addr_t bus_addr;
|
||||
unsigned long len;
|
||||
void __iomem *vaddr;
|
||||
};
|
||||
|
||||
struct vnic_dev;
|
||||
struct vnic_stats;
|
||||
|
||||
void *vnic_dev_priv(struct vnic_dev *vdev);
|
||||
unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev,
|
||||
enum vnic_res_type type);
|
||||
void vnic_register_cbacks(struct vnic_dev *vdev,
|
||||
void *(*alloc_consistent)(void *priv, size_t size,
|
||||
bus_addr_t *dma_handle, struct iflib_dma_info *res, u8 *name),
|
||||
void (*free_consistent)(void *priv,
|
||||
size_t size, void *vaddr,
|
||||
bus_addr_t dma_handle, struct iflib_dma_info *res));
|
||||
void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
|
||||
unsigned int index);
|
||||
uint8_t vnic_dev_get_res_bar(struct vnic_dev *vdev,
|
||||
enum vnic_res_type type);
|
||||
uint32_t vnic_dev_get_res_offset(struct vnic_dev *vdev,
|
||||
enum vnic_res_type type, unsigned int index);
|
||||
unsigned long vnic_dev_get_res_type_len(struct vnic_dev *vdev,
|
||||
enum vnic_res_type type);
|
||||
unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring);
|
||||
int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
||||
u64 *a0, u64 *a1, int wait);
|
||||
int vnic_dev_cmd_args(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
||||
u64 *args, int nargs, int wait);
|
||||
void vnic_dev_cmd_proxy_by_index_start(struct vnic_dev *vdev, u16 index);
|
||||
void vnic_dev_cmd_proxy_by_bdf_start(struct vnic_dev *vdev, u16 bdf);
|
||||
void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev);
|
||||
int vnic_dev_fw_info(struct vnic_dev *vdev,
|
||||
struct vnic_devcmd_fw_info **fw_info);
|
||||
int vnic_dev_capable_adv_filters(struct vnic_dev *vdev);
|
||||
int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd);
|
||||
int vnic_dev_capable_filter_mode(struct vnic_dev *vdev, u32 *mode,
|
||||
u8 *filter_actions);
|
||||
void vnic_dev_capable_udp_rss_weak(struct vnic_dev *vdev, bool *cfg_chk,
|
||||
bool *weak);
|
||||
int vnic_dev_asic_info(struct vnic_dev *vdev, u16 *asic_type, u16 *asic_rev);
|
||||
int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, size_t size,
|
||||
void *value);
|
||||
int vnic_dev_stats_clear(struct vnic_dev *vdev);
|
||||
int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
|
||||
int vnic_dev_counter_dma_cfg(struct vnic_dev *vdev, u32 period,
|
||||
u32 num_counters);
|
||||
int vnic_dev_hang_notify(struct vnic_dev *vdev);
|
||||
int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
|
||||
int broadcast, int promisc, int allmulti);
|
||||
int vnic_dev_packet_filter_all(struct vnic_dev *vdev, int directed,
|
||||
int multicast, int broadcast, int promisc, int allmulti);
|
||||
int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
|
||||
int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
|
||||
int vnic_dev_get_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
|
||||
int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr);
|
||||
int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr);
|
||||
void vnic_dev_set_reset_flag(struct vnic_dev *vdev, int state);
|
||||
int vnic_dev_notify_unset(struct vnic_dev *vdev);
|
||||
int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
|
||||
void *notify_addr, bus_addr_t notify_pa, u16 intr);
|
||||
int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev);
|
||||
int vnic_dev_link_status(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_port_speed(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_msg_lvl(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_mtu(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_notify_status(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_uif(struct vnic_dev *vdev);
|
||||
int vnic_dev_close(struct vnic_dev *vdev);
|
||||
int vnic_dev_enable(struct vnic_dev *vdev);
|
||||
int vnic_dev_enable_wait(struct vnic_dev *vdev);
|
||||
int vnic_dev_disable(struct vnic_dev *vdev);
|
||||
int vnic_dev_open(struct vnic_dev *vdev, int arg);
|
||||
int vnic_dev_open_done(struct vnic_dev *vdev, int *done);
|
||||
int vnic_dev_init(struct vnic_dev *vdev, int arg);
|
||||
int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err);
|
||||
int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len);
|
||||
int vnic_dev_deinit(struct vnic_dev *vdev);
|
||||
void vnic_dev_intr_coal_timer_info_default(struct vnic_dev *vdev);
|
||||
int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev);
|
||||
int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
|
||||
int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
|
||||
int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);
|
||||
int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);
|
||||
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
|
||||
enum vnic_dev_intr_mode intr_mode);
|
||||
enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_intr_coal_timer_usec_to_hw(struct vnic_dev *vdev, u32 usec);
|
||||
u32 vnic_dev_intr_coal_timer_hw_to_usec(struct vnic_dev *vdev, u32 hw_cycles);
|
||||
u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev);
|
||||
int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
|
||||
u8 ig_vlan_rewrite_mode);
|
||||
struct enic;
|
||||
struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
|
||||
struct enic_bar_info *mem, unsigned int num_bars);
|
||||
struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev);
|
||||
int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev);
|
||||
int vnic_dev_alloc_counter_mem(struct vnic_dev *vdev);
|
||||
int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback);
|
||||
int vnic_dev_get_size(void);
|
||||
int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op);
|
||||
int vnic_dev_perbi(struct vnic_dev *vdev, u64 arg, u32 op);
|
||||
u32 vnic_dev_perbi_rebuild_cnt(struct vnic_dev *vdev);
|
||||
int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len);
|
||||
int vnic_dev_enable2(struct vnic_dev *vdev, int active);
|
||||
int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status);
|
||||
int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status);
|
||||
int vnic_dev_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
|
||||
int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
|
||||
struct filter_v2 *data, struct filter_action_v2 *action_v2);
|
||||
int vnic_dev_overlay_offload_ctrl(struct vnic_dev *vdev,
|
||||
u8 overlay, u8 config);
|
||||
int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay,
|
||||
u16 vxlan_udp_port_number);
|
||||
int vnic_dev_capable_vxlan(struct vnic_dev *vdev);
|
||||
bool vnic_dev_counter_alloc(struct vnic_dev *vdev, uint32_t *idx);
|
||||
bool vnic_dev_counter_free(struct vnic_dev *vdev, uint32_t idx);
|
||||
bool vnic_dev_counter_query(struct vnic_dev *vdev, uint32_t idx,
|
||||
bool reset, uint64_t *packets, uint64_t *bytes);
|
||||
|
||||
device_t dev_from_vnic_dev(struct vnic_dev *vdev);
|
||||
|
||||
#endif /* _VNIC_DEV_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,66 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_ENIC_H_
|
||||
#define _VNIC_ENIC_H_
|
||||
|
||||
/* Hardware intr coalesce timer is in units of 1.5us */
|
||||
#define INTR_COALESCE_USEC_TO_HW(usec) ((usec) * 2 / 3)
|
||||
#define INTR_COALESCE_HW_TO_USEC(usec) ((usec) * 3 / 2)
|
||||
|
||||
/* Device-specific region: enet configuration */
|
||||
struct vnic_enet_config {
|
||||
u32 flags;
|
||||
u32 wq_desc_count;
|
||||
u32 rq_desc_count;
|
||||
u16 mtu;
|
||||
u16 intr_timer_deprecated;
|
||||
u8 intr_timer_type;
|
||||
u8 intr_mode;
|
||||
char devname[16];
|
||||
u32 intr_timer_usec;
|
||||
u16 loop_tag;
|
||||
u16 vf_rq_count;
|
||||
u16 num_arfs;
|
||||
u64 mem_paddr;
|
||||
u16 rdma_qp_id;
|
||||
u16 rdma_qp_count;
|
||||
u16 rdma_resgrp;
|
||||
u32 rdma_mr_id;
|
||||
u32 rdma_mr_count;
|
||||
u32 max_pkt_size;
|
||||
};
|
||||
|
||||
#define VENETF_TSO 0x1 /* TSO enabled */
|
||||
#define VENETF_LRO 0x2 /* LRO enabled */
|
||||
#define VENETF_RXCSUM 0x4 /* RX csum enabled */
|
||||
#define VENETF_TXCSUM 0x8 /* TX csum enabled */
|
||||
#define VENETF_RSS 0x10 /* RSS enabled */
|
||||
#define VENETF_RSSHASH_IPV4 0x20 /* Hash on IPv4 fields */
|
||||
#define VENETF_RSSHASH_TCPIPV4 0x40 /* Hash on TCP + IPv4 fields */
|
||||
#define VENETF_RSSHASH_IPV6 0x80 /* Hash on IPv6 fields */
|
||||
#define VENETF_RSSHASH_TCPIPV6 0x100 /* Hash on TCP + IPv6 fields */
|
||||
#define VENETF_RSSHASH_IPV6_EX 0x200 /* Hash on IPv6 extended fields */
|
||||
#define VENETF_RSSHASH_TCPIPV6_EX 0x400 /* Hash on TCP + IPv6 ext. fields */
|
||||
#define VENETF_LOOP 0x800 /* Loopback enabled */
|
||||
#define VENETF_FAILOVER 0x1000 /* Fabric failover enabled */
|
||||
#define VENETF_USPACE_NIC 0x2000 /* vHPC enabled */
|
||||
#define VENETF_VMQ 0x4000 /* VMQ enabled */
|
||||
#define VENETF_ARFS 0x8000 /* ARFS enabled */
|
||||
#define VENETF_VXLAN 0x10000 /* VxLAN offload */
|
||||
#define VENETF_NVGRE 0x20000 /* NVGRE offload */
|
||||
#define VENETF_GRPINTR 0x40000 /* group interrupt */
|
||||
#define VENETF_NICSWITCH 0x80000 /* NICSWITCH enabled */
|
||||
#define VENETF_RSSHASH_UDPIPV4 0x100000 /* Hash on UDP + IPv4 fields */
|
||||
#define VENETF_RSSHASH_UDPIPV6 0x200000 /* Hash on UDP + IPv6 fields */
|
||||
|
||||
#define VENET_INTR_TYPE_MIN 0 /* Timer specs min interrupt spacing */
|
||||
#define VENET_INTR_TYPE_IDLE 1 /* Timer specs idle time before irq */
|
||||
|
||||
#define VENET_INTR_MODE_ANY 0 /* Try MSI-X, then MSI, then INTx */
|
||||
#define VENET_INTR_MODE_MSI 1 /* Try MSI then INTx */
|
||||
#define VENET_INTR_MODE_INTX 2 /* Try INTx only */
|
||||
|
||||
#endif /* _VNIC_ENIC_H_ */
|
||||
@@ -0,0 +1,49 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "enic.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_intr.h"
|
||||
|
||||
void vnic_intr_free(struct vnic_intr *intr)
|
||||
{
|
||||
intr->ctrl = NULL;
|
||||
}
|
||||
|
||||
int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
|
||||
unsigned int index)
|
||||
{
|
||||
intr->index = index;
|
||||
intr->vdev = vdev;
|
||||
|
||||
intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index);
|
||||
if (!intr->ctrl) {
|
||||
pr_err("Failed to hook INTR[%d].ctrl resource\n", index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_intr_init(struct vnic_intr *intr, u32 coalescing_timer,
|
||||
unsigned int coalescing_type, unsigned int mask_on_assertion)
|
||||
{
|
||||
vnic_intr_coalescing_timer_set(intr, coalescing_timer);
|
||||
ENIC_BUS_WRITE_4(intr->ctrl, INTR_COALESCING_TYPE, coalescing_type);
|
||||
ENIC_BUS_WRITE_4(intr->ctrl, INTR_MASK_ON_ASSERTION, mask_on_assertion);
|
||||
ENIC_BUS_WRITE_4(intr->ctrl, INTR_CREDITS, 0);
|
||||
}
|
||||
|
||||
void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
|
||||
u32 coalescing_timer)
|
||||
{
|
||||
ENIC_BUS_WRITE_4(intr->ctrl, INTR_COALESCING_TIMER,
|
||||
vnic_dev_intr_coal_timer_usec_to_hw(intr->vdev, coalescing_timer));
|
||||
}
|
||||
|
||||
void vnic_intr_clean(struct vnic_intr *intr)
|
||||
{
|
||||
ENIC_BUS_WRITE_4(intr->ctrl, INTR_CREDITS, 0);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_INTR_H_
|
||||
#define _VNIC_INTR_H_
|
||||
|
||||
|
||||
#include "vnic_dev.h"
|
||||
|
||||
#define VNIC_INTR_TIMER_TYPE_ABS 0
|
||||
#define VNIC_INTR_TIMER_TYPE_QUIET 1
|
||||
|
||||
/* Interrupt control */
|
||||
struct vnic_intr_ctrl {
|
||||
u32 coalescing_timer; /* 0x00 */
|
||||
#define INTR_COALESCING_TIMER 0x00
|
||||
u32 pad0;
|
||||
u32 coalescing_value; /* 0x08 */
|
||||
#define INTR_COALESCING_VALUE 0x08
|
||||
u32 pad1;
|
||||
u32 coalescing_type; /* 0x10 */
|
||||
#define INTR_COALESCING_TYPE 0x10
|
||||
u32 pad2;
|
||||
u32 mask_on_assertion; /* 0x18 */
|
||||
#define INTR_MASK_ON_ASSERTION 0x18
|
||||
u32 pad3;
|
||||
u32 mask; /* 0x20 */
|
||||
#define INTR_MASK 0x20
|
||||
u32 pad4;
|
||||
u32 int_credits; /* 0x28 */
|
||||
#define INTR_CREDITS 0x28
|
||||
u32 pad5;
|
||||
u32 int_credit_return; /* 0x30 */
|
||||
#define INTR_CREDIT_RETURN 0x30
|
||||
u32 pad6;
|
||||
};
|
||||
|
||||
struct vnic_intr {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_res *ctrl;
|
||||
};
|
||||
|
||||
static inline void vnic_intr_mask(struct vnic_intr *intr)
|
||||
{
|
||||
ENIC_BUS_WRITE_4(intr->ctrl, INTR_MASK, 1);
|
||||
}
|
||||
|
||||
static inline int vnic_intr_masked(struct vnic_intr *intr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ENIC_BUS_READ_4(intr->ctrl, INTR_MASK);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void vnic_intr_unmask(struct vnic_intr *intr)
|
||||
{
|
||||
ENIC_BUS_WRITE_4(intr->ctrl, INTR_MASK, 0);
|
||||
}
|
||||
|
||||
static inline void vnic_intr_return_credits(struct vnic_intr *intr,
|
||||
unsigned int credits, int unmask, int reset_timer)
|
||||
{
|
||||
#define VNIC_INTR_UNMASK_SHIFT 16
|
||||
#define VNIC_INTR_RESET_TIMER_SHIFT 17
|
||||
|
||||
u32 int_credit_return = (credits & 0xffff) |
|
||||
(unmask ? (1 << VNIC_INTR_UNMASK_SHIFT) : 0) |
|
||||
(reset_timer ? (1 << VNIC_INTR_RESET_TIMER_SHIFT) : 0);
|
||||
|
||||
ENIC_BUS_WRITE_4(intr->ctrl, INTR_CREDIT_RETURN, int_credit_return);
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_intr_credits(struct vnic_intr *intr)
|
||||
{
|
||||
return ENIC_BUS_READ_4(intr->ctrl, INTR_CREDITS);
|
||||
}
|
||||
|
||||
static inline void vnic_intr_return_all_credits(struct vnic_intr *intr)
|
||||
{
|
||||
unsigned int credits = vnic_intr_credits(intr);
|
||||
int unmask = 1;
|
||||
int reset_timer = 1;
|
||||
|
||||
vnic_intr_return_credits(intr, credits, unmask, reset_timer);
|
||||
}
|
||||
|
||||
void vnic_intr_free(struct vnic_intr *intr);
|
||||
int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
|
||||
unsigned int index);
|
||||
void vnic_intr_init(struct vnic_intr *intr, u32 coalescing_timer,
|
||||
unsigned int coalescing_type, unsigned int mask_on_assertion);
|
||||
void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
|
||||
u32 coalescing_timer);
|
||||
void vnic_intr_clean(struct vnic_intr *intr);
|
||||
|
||||
#endif /* _VNIC_INTR_H_ */
|
||||
@@ -0,0 +1,60 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_NIC_H_
|
||||
#define _VNIC_NIC_H_
|
||||
|
||||
#define NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD 0xffUL
|
||||
#define NIC_CFG_RSS_DEFAULT_CPU_SHIFT 0
|
||||
#define NIC_CFG_RSS_HASH_TYPE (0xffUL << 8)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_MASK_FIELD 0xffUL
|
||||
#define NIC_CFG_RSS_HASH_TYPE_SHIFT 8
|
||||
#define NIC_CFG_RSS_HASH_BITS (7UL << 16)
|
||||
#define NIC_CFG_RSS_HASH_BITS_MASK_FIELD 7UL
|
||||
#define NIC_CFG_RSS_HASH_BITS_SHIFT 16
|
||||
#define NIC_CFG_RSS_BASE_CPU (7UL << 19)
|
||||
#define NIC_CFG_RSS_BASE_CPU_MASK_FIELD 7UL
|
||||
#define NIC_CFG_RSS_BASE_CPU_SHIFT 19
|
||||
#define NIC_CFG_RSS_ENABLE (1UL << 22)
|
||||
#define NIC_CFG_RSS_ENABLE_MASK_FIELD 1UL
|
||||
#define NIC_CFG_RSS_ENABLE_SHIFT 22
|
||||
#define NIC_CFG_TSO_IPID_SPLIT_EN (1UL << 23)
|
||||
#define NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD 1UL
|
||||
#define NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT 23
|
||||
#define NIC_CFG_IG_VLAN_STRIP_EN (1UL << 24)
|
||||
#define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD 1UL
|
||||
#define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT 24
|
||||
|
||||
#define NIC_CFG_RSS_HASH_TYPE_UDP_IPV4 (1 << 0)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_IPV4 (1 << 1)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 (1 << 2)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_IPV6 (1 << 3)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6 (1 << 4)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_RSVD1 (1 << 5)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_RSVD2 (1 << 6)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_UDP_IPV6 (1 << 7)
|
||||
|
||||
static inline void vnic_set_nic_cfg(u32 *nic_cfg,
|
||||
u8 rss_default_cpu, u8 rss_hash_type,
|
||||
u8 rss_hash_bits, u8 rss_base_cpu,
|
||||
u8 rss_enable, u8 tso_ipid_split_en,
|
||||
u8 ig_vlan_strip_en)
|
||||
{
|
||||
*nic_cfg = (rss_default_cpu & NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD) |
|
||||
((rss_hash_type & NIC_CFG_RSS_HASH_TYPE_MASK_FIELD)
|
||||
<< NIC_CFG_RSS_HASH_TYPE_SHIFT) |
|
||||
((rss_hash_bits & NIC_CFG_RSS_HASH_BITS_MASK_FIELD)
|
||||
<< NIC_CFG_RSS_HASH_BITS_SHIFT) |
|
||||
((rss_base_cpu & NIC_CFG_RSS_BASE_CPU_MASK_FIELD)
|
||||
<< NIC_CFG_RSS_BASE_CPU_SHIFT) |
|
||||
((rss_enable & NIC_CFG_RSS_ENABLE_MASK_FIELD)
|
||||
<< NIC_CFG_RSS_ENABLE_SHIFT) |
|
||||
((tso_ipid_split_en & NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD)
|
||||
<< NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT) |
|
||||
((ig_vlan_strip_en & NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD)
|
||||
<< NIC_CFG_IG_VLAN_STRIP_EN_SHIFT);
|
||||
}
|
||||
|
||||
#endif /* _VNIC_NIC_H_ */
|
||||
@@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_RESOURCE_H_
|
||||
#define _VNIC_RESOURCE_H_
|
||||
|
||||
#define VNIC_RES_MAGIC 0x766E6963L /* 'vnic' */
|
||||
#define VNIC_RES_VERSION 0x00000000L
|
||||
#define MGMTVNIC_MAGIC 0x544d474dL /* 'MGMT' */
|
||||
#define MGMTVNIC_VERSION 0x00000000L
|
||||
|
||||
/* The MAC address assigned to the CFG vNIC is fixed. */
|
||||
#define MGMTVNIC_MAC { 0x02, 0x00, 0x54, 0x4d, 0x47, 0x4d }
|
||||
|
||||
/* vNIC resource types */
|
||||
enum vnic_res_type {
|
||||
RES_TYPE_EOL, /* End-of-list */
|
||||
RES_TYPE_WQ, /* Work queues */
|
||||
RES_TYPE_RQ, /* Receive queues */
|
||||
RES_TYPE_CQ, /* Completion queues */
|
||||
RES_TYPE_MEM, /* Window to dev memory */
|
||||
RES_TYPE_NIC_CFG, /* Enet NIC config registers */
|
||||
RES_TYPE_RSS_KEY, /* Enet RSS secret key */
|
||||
RES_TYPE_RSS_CPU, /* Enet RSS indirection table */
|
||||
RES_TYPE_TX_STATS, /* Netblock Tx statistic regs */
|
||||
RES_TYPE_RX_STATS, /* Netblock Rx statistic regs */
|
||||
RES_TYPE_INTR_CTRL, /* Interrupt ctrl table */
|
||||
RES_TYPE_INTR_TABLE, /* MSI/MSI-X Interrupt table */
|
||||
RES_TYPE_INTR_PBA, /* MSI/MSI-X PBA table */
|
||||
RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status */
|
||||
RES_TYPE_DEBUG, /* Debug-only info */
|
||||
RES_TYPE_DEV, /* Device-specific region */
|
||||
RES_TYPE_DEVCMD, /* Device command region */
|
||||
RES_TYPE_PASS_THRU_PAGE, /* Pass-thru page */
|
||||
RES_TYPE_SUBVNIC, /* subvnic resource type */
|
||||
RES_TYPE_MQ_WQ, /* MQ Work queues */
|
||||
RES_TYPE_MQ_RQ, /* MQ Receive queues */
|
||||
RES_TYPE_MQ_CQ, /* MQ Completion queues */
|
||||
RES_TYPE_DEPRECATED1, /* Old version of devcmd 2 */
|
||||
RES_TYPE_DEVCMD2, /* Device control region */
|
||||
RES_TYPE_MAX, /* Count of resource types */
|
||||
};
|
||||
|
||||
struct vnic_resource_header {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
};
|
||||
|
||||
struct mgmt_barmap_hdr {
|
||||
u32 magic; /* magic number */
|
||||
u32 version; /* header format version */
|
||||
u16 lif; /* loopback lif for mgmt frames */
|
||||
u16 pci_slot; /* installed pci slot */
|
||||
char serial[16]; /* card serial number */
|
||||
};
|
||||
|
||||
struct vnic_resource {
|
||||
u8 type;
|
||||
u8 bar;
|
||||
u8 pad[2];
|
||||
u32 bar_offset;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
#endif /* _VNIC_RESOURCE_H_ */
|
||||
@@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "enic.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_rq.h"
|
||||
|
||||
void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index,
|
||||
unsigned int fetch_index, unsigned int posted_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset)
|
||||
{
|
||||
u64 paddr;
|
||||
unsigned int count = rq->ring.desc_count;
|
||||
|
||||
paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET;
|
||||
ENIC_BUS_WRITE_8(rq->ctrl, RX_RING_BASE, paddr);
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_RING_SIZE, count);
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_CQ_INDEX, cq_index);
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_ERROR_INTR_ENABLE, error_interrupt_enable);
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_ERROR_INTR_OFFSET, error_interrupt_offset);
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_ERROR_STATUS, 0);
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_FETCH_INDEX, fetch_index);
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_POSTED_INDEX, posted_index);
|
||||
}
|
||||
|
||||
void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset)
|
||||
{
|
||||
u32 fetch_index = 0;
|
||||
|
||||
/* Use current fetch_index as the ring starting point */
|
||||
fetch_index = ENIC_BUS_READ_4(rq->ctrl, RX_FETCH_INDEX);
|
||||
|
||||
if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone */
|
||||
/* Hardware surprise removal: reset fetch_index */
|
||||
fetch_index = 0;
|
||||
}
|
||||
|
||||
vnic_rq_init_start(rq, cq_index,
|
||||
fetch_index, fetch_index,
|
||||
error_interrupt_enable,
|
||||
error_interrupt_offset);
|
||||
rq->rxst_idx = 0;
|
||||
rq->tot_pkts = 0;
|
||||
}
|
||||
|
||||
unsigned int vnic_rq_error_status(struct vnic_rq *rq)
|
||||
{
|
||||
return ENIC_BUS_READ_4(rq->ctrl, RX_ERROR_STATUS);
|
||||
}
|
||||
|
||||
void vnic_rq_enable(struct vnic_rq *rq)
|
||||
{
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_ENABLE, 1);
|
||||
}
|
||||
|
||||
int vnic_rq_disable(struct vnic_rq *rq)
|
||||
{
|
||||
unsigned int wait;
|
||||
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_ENABLE, 0);
|
||||
|
||||
/* Wait for HW to ACK disable request */
|
||||
for (wait = 0; wait < 1000; wait++) {
|
||||
if (!(ENIC_BUS_READ_4(rq->ctrl, RX_RUNNING)))
|
||||
return 0;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
pr_err("Failed to disable RQ[%d]\n", rq->index);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
void vnic_rq_clean(struct vnic_rq *rq)
|
||||
{
|
||||
u32 fetch_index;
|
||||
unsigned int count = rq->ring.desc_count;
|
||||
|
||||
rq->ring.desc_avail = count - 1;
|
||||
rq->rx_nb_hold = 0;
|
||||
|
||||
/* Use current fetch_index as the ring starting point */
|
||||
fetch_index = ENIC_BUS_READ_4(rq->ctrl, RX_FETCH_INDEX);
|
||||
if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone */
|
||||
/* Hardware surprise removal: reset fetch_index */
|
||||
fetch_index = 0;
|
||||
}
|
||||
|
||||
ENIC_BUS_WRITE_4(rq->ctrl, RX_POSTED_INDEX, fetch_index);
|
||||
|
||||
vnic_dev_clear_desc_ring(&rq->ring);
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_RQ_H_
|
||||
#define _VNIC_RQ_H_
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_cq.h"
|
||||
|
||||
/* Receive queue control */
|
||||
struct vnic_rq_ctrl {
|
||||
u64 ring_base; /* 0x00 */
|
||||
#define RX_RING_BASE 0x00
|
||||
u32 ring_size; /* 0x08 */
|
||||
#define RX_RING_SIZE 0x08
|
||||
u32 pad0;
|
||||
u32 posted_index; /* 0x10 */
|
||||
#define RX_POSTED_INDEX 0x10
|
||||
u32 pad1;
|
||||
u32 cq_index; /* 0x18 */
|
||||
#define RX_CQ_INDEX 0x18
|
||||
u32 pad2;
|
||||
u32 enable; /* 0x20 */
|
||||
#define RX_ENABLE 0x20
|
||||
u32 pad3;
|
||||
u32 running; /* 0x28 */
|
||||
#define RX_RUNNING 0x28
|
||||
u32 pad4;
|
||||
u32 fetch_index; /* 0x30 */
|
||||
#define RX_FETCH_INDEX 0x30
|
||||
u32 pad5;
|
||||
u32 error_interrupt_enable; /* 0x38 */
|
||||
#define RX_ERROR_INTR_ENABLE 0x38
|
||||
u32 pad6;
|
||||
u32 error_interrupt_offset; /* 0x40 */
|
||||
#define RX_ERROR_INTR_OFFSET 0x40
|
||||
u32 pad7;
|
||||
u32 error_status; /* 0x48 */
|
||||
#define RX_ERROR_STATUS 0x48
|
||||
u32 pad8;
|
||||
u32 tcp_sn; /* 0x50 */
|
||||
#define RX_TCP_SN 0x50
|
||||
u32 pad9;
|
||||
u32 unused; /* 0x58 */
|
||||
u32 pad10;
|
||||
u32 dca_select; /* 0x60 */
|
||||
#define RX_DCA_SELECT 0x60
|
||||
u32 pad11;
|
||||
u32 dca_value; /* 0x68 */
|
||||
#define RX_DCA_VALUE 0x68
|
||||
u32 pad12;
|
||||
u32 data_ring; /* 0x70 */
|
||||
};
|
||||
|
||||
struct vnic_rq {
|
||||
unsigned int index;
|
||||
unsigned int posted_index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_res *ctrl;
|
||||
struct vnic_dev_ring ring;
|
||||
int num_free_mbufs;
|
||||
struct rte_mbuf **mbuf_ring; /* array of allocated mbufs */
|
||||
unsigned int mbuf_next_idx; /* next mb to consume */
|
||||
void *os_buf_head;
|
||||
unsigned int pkts_outstanding;
|
||||
uint16_t rx_nb_hold;
|
||||
uint16_t rx_free_thresh;
|
||||
unsigned int socket_id;
|
||||
struct rte_mempool *mp;
|
||||
uint16_t rxst_idx;
|
||||
uint32_t tot_pkts;
|
||||
uint8_t in_use;
|
||||
unsigned int max_mbufs_per_pkt;
|
||||
uint16_t tot_nb_desc;
|
||||
bool need_initial_post;
|
||||
struct iflib_dma_info data;
|
||||
};
|
||||
|
||||
static inline unsigned int vnic_rq_desc_avail(struct vnic_rq *rq)
|
||||
{
|
||||
/* how many does SW own? */
|
||||
return rq->ring.desc_avail;
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_rq_desc_used(struct vnic_rq *rq)
|
||||
{
|
||||
/* how many does HW own? */
|
||||
return rq->ring.desc_count - rq->ring.desc_avail - 1;
|
||||
}
|
||||
|
||||
enum desc_return_options {
|
||||
VNIC_RQ_RETURN_DESC,
|
||||
VNIC_RQ_DEFER_RETURN_DESC,
|
||||
};
|
||||
|
||||
static inline int vnic_rq_fill(struct vnic_rq *rq,
|
||||
int (*buf_fill)(struct vnic_rq *rq))
|
||||
{
|
||||
int err;
|
||||
|
||||
while (vnic_rq_desc_avail(rq) > 0) {
|
||||
|
||||
err = (*buf_fill)(rq);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int vnic_rq_fill_count(struct vnic_rq *rq,
|
||||
int (*buf_fill)(struct vnic_rq *rq), unsigned int count)
|
||||
{
|
||||
int err;
|
||||
|
||||
while ((vnic_rq_desc_avail(rq) > 0) && (count--)) {
|
||||
|
||||
err = (*buf_fill)(rq);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_rq_free(struct vnic_rq *rq);
|
||||
void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index,
|
||||
unsigned int fetch_index, unsigned int posted_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset);
|
||||
void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset);
|
||||
void vnic_rq_error_out(struct vnic_rq *rq, unsigned int error);
|
||||
unsigned int vnic_rq_error_status(struct vnic_rq *rq);
|
||||
void vnic_rq_enable(struct vnic_rq *rq);
|
||||
int vnic_rq_disable(struct vnic_rq *rq);
|
||||
void vnic_rq_clean(struct vnic_rq *rq);
|
||||
|
||||
#endif /* _VNIC_RQ_H_ */
|
||||
@@ -0,0 +1,32 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_RSS_H_
|
||||
#define _VNIC_RSS_H_
|
||||
|
||||
/* RSS key array */
|
||||
union vnic_rss_key {
|
||||
struct {
|
||||
u8 b[10];
|
||||
u8 b_pad[6];
|
||||
} key[4];
|
||||
u64 raw[8];
|
||||
};
|
||||
|
||||
/* RSS cpu array */
|
||||
union vnic_rss_cpu {
|
||||
struct {
|
||||
u8 b[4];
|
||||
u8 b_pad[4];
|
||||
} cpu[32];
|
||||
u64 raw[32];
|
||||
};
|
||||
|
||||
void vnic_set_rss_key(union vnic_rss_key *rss_key, u8 *key);
|
||||
void vnic_set_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu);
|
||||
void vnic_get_rss_key(union vnic_rss_key *rss_key, u8 *key);
|
||||
void vnic_get_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu);
|
||||
|
||||
#endif /* _VNIC_RSS_H_ */
|
||||
@@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_STATS_H_
|
||||
#define _VNIC_STATS_H_
|
||||
|
||||
/* Tx statistics */
|
||||
struct vnic_tx_stats {
|
||||
u64 tx_frames_ok;
|
||||
u64 tx_unicast_frames_ok;
|
||||
u64 tx_multicast_frames_ok;
|
||||
u64 tx_broadcast_frames_ok;
|
||||
u64 tx_bytes_ok;
|
||||
u64 tx_unicast_bytes_ok;
|
||||
u64 tx_multicast_bytes_ok;
|
||||
u64 tx_broadcast_bytes_ok;
|
||||
u64 tx_drops;
|
||||
u64 tx_errors;
|
||||
u64 tx_tso;
|
||||
u64 rsvd[16];
|
||||
};
|
||||
|
||||
/* Rx statistics */
|
||||
struct vnic_rx_stats {
|
||||
u64 rx_frames_ok;
|
||||
u64 rx_frames_total;
|
||||
u64 rx_unicast_frames_ok;
|
||||
u64 rx_multicast_frames_ok;
|
||||
u64 rx_broadcast_frames_ok;
|
||||
u64 rx_bytes_ok;
|
||||
u64 rx_unicast_bytes_ok;
|
||||
u64 rx_multicast_bytes_ok;
|
||||
u64 rx_broadcast_bytes_ok;
|
||||
u64 rx_drop;
|
||||
u64 rx_no_bufs;
|
||||
u64 rx_errors;
|
||||
u64 rx_rss;
|
||||
u64 rx_crc_errors;
|
||||
u64 rx_frames_64;
|
||||
u64 rx_frames_127;
|
||||
u64 rx_frames_255;
|
||||
u64 rx_frames_511;
|
||||
u64 rx_frames_1023;
|
||||
u64 rx_frames_1518;
|
||||
u64 rx_frames_to_max;
|
||||
u64 rsvd[16];
|
||||
};
|
||||
|
||||
struct vnic_stats {
|
||||
struct vnic_tx_stats tx;
|
||||
struct vnic_rx_stats rx;
|
||||
};
|
||||
|
||||
#endif /* _VNIC_STATS_H_ */
|
||||
@@ -0,0 +1,89 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "enic.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
|
||||
void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
|
||||
unsigned int fetch_index, unsigned int posted_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset)
|
||||
{
|
||||
u64 paddr;
|
||||
unsigned int count = wq->ring.desc_count;
|
||||
|
||||
paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
|
||||
ENIC_BUS_WRITE_8(wq->ctrl, TX_RING_BASE, paddr);
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_RING_SIZE, count);
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_FETCH_INDEX, fetch_index);
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_POSTED_INDEX, posted_index);
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_CQ_INDEX, cq_index);
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_ERROR_INTR_ENABLE, error_interrupt_enable);
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_ERROR_INTR_OFFSET, error_interrupt_offset);
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_ERROR_STATUS, 0);
|
||||
|
||||
wq->head_idx = fetch_index;
|
||||
wq->tail_idx = wq->head_idx;
|
||||
}
|
||||
|
||||
void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset)
|
||||
{
|
||||
vnic_wq_init_start(wq, cq_index, 0, 0,
|
||||
error_interrupt_enable,
|
||||
error_interrupt_offset);
|
||||
wq->cq_pend = 0;
|
||||
wq->last_completed_index = 0;
|
||||
}
|
||||
|
||||
unsigned int vnic_wq_error_status(struct vnic_wq *wq)
|
||||
{
|
||||
return ENIC_BUS_READ_4(wq->ctrl, TX_ERROR_STATUS);
|
||||
}
|
||||
|
||||
void vnic_wq_enable(struct vnic_wq *wq)
|
||||
{
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_ENABLE, 1);
|
||||
}
|
||||
|
||||
int vnic_wq_disable(struct vnic_wq *wq)
|
||||
{
|
||||
unsigned int wait;
|
||||
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_ENABLE, 0);
|
||||
|
||||
/* Wait for HW to ACK disable request */
|
||||
for (wait = 0; wait < 1000; wait++) {
|
||||
if (!(ENIC_BUS_READ_4(wq->ctrl, TX_RUNNING)))
|
||||
return 0;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
pr_err("Failed to disable WQ[%d]\n", wq->index);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
void vnic_wq_clean(struct vnic_wq *wq)
|
||||
{
|
||||
unsigned int to_clean = wq->tail_idx;
|
||||
|
||||
while (vnic_wq_desc_used(wq) > 0) {
|
||||
to_clean = buf_idx_incr(wq->ring.desc_count, to_clean);
|
||||
wq->ring.desc_avail++;
|
||||
}
|
||||
|
||||
wq->head_idx = 0;
|
||||
wq->tail_idx = 0;
|
||||
wq->last_completed_index = 0;
|
||||
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_FETCH_INDEX, 0);
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_POSTED_INDEX, 0);
|
||||
ENIC_BUS_WRITE_4(wq->ctrl, TX_ERROR_STATUS, 0);
|
||||
|
||||
vnic_dev_clear_desc_ring(&wq->ring);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_WQ_H_
|
||||
#define _VNIC_WQ_H_
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_cq.h"
|
||||
|
||||
/* Work queue control */
|
||||
struct vnic_wq_ctrl {
|
||||
u64 ring_base; /* 0x00 */
|
||||
#define TX_RING_BASE 0x00
|
||||
u32 ring_size; /* 0x08 */
|
||||
#define TX_RING_SIZE 0x08
|
||||
u32 pad0;
|
||||
u32 posted_index; /* 0x10 */
|
||||
#define TX_POSTED_INDEX 0x10
|
||||
u32 pad1;
|
||||
u32 cq_index; /* 0x18 */
|
||||
#define TX_CQ_INDEX 0x18
|
||||
u32 pad2;
|
||||
u32 enable; /* 0x20 */
|
||||
#define TX_ENABLE 0x20
|
||||
u32 pad3;
|
||||
u32 running; /* 0x28 */
|
||||
#define TX_RUNNING 0x28
|
||||
u32 pad4;
|
||||
u32 fetch_index; /* 0x30 */
|
||||
#define TX_FETCH_INDEX 0x30
|
||||
u32 pad5;
|
||||
u32 dca_value; /* 0x38 */
|
||||
#define TX_DCA_VALUE 0x38
|
||||
u32 pad6;
|
||||
u32 error_interrupt_enable; /* 0x40 */
|
||||
#define TX_ERROR_INTR_ENABLE 0x40
|
||||
u32 pad7;
|
||||
u32 error_interrupt_offset; /* 0x48 */
|
||||
#define TX_ERROR_INTR_OFFSET 0x48
|
||||
u32 pad8;
|
||||
u32 error_status; /* 0x50 */
|
||||
#define TX_ERROR_STATUS 0x50
|
||||
u32 pad9;
|
||||
};
|
||||
|
||||
struct vnic_wq {
|
||||
unsigned int index;
|
||||
uint64_t tx_offload_notsup_mask;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_res *ctrl;
|
||||
struct vnic_dev_ring ring;
|
||||
unsigned int head_idx;
|
||||
unsigned int cq_pend;
|
||||
unsigned int tail_idx;
|
||||
unsigned int socket_id;
|
||||
unsigned int processed;
|
||||
const struct rte_memzone *cqmsg_rz;
|
||||
uint16_t last_completed_index;
|
||||
uint64_t offloads;
|
||||
};
|
||||
|
||||
static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq)
|
||||
{
|
||||
/* how many does SW own? */
|
||||
return wq->ring.desc_avail;
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_wq_desc_used(struct vnic_wq *wq)
|
||||
{
|
||||
/* how many does HW own? */
|
||||
return wq->ring.desc_count - wq->ring.desc_avail - 1;
|
||||
}
|
||||
|
||||
#define PI_LOG2_CACHE_LINE_SIZE 5
|
||||
#define PI_INDEX_BITS 12
|
||||
#define PI_INDEX_MASK ((1U << PI_INDEX_BITS) - 1)
|
||||
#define PI_PREFETCH_LEN_MASK ((1U << PI_LOG2_CACHE_LINE_SIZE) - 1)
|
||||
#define PI_PREFETCH_LEN_OFF 16
|
||||
#define PI_PREFETCH_ADDR_BITS 43
|
||||
#define PI_PREFETCH_ADDR_MASK ((1ULL << PI_PREFETCH_ADDR_BITS) - 1)
|
||||
#define PI_PREFETCH_ADDR_OFF 21
|
||||
|
||||
static inline uint32_t
|
||||
buf_idx_incr(uint32_t n_descriptors, uint32_t idx)
|
||||
{
|
||||
idx++;
|
||||
if (unlikely(idx == n_descriptors))
|
||||
idx = 0;
|
||||
return idx;
|
||||
}
|
||||
|
||||
void vnic_wq_free(struct vnic_wq *wq);
|
||||
void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
|
||||
unsigned int fetch_index, unsigned int posted_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset);
|
||||
void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset);
|
||||
void vnic_wq_error_out(struct vnic_wq *wq, unsigned int error);
|
||||
unsigned int vnic_wq_error_status(struct vnic_wq *wq);
|
||||
void vnic_wq_enable(struct vnic_wq *wq);
|
||||
int vnic_wq_disable(struct vnic_wq *wq);
|
||||
void vnic_wq_clean(struct vnic_wq *wq);
|
||||
|
||||
#endif /* _VNIC_WQ_H_ */
|
||||
@@ -0,0 +1,84 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _WQ_ENET_DESC_H_
|
||||
#define _WQ_ENET_DESC_H_
|
||||
|
||||
/* Ethernet work queue descriptor: 16B */
|
||||
struct wq_enet_desc {
|
||||
__le64 address;
|
||||
__le16 length;
|
||||
__le16 mss_loopback;
|
||||
__le16 header_length_flags;
|
||||
__le16 vlan_tag;
|
||||
};
|
||||
|
||||
#define WQ_ENET_ADDR_BITS 64
|
||||
#define WQ_ENET_LEN_BITS 14
|
||||
#define WQ_ENET_LEN_MASK ((1 << WQ_ENET_LEN_BITS) - 1)
|
||||
#define WQ_ENET_MSS_BITS 14
|
||||
#define WQ_ENET_MSS_MASK ((1 << WQ_ENET_MSS_BITS) - 1)
|
||||
#define WQ_ENET_MSS_SHIFT 2
|
||||
#define WQ_ENET_LOOPBACK_SHIFT 1
|
||||
#define WQ_ENET_HDRLEN_BITS 10
|
||||
#define WQ_ENET_HDRLEN_MASK ((1 << WQ_ENET_HDRLEN_BITS) - 1)
|
||||
#define WQ_ENET_FLAGS_OM_BITS 2
|
||||
#define WQ_ENET_FLAGS_OM_MASK ((1 << WQ_ENET_FLAGS_OM_BITS) - 1)
|
||||
#define WQ_ENET_FLAGS_EOP_SHIFT 12
|
||||
#define WQ_ENET_FLAGS_CQ_ENTRY_SHIFT 13
|
||||
#define WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT 14
|
||||
#define WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT 15
|
||||
|
||||
#define WQ_ENET_OFFLOAD_MODE_CSUM 0
|
||||
#define WQ_ENET_OFFLOAD_MODE_RESERVED 1
|
||||
#define WQ_ENET_OFFLOAD_MODE_CSUM_L4 2
|
||||
#define WQ_ENET_OFFLOAD_MODE_TSO 3
|
||||
|
||||
static inline void wq_enet_desc_enc(struct wq_enet_desc *desc,
|
||||
u64 address, u16 length, u16 mss, u16 header_length,
|
||||
u8 offload_mode, u8 eop, u8 cq_entry, u8 fcoe_encap,
|
||||
u8 vlan_tag_insert, u16 vlan_tag, u8 loopback)
|
||||
{
|
||||
desc->address = cpu_to_le64(address);
|
||||
desc->length = cpu_to_le16(length & WQ_ENET_LEN_MASK);
|
||||
desc->mss_loopback = cpu_to_le16((mss & WQ_ENET_MSS_MASK) <<
|
||||
WQ_ENET_MSS_SHIFT | (loopback & 1) << WQ_ENET_LOOPBACK_SHIFT);
|
||||
desc->header_length_flags = cpu_to_le16(
|
||||
(header_length & WQ_ENET_HDRLEN_MASK) |
|
||||
(offload_mode & WQ_ENET_FLAGS_OM_MASK) << WQ_ENET_HDRLEN_BITS |
|
||||
(eop & 1) << WQ_ENET_FLAGS_EOP_SHIFT |
|
||||
(cq_entry & 1) << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT |
|
||||
(fcoe_encap & 1) << WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT |
|
||||
(vlan_tag_insert & 1) << WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT);
|
||||
desc->vlan_tag = cpu_to_le16(vlan_tag);
|
||||
}
|
||||
|
||||
static inline void wq_enet_desc_dec(struct wq_enet_desc *desc,
|
||||
u64 *address, u16 *length, u16 *mss, u16 *header_length,
|
||||
u8 *offload_mode, u8 *eop, u8 *cq_entry, u8 *fcoe_encap,
|
||||
u8 *vlan_tag_insert, u16 *vlan_tag, u8 *loopback)
|
||||
{
|
||||
*address = le64_to_cpu(desc->address);
|
||||
*length = le16_to_cpu(desc->length) & WQ_ENET_LEN_MASK;
|
||||
*mss = (le16_to_cpu(desc->mss_loopback) >> WQ_ENET_MSS_SHIFT) &
|
||||
WQ_ENET_MSS_MASK;
|
||||
*loopback = (u8)((le16_to_cpu(desc->mss_loopback) >>
|
||||
WQ_ENET_LOOPBACK_SHIFT) & 1);
|
||||
*header_length = le16_to_cpu(desc->header_length_flags) &
|
||||
WQ_ENET_HDRLEN_MASK;
|
||||
*offload_mode = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_HDRLEN_BITS) & WQ_ENET_FLAGS_OM_MASK);
|
||||
*eop = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_FLAGS_EOP_SHIFT) & 1);
|
||||
*cq_entry = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_FLAGS_CQ_ENTRY_SHIFT) & 1);
|
||||
*fcoe_encap = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT) & 1);
|
||||
*vlan_tag_insert = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT) & 1);
|
||||
*vlan_tag = le16_to_cpu(desc->vlan_tag);
|
||||
}
|
||||
|
||||
#endif /* _WQ_ENET_DESC_H_ */
|
||||
@@ -107,6 +107,7 @@ SUBDIR= \
|
||||
${_efirt} \
|
||||
${_em} \
|
||||
${_ena} \
|
||||
${_enic} \
|
||||
${_enetc} \
|
||||
${_et} \
|
||||
evdev \
|
||||
@@ -782,6 +783,7 @@ _x86bios= x86bios
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
_amdgpio= amdgpio
|
||||
_ccp= ccp
|
||||
_enic= enic
|
||||
_iavf= iavf
|
||||
_ioat= ioat
|
||||
_ixl= ixl
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#$FreeBSD: head/sys/modules/ix/Makefile 327031 2017-12-20 18:15:06Z erj $
|
||||
|
||||
.PATH: ${SRCTOP}/sys/dev/enic
|
||||
|
||||
COPTS=-g
|
||||
#WITH_DEBUG_FILES=yes
|
||||
DEBUG_FLAGS=-g
|
||||
|
||||
KMOD = if_enic
|
||||
SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h ifdi_if.h
|
||||
SRCS += opt_inet.h opt_inet6.h opt_rss.h
|
||||
|
||||
SRCS += if_enic.c enic_txrx.c enic_res.c
|
||||
SRCS += vnic_cq.c vnic_dev.c vnic_intr.c vnic_rq.c vnic_wq.c
|
||||
|
||||
|
||||
CFLAGS+= -I${SRCTOP}/sys/dev/enic_native -I${SRCTOP}/sys/dev/enic_native/base
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
Reference in New Issue
Block a user