mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
23
drivers/net/ethernet/cisco/Kconfig
Normal file
23
drivers/net/ethernet/cisco/Kconfig
Normal file
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
# Cisco device configuration
|
||||
#
|
||||
|
||||
config NET_VENDOR_CISCO
|
||||
bool "Cisco devices"
|
||||
default y
|
||||
depends on PCI
|
||||
---help---
|
||||
If you have a network (Ethernet) card belonging to this class, say Y
|
||||
and read the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
Note that the answer to this question doesn't directly affect the
|
||||
kernel: saying N will just cause the configurator to skip all
|
||||
the questions about Cisco cards. If you say Y, you will be asked for
|
||||
your specific card in the following questions.
|
||||
|
||||
if NET_VENDOR_CISCO
|
||||
|
||||
source "drivers/net/ethernet/cisco/enic/Kconfig"
|
||||
|
||||
endif # NET_VENDOR_CISCO
|
5
drivers/net/ethernet/cisco/Makefile
Normal file
5
drivers/net/ethernet/cisco/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# Makefile for the Cisco device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ENIC) += enic/
|
9
drivers/net/ethernet/cisco/enic/Kconfig
Normal file
9
drivers/net/ethernet/cisco/enic/Kconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Cisco device configuration
|
||||
#
|
||||
|
||||
config ENIC
|
||||
tristate "Cisco VIC Ethernet NIC Support"
|
||||
depends on PCI
|
||||
---help---
|
||||
This enables the support for the Cisco VIC Ethernet card.
|
6
drivers/net/ethernet/cisco/enic/Makefile
Normal file
6
drivers/net/ethernet/cisco/enic/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
obj-$(CONFIG_ENIC) := enic.o
|
||||
|
||||
enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \
|
||||
enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o \
|
||||
enic_ethtool.o enic_api.o enic_clsf.o
|
||||
|
80
drivers/net/ethernet/cisco/enic/cq_desc.h
Normal file
80
drivers/net/ethernet/cisco/enic/cq_desc.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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,
|
||||
};
|
||||
|
||||
/* 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_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_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;
|
||||
}
|
||||
|
||||
#endif /* _CQ_DESC_H_ */
|
185
drivers/net/ethernet/cisco/enic/cq_enet_desc.h
Normal file
185
drivers/net/ethernet/cisco/enic/cq_enet_desc.h
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_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;
|
||||
};
|
||||
|
||||
#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_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_ */
|
250
drivers/net/ethernet/cisco/enic/enic.h
Normal file
250
drivers/net/ethernet/cisco/enic/enic.h
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ENIC_H_
|
||||
#define _ENIC_H_
|
||||
|
||||
#include "vnic_enet.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
#include "vnic_rq.h"
|
||||
#include "vnic_cq.h"
|
||||
#include "vnic_intr.h"
|
||||
#include "vnic_stats.h"
|
||||
#include "vnic_nic.h"
|
||||
#include "vnic_rss.h"
|
||||
#include <linux/irq.h>
|
||||
|
||||
#define DRV_NAME "enic"
|
||||
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
|
||||
#define DRV_VERSION "2.1.1.67"
|
||||
#define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc"
|
||||
|
||||
#define ENIC_BARS_MAX 6
|
||||
|
||||
#define ENIC_WQ_MAX 8
|
||||
#define ENIC_RQ_MAX 8
|
||||
#define ENIC_CQ_MAX (ENIC_WQ_MAX + ENIC_RQ_MAX)
|
||||
#define ENIC_INTR_MAX (ENIC_CQ_MAX + 2)
|
||||
|
||||
#define ENIC_AIC_LARGE_PKT_DIFF 3
|
||||
|
||||
struct enic_msix_entry {
|
||||
int requested;
|
||||
char devname[IFNAMSIZ];
|
||||
irqreturn_t (*isr)(int, void *);
|
||||
void *devid;
|
||||
};
|
||||
|
||||
/* Store only the lower range. Higher range is given by fw. */
|
||||
struct enic_intr_mod_range {
|
||||
u32 small_pkt_range_start;
|
||||
u32 large_pkt_range_start;
|
||||
};
|
||||
|
||||
struct enic_intr_mod_table {
|
||||
u32 rx_rate;
|
||||
u32 range_percent;
|
||||
};
|
||||
|
||||
#define ENIC_MAX_LINK_SPEEDS 3
|
||||
#define ENIC_LINK_SPEED_10G 10000
|
||||
#define ENIC_LINK_SPEED_4G 4000
|
||||
#define ENIC_LINK_40G_INDEX 2
|
||||
#define ENIC_LINK_10G_INDEX 1
|
||||
#define ENIC_LINK_4G_INDEX 0
|
||||
#define ENIC_RX_COALESCE_RANGE_END 125
|
||||
#define ENIC_AIC_TS_BREAK 100
|
||||
|
||||
struct enic_rx_coal {
|
||||
u32 small_pkt_range_start;
|
||||
u32 large_pkt_range_start;
|
||||
u32 range_end;
|
||||
u32 use_adaptive_rx_coalesce;
|
||||
};
|
||||
|
||||
/* priv_flags */
|
||||
#define ENIC_SRIOV_ENABLED (1 << 0)
|
||||
|
||||
/* enic port profile set flags */
|
||||
#define ENIC_PORT_REQUEST_APPLIED (1 << 0)
|
||||
#define ENIC_SET_REQUEST (1 << 1)
|
||||
#define ENIC_SET_NAME (1 << 2)
|
||||
#define ENIC_SET_INSTANCE (1 << 3)
|
||||
#define ENIC_SET_HOST (1 << 4)
|
||||
|
||||
struct enic_port_profile {
|
||||
u32 set;
|
||||
u8 request;
|
||||
char name[PORT_PROFILE_MAX];
|
||||
u8 instance_uuid[PORT_UUID_MAX];
|
||||
u8 host_uuid[PORT_UUID_MAX];
|
||||
u8 vf_mac[ETH_ALEN];
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
/* enic_rfs_fltr_node - rfs filter node in hash table
|
||||
* @@keys: IPv4 5 tuple
|
||||
* @flow_id: flow_id of clsf filter provided by kernel
|
||||
* @fltr_id: filter id of clsf filter returned by adaptor
|
||||
* @rq_id: desired rq index
|
||||
* @node: hlist_node
|
||||
*/
|
||||
struct enic_rfs_fltr_node {
|
||||
struct flow_keys keys;
|
||||
u32 flow_id;
|
||||
u16 fltr_id;
|
||||
u16 rq_id;
|
||||
struct hlist_node node;
|
||||
};
|
||||
|
||||
/* enic_rfs_flw_tbl - rfs flow table
|
||||
* @max: Maximum number of filters vNIC supports
|
||||
* @free: Number of free filters available
|
||||
* @toclean: hash table index to clean next
|
||||
* @ht_head: hash table list head
|
||||
* @lock: spin lock
|
||||
* @rfs_may_expire: timer function for enic_rps_may_expire_flow
|
||||
*/
|
||||
struct enic_rfs_flw_tbl {
|
||||
u16 max;
|
||||
int free;
|
||||
|
||||
#define ENIC_RFS_FLW_BITSHIFT (10)
|
||||
#define ENIC_RFS_FLW_MASK ((1 << ENIC_RFS_FLW_BITSHIFT) - 1)
|
||||
u16 toclean:ENIC_RFS_FLW_BITSHIFT;
|
||||
struct hlist_head ht_head[1 << ENIC_RFS_FLW_BITSHIFT];
|
||||
spinlock_t lock;
|
||||
struct timer_list rfs_may_expire;
|
||||
};
|
||||
|
||||
/* Per-instance private data structure */
|
||||
struct enic {
|
||||
struct net_device *netdev;
|
||||
struct pci_dev *pdev;
|
||||
struct vnic_enet_config config;
|
||||
struct vnic_dev_bar bar[ENIC_BARS_MAX];
|
||||
struct vnic_dev *vdev;
|
||||
struct timer_list notify_timer;
|
||||
struct work_struct reset;
|
||||
struct work_struct change_mtu_work;
|
||||
struct msix_entry msix_entry[ENIC_INTR_MAX];
|
||||
struct enic_msix_entry msix[ENIC_INTR_MAX];
|
||||
u32 msg_enable;
|
||||
spinlock_t devcmd_lock;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
unsigned int flags;
|
||||
unsigned int priv_flags;
|
||||
unsigned int mc_count;
|
||||
unsigned int uc_count;
|
||||
u32 port_mtu;
|
||||
struct enic_rx_coal rx_coalesce_setting;
|
||||
u32 rx_coalesce_usecs;
|
||||
u32 tx_coalesce_usecs;
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
u16 num_vfs;
|
||||
#endif
|
||||
spinlock_t enic_api_lock;
|
||||
struct enic_port_profile *pp;
|
||||
|
||||
/* work queue cache line section */
|
||||
____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
|
||||
spinlock_t wq_lock[ENIC_WQ_MAX];
|
||||
unsigned int wq_count;
|
||||
u16 loop_enable;
|
||||
u16 loop_tag;
|
||||
|
||||
/* receive queue cache line section */
|
||||
____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX];
|
||||
unsigned int rq_count;
|
||||
u64 rq_truncated_pkts;
|
||||
u64 rq_bad_fcs;
|
||||
struct napi_struct napi[ENIC_RQ_MAX + ENIC_WQ_MAX];
|
||||
|
||||
/* interrupt resource cache line section */
|
||||
____cacheline_aligned struct vnic_intr intr[ENIC_INTR_MAX];
|
||||
unsigned int intr_count;
|
||||
u32 __iomem *legacy_pba; /* memory-mapped */
|
||||
|
||||
/* completion queue cache line section */
|
||||
____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX];
|
||||
unsigned int cq_count;
|
||||
struct enic_rfs_flw_tbl rfs_h;
|
||||
u32 rx_copybreak;
|
||||
};
|
||||
|
||||
static inline struct device *enic_get_dev(struct enic *enic)
|
||||
{
|
||||
return &(enic->pdev->dev);
|
||||
}
|
||||
|
||||
static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq)
|
||||
{
|
||||
return rq;
|
||||
}
|
||||
|
||||
static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq)
|
||||
{
|
||||
return enic->rq_count + wq;
|
||||
}
|
||||
|
||||
static inline unsigned int enic_legacy_io_intr(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int enic_legacy_err_intr(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline unsigned int enic_legacy_notify_intr(void)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
static inline unsigned int enic_msix_rq_intr(struct enic *enic,
|
||||
unsigned int rq)
|
||||
{
|
||||
return enic->cq[enic_cq_rq(enic, rq)].interrupt_offset;
|
||||
}
|
||||
|
||||
static inline unsigned int enic_msix_wq_intr(struct enic *enic,
|
||||
unsigned int wq)
|
||||
{
|
||||
return enic->cq[enic_cq_wq(enic, wq)].interrupt_offset;
|
||||
}
|
||||
|
||||
static inline unsigned int enic_msix_err_intr(struct enic *enic)
|
||||
{
|
||||
return enic->rq_count + enic->wq_count;
|
||||
}
|
||||
|
||||
static inline unsigned int enic_msix_notify_intr(struct enic *enic)
|
||||
{
|
||||
return enic->rq_count + enic->wq_count + 1;
|
||||
}
|
||||
|
||||
void enic_reset_addr_lists(struct enic *enic);
|
||||
int enic_sriov_enabled(struct enic *enic);
|
||||
int enic_is_valid_vf(struct enic *enic, int vf);
|
||||
int enic_is_dynamic(struct enic *enic);
|
||||
void enic_set_ethtool_ops(struct net_device *netdev);
|
||||
|
||||
#endif /* _ENIC_H_ */
|
48
drivers/net/ethernet/cisco/enic/enic_api.c
Normal file
48
drivers/net/ethernet/cisco/enic/enic_api.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Copyright 2013 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_devcmd.h"
|
||||
|
||||
#include "enic_res.h"
|
||||
#include "enic.h"
|
||||
#include "enic_api.h"
|
||||
|
||||
int enic_api_devcmd_proxy_by_index(struct net_device *netdev, int vf,
|
||||
enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait)
|
||||
{
|
||||
int err;
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
struct vnic_dev *vdev = enic->vdev;
|
||||
|
||||
spin_lock(&enic->enic_api_lock);
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
|
||||
vnic_dev_cmd_proxy_by_index_start(vdev, vf);
|
||||
err = vnic_dev_cmd(vdev, cmd, a0, a1, wait);
|
||||
vnic_dev_cmd_proxy_end(vdev);
|
||||
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
spin_unlock(&enic->enic_api_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(enic_api_devcmd_proxy_by_index);
|
30
drivers/net/ethernet/cisco/enic/enic_api.h
Normal file
30
drivers/net/ethernet/cisco/enic/enic_api.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Copyright 2013 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ENIC_API_H__
|
||||
#define __ENIC_API_H__
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_devcmd.h"
|
||||
|
||||
int enic_api_devcmd_proxy_by_index(struct net_device *netdev, int vf,
|
||||
enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait);
|
||||
|
||||
#endif
|
284
drivers/net/ethernet/cisco/enic/enic_clsf.c
Normal file
284
drivers/net/ethernet/cisco/enic/enic_clsf.c
Normal file
|
@ -0,0 +1,284 @@
|
|||
#include <linux/if.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/flow_keys.h>
|
||||
#include "enic_res.h"
|
||||
#include "enic_clsf.h"
|
||||
|
||||
/* enic_addfltr_5t - Add ipv4 5tuple filter
|
||||
* @enic: enic struct of vnic
|
||||
* @keys: flow_keys of ipv4 5tuple
|
||||
* @rq: rq number to steer to
|
||||
*
|
||||
* This function returns filter_id(hardware_id) of the filter
|
||||
* added. In case of error it returns an negative number.
|
||||
*/
|
||||
int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq)
|
||||
{
|
||||
int res;
|
||||
struct filter data;
|
||||
|
||||
switch (keys->ip_proto) {
|
||||
case IPPROTO_TCP:
|
||||
data.u.ipv4.protocol = PROTO_TCP;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
data.u.ipv4.protocol = PROTO_UDP;
|
||||
break;
|
||||
default:
|
||||
return -EPROTONOSUPPORT;
|
||||
};
|
||||
data.type = FILTER_IPV4_5TUPLE;
|
||||
data.u.ipv4.src_addr = ntohl(keys->src);
|
||||
data.u.ipv4.dst_addr = ntohl(keys->dst);
|
||||
data.u.ipv4.src_port = ntohs(keys->port16[0]);
|
||||
data.u.ipv4.dst_port = ntohs(keys->port16[1]);
|
||||
data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
res = vnic_dev_classifier(enic->vdev, CLSF_ADD, &rq, &data);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
res = (res == 0) ? rq : res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* enic_delfltr - Delete clsf filter
|
||||
* @enic: enic struct of vnic
|
||||
* @filter_id: filter_is(hardware_id) of filter to be deleted
|
||||
*
|
||||
* This function returns zero in case of success, negative number incase of
|
||||
* error.
|
||||
*/
|
||||
int enic_delfltr(struct enic *enic, u16 filter_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
ret = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* enic_rfs_flw_tbl_init - initialize enic->rfs_h members
|
||||
* @enic: enic data
|
||||
*/
|
||||
void enic_rfs_flw_tbl_init(struct enic *enic)
|
||||
{
|
||||
int i;
|
||||
|
||||
spin_lock_init(&enic->rfs_h.lock);
|
||||
for (i = 0; i <= ENIC_RFS_FLW_MASK; i++)
|
||||
INIT_HLIST_HEAD(&enic->rfs_h.ht_head[i]);
|
||||
enic->rfs_h.max = enic->config.num_arfs;
|
||||
enic->rfs_h.free = enic->rfs_h.max;
|
||||
enic->rfs_h.toclean = 0;
|
||||
enic_rfs_timer_start(enic);
|
||||
}
|
||||
|
||||
void enic_rfs_flw_tbl_free(struct enic *enic)
|
||||
{
|
||||
int i;
|
||||
|
||||
enic_rfs_timer_stop(enic);
|
||||
spin_lock_bh(&enic->rfs_h.lock);
|
||||
enic->rfs_h.free = 0;
|
||||
for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) {
|
||||
struct hlist_head *hhead;
|
||||
struct hlist_node *tmp;
|
||||
struct enic_rfs_fltr_node *n;
|
||||
|
||||
hhead = &enic->rfs_h.ht_head[i];
|
||||
hlist_for_each_entry_safe(n, tmp, hhead, node) {
|
||||
enic_delfltr(enic, n->fltr_id);
|
||||
hlist_del(&n->node);
|
||||
kfree(n);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&enic->rfs_h.lock);
|
||||
}
|
||||
|
||||
struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) {
|
||||
struct hlist_head *hhead;
|
||||
struct hlist_node *tmp;
|
||||
struct enic_rfs_fltr_node *n;
|
||||
|
||||
hhead = &enic->rfs_h.ht_head[i];
|
||||
hlist_for_each_entry_safe(n, tmp, hhead, node)
|
||||
if (n->fltr_id == fltr_id)
|
||||
return n;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
void enic_flow_may_expire(unsigned long data)
|
||||
{
|
||||
struct enic *enic = (struct enic *)data;
|
||||
bool res;
|
||||
int j;
|
||||
|
||||
spin_lock_bh(&enic->rfs_h.lock);
|
||||
for (j = 0; j < ENIC_CLSF_EXPIRE_COUNT; j++) {
|
||||
struct hlist_head *hhead;
|
||||
struct hlist_node *tmp;
|
||||
struct enic_rfs_fltr_node *n;
|
||||
|
||||
hhead = &enic->rfs_h.ht_head[enic->rfs_h.toclean++];
|
||||
hlist_for_each_entry_safe(n, tmp, hhead, node) {
|
||||
res = rps_may_expire_flow(enic->netdev, n->rq_id,
|
||||
n->flow_id, n->fltr_id);
|
||||
if (res) {
|
||||
res = enic_delfltr(enic, n->fltr_id);
|
||||
if (unlikely(res))
|
||||
continue;
|
||||
hlist_del(&n->node);
|
||||
kfree(n);
|
||||
enic->rfs_h.free++;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&enic->rfs_h.lock);
|
||||
mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4);
|
||||
}
|
||||
|
||||
static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h,
|
||||
struct flow_keys *k)
|
||||
{
|
||||
struct enic_rfs_fltr_node *tpos;
|
||||
|
||||
hlist_for_each_entry(tpos, h, node)
|
||||
if (tpos->keys.src == k->src &&
|
||||
tpos->keys.dst == k->dst &&
|
||||
tpos->keys.ports == k->ports &&
|
||||
tpos->keys.ip_proto == k->ip_proto &&
|
||||
tpos->keys.n_proto == k->n_proto)
|
||||
return tpos;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
|
||||
u16 rxq_index, u32 flow_id)
|
||||
{
|
||||
struct flow_keys keys;
|
||||
struct enic_rfs_fltr_node *n;
|
||||
struct enic *enic;
|
||||
u16 tbl_idx;
|
||||
int res, i;
|
||||
|
||||
enic = netdev_priv(dev);
|
||||
res = skb_flow_dissect(skb, &keys);
|
||||
if (!res || keys.n_proto != htons(ETH_P_IP) ||
|
||||
(keys.ip_proto != IPPROTO_TCP && keys.ip_proto != IPPROTO_UDP))
|
||||
return -EPROTONOSUPPORT;
|
||||
|
||||
tbl_idx = skb_get_hash_raw(skb) & ENIC_RFS_FLW_MASK;
|
||||
spin_lock_bh(&enic->rfs_h.lock);
|
||||
n = htbl_key_search(&enic->rfs_h.ht_head[tbl_idx], &keys);
|
||||
|
||||
if (n) { /* entry already present */
|
||||
if (rxq_index == n->rq_id) {
|
||||
res = -EEXIST;
|
||||
goto ret_unlock;
|
||||
}
|
||||
|
||||
/* desired rq changed for the flow, we need to delete
|
||||
* old fltr and add new one
|
||||
*
|
||||
* The moment we delete the fltr, the upcoming pkts
|
||||
* are put it default rq based on rss. When we add
|
||||
* new filter, upcoming pkts are put in desired queue.
|
||||
* This could cause ooo pkts.
|
||||
*
|
||||
* Lets 1st try adding new fltr and then del old one.
|
||||
*/
|
||||
i = --enic->rfs_h.free;
|
||||
/* clsf tbl is full, we have to del old fltr first*/
|
||||
if (unlikely(i < 0)) {
|
||||
enic->rfs_h.free++;
|
||||
res = enic_delfltr(enic, n->fltr_id);
|
||||
if (unlikely(res < 0))
|
||||
goto ret_unlock;
|
||||
res = enic_addfltr_5t(enic, &keys, rxq_index);
|
||||
if (res < 0) {
|
||||
hlist_del(&n->node);
|
||||
enic->rfs_h.free++;
|
||||
goto ret_unlock;
|
||||
}
|
||||
/* add new fltr 1st then del old fltr */
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
res = enic_addfltr_5t(enic, &keys, rxq_index);
|
||||
if (res < 0) {
|
||||
enic->rfs_h.free++;
|
||||
goto ret_unlock;
|
||||
}
|
||||
ret = enic_delfltr(enic, n->fltr_id);
|
||||
/* deleting old fltr failed. Add old fltr to list.
|
||||
* enic_flow_may_expire() will try to delete it later.
|
||||
*/
|
||||
if (unlikely(ret < 0)) {
|
||||
struct enic_rfs_fltr_node *d;
|
||||
struct hlist_head *head;
|
||||
|
||||
head = &enic->rfs_h.ht_head[tbl_idx];
|
||||
d = kmalloc(sizeof(*d), GFP_ATOMIC);
|
||||
if (d) {
|
||||
d->fltr_id = n->fltr_id;
|
||||
INIT_HLIST_NODE(&d->node);
|
||||
hlist_add_head(&d->node, head);
|
||||
}
|
||||
} else {
|
||||
enic->rfs_h.free++;
|
||||
}
|
||||
}
|
||||
n->rq_id = rxq_index;
|
||||
n->fltr_id = res;
|
||||
n->flow_id = flow_id;
|
||||
/* entry not present */
|
||||
} else {
|
||||
i = --enic->rfs_h.free;
|
||||
if (i <= 0) {
|
||||
enic->rfs_h.free++;
|
||||
res = -EBUSY;
|
||||
goto ret_unlock;
|
||||
}
|
||||
|
||||
n = kmalloc(sizeof(*n), GFP_ATOMIC);
|
||||
if (!n) {
|
||||
res = -ENOMEM;
|
||||
enic->rfs_h.free++;
|
||||
goto ret_unlock;
|
||||
}
|
||||
|
||||
res = enic_addfltr_5t(enic, &keys, rxq_index);
|
||||
if (res < 0) {
|
||||
kfree(n);
|
||||
enic->rfs_h.free++;
|
||||
goto ret_unlock;
|
||||
}
|
||||
n->rq_id = rxq_index;
|
||||
n->fltr_id = res;
|
||||
n->flow_id = flow_id;
|
||||
n->keys = keys;
|
||||
INIT_HLIST_NODE(&n->node);
|
||||
hlist_add_head(&n->node, &enic->rfs_h.ht_head[tbl_idx]);
|
||||
}
|
||||
|
||||
ret_unlock:
|
||||
spin_unlock_bh(&enic->rfs_h.lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RFS_ACCEL */
|
37
drivers/net/ethernet/cisco/enic/enic_clsf.h
Normal file
37
drivers/net/ethernet/cisco/enic/enic_clsf.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef _ENIC_CLSF_H_
|
||||
#define _ENIC_CLSF_H_
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "enic.h"
|
||||
|
||||
#define ENIC_CLSF_EXPIRE_COUNT 128
|
||||
|
||||
int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq);
|
||||
int enic_delfltr(struct enic *enic, u16 filter_id);
|
||||
void enic_rfs_flw_tbl_init(struct enic *enic);
|
||||
void enic_rfs_flw_tbl_free(struct enic *enic);
|
||||
struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id);
|
||||
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
|
||||
u16 rxq_index, u32 flow_id);
|
||||
void enic_flow_may_expire(unsigned long data);
|
||||
|
||||
static inline void enic_rfs_timer_start(struct enic *enic)
|
||||
{
|
||||
init_timer(&enic->rfs_h.rfs_may_expire);
|
||||
enic->rfs_h.rfs_may_expire.function = enic_flow_may_expire;
|
||||
enic->rfs_h.rfs_may_expire.data = (unsigned long)enic;
|
||||
mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4);
|
||||
}
|
||||
|
||||
static inline void enic_rfs_timer_stop(struct enic *enic)
|
||||
{
|
||||
del_timer_sync(&enic->rfs_h.rfs_may_expire);
|
||||
}
|
||||
#else
|
||||
static inline void enic_rfs_timer_start(struct enic *enic) {}
|
||||
static inline void enic_rfs_timer_stop(struct enic *enic) {}
|
||||
#endif /* CONFIG_RFS_ACCEL */
|
||||
|
||||
#endif /* _ENIC_CLSF_H_ */
|
292
drivers/net/ethernet/cisco/enic/enic_dev.c
Normal file
292
drivers/net/ethernet/cisco/enic/enic_dev.c
Normal file
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_vic.h"
|
||||
#include "enic_res.h"
|
||||
#include "enic.h"
|
||||
#include "enic_dev.h"
|
||||
|
||||
int enic_dev_fw_info(struct enic *enic, struct vnic_devcmd_fw_info **fw_info)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_fw_info(enic->vdev, fw_info);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_stats_dump(struct enic *enic, struct vnic_stats **vstats)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_stats_dump(enic->vdev, vstats);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_add_station_addr(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!is_valid_ether_addr(enic->netdev->dev_addr))
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_add_addr(enic->vdev, enic->netdev->dev_addr);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_del_station_addr(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!is_valid_ether_addr(enic->netdev->dev_addr))
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_del_addr(enic->vdev, enic->netdev->dev_addr);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_packet_filter(struct enic *enic, int directed, int multicast,
|
||||
int broadcast, int promisc, int allmulti)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_packet_filter(enic->vdev, directed,
|
||||
multicast, broadcast, promisc, allmulti);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_add_addr(struct enic *enic, const u8 *addr)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_add_addr(enic->vdev, addr);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_del_addr(struct enic *enic, const u8 *addr)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_del_addr(enic->vdev, addr);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_notify_unset(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_notify_unset(enic->vdev);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_hang_notify(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_hang_notify(enic->vdev);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_set_ig_vlan_rewrite_mode(enic->vdev,
|
||||
IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_enable(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_enable_wait(enic->vdev);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_disable(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_disable(enic->vdev);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_intr_coal_timer_info(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_intr_coal_timer_info(enic->vdev);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_vnic_dev_deinit(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_deinit(enic->vdev);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_init_prov2(enic->vdev,
|
||||
(u8 *)vp, vic_provinfo_size(vp));
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_deinit_done(struct enic *enic, int *status)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_deinit_done(enic->vdev, status);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* rtnl lock is held */
|
||||
int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
|
||||
{
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = enic_add_vlan(enic, vid);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* rtnl lock is held */
|
||||
int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
|
||||
{
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = enic_del_vlan(enic, vid);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_enable2(struct enic *enic, int active)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_enable2(enic->vdev, active);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_enable2_done(struct enic *enic, int *status)
|
||||
{
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&enic->devcmd_lock);
|
||||
err = vnic_dev_enable2_done(enic->vdev, status);
|
||||
spin_unlock_bh(&enic->devcmd_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int enic_dev_status_to_errno(int devcmd_status)
|
||||
{
|
||||
switch (devcmd_status) {
|
||||
case ERR_SUCCESS:
|
||||
return 0;
|
||||
case ERR_EINVAL:
|
||||
return -EINVAL;
|
||||
case ERR_EFAULT:
|
||||
return -EFAULT;
|
||||
case ERR_EPERM:
|
||||
return -EPERM;
|
||||
case ERR_EBUSY:
|
||||
return -EBUSY;
|
||||
case ERR_ECMDUNKNOWN:
|
||||
case ERR_ENOTSUPPORTED:
|
||||
return -EOPNOTSUPP;
|
||||
case ERR_EBADSTATE:
|
||||
return -EINVAL;
|
||||
case ERR_ENOMEM:
|
||||
return -ENOMEM;
|
||||
case ERR_ETIMEDOUT:
|
||||
return -ETIMEDOUT;
|
||||
case ERR_ELINKDOWN:
|
||||
return -ENETDOWN;
|
||||
case ERR_EINPROGRESS:
|
||||
return -EINPROGRESS;
|
||||
case ERR_EMAXRES:
|
||||
default:
|
||||
return (devcmd_status < 0) ? devcmd_status : -1;
|
||||
}
|
||||
}
|
65
drivers/net/ethernet/cisco/enic/enic_dev.h
Normal file
65
drivers/net/ethernet/cisco/enic/enic_dev.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ENIC_DEV_H_
|
||||
#define _ENIC_DEV_H_
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_vic.h"
|
||||
|
||||
/*
|
||||
* Calls the devcmd function given by argument vnicdevcmdfn.
|
||||
* If vf argument is valid, it proxies the devcmd
|
||||
*/
|
||||
#define ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnicdevcmdfn, ...) \
|
||||
do { \
|
||||
spin_lock_bh(&enic->devcmd_lock); \
|
||||
if (enic_is_valid_vf(enic, vf)) { \
|
||||
vnic_dev_cmd_proxy_by_index_start(enic->vdev, vf); \
|
||||
err = vnicdevcmdfn(enic->vdev, ##__VA_ARGS__); \
|
||||
vnic_dev_cmd_proxy_end(enic->vdev); \
|
||||
} else { \
|
||||
err = vnicdevcmdfn(enic->vdev, ##__VA_ARGS__); \
|
||||
} \
|
||||
spin_unlock_bh(&enic->devcmd_lock); \
|
||||
} while (0)
|
||||
|
||||
int enic_dev_fw_info(struct enic *enic, struct vnic_devcmd_fw_info **fw_info);
|
||||
int enic_dev_stats_dump(struct enic *enic, struct vnic_stats **vstats);
|
||||
int enic_dev_add_station_addr(struct enic *enic);
|
||||
int enic_dev_del_station_addr(struct enic *enic);
|
||||
int enic_dev_packet_filter(struct enic *enic, int directed, int multicast,
|
||||
int broadcast, int promisc, int allmulti);
|
||||
int enic_dev_add_addr(struct enic *enic, const u8 *addr);
|
||||
int enic_dev_del_addr(struct enic *enic, const u8 *addr);
|
||||
int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid);
|
||||
int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid);
|
||||
int enic_dev_notify_unset(struct enic *enic);
|
||||
int enic_dev_hang_notify(struct enic *enic);
|
||||
int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic);
|
||||
int enic_dev_enable(struct enic *enic);
|
||||
int enic_dev_disable(struct enic *enic);
|
||||
int enic_dev_intr_coal_timer_info(struct enic *enic);
|
||||
int enic_vnic_dev_deinit(struct enic *enic);
|
||||
int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp);
|
||||
int enic_dev_deinit_done(struct enic *enic, int *status);
|
||||
int enic_dev_enable2(struct enic *enic, int arg);
|
||||
int enic_dev_enable2_done(struct enic *enic, int *status);
|
||||
int enic_dev_status_to_errno(int devcmd_status);
|
||||
|
||||
#endif /* _ENIC_DEV_H_ */
|
438
drivers/net/ethernet/cisco/enic/enic_ethtool.c
Normal file
438
drivers/net/ethernet/cisco/enic/enic_ethtool.c
Normal file
|
@ -0,0 +1,438 @@
|
|||
/**
|
||||
* Copyright 2013 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include "enic_res.h"
|
||||
#include "enic.h"
|
||||
#include "enic_dev.h"
|
||||
#include "enic_clsf.h"
|
||||
|
||||
struct enic_stat {
|
||||
char name[ETH_GSTRING_LEN];
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
#define ENIC_TX_STAT(stat) { \
|
||||
.name = #stat, \
|
||||
.index = offsetof(struct vnic_tx_stats, stat) / sizeof(u64) \
|
||||
}
|
||||
|
||||
#define ENIC_RX_STAT(stat) { \
|
||||
.name = #stat, \
|
||||
.index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \
|
||||
}
|
||||
|
||||
static const struct enic_stat enic_tx_stats[] = {
|
||||
ENIC_TX_STAT(tx_frames_ok),
|
||||
ENIC_TX_STAT(tx_unicast_frames_ok),
|
||||
ENIC_TX_STAT(tx_multicast_frames_ok),
|
||||
ENIC_TX_STAT(tx_broadcast_frames_ok),
|
||||
ENIC_TX_STAT(tx_bytes_ok),
|
||||
ENIC_TX_STAT(tx_unicast_bytes_ok),
|
||||
ENIC_TX_STAT(tx_multicast_bytes_ok),
|
||||
ENIC_TX_STAT(tx_broadcast_bytes_ok),
|
||||
ENIC_TX_STAT(tx_drops),
|
||||
ENIC_TX_STAT(tx_errors),
|
||||
ENIC_TX_STAT(tx_tso),
|
||||
};
|
||||
|
||||
static const struct enic_stat enic_rx_stats[] = {
|
||||
ENIC_RX_STAT(rx_frames_ok),
|
||||
ENIC_RX_STAT(rx_frames_total),
|
||||
ENIC_RX_STAT(rx_unicast_frames_ok),
|
||||
ENIC_RX_STAT(rx_multicast_frames_ok),
|
||||
ENIC_RX_STAT(rx_broadcast_frames_ok),
|
||||
ENIC_RX_STAT(rx_bytes_ok),
|
||||
ENIC_RX_STAT(rx_unicast_bytes_ok),
|
||||
ENIC_RX_STAT(rx_multicast_bytes_ok),
|
||||
ENIC_RX_STAT(rx_broadcast_bytes_ok),
|
||||
ENIC_RX_STAT(rx_drop),
|
||||
ENIC_RX_STAT(rx_no_bufs),
|
||||
ENIC_RX_STAT(rx_errors),
|
||||
ENIC_RX_STAT(rx_rss),
|
||||
ENIC_RX_STAT(rx_crc_errors),
|
||||
ENIC_RX_STAT(rx_frames_64),
|
||||
ENIC_RX_STAT(rx_frames_127),
|
||||
ENIC_RX_STAT(rx_frames_255),
|
||||
ENIC_RX_STAT(rx_frames_511),
|
||||
ENIC_RX_STAT(rx_frames_1023),
|
||||
ENIC_RX_STAT(rx_frames_1518),
|
||||
ENIC_RX_STAT(rx_frames_to_max),
|
||||
};
|
||||
|
||||
static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
|
||||
static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
|
||||
|
||||
void enic_intr_coal_set_rx(struct enic *enic, u32 timer)
|
||||
{
|
||||
int i;
|
||||
int intr;
|
||||
|
||||
for (i = 0; i < enic->rq_count; i++) {
|
||||
intr = enic_msix_rq_intr(enic, i);
|
||||
vnic_intr_coalescing_timer_set(&enic->intr[intr], timer);
|
||||
}
|
||||
}
|
||||
|
||||
static int enic_get_settings(struct net_device *netdev,
|
||||
struct ethtool_cmd *ecmd)
|
||||
{
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
|
||||
ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
|
||||
ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
|
||||
ecmd->port = PORT_FIBRE;
|
||||
ecmd->transceiver = XCVR_EXTERNAL;
|
||||
|
||||
if (netif_carrier_ok(netdev)) {
|
||||
ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev));
|
||||
ecmd->duplex = DUPLEX_FULL;
|
||||
} else {
|
||||
ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
|
||||
ecmd->duplex = DUPLEX_UNKNOWN;
|
||||
}
|
||||
|
||||
ecmd->autoneg = AUTONEG_DISABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void enic_get_drvinfo(struct net_device *netdev,
|
||||
struct ethtool_drvinfo *drvinfo)
|
||||
{
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
struct vnic_devcmd_fw_info *fw_info;
|
||||
|
||||
enic_dev_fw_info(enic, &fw_info);
|
||||
|
||||
strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
|
||||
strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
|
||||
strlcpy(drvinfo->fw_version, fw_info->fw_version,
|
||||
sizeof(drvinfo->fw_version));
|
||||
strlcpy(drvinfo->bus_info, pci_name(enic->pdev),
|
||||
sizeof(drvinfo->bus_info));
|
||||
}
|
||||
|
||||
static void enic_get_strings(struct net_device *netdev, u32 stringset,
|
||||
u8 *data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
for (i = 0; i < enic_n_tx_stats; i++) {
|
||||
memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN);
|
||||
data += ETH_GSTRING_LEN;
|
||||
}
|
||||
for (i = 0; i < enic_n_rx_stats; i++) {
|
||||
memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN);
|
||||
data += ETH_GSTRING_LEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int enic_get_sset_count(struct net_device *netdev, int sset)
|
||||
{
|
||||
switch (sset) {
|
||||
case ETH_SS_STATS:
|
||||
return enic_n_tx_stats + enic_n_rx_stats;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void enic_get_ethtool_stats(struct net_device *netdev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
struct vnic_stats *vstats;
|
||||
unsigned int i;
|
||||
|
||||
enic_dev_stats_dump(enic, &vstats);
|
||||
|
||||
for (i = 0; i < enic_n_tx_stats; i++)
|
||||
*(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index];
|
||||
for (i = 0; i < enic_n_rx_stats; i++)
|
||||
*(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index];
|
||||
}
|
||||
|
||||
static u32 enic_get_msglevel(struct net_device *netdev)
|
||||
{
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
return enic->msg_enable;
|
||||
}
|
||||
|
||||
static void enic_set_msglevel(struct net_device *netdev, u32 value)
|
||||
{
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
enic->msg_enable = value;
|
||||
}
|
||||
|
||||
static int enic_get_coalesce(struct net_device *netdev,
|
||||
struct ethtool_coalesce *ecmd)
|
||||
{
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting;
|
||||
|
||||
ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
|
||||
ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
|
||||
if (rxcoal->use_adaptive_rx_coalesce)
|
||||
ecmd->use_adaptive_rx_coalesce = 1;
|
||||
ecmd->rx_coalesce_usecs_low = rxcoal->small_pkt_range_start;
|
||||
ecmd->rx_coalesce_usecs_high = rxcoal->range_end;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enic_set_coalesce(struct net_device *netdev,
|
||||
struct ethtool_coalesce *ecmd)
|
||||
{
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
u32 tx_coalesce_usecs;
|
||||
u32 rx_coalesce_usecs;
|
||||
u32 rx_coalesce_usecs_low;
|
||||
u32 rx_coalesce_usecs_high;
|
||||
u32 coalesce_usecs_max;
|
||||
unsigned int i, intr;
|
||||
struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting;
|
||||
|
||||
coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev);
|
||||
tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs,
|
||||
coalesce_usecs_max);
|
||||
rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs,
|
||||
coalesce_usecs_max);
|
||||
|
||||
rx_coalesce_usecs_low = min_t(u32, ecmd->rx_coalesce_usecs_low,
|
||||
coalesce_usecs_max);
|
||||
rx_coalesce_usecs_high = min_t(u32, ecmd->rx_coalesce_usecs_high,
|
||||
coalesce_usecs_max);
|
||||
|
||||
switch (vnic_dev_get_intr_mode(enic->vdev)) {
|
||||
case VNIC_DEV_INTR_MODE_INTX:
|
||||
if (tx_coalesce_usecs != rx_coalesce_usecs)
|
||||
return -EINVAL;
|
||||
if (ecmd->use_adaptive_rx_coalesce ||
|
||||
ecmd->rx_coalesce_usecs_low ||
|
||||
ecmd->rx_coalesce_usecs_high)
|
||||
return -EINVAL;
|
||||
|
||||
intr = enic_legacy_io_intr();
|
||||
vnic_intr_coalescing_timer_set(&enic->intr[intr],
|
||||
tx_coalesce_usecs);
|
||||
break;
|
||||
case VNIC_DEV_INTR_MODE_MSI:
|
||||
if (tx_coalesce_usecs != rx_coalesce_usecs)
|
||||
return -EINVAL;
|
||||
if (ecmd->use_adaptive_rx_coalesce ||
|
||||
ecmd->rx_coalesce_usecs_low ||
|
||||
ecmd->rx_coalesce_usecs_high)
|
||||
return -EINVAL;
|
||||
|
||||
vnic_intr_coalescing_timer_set(&enic->intr[0],
|
||||
tx_coalesce_usecs);
|
||||
break;
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
if (ecmd->rx_coalesce_usecs_high &&
|
||||
(rx_coalesce_usecs_high <
|
||||
rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < enic->wq_count; i++) {
|
||||
intr = enic_msix_wq_intr(enic, i);
|
||||
vnic_intr_coalescing_timer_set(&enic->intr[intr],
|
||||
tx_coalesce_usecs);
|
||||
}
|
||||
|
||||
rxcoal->use_adaptive_rx_coalesce =
|
||||
!!ecmd->use_adaptive_rx_coalesce;
|
||||
if (!rxcoal->use_adaptive_rx_coalesce)
|
||||
enic_intr_coal_set_rx(enic, rx_coalesce_usecs);
|
||||
|
||||
if (ecmd->rx_coalesce_usecs_high) {
|
||||
rxcoal->range_end = rx_coalesce_usecs_high;
|
||||
rxcoal->small_pkt_range_start = rx_coalesce_usecs_low;
|
||||
rxcoal->large_pkt_range_start = rx_coalesce_usecs_low +
|
||||
ENIC_AIC_LARGE_PKT_DIFF;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
enic->tx_coalesce_usecs = tx_coalesce_usecs;
|
||||
enic->rx_coalesce_usecs = rx_coalesce_usecs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enic_grxclsrlall(struct enic *enic, struct ethtool_rxnfc *cmd,
|
||||
u32 *rule_locs)
|
||||
{
|
||||
int j, ret = 0, cnt = 0;
|
||||
|
||||
cmd->data = enic->rfs_h.max - enic->rfs_h.free;
|
||||
for (j = 0; j < (1 << ENIC_RFS_FLW_BITSHIFT); j++) {
|
||||
struct hlist_head *hhead;
|
||||
struct hlist_node *tmp;
|
||||
struct enic_rfs_fltr_node *n;
|
||||
|
||||
hhead = &enic->rfs_h.ht_head[j];
|
||||
hlist_for_each_entry_safe(n, tmp, hhead, node) {
|
||||
if (cnt == cmd->rule_cnt)
|
||||
return -EMSGSIZE;
|
||||
rule_locs[cnt] = n->fltr_id;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
cmd->rule_cnt = cnt;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
struct ethtool_rx_flow_spec *fsp =
|
||||
(struct ethtool_rx_flow_spec *)&cmd->fs;
|
||||
struct enic_rfs_fltr_node *n;
|
||||
|
||||
n = htbl_fltr_search(enic, (u16)fsp->location);
|
||||
if (!n)
|
||||
return -EINVAL;
|
||||
switch (n->keys.ip_proto) {
|
||||
case IPPROTO_TCP:
|
||||
fsp->flow_type = TCP_V4_FLOW;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
fsp->flow_type = UDP_V4_FLOW;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
fsp->h_u.tcp_ip4_spec.ip4src = n->keys.src;
|
||||
fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0;
|
||||
|
||||
fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.dst;
|
||||
fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0;
|
||||
|
||||
fsp->h_u.tcp_ip4_spec.psrc = n->keys.port16[0];
|
||||
fsp->m_u.tcp_ip4_spec.psrc = (__u16)~0;
|
||||
|
||||
fsp->h_u.tcp_ip4_spec.pdst = n->keys.port16[1];
|
||||
fsp->m_u.tcp_ip4_spec.pdst = (__u16)~0;
|
||||
|
||||
fsp->ring_cookie = n->rq_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
||||
u32 *rule_locs)
|
||||
{
|
||||
struct enic *enic = netdev_priv(dev);
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd->cmd) {
|
||||
case ETHTOOL_GRXRINGS:
|
||||
cmd->data = enic->rq_count;
|
||||
break;
|
||||
case ETHTOOL_GRXCLSRLCNT:
|
||||
spin_lock_bh(&enic->rfs_h.lock);
|
||||
cmd->rule_cnt = enic->rfs_h.max - enic->rfs_h.free;
|
||||
cmd->data = enic->rfs_h.max;
|
||||
spin_unlock_bh(&enic->rfs_h.lock);
|
||||
break;
|
||||
case ETHTOOL_GRXCLSRLALL:
|
||||
spin_lock_bh(&enic->rfs_h.lock);
|
||||
ret = enic_grxclsrlall(enic, cmd, rule_locs);
|
||||
spin_unlock_bh(&enic->rfs_h.lock);
|
||||
break;
|
||||
case ETHTOOL_GRXCLSRULE:
|
||||
spin_lock_bh(&enic->rfs_h.lock);
|
||||
ret = enic_grxclsrule(enic, cmd);
|
||||
spin_unlock_bh(&enic->rfs_h.lock);
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enic_get_tunable(struct net_device *dev,
|
||||
const struct ethtool_tunable *tuna, void *data)
|
||||
{
|
||||
struct enic *enic = netdev_priv(dev);
|
||||
int ret = 0;
|
||||
|
||||
switch (tuna->id) {
|
||||
case ETHTOOL_RX_COPYBREAK:
|
||||
*(u32 *)data = enic->rx_copybreak;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enic_set_tunable(struct net_device *dev,
|
||||
const struct ethtool_tunable *tuna,
|
||||
const void *data)
|
||||
{
|
||||
struct enic *enic = netdev_priv(dev);
|
||||
int ret = 0;
|
||||
|
||||
switch (tuna->id) {
|
||||
case ETHTOOL_RX_COPYBREAK:
|
||||
enic->rx_copybreak = *(u32 *)data;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops enic_ethtool_ops = {
|
||||
.get_settings = enic_get_settings,
|
||||
.get_drvinfo = enic_get_drvinfo,
|
||||
.get_msglevel = enic_get_msglevel,
|
||||
.set_msglevel = enic_set_msglevel,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_strings = enic_get_strings,
|
||||
.get_sset_count = enic_get_sset_count,
|
||||
.get_ethtool_stats = enic_get_ethtool_stats,
|
||||
.get_coalesce = enic_get_coalesce,
|
||||
.set_coalesce = enic_set_coalesce,
|
||||
.get_rxnfc = enic_get_rxnfc,
|
||||
.get_tunable = enic_get_tunable,
|
||||
.set_tunable = enic_set_tunable,
|
||||
};
|
||||
|
||||
void enic_set_ethtool_ops(struct net_device *netdev)
|
||||
{
|
||||
netdev->ethtool_ops = &enic_ethtool_ops;
|
||||
}
|
2655
drivers/net/ethernet/cisco/enic/enic_main.c
Normal file
2655
drivers/net/ethernet/cisco/enic/enic_main.c
Normal file
File diff suppressed because it is too large
Load diff
368
drivers/net/ethernet/cisco/enic/enic_pp.c
Normal file
368
drivers/net/ethernet/cisco/enic/enic_pp.c
Normal file
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
#include "vnic_vic.h"
|
||||
#include "enic_res.h"
|
||||
#include "enic.h"
|
||||
#include "enic_dev.h"
|
||||
#include "enic_pp.h"
|
||||
|
||||
/*
|
||||
* Checks validity of vf index that came in
|
||||
* port profile request
|
||||
*/
|
||||
int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err)
|
||||
{
|
||||
if (vf != PORT_SELF_VF) {
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
if (enic_sriov_enabled(enic)) {
|
||||
if (vf < 0 || vf >= enic->num_vfs) {
|
||||
*err = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
} else {
|
||||
*err = -EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
#else
|
||||
*err = -EOPNOTSUPP;
|
||||
goto err_out;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (vf == PORT_SELF_VF && !enic_is_dynamic(enic)) {
|
||||
*err = -EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
*err = 0;
|
||||
return 1;
|
||||
|
||||
err_out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enic_set_port_profile(struct enic *enic, int vf)
|
||||
{
|
||||
struct net_device *netdev = enic->netdev;
|
||||
struct enic_port_profile *pp;
|
||||
struct vic_provinfo *vp;
|
||||
const u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
|
||||
const __be16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX);
|
||||
char uuid_str[38];
|
||||
char client_mac_str[18];
|
||||
u8 *client_mac;
|
||||
int err;
|
||||
|
||||
ENIC_PP_BY_INDEX(enic, vf, pp, &err);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!(pp->set & ENIC_SET_NAME) || !strlen(pp->name))
|
||||
return -EINVAL;
|
||||
|
||||
vp = vic_provinfo_alloc(GFP_KERNEL, oui,
|
||||
VIC_PROVINFO_GENERIC_TYPE);
|
||||
if (!vp)
|
||||
return -ENOMEM;
|
||||
|
||||
VIC_PROVINFO_ADD_TLV(vp,
|
||||
VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
|
||||
strlen(pp->name) + 1, pp->name);
|
||||
|
||||
if (!is_zero_ether_addr(pp->mac_addr)) {
|
||||
client_mac = pp->mac_addr;
|
||||
} else if (vf == PORT_SELF_VF) {
|
||||
client_mac = netdev->dev_addr;
|
||||
} else {
|
||||
netdev_err(netdev, "Cannot find pp mac address "
|
||||
"for VF %d\n", vf);
|
||||
err = -EINVAL;
|
||||
goto add_tlv_failure;
|
||||
}
|
||||
|
||||
VIC_PROVINFO_ADD_TLV(vp,
|
||||
VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
|
||||
ETH_ALEN, client_mac);
|
||||
|
||||
snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac);
|
||||
VIC_PROVINFO_ADD_TLV(vp,
|
||||
VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
|
||||
sizeof(client_mac_str), client_mac_str);
|
||||
|
||||
if (pp->set & ENIC_SET_INSTANCE) {
|
||||
sprintf(uuid_str, "%pUB", pp->instance_uuid);
|
||||
VIC_PROVINFO_ADD_TLV(vp,
|
||||
VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
|
||||
sizeof(uuid_str), uuid_str);
|
||||
}
|
||||
|
||||
if (pp->set & ENIC_SET_HOST) {
|
||||
sprintf(uuid_str, "%pUB", pp->host_uuid);
|
||||
VIC_PROVINFO_ADD_TLV(vp,
|
||||
VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
|
||||
sizeof(uuid_str), uuid_str);
|
||||
}
|
||||
|
||||
VIC_PROVINFO_ADD_TLV(vp,
|
||||
VIC_GENERIC_PROV_TLV_OS_TYPE,
|
||||
sizeof(os_type), &os_type);
|
||||
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_init_prov2, (u8 *)vp,
|
||||
vic_provinfo_size(vp));
|
||||
err = enic_dev_status_to_errno(err);
|
||||
|
||||
add_tlv_failure:
|
||||
vic_provinfo_free(vp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int enic_unset_port_profile(struct enic *enic, int vf)
|
||||
{
|
||||
int err;
|
||||
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_deinit);
|
||||
if (err)
|
||||
return enic_dev_status_to_errno(err);
|
||||
|
||||
if (vf == PORT_SELF_VF)
|
||||
enic_reset_addr_lists(enic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enic_are_pp_different(struct enic_port_profile *pp1,
|
||||
struct enic_port_profile *pp2)
|
||||
{
|
||||
return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid,
|
||||
pp2->instance_uuid, PORT_UUID_MAX) |
|
||||
!!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) |
|
||||
!ether_addr_equal(pp1->mac_addr, pp2->mac_addr);
|
||||
}
|
||||
|
||||
static int enic_pp_preassociate(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp);
|
||||
static int enic_pp_disassociate(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp);
|
||||
static int enic_pp_preassociate_rr(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp);
|
||||
static int enic_pp_associate(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp);
|
||||
|
||||
static int (*enic_pp_handlers[])(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_state,
|
||||
int *restore_pp) = {
|
||||
[PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate,
|
||||
[PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr,
|
||||
[PORT_REQUEST_ASSOCIATE] = enic_pp_associate,
|
||||
[PORT_REQUEST_DISASSOCIATE] = enic_pp_disassociate,
|
||||
};
|
||||
|
||||
static const int enic_pp_handlers_count =
|
||||
ARRAY_SIZE(enic_pp_handlers);
|
||||
|
||||
static int enic_pp_preassociate(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int enic_pp_disassociate(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp)
|
||||
{
|
||||
struct net_device *netdev = enic->netdev;
|
||||
struct enic_port_profile *pp;
|
||||
int err;
|
||||
|
||||
ENIC_PP_BY_INDEX(enic, vf, pp, &err);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Deregister mac addresses */
|
||||
if (!is_zero_ether_addr(pp->mac_addr))
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
|
||||
pp->mac_addr);
|
||||
else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
|
||||
netdev->dev_addr);
|
||||
|
||||
return enic_unset_port_profile(enic, vf);
|
||||
}
|
||||
|
||||
static int enic_pp_preassociate_rr(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp)
|
||||
{
|
||||
struct enic_port_profile *pp;
|
||||
int err;
|
||||
int active = 0;
|
||||
|
||||
ENIC_PP_BY_INDEX(enic, vf, pp, &err);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (pp->request != PORT_REQUEST_ASSOCIATE) {
|
||||
/* If pre-associate is not part of an associate.
|
||||
We always disassociate first */
|
||||
err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, vf,
|
||||
prev_pp, restore_pp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*restore_pp = 0;
|
||||
}
|
||||
|
||||
*restore_pp = 0;
|
||||
|
||||
err = enic_set_port_profile(enic, vf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* If pre-associate is not part of an associate. */
|
||||
if (pp->request != PORT_REQUEST_ASSOCIATE) {
|
||||
/* Enable device as standby */
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2,
|
||||
active);
|
||||
err = enic_dev_status_to_errno(err);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int enic_pp_associate(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp)
|
||||
{
|
||||
struct net_device *netdev = enic->netdev;
|
||||
struct enic_port_profile *pp;
|
||||
int err;
|
||||
int active = 1;
|
||||
|
||||
ENIC_PP_BY_INDEX(enic, vf, pp, &err);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Check if a pre-associate was called before */
|
||||
if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR ||
|
||||
(prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR &&
|
||||
enic_are_pp_different(prev_pp, pp))) {
|
||||
err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](
|
||||
enic, vf, prev_pp, restore_pp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*restore_pp = 0;
|
||||
}
|
||||
|
||||
err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR](
|
||||
enic, vf, prev_pp, restore_pp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*restore_pp = 0;
|
||||
|
||||
/* Enable device as active */
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2, active);
|
||||
err = enic_dev_status_to_errno(err);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Register mac address */
|
||||
if (!is_zero_ether_addr(pp->mac_addr))
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
|
||||
pp->mac_addr);
|
||||
else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
|
||||
netdev->dev_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int enic_process_set_pp_request(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp)
|
||||
{
|
||||
struct enic_port_profile *pp;
|
||||
int err;
|
||||
|
||||
ENIC_PP_BY_INDEX(enic, vf, pp, &err);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (pp->request >= enic_pp_handlers_count
|
||||
|| !enic_pp_handlers[pp->request])
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return enic_pp_handlers[pp->request](enic, vf, prev_pp, restore_pp);
|
||||
}
|
||||
|
||||
int enic_process_get_pp_request(struct enic *enic, int vf,
|
||||
int request, u16 *response)
|
||||
{
|
||||
int err, status = ERR_SUCCESS;
|
||||
|
||||
switch (request) {
|
||||
|
||||
case PORT_REQUEST_PREASSOCIATE_RR:
|
||||
case PORT_REQUEST_ASSOCIATE:
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
|
||||
vnic_dev_enable2_done, &status);
|
||||
break;
|
||||
|
||||
case PORT_REQUEST_DISASSOCIATE:
|
||||
ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
|
||||
vnic_dev_deinit_done, &status);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (err)
|
||||
status = err;
|
||||
|
||||
switch (status) {
|
||||
case ERR_SUCCESS:
|
||||
*response = PORT_PROFILE_RESPONSE_SUCCESS;
|
||||
break;
|
||||
case ERR_EINVAL:
|
||||
*response = PORT_PROFILE_RESPONSE_INVALID;
|
||||
break;
|
||||
case ERR_EBADSTATE:
|
||||
*response = PORT_PROFILE_RESPONSE_BADSTATE;
|
||||
break;
|
||||
case ERR_ENOMEM:
|
||||
*response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
case ERR_EINPROGRESS:
|
||||
*response = PORT_PROFILE_RESPONSE_INPROGRESS;
|
||||
break;
|
||||
default:
|
||||
*response = PORT_PROFILE_RESPONSE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
36
drivers/net/ethernet/cisco/enic/enic_pp.h
Normal file
36
drivers/net/ethernet/cisco/enic/enic_pp.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ENIC_PP_H_
|
||||
#define _ENIC_PP_H_
|
||||
|
||||
#define ENIC_PP_BY_INDEX(enic, vf, pp, err) \
|
||||
do { \
|
||||
if (enic_is_valid_pp_vf(enic, vf, err)) \
|
||||
pp = (vf == PORT_SELF_VF) ? enic->pp : enic->pp + vf; \
|
||||
else \
|
||||
pp = NULL; \
|
||||
} while (0)
|
||||
|
||||
int enic_process_set_pp_request(struct enic *enic, int vf,
|
||||
struct enic_port_profile *prev_pp, int *restore_pp);
|
||||
int enic_process_get_pp_request(struct enic *enic, int vf,
|
||||
int request, u16 *response);
|
||||
int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err);
|
||||
|
||||
#endif /* _ENIC_PP_H_ */
|
385
drivers/net/ethernet/cisco/enic/enic_res.c
Normal file
385
drivers/net/ethernet/cisco/enic/enic_res.c
Normal file
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.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);
|
||||
|
||||
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 */
|
||||
|
||||
if (c->mtu == 0)
|
||||
c->mtu = 1500;
|
||||
c->mtu = min_t(u16, ENIC_MAX_MTU,
|
||||
max_t(u16, ENIC_MIN_MTU,
|
||||
c->mtu));
|
||||
|
||||
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 %pM wq/rq %d/%d mtu %d\n",
|
||||
enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu);
|
||||
|
||||
dev_info(enic_get_dev(enic), "vNIC csum tx/rx %s/%s "
|
||||
"tso/lro %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, TSO) ? "yes" : "no",
|
||||
ENIC_SETTING(enic, LRO) ? "yes" : "no",
|
||||
ENIC_SETTING(enic, RSS) ? "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);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len)
|
||||
{
|
||||
u64 a0 = (u64)key_pa, a1 = len;
|
||||
int wait = 1000;
|
||||
|
||||
return vnic_dev_cmd(enic->vdev, CMD_RSS_KEY, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len)
|
||||
{
|
||||
u64 a0 = (u64)cpu_pa, a1 = len;
|
||||
int wait = 1000;
|
||||
|
||||
return vnic_dev_cmd(enic->vdev, CMD_RSS_CPU, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
void enic_free_vnic_resources(struct enic *enic)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < enic->wq_count; i++)
|
||||
vnic_wq_free(&enic->wq[i]);
|
||||
for (i = 0; i < enic->rq_count; i++)
|
||||
vnic_rq_free(&enic->rq[i]);
|
||||
for (i = 0; i < enic->cq_count; i++)
|
||||
vnic_cq_free(&enic->cq[i]);
|
||||
for (i = 0; i < enic->intr_count; i++)
|
||||
vnic_intr_free(&enic->intr[i]);
|
||||
}
|
||||
|
||||
void enic_get_res_counts(struct enic *enic)
|
||||
{
|
||||
enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
|
||||
enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
|
||||
enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
|
||||
enic->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->wq_count, enic->rq_count,
|
||||
enic->cq_count, enic->intr_count);
|
||||
}
|
||||
|
||||
void enic_init_vnic_resources(struct enic *enic)
|
||||
{
|
||||
enum vnic_dev_intr_mode intr_mode;
|
||||
unsigned int mask_on_assertion;
|
||||
unsigned int interrupt_offset;
|
||||
unsigned int error_interrupt_enable;
|
||||
unsigned int error_interrupt_offset;
|
||||
unsigned int cq_index;
|
||||
unsigned int i;
|
||||
|
||||
intr_mode = vnic_dev_get_intr_mode(enic->vdev);
|
||||
|
||||
/* Init RQ/WQ resources.
|
||||
*
|
||||
* RQ[0 - n-1] point to CQ[0 - n-1]
|
||||
* WQ[0 - m-1] point to CQ[n - n+m-1]
|
||||
*
|
||||
* Error interrupt is not enabled for MSI.
|
||||
*/
|
||||
|
||||
switch (intr_mode) {
|
||||
case VNIC_DEV_INTR_MODE_INTX:
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
error_interrupt_enable = 1;
|
||||
error_interrupt_offset = enic->intr_count - 2;
|
||||
break;
|
||||
default:
|
||||
error_interrupt_enable = 0;
|
||||
error_interrupt_offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->rq_count; i++) {
|
||||
cq_index = i;
|
||||
vnic_rq_init(&enic->rq[i],
|
||||
cq_index,
|
||||
error_interrupt_enable,
|
||||
error_interrupt_offset);
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->wq_count; i++) {
|
||||
cq_index = enic->rq_count + i;
|
||||
vnic_wq_init(&enic->wq[i],
|
||||
cq_index,
|
||||
error_interrupt_enable,
|
||||
error_interrupt_offset);
|
||||
}
|
||||
|
||||
/* Init CQ resources
|
||||
*
|
||||
* CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
|
||||
* CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
|
||||
*/
|
||||
|
||||
for (i = 0; i < enic->cq_count; i++) {
|
||||
|
||||
switch (intr_mode) {
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
interrupt_offset = i;
|
||||
break;
|
||||
default:
|
||||
interrupt_offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
vnic_cq_init(&enic->cq[i],
|
||||
0 /* flow_control_enable */,
|
||||
1 /* color_enable */,
|
||||
0 /* cq_head */,
|
||||
0 /* cq_tail */,
|
||||
1 /* cq_tail_color */,
|
||||
1 /* interrupt_enable */,
|
||||
1 /* cq_entry_enable */,
|
||||
0 /* cq_message_enable */,
|
||||
interrupt_offset,
|
||||
0 /* cq_message_addr */);
|
||||
}
|
||||
|
||||
/* Init INTR resources
|
||||
*
|
||||
* mask_on_assertion is not used for INTx due to the level-
|
||||
* triggered nature of INTx
|
||||
*/
|
||||
|
||||
switch (intr_mode) {
|
||||
case VNIC_DEV_INTR_MODE_MSI:
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
mask_on_assertion = 1;
|
||||
break;
|
||||
default:
|
||||
mask_on_assertion = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->intr_count; i++) {
|
||||
vnic_intr_init(&enic->intr[i],
|
||||
enic->config.intr_timer_usec,
|
||||
enic->config.intr_timer_type,
|
||||
mask_on_assertion);
|
||||
}
|
||||
}
|
||||
|
||||
int enic_alloc_vnic_resources(struct enic *enic)
|
||||
{
|
||||
enum vnic_dev_intr_mode intr_mode;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
intr_mode = vnic_dev_get_intr_mode(enic->vdev);
|
||||
|
||||
dev_info(enic_get_dev(enic), "vNIC resources used: "
|
||||
"wq %d rq %d cq %d intr %d intr mode %s\n",
|
||||
enic->wq_count, enic->rq_count,
|
||||
enic->cq_count, enic->intr_count,
|
||||
intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
|
||||
intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
|
||||
intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
|
||||
"unknown");
|
||||
|
||||
/* Allocate queue resources
|
||||
*/
|
||||
|
||||
for (i = 0; i < enic->wq_count; i++) {
|
||||
err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
|
||||
enic->config.wq_desc_count,
|
||||
sizeof(struct wq_enet_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->rq_count; i++) {
|
||||
err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
|
||||
enic->config.rq_desc_count,
|
||||
sizeof(struct rq_enet_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->cq_count; i++) {
|
||||
if (i < enic->rq_count)
|
||||
err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
|
||||
enic->config.rq_desc_count,
|
||||
sizeof(struct cq_enet_rq_desc));
|
||||
else
|
||||
err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
|
||||
enic->config.wq_desc_count,
|
||||
sizeof(struct cq_enet_wq_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->intr_count; i++) {
|
||||
err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
/* Hook remaining resource
|
||||
*/
|
||||
|
||||
enic->legacy_pba = vnic_dev_get_res(enic->vdev,
|
||||
RES_TYPE_INTR_PBA_LEGACY, 0);
|
||||
if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
|
||||
dev_err(enic_get_dev(enic),
|
||||
"Failed to hook legacy pba resource\n");
|
||||
err = -ENODEV;
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_cleanup:
|
||||
enic_free_vnic_resources(enic);
|
||||
|
||||
return err;
|
||||
}
|
153
drivers/net/ethernet/cisco/enic/enic_res.h
Normal file
153
drivers/net/ethernet/cisco/enic/enic_res.h
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_MIN_MTU 68
|
||||
#define ENIC_MAX_MTU 9000
|
||||
|
||||
#define ENIC_MULTICAST_PERFECT_FILTERS 32
|
||||
#define ENIC_UNICAST_PERFECT_FILTERS 32
|
||||
|
||||
#define ENIC_NON_TSO_MAX_DESC 16
|
||||
|
||||
#define ENIC_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0)
|
||||
|
||||
static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len,
|
||||
unsigned int mss_or_csum_offset, unsigned int hdr_len,
|
||||
int vlan_tag_insert, unsigned int vlan_tag,
|
||||
int offload_mode, int cq_entry, int sop, int eop, int loopback)
|
||||
{
|
||||
struct wq_enet_desc *desc = vnic_wq_next_desc(wq);
|
||||
u8 desc_skip_cnt = 1;
|
||||
u8 compressed_send = 0;
|
||||
u64 wrid = 0;
|
||||
|
||||
wq_enet_desc_enc(desc,
|
||||
(u64)dma_addr | VNIC_PADDR_TARGET,
|
||||
(u16)len,
|
||||
(u16)mss_or_csum_offset,
|
||||
(u16)hdr_len, (u8)offload_mode,
|
||||
(u8)eop, (u8)cq_entry,
|
||||
0, /* fcoe_encap */
|
||||
(u8)vlan_tag_insert,
|
||||
(u16)vlan_tag,
|
||||
(u8)loopback);
|
||||
|
||||
vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop, desc_skip_cnt,
|
||||
(u8)cq_entry, compressed_send, wrid);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc_cont(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len,
|
||||
int eop, int loopback)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
0, 0, 0, 0, 0,
|
||||
eop, 0 /* !SOP */, eop, loopback);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc(struct vnic_wq *wq, void *os_buf,
|
||||
dma_addr_t dma_addr, unsigned int len, int vlan_tag_insert,
|
||||
unsigned int vlan_tag, int eop, int loopback)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
0, 0, vlan_tag_insert, vlan_tag,
|
||||
WQ_ENET_OFFLOAD_MODE_CSUM,
|
||||
eop, 1 /* SOP */, eop, loopback);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc_csum(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len,
|
||||
int ip_csum, int tcpudp_csum, int vlan_tag_insert,
|
||||
unsigned int vlan_tag, int eop, int loopback)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
(ip_csum ? 1 : 0) + (tcpudp_csum ? 2 : 0),
|
||||
0, vlan_tag_insert, vlan_tag,
|
||||
WQ_ENET_OFFLOAD_MODE_CSUM,
|
||||
eop, 1 /* SOP */, eop, loopback);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc_csum_l4(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len,
|
||||
unsigned int csum_offset, unsigned int hdr_len,
|
||||
int vlan_tag_insert, unsigned int vlan_tag, int eop, int loopback)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
csum_offset, hdr_len, vlan_tag_insert, vlan_tag,
|
||||
WQ_ENET_OFFLOAD_MODE_CSUM_L4,
|
||||
eop, 1 /* SOP */, eop, loopback);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc_tso(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len,
|
||||
unsigned int mss, unsigned int hdr_len, int vlan_tag_insert,
|
||||
unsigned int vlan_tag, int eop, int loopback)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
mss, hdr_len, vlan_tag_insert, vlan_tag,
|
||||
WQ_ENET_OFFLOAD_MODE_TSO,
|
||||
eop, 1 /* SOP */, eop, loopback);
|
||||
}
|
||||
|
||||
static inline void enic_queue_rq_desc(struct vnic_rq *rq,
|
||||
void *os_buf, unsigned int os_buf_index,
|
||||
dma_addr_t dma_addr, unsigned int len)
|
||||
{
|
||||
struct rq_enet_desc *desc = vnic_rq_next_desc(rq);
|
||||
u64 wrid = 0;
|
||||
u8 type = os_buf_index ?
|
||||
RQ_ENET_TYPE_NOT_SOP : RQ_ENET_TYPE_ONLY_SOP;
|
||||
|
||||
rq_enet_desc_enc(desc,
|
||||
(u64)dma_addr | VNIC_PADDR_TARGET,
|
||||
type, (u16)len);
|
||||
|
||||
vnic_rq_post(rq, os_buf, os_buf_index, dma_addr, len, wrid);
|
||||
}
|
||||
|
||||
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);
|
||||
int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len);
|
||||
int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len);
|
||||
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_ */
|
60
drivers/net/ethernet/cisco/enic/rq_enet_desc.h
Normal file
60
drivers/net/ethernet/cisco/enic/rq_enet_desc.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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(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_ */
|
91
drivers/net/ethernet/cisco/enic/vnic_cq.c
Normal file
91
drivers/net/ethernet/cisco/enic/vnic_cq.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_cq.h"
|
||||
|
||||
void vnic_cq_free(struct vnic_cq *cq)
|
||||
{
|
||||
vnic_dev_free_desc_ring(cq->vdev, &cq->ring);
|
||||
|
||||
cq->ctrl = NULL;
|
||||
}
|
||||
|
||||
int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
cq->index = index;
|
||||
cq->vdev = vdev;
|
||||
|
||||
cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index);
|
||||
if (!cq->ctrl) {
|
||||
pr_err("Failed to hook CQ[%d] resource\n", index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = vnic_dev_alloc_desc_ring(vdev, &cq->ring, desc_count, desc_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
writeq(paddr, &cq->ctrl->ring_base);
|
||||
iowrite32(cq->ring.desc_count, &cq->ctrl->ring_size);
|
||||
iowrite32(flow_control_enable, &cq->ctrl->flow_control_enable);
|
||||
iowrite32(color_enable, &cq->ctrl->color_enable);
|
||||
iowrite32(cq_head, &cq->ctrl->cq_head);
|
||||
iowrite32(cq_tail, &cq->ctrl->cq_tail);
|
||||
iowrite32(cq_tail_color, &cq->ctrl->cq_tail_color);
|
||||
iowrite32(interrupt_enable, &cq->ctrl->interrupt_enable);
|
||||
iowrite32(cq_entry_enable, &cq->ctrl->cq_entry_enable);
|
||||
iowrite32(cq_message_enable, &cq->ctrl->cq_message_enable);
|
||||
iowrite32(interrupt_offset, &cq->ctrl->interrupt_offset);
|
||||
writeq(cq_message_addr, &cq->ctrl->cq_message_addr);
|
||||
|
||||
cq->interrupt_offset = interrupt_offset;
|
||||
}
|
||||
|
||||
void vnic_cq_clean(struct vnic_cq *cq)
|
||||
{
|
||||
cq->to_clean = 0;
|
||||
cq->last_color = 0;
|
||||
|
||||
iowrite32(0, &cq->ctrl->cq_head);
|
||||
iowrite32(0, &cq->ctrl->cq_tail);
|
||||
iowrite32(1, &cq->ctrl->cq_tail_color);
|
||||
|
||||
vnic_dev_clear_desc_ring(&cq->ring);
|
||||
}
|
123
drivers/net/ethernet/cisco/enic/vnic_cq.h
Normal file
123
drivers/net/ethernet/cisco/enic/vnic_cq.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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 */
|
||||
u32 ring_size; /* 0x08 */
|
||||
u32 pad0;
|
||||
u32 flow_control_enable; /* 0x10 */
|
||||
u32 pad1;
|
||||
u32 color_enable; /* 0x18 */
|
||||
u32 pad2;
|
||||
u32 cq_head; /* 0x20 */
|
||||
u32 pad3;
|
||||
u32 cq_tail; /* 0x28 */
|
||||
u32 pad4;
|
||||
u32 cq_tail_color; /* 0x30 */
|
||||
u32 pad5;
|
||||
u32 interrupt_enable; /* 0x38 */
|
||||
u32 pad6;
|
||||
u32 cq_entry_enable; /* 0x40 */
|
||||
u32 pad7;
|
||||
u32 cq_message_enable; /* 0x48 */
|
||||
u32 pad8;
|
||||
u32 interrupt_offset; /* 0x50 */
|
||||
u32 pad9;
|
||||
u64 cq_message_addr; /* 0x58 */
|
||||
u32 pad10;
|
||||
};
|
||||
|
||||
struct vnic_rx_bytes_counter {
|
||||
unsigned int small_pkt_bytes_cnt;
|
||||
unsigned int large_pkt_bytes_cnt;
|
||||
};
|
||||
|
||||
struct vnic_cq {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_cq_ctrl __iomem *ctrl; /* memory-mapped */
|
||||
struct vnic_dev_ring ring;
|
||||
unsigned int to_clean;
|
||||
unsigned int last_color;
|
||||
unsigned int interrupt_offset;
|
||||
struct vnic_rx_bytes_counter pkt_size_counter;
|
||||
unsigned int cur_rx_coal_timeval;
|
||||
unsigned int tobe_rx_coal_timeval;
|
||||
ktime_t prev_ts;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void vnic_cq_free(struct vnic_cq *cq);
|
||||
int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
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);
|
||||
|
||||
#endif /* _VNIC_CQ_H_ */
|
1108
drivers/net/ethernet/cisco/enic/vnic_dev.c
Normal file
1108
drivers/net/ethernet/cisco/enic/vnic_dev.c
Normal file
File diff suppressed because it is too large
Load diff
139
drivers/net/ethernet/cisco/enic/vnic_dev.h
Normal file
139
drivers/net/ethernet/cisco/enic/vnic_dev.h
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_DEV_H_
|
||||
#define _VNIC_DEV_H_
|
||||
|
||||
#include "vnic_resource.h"
|
||||
#include "vnic_devcmd.h"
|
||||
|
||||
#ifndef VNIC_PADDR_TARGET
|
||||
#define VNIC_PADDR_TARGET 0x0000000000000000ULL
|
||||
#endif
|
||||
|
||||
#ifndef readq
|
||||
static inline u64 readq(void __iomem *reg)
|
||||
{
|
||||
return (((u64)readl(reg + 0x4UL) << 32) |
|
||||
(u64)readl(reg));
|
||||
}
|
||||
|
||||
static inline void writeq(u64 val, void __iomem *reg)
|
||||
{
|
||||
writel(val & 0xffffffff, reg);
|
||||
writel(val >> 32, reg + 0x4UL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
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;
|
||||
dma_addr_t bus_addr;
|
||||
unsigned long len;
|
||||
};
|
||||
|
||||
struct vnic_dev_ring {
|
||||
void *descs;
|
||||
size_t size;
|
||||
dma_addr_t base_addr;
|
||||
size_t base_align;
|
||||
void *descs_unaligned;
|
||||
size_t size_unaligned;
|
||||
dma_addr_t base_addr_unaligned;
|
||||
unsigned int desc_size;
|
||||
unsigned int desc_count;
|
||||
unsigned int desc_avail;
|
||||
};
|
||||
|
||||
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 __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
|
||||
unsigned int index);
|
||||
void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring);
|
||||
int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
void vnic_dev_free_desc_ring(struct vnic_dev *vdev,
|
||||
struct vnic_dev_ring *ring);
|
||||
int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
||||
u64 *a0, u64 *a1, int wait);
|
||||
void vnic_dev_cmd_proxy_by_index_start(struct vnic_dev *vdev, u16 index);
|
||||
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_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size,
|
||||
void *value);
|
||||
int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
|
||||
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_add_addr(struct vnic_dev *vdev, const u8 *addr);
|
||||
int vnic_dev_del_addr(struct vnic_dev *vdev, const u8 *addr);
|
||||
int vnic_dev_get_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
|
||||
int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr);
|
||||
int vnic_dev_notify_unset(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);
|
||||
int vnic_dev_close(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_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_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);
|
||||
void vnic_dev_unregister(struct vnic_dev *vdev);
|
||||
int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
|
||||
u8 ig_vlan_rewrite_mode);
|
||||
struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
|
||||
void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar,
|
||||
unsigned int num_bars);
|
||||
struct pci_dev *vnic_dev_get_pdev(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 *data);
|
||||
|
||||
#endif /* _VNIC_DEV_H_ */
|
632
drivers/net/ethernet/cisco/enic/vnic_devcmd.h
Normal file
632
drivers/net/ethernet/cisco/enic/vnic_devcmd.h
Normal file
|
@ -0,0 +1,632 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_DEVCMD_H_
|
||||
#define _VNIC_DEVCMD_H_
|
||||
|
||||
#define _CMD_NBITS 14
|
||||
#define _CMD_VTYPEBITS 10
|
||||
#define _CMD_FLAGSBITS 6
|
||||
#define _CMD_DIRBITS 2
|
||||
|
||||
#define _CMD_NMASK ((1 << _CMD_NBITS)-1)
|
||||
#define _CMD_VTYPEMASK ((1 << _CMD_VTYPEBITS)-1)
|
||||
#define _CMD_FLAGSMASK ((1 << _CMD_FLAGSBITS)-1)
|
||||
#define _CMD_DIRMASK ((1 << _CMD_DIRBITS)-1)
|
||||
|
||||
#define _CMD_NSHIFT 0
|
||||
#define _CMD_VTYPESHIFT (_CMD_NSHIFT+_CMD_NBITS)
|
||||
#define _CMD_FLAGSSHIFT (_CMD_VTYPESHIFT+_CMD_VTYPEBITS)
|
||||
#define _CMD_DIRSHIFT (_CMD_FLAGSSHIFT+_CMD_FLAGSBITS)
|
||||
|
||||
/*
|
||||
* Direction bits (from host perspective).
|
||||
*/
|
||||
#define _CMD_DIR_NONE 0U
|
||||
#define _CMD_DIR_WRITE 1U
|
||||
#define _CMD_DIR_READ 2U
|
||||
#define _CMD_DIR_RW (_CMD_DIR_WRITE | _CMD_DIR_READ)
|
||||
|
||||
/*
|
||||
* Flag bits.
|
||||
*/
|
||||
#define _CMD_FLAGS_NONE 0U
|
||||
#define _CMD_FLAGS_NOWAIT 1U
|
||||
|
||||
/*
|
||||
* vNIC type bits.
|
||||
*/
|
||||
#define _CMD_VTYPE_NONE 0U
|
||||
#define _CMD_VTYPE_ENET 1U
|
||||
#define _CMD_VTYPE_FC 2U
|
||||
#define _CMD_VTYPE_SCSI 4U
|
||||
#define _CMD_VTYPE_ALL (_CMD_VTYPE_ENET | _CMD_VTYPE_FC | _CMD_VTYPE_SCSI)
|
||||
|
||||
/*
|
||||
* Used to create cmds..
|
||||
*/
|
||||
#define _CMDCF(dir, flags, vtype, nr) \
|
||||
(((dir) << _CMD_DIRSHIFT) | \
|
||||
((flags) << _CMD_FLAGSSHIFT) | \
|
||||
((vtype) << _CMD_VTYPESHIFT) | \
|
||||
((nr) << _CMD_NSHIFT))
|
||||
#define _CMDC(dir, vtype, nr) _CMDCF(dir, 0, vtype, nr)
|
||||
#define _CMDCNW(dir, vtype, nr) _CMDCF(dir, _CMD_FLAGS_NOWAIT, vtype, nr)
|
||||
|
||||
/*
|
||||
* Used to decode cmds..
|
||||
*/
|
||||
#define _CMD_DIR(cmd) (((cmd) >> _CMD_DIRSHIFT) & _CMD_DIRMASK)
|
||||
#define _CMD_FLAGS(cmd) (((cmd) >> _CMD_FLAGSSHIFT) & _CMD_FLAGSMASK)
|
||||
#define _CMD_VTYPE(cmd) (((cmd) >> _CMD_VTYPESHIFT) & _CMD_VTYPEMASK)
|
||||
#define _CMD_N(cmd) (((cmd) >> _CMD_NSHIFT) & _CMD_NMASK)
|
||||
|
||||
enum vnic_devcmd_cmd {
|
||||
CMD_NONE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_NONE, 0),
|
||||
|
||||
/*
|
||||
* mcpu fw info in mem:
|
||||
* in:
|
||||
* (u64)a0=paddr to struct vnic_devcmd_fw_info
|
||||
* action:
|
||||
* Fills in struct vnic_devcmd_fw_info (128 bytes)
|
||||
* note:
|
||||
* An old definition of CMD_MCPU_FW_INFO
|
||||
*/
|
||||
CMD_MCPU_FW_INFO_OLD = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 1),
|
||||
|
||||
/*
|
||||
* mcpu fw info in mem:
|
||||
* in:
|
||||
* (u64)a0=paddr to struct vnic_devcmd_fw_info
|
||||
* (u16)a1=size of the structure
|
||||
* out:
|
||||
* (u16)a1=0 for in:a1 = 0,
|
||||
* data size actually written for other values.
|
||||
* action:
|
||||
* Fills in first 128 bytes of vnic_devcmd_fw_info for in:a1 = 0,
|
||||
* first in:a1 bytes for 0 < in:a1 <= 132,
|
||||
* 132 bytes for other values of in:a1.
|
||||
* note:
|
||||
* CMD_MCPU_FW_INFO and CMD_MCPU_FW_INFO_OLD have the same enum 1
|
||||
* for source compatibility.
|
||||
*/
|
||||
CMD_MCPU_FW_INFO = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 1),
|
||||
|
||||
/* dev-specific block member:
|
||||
* in: (u16)a0=offset,(u8)a1=size
|
||||
* out: a0=value */
|
||||
CMD_DEV_SPEC = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 2),
|
||||
|
||||
/* stats clear */
|
||||
CMD_STATS_CLEAR = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 3),
|
||||
|
||||
/* stats dump in mem: (u64)a0=paddr to stats area,
|
||||
* (u16)a1=sizeof stats area */
|
||||
CMD_STATS_DUMP = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 4),
|
||||
|
||||
/* set Rx packet filter: (u32)a0=filters (see CMD_PFILTER_*) */
|
||||
CMD_PACKET_FILTER = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 7),
|
||||
|
||||
/* set Rx packet filter for all: (u32)a0=filters (see CMD_PFILTER_*) */
|
||||
CMD_PACKET_FILTER_ALL = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 7),
|
||||
|
||||
/* hang detection notification */
|
||||
CMD_HANG_NOTIFY = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8),
|
||||
|
||||
/* MAC address in (u48)a0 */
|
||||
CMD_GET_MAC_ADDR = _CMDC(_CMD_DIR_READ,
|
||||
_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 9),
|
||||
|
||||
/* add addr from (u48)a0 */
|
||||
CMD_ADDR_ADD = _CMDCNW(_CMD_DIR_WRITE,
|
||||
_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 12),
|
||||
|
||||
/* del addr from (u48)a0 */
|
||||
CMD_ADDR_DEL = _CMDCNW(_CMD_DIR_WRITE,
|
||||
_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 13),
|
||||
|
||||
/* add VLAN id in (u16)a0 */
|
||||
CMD_VLAN_ADD = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 14),
|
||||
|
||||
/* del VLAN id in (u16)a0 */
|
||||
CMD_VLAN_DEL = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 15),
|
||||
|
||||
/* nic_cfg in (u32)a0 */
|
||||
CMD_NIC_CFG = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 16),
|
||||
|
||||
/* union vnic_rss_key in mem: (u64)a0=paddr, (u16)a1=len */
|
||||
CMD_RSS_KEY = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 17),
|
||||
|
||||
/* union vnic_rss_cpu in mem: (u64)a0=paddr, (u16)a1=len */
|
||||
CMD_RSS_CPU = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 18),
|
||||
|
||||
/* initiate softreset */
|
||||
CMD_SOFT_RESET = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 19),
|
||||
|
||||
/* softreset status:
|
||||
* out: a0=0 reset complete, a0=1 reset in progress */
|
||||
CMD_SOFT_RESET_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 20),
|
||||
|
||||
/* set struct vnic_devcmd_notify buffer in mem:
|
||||
* in:
|
||||
* (u64)a0=paddr to notify (set paddr=0 to unset)
|
||||
* (u32)a1 & 0x00000000ffffffff=sizeof(struct vnic_devcmd_notify)
|
||||
* (u16)a1 & 0x0000ffff00000000=intr num (-1 for no intr)
|
||||
* out:
|
||||
* (u32)a1 = effective size
|
||||
*/
|
||||
CMD_NOTIFY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 21),
|
||||
|
||||
/* UNDI API: (u64)a0=paddr to s_PXENV_UNDI_ struct,
|
||||
* (u8)a1=PXENV_UNDI_xxx */
|
||||
CMD_UNDI = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 22),
|
||||
|
||||
/* initiate open sequence (u32)a0=flags (see CMD_OPENF_*) */
|
||||
CMD_OPEN = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 23),
|
||||
|
||||
/* open status:
|
||||
* out: a0=0 open complete, a0=1 open in progress */
|
||||
CMD_OPEN_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 24),
|
||||
|
||||
/* close vnic */
|
||||
CMD_CLOSE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25),
|
||||
|
||||
/* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */
|
||||
/***** Replaced by CMD_INIT *****/
|
||||
CMD_INIT_v1 = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26),
|
||||
|
||||
/* variant of CMD_INIT, with provisioning info
|
||||
* (u64)a0=paddr of vnic_devcmd_provinfo
|
||||
* (u32)a1=sizeof provision info */
|
||||
CMD_INIT_PROV_INFO = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 27),
|
||||
|
||||
/* enable virtual link */
|
||||
CMD_ENABLE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28),
|
||||
|
||||
/* enable virtual link, waiting variant. */
|
||||
CMD_ENABLE_WAIT = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28),
|
||||
|
||||
/* disable virtual link */
|
||||
CMD_DISABLE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29),
|
||||
|
||||
/* stats dump sum of all vnic stats on same uplink in mem:
|
||||
* (u64)a0=paddr
|
||||
* (u16)a1=sizeof stats area */
|
||||
CMD_STATS_DUMP_ALL = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 30),
|
||||
|
||||
/* init status:
|
||||
* out: a0=0 init complete, a0=1 init in progress
|
||||
* if a0=0, a1=errno */
|
||||
CMD_INIT_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 31),
|
||||
|
||||
/* INT13 API: (u64)a0=paddr to vnic_int13_params struct
|
||||
* (u32)a1=INT13_CMD_xxx */
|
||||
CMD_INT13 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_FC, 32),
|
||||
|
||||
/* logical uplink enable/disable: (u64)a0: 0/1=disable/enable */
|
||||
CMD_LOGICAL_UPLINK = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 33),
|
||||
|
||||
/* undo initialize of virtual link */
|
||||
CMD_DEINIT = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34),
|
||||
|
||||
/* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */
|
||||
CMD_INIT = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 35),
|
||||
|
||||
/* check fw capability of a cmd:
|
||||
* in: (u32)a0=cmd
|
||||
* out: (u32)a0=errno, 0:valid cmd, a1=supported VNIC_STF_* bits */
|
||||
CMD_CAPABILITY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 36),
|
||||
|
||||
/* persistent binding info
|
||||
* in: (u64)a0=paddr of arg
|
||||
* (u32)a1=CMD_PERBI_XXX */
|
||||
CMD_PERBI = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_FC, 37),
|
||||
|
||||
/* Interrupt Assert Register functionality
|
||||
* in: (u16)a0=interrupt number to assert
|
||||
*/
|
||||
CMD_IAR = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 38),
|
||||
|
||||
/* initiate hangreset, like softreset after hang detected */
|
||||
CMD_HANG_RESET = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 39),
|
||||
|
||||
/* hangreset status:
|
||||
* out: a0=0 reset complete, a0=1 reset in progress */
|
||||
CMD_HANG_RESET_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 40),
|
||||
|
||||
/*
|
||||
* Set hw ingress packet vlan rewrite mode:
|
||||
* in: (u32)a0=new vlan rewrite mode
|
||||
* out: (u32)a0=old vlan rewrite mode */
|
||||
CMD_IG_VLAN_REWRITE_MODE = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 41),
|
||||
|
||||
/*
|
||||
* in: (u16)a0=bdf of target vnic
|
||||
* (u32)a1=cmd to proxy
|
||||
* a2-a15=args to cmd in a1
|
||||
* out: (u32)a0=status of proxied cmd
|
||||
* a1-a15=out args of proxied cmd */
|
||||
CMD_PROXY_BY_BDF = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 42),
|
||||
|
||||
/*
|
||||
* As for BY_BDF except a0 is index of hvnlink subordinate vnic
|
||||
* or SR-IOV virtual vnic
|
||||
*/
|
||||
CMD_PROXY_BY_INDEX = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 43),
|
||||
|
||||
/*
|
||||
* For HPP toggle:
|
||||
* adapter-info-get
|
||||
* in: (u64)a0=phsical address of buffer passed in from caller.
|
||||
* (u16)a1=size of buffer specified in a0.
|
||||
* out: (u64)a0=phsical address of buffer passed in from caller.
|
||||
* (u16)a1=actual bytes from VIF-CONFIG-INFO TLV, or
|
||||
* 0 if no VIF-CONFIG-INFO TLV was ever received. */
|
||||
CMD_CONFIG_INFO_GET = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 44),
|
||||
|
||||
/* INT13 API: (u64)a0=paddr to vnic_int13_params struct
|
||||
* (u32)a1=INT13_CMD_xxx
|
||||
*/
|
||||
CMD_INT13_ALL = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 45),
|
||||
|
||||
/* Set default vlan:
|
||||
* in: (u16)a0=new default vlan
|
||||
* (u16)a1=zero for overriding vlan with param a0,
|
||||
* non-zero for resetting vlan to the default
|
||||
* out: (u16)a0=old default vlan
|
||||
*/
|
||||
CMD_SET_DEFAULT_VLAN = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 46),
|
||||
|
||||
/* init_prov_info2:
|
||||
* Variant of CMD_INIT_PROV_INFO, where it will not try to enable
|
||||
* the vnic until CMD_ENABLE2 is issued.
|
||||
* (u64)a0=paddr of vnic_devcmd_provinfo
|
||||
* (u32)a1=sizeof provision info
|
||||
*/
|
||||
CMD_INIT_PROV_INFO2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 47),
|
||||
|
||||
/* enable2:
|
||||
* (u32)a0=0 ==> standby
|
||||
* =CMD_ENABLE2_ACTIVE ==> active
|
||||
*/
|
||||
CMD_ENABLE2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 48),
|
||||
|
||||
/*
|
||||
* cmd_status:
|
||||
* Returns the status of the specified command
|
||||
* Input:
|
||||
* a0 = command for which status is being queried.
|
||||
* Possible values are:
|
||||
* CMD_SOFT_RESET
|
||||
* CMD_HANG_RESET
|
||||
* CMD_OPEN
|
||||
* CMD_INIT
|
||||
* CMD_INIT_PROV_INFO
|
||||
* CMD_DEINIT
|
||||
* CMD_INIT_PROV_INFO2
|
||||
* CMD_ENABLE2
|
||||
* Output:
|
||||
* if status == STAT_ERROR
|
||||
* a0 = ERR_ENOTSUPPORTED - status for command in a0 is
|
||||
* not supported
|
||||
* if status == STAT_NONE
|
||||
* a0 = status of the devcmd specified in a0 as follows.
|
||||
* ERR_SUCCESS - command in a0 completed successfully
|
||||
* ERR_EINPROGRESS - command in a0 is still in progress
|
||||
*/
|
||||
CMD_STATUS = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 49),
|
||||
|
||||
/*
|
||||
* Returns interrupt coalescing timer conversion factors.
|
||||
* After calling this devcmd, ENIC driver can convert
|
||||
* interrupt coalescing timer in usec into CPU cycles as follows:
|
||||
*
|
||||
* intr_timer_cycles = intr_timer_usec * multiplier / divisor
|
||||
*
|
||||
* Interrupt coalescing timer in usecs can be obtained from
|
||||
* CPU cycles as follows:
|
||||
*
|
||||
* intr_timer_usec = intr_timer_cycles * divisor / multiplier
|
||||
*
|
||||
* in: none
|
||||
* out: (u32)a0 = multiplier
|
||||
* (u32)a1 = divisor
|
||||
* (u32)a2 = maximum timer value in usec
|
||||
*/
|
||||
CMD_INTR_COAL_CONVERT = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 50),
|
||||
|
||||
/*
|
||||
* Set the predefined mac address as default
|
||||
* in:
|
||||
* (u48)a0 = mac addr
|
||||
*/
|
||||
CMD_SET_MAC_ADDR = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 55),
|
||||
|
||||
/* Update the provisioning info of the given VIF
|
||||
* (u64)a0=paddr of vnic_devcmd_provinfo
|
||||
* (u32)a1=sizeof provision info
|
||||
*/
|
||||
CMD_PROV_INFO_UPDATE = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 56),
|
||||
|
||||
/* Add a filter.
|
||||
* in: (u64) a0= filter address
|
||||
* (u32) a1= size of filter
|
||||
* out: (u32) a0=filter identifier
|
||||
*/
|
||||
CMD_ADD_FILTER = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 58),
|
||||
|
||||
/* Delete a filter.
|
||||
* in: (u32) a0=filter identifier
|
||||
*/
|
||||
CMD_DEL_FILTER = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 59),
|
||||
|
||||
/* Enable a Queue Pair in User space NIC
|
||||
* in: (u32) a0=Queue Pair number
|
||||
* (u32) a1= command
|
||||
*/
|
||||
CMD_QP_ENABLE = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 60),
|
||||
|
||||
/* Disable a Queue Pair in User space NIC
|
||||
* in: (u32) a0=Queue Pair number
|
||||
* (u32) a1= command
|
||||
*/
|
||||
CMD_QP_DISABLE = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 61),
|
||||
|
||||
/* Stats dump Queue Pair in User space NIC
|
||||
* in: (u32) a0=Queue Pair number
|
||||
* (u64) a1=host buffer addr for status dump
|
||||
* (u32) a2=length of the buffer
|
||||
*/
|
||||
CMD_QP_STATS_DUMP = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 62),
|
||||
|
||||
/* Clear stats for Queue Pair in User space NIC
|
||||
* in: (u32) a0=Queue Pair number
|
||||
*/
|
||||
CMD_QP_STATS_CLEAR = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 63),
|
||||
};
|
||||
|
||||
/* CMD_ENABLE2 flags */
|
||||
#define CMD_ENABLE2_STANDBY 0x0
|
||||
#define CMD_ENABLE2_ACTIVE 0x1
|
||||
|
||||
/* flags for CMD_OPEN */
|
||||
#define CMD_OPENF_OPROM 0x1 /* open coming from option rom */
|
||||
|
||||
/* flags for CMD_INIT */
|
||||
#define CMD_INITF_DEFAULT_MAC 0x1 /* init with default mac addr */
|
||||
|
||||
/* flags for CMD_PACKET_FILTER */
|
||||
#define CMD_PFILTER_DIRECTED 0x01
|
||||
#define CMD_PFILTER_MULTICAST 0x02
|
||||
#define CMD_PFILTER_BROADCAST 0x04
|
||||
#define CMD_PFILTER_PROMISCUOUS 0x08
|
||||
#define CMD_PFILTER_ALL_MULTICAST 0x10
|
||||
|
||||
/* Commands for CMD_QP_ENABLE/CM_QP_DISABLE */
|
||||
#define CMD_QP_RQWQ 0x0
|
||||
|
||||
/* rewrite modes for CMD_IG_VLAN_REWRITE_MODE */
|
||||
#define IG_VLAN_REWRITE_MODE_DEFAULT_TRUNK 0
|
||||
#define IG_VLAN_REWRITE_MODE_UNTAG_DEFAULT_VLAN 1
|
||||
#define IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN 2
|
||||
#define IG_VLAN_REWRITE_MODE_PASS_THRU 3
|
||||
|
||||
enum vnic_devcmd_status {
|
||||
STAT_NONE = 0,
|
||||
STAT_BUSY = 1 << 0, /* cmd in progress */
|
||||
STAT_ERROR = 1 << 1, /* last cmd caused error (code in a0) */
|
||||
};
|
||||
|
||||
enum vnic_devcmd_error {
|
||||
ERR_SUCCESS = 0,
|
||||
ERR_EINVAL = 1,
|
||||
ERR_EFAULT = 2,
|
||||
ERR_EPERM = 3,
|
||||
ERR_EBUSY = 4,
|
||||
ERR_ECMDUNKNOWN = 5,
|
||||
ERR_EBADSTATE = 6,
|
||||
ERR_ENOMEM = 7,
|
||||
ERR_ETIMEDOUT = 8,
|
||||
ERR_ELINKDOWN = 9,
|
||||
ERR_EMAXRES = 10,
|
||||
ERR_ENOTSUPPORTED = 11,
|
||||
ERR_EINPROGRESS = 12,
|
||||
ERR_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* note: hw_version and asic_rev refer to the same thing,
|
||||
* but have different formats. hw_version is
|
||||
* a 32-byte string (e.g. "A2") and asic_rev is
|
||||
* a 16-bit integer (e.g. 0xA2).
|
||||
*/
|
||||
struct vnic_devcmd_fw_info {
|
||||
char fw_version[32];
|
||||
char fw_build[32];
|
||||
char hw_version[32];
|
||||
char hw_serial_number[32];
|
||||
u16 asic_type;
|
||||
u16 asic_rev;
|
||||
};
|
||||
|
||||
struct vnic_devcmd_notify {
|
||||
u32 csum; /* checksum over following words */
|
||||
|
||||
u32 link_state; /* link up == 1 */
|
||||
u32 port_speed; /* effective port speed (rate limit) */
|
||||
u32 mtu; /* MTU */
|
||||
u32 msglvl; /* requested driver msg lvl */
|
||||
u32 uif; /* uplink interface */
|
||||
u32 status; /* status bits (see VNIC_STF_*) */
|
||||
u32 error; /* error code (see ERR_*) for first ERR */
|
||||
u32 link_down_cnt; /* running count of link down transitions */
|
||||
u32 perbi_rebuild_cnt; /* running count of perbi rebuilds */
|
||||
};
|
||||
#define VNIC_STF_FATAL_ERR 0x0001 /* fatal fw error */
|
||||
#define VNIC_STF_STD_PAUSE 0x0002 /* standard link-level pause on */
|
||||
#define VNIC_STF_PFC_PAUSE 0x0004 /* priority flow control pause on */
|
||||
/* all supported status flags */
|
||||
#define VNIC_STF_ALL (VNIC_STF_FATAL_ERR |\
|
||||
VNIC_STF_STD_PAUSE |\
|
||||
VNIC_STF_PFC_PAUSE |\
|
||||
0)
|
||||
|
||||
struct vnic_devcmd_provinfo {
|
||||
u8 oui[3];
|
||||
u8 type;
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
/* These are used in flags field of different filters to denote
|
||||
* valid fields used.
|
||||
*/
|
||||
#define FILTER_FIELD_VALID(fld) (1 << (fld - 1))
|
||||
|
||||
#define FILTER_FIELDS_USNIC ( \
|
||||
FILTER_FIELD_VALID(1) | \
|
||||
FILTER_FIELD_VALID(2) | \
|
||||
FILTER_FIELD_VALID(3) | \
|
||||
FILTER_FIELD_VALID(4))
|
||||
|
||||
#define FILTER_FIELDS_IPV4_5TUPLE ( \
|
||||
FILTER_FIELD_VALID(1) | \
|
||||
FILTER_FIELD_VALID(2) | \
|
||||
FILTER_FIELD_VALID(3) | \
|
||||
FILTER_FIELD_VALID(4) | \
|
||||
FILTER_FIELD_VALID(5))
|
||||
|
||||
#define FILTER_FIELDS_MAC_VLAN ( \
|
||||
FILTER_FIELD_VALID(1) | \
|
||||
FILTER_FIELD_VALID(2))
|
||||
|
||||
#define FILTER_FIELD_USNIC_VLAN FILTER_FIELD_VALID(1)
|
||||
#define FILTER_FIELD_USNIC_ETHTYPE FILTER_FIELD_VALID(2)
|
||||
#define FILTER_FIELD_USNIC_PROTO FILTER_FIELD_VALID(3)
|
||||
#define FILTER_FIELD_USNIC_ID FILTER_FIELD_VALID(4)
|
||||
|
||||
struct filter_usnic_id {
|
||||
u32 flags;
|
||||
u16 vlan;
|
||||
u16 ethtype;
|
||||
u8 proto_version;
|
||||
u32 usnic_id;
|
||||
} __packed;
|
||||
|
||||
#define FILTER_FIELD_5TUP_PROTO FILTER_FIELD_VALID(1)
|
||||
#define FILTER_FIELD_5TUP_SRC_AD FILTER_FIELD_VALID(2)
|
||||
#define FILTER_FIELD_5TUP_DST_AD FILTER_FIELD_VALID(3)
|
||||
#define FILTER_FIELD_5TUP_SRC_PT FILTER_FIELD_VALID(4)
|
||||
#define FILTER_FIELD_5TUP_DST_PT FILTER_FIELD_VALID(5)
|
||||
|
||||
/* Enums for the protocol field. */
|
||||
enum protocol_e {
|
||||
PROTO_UDP = 0,
|
||||
PROTO_TCP = 1,
|
||||
};
|
||||
|
||||
struct filter_ipv4_5tuple {
|
||||
u32 flags;
|
||||
u32 protocol;
|
||||
u32 src_addr;
|
||||
u32 dst_addr;
|
||||
u16 src_port;
|
||||
u16 dst_port;
|
||||
} __packed;
|
||||
|
||||
#define FILTER_FIELD_VMQ_VLAN FILTER_FIELD_VALID(1)
|
||||
#define FILTER_FIELD_VMQ_MAC FILTER_FIELD_VALID(2)
|
||||
|
||||
struct filter_mac_vlan {
|
||||
u32 flags;
|
||||
u16 vlan;
|
||||
u8 mac_addr[6];
|
||||
} __packed;
|
||||
|
||||
/* Specifies the filter_action type. */
|
||||
enum {
|
||||
FILTER_ACTION_RQ_STEERING = 0,
|
||||
FILTER_ACTION_MAX
|
||||
};
|
||||
|
||||
struct filter_action {
|
||||
u32 type;
|
||||
union {
|
||||
u32 rq_idx;
|
||||
} u;
|
||||
} __packed;
|
||||
|
||||
/* Specifies the filter type. */
|
||||
enum filter_type {
|
||||
FILTER_USNIC_ID = 0,
|
||||
FILTER_IPV4_5TUPLE = 1,
|
||||
FILTER_MAC_VLAN = 2,
|
||||
FILTER_MAX
|
||||
};
|
||||
|
||||
struct filter {
|
||||
u32 type;
|
||||
union {
|
||||
struct filter_usnic_id usnic;
|
||||
struct filter_ipv4_5tuple ipv4;
|
||||
struct filter_mac_vlan mac_vlan;
|
||||
} u;
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
CLSF_TLV_FILTER = 0,
|
||||
CLSF_TLV_ACTION = 1,
|
||||
};
|
||||
|
||||
/* Maximum size of buffer to CMD_ADD_FILTER */
|
||||
#define FILTER_MAX_BUF_SIZE 100
|
||||
|
||||
struct filter_tlv {
|
||||
u_int32_t type;
|
||||
u_int32_t length;
|
||||
u_int32_t val[0];
|
||||
};
|
||||
|
||||
enum {
|
||||
CLSF_ADD = 0,
|
||||
CLSF_DEL = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Writing cmd register causes STAT_BUSY to get set in status register.
|
||||
* When cmd completes, STAT_BUSY will be cleared.
|
||||
*
|
||||
* If cmd completed successfully STAT_ERROR will be clear
|
||||
* and args registers contain cmd-specific results.
|
||||
*
|
||||
* If cmd error, STAT_ERROR will be set and args[0] contains error code.
|
||||
*
|
||||
* status register is read-only. While STAT_BUSY is set,
|
||||
* all other register contents are read-only.
|
||||
*/
|
||||
|
||||
/* Make sizeof(vnic_devcmd) a power-of-2 for I/O BAR. */
|
||||
#define VNIC_DEVCMD_NARGS 15
|
||||
struct vnic_devcmd {
|
||||
u32 status; /* RO */
|
||||
u32 cmd; /* RW */
|
||||
u64 args[VNIC_DEVCMD_NARGS]; /* RW cmd args (little-endian) */
|
||||
};
|
||||
|
||||
#endif /* _VNIC_DEVCMD_H_ */
|
59
drivers/net/ethernet/cisco/enic/vnic_enet.h
Normal file
59
drivers/net/ethernet/cisco/enic/vnic_enet.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_ENIC_H_
|
||||
#define _VNIC_ENIC_H_
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
#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 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_ */
|
68
drivers/net/ethernet/cisco/enic/vnic_intr.c
Normal file
68
drivers/net/ethernet/cisco/enic/vnic_intr.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.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);
|
||||
iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
|
||||
iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
|
||||
iowrite32(0, &intr->ctrl->int_credits);
|
||||
}
|
||||
|
||||
void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
|
||||
u32 coalescing_timer)
|
||||
{
|
||||
iowrite32(vnic_dev_intr_coal_timer_usec_to_hw(intr->vdev,
|
||||
coalescing_timer), &intr->ctrl->coalescing_timer);
|
||||
}
|
||||
|
||||
void vnic_intr_clean(struct vnic_intr *intr)
|
||||
{
|
||||
iowrite32(0, &intr->ctrl->int_credits);
|
||||
}
|
111
drivers/net/ethernet/cisco/enic/vnic_intr.h
Normal file
111
drivers/net/ethernet/cisco/enic/vnic_intr.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_INTR_H_
|
||||
#define _VNIC_INTR_H_
|
||||
|
||||
#include <linux/pci.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 */
|
||||
u32 pad0;
|
||||
u32 coalescing_value; /* 0x08 */
|
||||
u32 pad1;
|
||||
u32 coalescing_type; /* 0x10 */
|
||||
u32 pad2;
|
||||
u32 mask_on_assertion; /* 0x18 */
|
||||
u32 pad3;
|
||||
u32 mask; /* 0x20 */
|
||||
u32 pad4;
|
||||
u32 int_credits; /* 0x28 */
|
||||
u32 pad5;
|
||||
u32 int_credit_return; /* 0x30 */
|
||||
u32 pad6;
|
||||
};
|
||||
|
||||
struct vnic_intr {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_intr_ctrl __iomem *ctrl; /* memory-mapped */
|
||||
};
|
||||
|
||||
static inline void vnic_intr_unmask(struct vnic_intr *intr)
|
||||
{
|
||||
iowrite32(0, &intr->ctrl->mask);
|
||||
}
|
||||
|
||||
static inline void vnic_intr_mask(struct vnic_intr *intr)
|
||||
{
|
||||
iowrite32(1, &intr->ctrl->mask);
|
||||
}
|
||||
|
||||
static inline int vnic_intr_masked(struct vnic_intr *intr)
|
||||
{
|
||||
return ioread32(&intr->ctrl->mask);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
iowrite32(int_credit_return, &intr->ctrl->int_credit_return);
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_intr_credits(struct vnic_intr *intr)
|
||||
{
|
||||
return ioread32(&intr->ctrl->int_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);
|
||||
}
|
||||
|
||||
static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba)
|
||||
{
|
||||
/* read PBA without clearing */
|
||||
return ioread32(legacy_pba);
|
||||
}
|
||||
|
||||
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_ */
|
72
drivers/net/ethernet/cisco/enic/vnic_nic.h
Normal file
72
drivers/net/ethernet/cisco/enic/vnic_nic.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_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_IPV6_EX (1 << 5)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX (1 << 6)
|
||||
|
||||
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_ */
|
76
drivers/net/ethernet/cisco/enic/vnic_resource.h
Normal file
76
drivers/net/ethernet/cisco/enic/vnic_resource.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_RSVD1,
|
||||
RES_TYPE_NIC_CFG, /* Enet NIC config registers */
|
||||
RES_TYPE_RSVD2,
|
||||
RES_TYPE_RSVD3,
|
||||
RES_TYPE_RSVD4,
|
||||
RES_TYPE_RSVD5,
|
||||
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_RSVD6,
|
||||
RES_TYPE_RSVD7,
|
||||
RES_TYPE_DEVCMD, /* Device command region */
|
||||
RES_TYPE_PASS_THRU_PAGE, /* Pass-thru page */
|
||||
|
||||
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_ */
|
216
drivers/net/ethernet/cisco/enic/vnic_rq.c
Normal file
216
drivers/net/ethernet/cisco/enic/vnic_rq.c
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_rq.h"
|
||||
|
||||
static int vnic_rq_alloc_bufs(struct vnic_rq *rq)
|
||||
{
|
||||
struct vnic_rq_buf *buf;
|
||||
unsigned int i, j, count = rq->ring.desc_count;
|
||||
unsigned int blks = VNIC_RQ_BUF_BLKS_NEEDED(count);
|
||||
|
||||
for (i = 0; i < blks; i++) {
|
||||
rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ(count), GFP_ATOMIC);
|
||||
if (!rq->bufs[i])
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < blks; i++) {
|
||||
buf = rq->bufs[i];
|
||||
for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES(count); j++) {
|
||||
buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES(count) + j;
|
||||
buf->desc = (u8 *)rq->ring.descs +
|
||||
rq->ring.desc_size * buf->index;
|
||||
if (buf->index + 1 == count) {
|
||||
buf->next = rq->bufs[0];
|
||||
break;
|
||||
} else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES(count)) {
|
||||
buf->next = rq->bufs[i + 1];
|
||||
} else {
|
||||
buf->next = buf + 1;
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rq->to_use = rq->to_clean = rq->bufs[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_rq_free(struct vnic_rq *rq)
|
||||
{
|
||||
struct vnic_dev *vdev;
|
||||
unsigned int i;
|
||||
|
||||
vdev = rq->vdev;
|
||||
|
||||
vnic_dev_free_desc_ring(vdev, &rq->ring);
|
||||
|
||||
for (i = 0; i < VNIC_RQ_BUF_BLKS_MAX; i++) {
|
||||
if (rq->bufs[i]) {
|
||||
kfree(rq->bufs[i]);
|
||||
rq->bufs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
rq->ctrl = NULL;
|
||||
}
|
||||
|
||||
int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
rq->index = index;
|
||||
rq->vdev = vdev;
|
||||
|
||||
rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index);
|
||||
if (!rq->ctrl) {
|
||||
pr_err("Failed to hook RQ[%d] resource\n", index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vnic_rq_disable(rq);
|
||||
|
||||
err = vnic_dev_alloc_desc_ring(vdev, &rq->ring, desc_count, desc_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = vnic_rq_alloc_bufs(rq);
|
||||
if (err) {
|
||||
vnic_rq_free(rq);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static 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;
|
||||
writeq(paddr, &rq->ctrl->ring_base);
|
||||
iowrite32(count, &rq->ctrl->ring_size);
|
||||
iowrite32(cq_index, &rq->ctrl->cq_index);
|
||||
iowrite32(error_interrupt_enable, &rq->ctrl->error_interrupt_enable);
|
||||
iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset);
|
||||
iowrite32(0, &rq->ctrl->dropped_packet_count);
|
||||
iowrite32(0, &rq->ctrl->error_status);
|
||||
iowrite32(fetch_index, &rq->ctrl->fetch_index);
|
||||
iowrite32(posted_index, &rq->ctrl->posted_index);
|
||||
|
||||
rq->to_use = rq->to_clean =
|
||||
&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES(count)]
|
||||
[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES(count)];
|
||||
}
|
||||
|
||||
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 = ioread32(&rq->ctrl->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);
|
||||
}
|
||||
|
||||
unsigned int vnic_rq_error_status(struct vnic_rq *rq)
|
||||
{
|
||||
return ioread32(&rq->ctrl->error_status);
|
||||
}
|
||||
|
||||
void vnic_rq_enable(struct vnic_rq *rq)
|
||||
{
|
||||
iowrite32(1, &rq->ctrl->enable);
|
||||
}
|
||||
|
||||
int vnic_rq_disable(struct vnic_rq *rq)
|
||||
{
|
||||
unsigned int wait;
|
||||
|
||||
iowrite32(0, &rq->ctrl->enable);
|
||||
|
||||
/* Wait for HW to ACK disable request */
|
||||
for (wait = 0; wait < 1000; wait++) {
|
||||
if (!(ioread32(&rq->ctrl->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,
|
||||
void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf))
|
||||
{
|
||||
struct vnic_rq_buf *buf;
|
||||
u32 fetch_index;
|
||||
unsigned int count = rq->ring.desc_count;
|
||||
|
||||
buf = rq->to_clean;
|
||||
|
||||
while (vnic_rq_desc_used(rq) > 0) {
|
||||
|
||||
(*buf_clean)(rq, buf);
|
||||
|
||||
buf = rq->to_clean = buf->next;
|
||||
rq->ring.desc_avail++;
|
||||
}
|
||||
|
||||
/* Use current fetch_index as the ring starting point */
|
||||
fetch_index = ioread32(&rq->ctrl->fetch_index);
|
||||
|
||||
if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone */
|
||||
/* Hardware surprise removal: reset fetch_index */
|
||||
fetch_index = 0;
|
||||
}
|
||||
rq->to_use = rq->to_clean =
|
||||
&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES(count)]
|
||||
[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES(count)];
|
||||
iowrite32(fetch_index, &rq->ctrl->posted_index);
|
||||
|
||||
vnic_dev_clear_desc_ring(&rq->ring);
|
||||
}
|
||||
|
334
drivers/net/ethernet/cisco/enic/vnic_rq.h
Normal file
334
drivers/net/ethernet/cisco/enic/vnic_rq.h
Normal file
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_RQ_H_
|
||||
#define _VNIC_RQ_H_
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_cq.h"
|
||||
|
||||
/* Receive queue control */
|
||||
struct vnic_rq_ctrl {
|
||||
u64 ring_base; /* 0x00 */
|
||||
u32 ring_size; /* 0x08 */
|
||||
u32 pad0;
|
||||
u32 posted_index; /* 0x10 */
|
||||
u32 pad1;
|
||||
u32 cq_index; /* 0x18 */
|
||||
u32 pad2;
|
||||
u32 enable; /* 0x20 */
|
||||
u32 pad3;
|
||||
u32 running; /* 0x28 */
|
||||
u32 pad4;
|
||||
u32 fetch_index; /* 0x30 */
|
||||
u32 pad5;
|
||||
u32 error_interrupt_enable; /* 0x38 */
|
||||
u32 pad6;
|
||||
u32 error_interrupt_offset; /* 0x40 */
|
||||
u32 pad7;
|
||||
u32 error_status; /* 0x48 */
|
||||
u32 pad8;
|
||||
u32 dropped_packet_count; /* 0x50 */
|
||||
u32 pad9;
|
||||
u32 dropped_packet_count_rc; /* 0x58 */
|
||||
u32 pad10;
|
||||
};
|
||||
|
||||
/* Break the vnic_rq_buf allocations into blocks of 32/64 entries */
|
||||
#define VNIC_RQ_BUF_MIN_BLK_ENTRIES 32
|
||||
#define VNIC_RQ_BUF_DFLT_BLK_ENTRIES 64
|
||||
#define VNIC_RQ_BUF_BLK_ENTRIES(entries) \
|
||||
((unsigned int)((entries < VNIC_RQ_BUF_DFLT_BLK_ENTRIES) ? \
|
||||
VNIC_RQ_BUF_MIN_BLK_ENTRIES : VNIC_RQ_BUF_DFLT_BLK_ENTRIES))
|
||||
#define VNIC_RQ_BUF_BLK_SZ(entries) \
|
||||
(VNIC_RQ_BUF_BLK_ENTRIES(entries) * sizeof(struct vnic_rq_buf))
|
||||
#define VNIC_RQ_BUF_BLKS_NEEDED(entries) \
|
||||
DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES(entries))
|
||||
#define VNIC_RQ_BUF_BLKS_MAX VNIC_RQ_BUF_BLKS_NEEDED(4096)
|
||||
|
||||
struct vnic_rq_buf {
|
||||
struct vnic_rq_buf *next;
|
||||
dma_addr_t dma_addr;
|
||||
void *os_buf;
|
||||
unsigned int os_buf_index;
|
||||
unsigned int len;
|
||||
unsigned int index;
|
||||
void *desc;
|
||||
uint64_t wr_id;
|
||||
};
|
||||
|
||||
struct vnic_rq {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_rq_ctrl __iomem *ctrl; /* memory-mapped */
|
||||
struct vnic_dev_ring ring;
|
||||
struct vnic_rq_buf *bufs[VNIC_RQ_BUF_BLKS_MAX];
|
||||
struct vnic_rq_buf *to_use;
|
||||
struct vnic_rq_buf *to_clean;
|
||||
void *os_buf_head;
|
||||
unsigned int pkts_outstanding;
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
#define ENIC_POLL_STATE_IDLE 0
|
||||
#define ENIC_POLL_STATE_NAPI (1 << 0) /* NAPI owns this poll */
|
||||
#define ENIC_POLL_STATE_POLL (1 << 1) /* poll owns this poll */
|
||||
#define ENIC_POLL_STATE_NAPI_YIELD (1 << 2) /* NAPI yielded this poll */
|
||||
#define ENIC_POLL_STATE_POLL_YIELD (1 << 3) /* poll yielded this poll */
|
||||
#define ENIC_POLL_YIELD (ENIC_POLL_STATE_NAPI_YIELD | \
|
||||
ENIC_POLL_STATE_POLL_YIELD)
|
||||
#define ENIC_POLL_LOCKED (ENIC_POLL_STATE_NAPI | \
|
||||
ENIC_POLL_STATE_POLL)
|
||||
#define ENIC_POLL_USER_PEND (ENIC_POLL_STATE_POLL | \
|
||||
ENIC_POLL_STATE_POLL_YIELD)
|
||||
unsigned int bpoll_state;
|
||||
spinlock_t bpoll_lock;
|
||||
#endif /* CONFIG_NET_RX_BUSY_POLL */
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline void *vnic_rq_next_desc(struct vnic_rq *rq)
|
||||
{
|
||||
return rq->to_use->desc;
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_rq_next_index(struct vnic_rq *rq)
|
||||
{
|
||||
return rq->to_use->index;
|
||||
}
|
||||
|
||||
static inline void vnic_rq_post(struct vnic_rq *rq,
|
||||
void *os_buf, unsigned int os_buf_index,
|
||||
dma_addr_t dma_addr, unsigned int len,
|
||||
uint64_t wrid)
|
||||
{
|
||||
struct vnic_rq_buf *buf = rq->to_use;
|
||||
|
||||
buf->os_buf = os_buf;
|
||||
buf->os_buf_index = os_buf_index;
|
||||
buf->dma_addr = dma_addr;
|
||||
buf->len = len;
|
||||
buf->wr_id = wrid;
|
||||
|
||||
buf = buf->next;
|
||||
rq->to_use = buf;
|
||||
rq->ring.desc_avail--;
|
||||
|
||||
/* Move the posted_index every nth descriptor
|
||||
*/
|
||||
|
||||
#ifndef VNIC_RQ_RETURN_RATE
|
||||
#define VNIC_RQ_RETURN_RATE 0xf /* keep 2^n - 1 */
|
||||
#endif
|
||||
|
||||
if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) {
|
||||
/* Adding write memory barrier prevents compiler and/or CPU
|
||||
* reordering, thus avoiding descriptor posting before
|
||||
* descriptor is initialized. Otherwise, hardware can read
|
||||
* stale descriptor fields.
|
||||
*/
|
||||
wmb();
|
||||
iowrite32(buf->index, &rq->ctrl->posted_index);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count)
|
||||
{
|
||||
rq->ring.desc_avail += count;
|
||||
}
|
||||
|
||||
enum desc_return_options {
|
||||
VNIC_RQ_RETURN_DESC,
|
||||
VNIC_RQ_DEFER_RETURN_DESC,
|
||||
};
|
||||
|
||||
static inline void vnic_rq_service(struct vnic_rq *rq,
|
||||
struct cq_desc *cq_desc, u16 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)
|
||||
{
|
||||
struct vnic_rq_buf *buf;
|
||||
int skipped;
|
||||
|
||||
buf = rq->to_clean;
|
||||
while (1) {
|
||||
|
||||
skipped = (buf->index != completed_index);
|
||||
|
||||
(*buf_service)(rq, cq_desc, buf, skipped, opaque);
|
||||
|
||||
if (desc_return == VNIC_RQ_RETURN_DESC)
|
||||
rq->ring.desc_avail++;
|
||||
|
||||
rq->to_clean = buf->next;
|
||||
|
||||
if (!skipped)
|
||||
break;
|
||||
|
||||
buf = rq->to_clean;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
static inline void enic_busy_poll_init_lock(struct vnic_rq *rq)
|
||||
{
|
||||
spin_lock_init(&rq->bpoll_lock);
|
||||
rq->bpoll_state = ENIC_POLL_STATE_IDLE;
|
||||
}
|
||||
|
||||
static inline bool enic_poll_lock_napi(struct vnic_rq *rq)
|
||||
{
|
||||
bool rc = true;
|
||||
|
||||
spin_lock(&rq->bpoll_lock);
|
||||
if (rq->bpoll_state & ENIC_POLL_LOCKED) {
|
||||
WARN_ON(rq->bpoll_state & ENIC_POLL_STATE_NAPI);
|
||||
rq->bpoll_state |= ENIC_POLL_STATE_NAPI_YIELD;
|
||||
rc = false;
|
||||
} else {
|
||||
rq->bpoll_state = ENIC_POLL_STATE_NAPI;
|
||||
}
|
||||
spin_unlock(&rq->bpoll_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline bool enic_poll_unlock_napi(struct vnic_rq *rq)
|
||||
{
|
||||
bool rc = false;
|
||||
|
||||
spin_lock(&rq->bpoll_lock);
|
||||
WARN_ON(rq->bpoll_state &
|
||||
(ENIC_POLL_STATE_POLL | ENIC_POLL_STATE_NAPI_YIELD));
|
||||
if (rq->bpoll_state & ENIC_POLL_STATE_POLL_YIELD)
|
||||
rc = true;
|
||||
rq->bpoll_state = ENIC_POLL_STATE_IDLE;
|
||||
spin_unlock(&rq->bpoll_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline bool enic_poll_lock_poll(struct vnic_rq *rq)
|
||||
{
|
||||
bool rc = true;
|
||||
|
||||
spin_lock_bh(&rq->bpoll_lock);
|
||||
if (rq->bpoll_state & ENIC_POLL_LOCKED) {
|
||||
rq->bpoll_state |= ENIC_POLL_STATE_POLL_YIELD;
|
||||
rc = false;
|
||||
} else {
|
||||
rq->bpoll_state |= ENIC_POLL_STATE_POLL;
|
||||
}
|
||||
spin_unlock_bh(&rq->bpoll_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline bool enic_poll_unlock_poll(struct vnic_rq *rq)
|
||||
{
|
||||
bool rc = false;
|
||||
|
||||
spin_lock_bh(&rq->bpoll_lock);
|
||||
WARN_ON(rq->bpoll_state & ENIC_POLL_STATE_NAPI);
|
||||
if (rq->bpoll_state & ENIC_POLL_STATE_POLL_YIELD)
|
||||
rc = true;
|
||||
rq->bpoll_state = ENIC_POLL_STATE_IDLE;
|
||||
spin_unlock_bh(&rq->bpoll_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline bool enic_poll_busy_polling(struct vnic_rq *rq)
|
||||
{
|
||||
WARN_ON(!(rq->bpoll_state & ENIC_POLL_LOCKED));
|
||||
return rq->bpoll_state & ENIC_POLL_USER_PEND;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void enic_busy_poll_init_lock(struct vnic_rq *rq)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool enic_poll_lock_napi(struct vnic_rq *rq)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool enic_poll_unlock_napi(struct vnic_rq *rq)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool enic_poll_lock_poll(struct vnic_rq *rq)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool enic_poll_unlock_poll(struct vnic_rq *rq)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool enic_poll_ll_polling(struct vnic_rq *rq)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_NET_RX_BUSY_POLL */
|
||||
|
||||
void vnic_rq_free(struct vnic_rq *rq);
|
||||
int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset);
|
||||
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,
|
||||
void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf));
|
||||
|
||||
#endif /* _VNIC_RQ_H_ */
|
40
drivers/net/ethernet/cisco/enic/vnic_rss.h
Normal file
40
drivers/net/ethernet/cisco/enic/vnic_rss.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#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];
|
||||
};
|
||||
|
||||
#endif /* _VNIC_RSS_H_ */
|
70
drivers/net/ethernet/cisco/enic/vnic_stats.h
Normal file
70
drivers/net/ethernet/cisco/enic/vnic_stats.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_ */
|
79
drivers/net/ethernet/cisco/enic/vnic_vic.c
Normal file
79
drivers/net/ethernet/cisco/enic/vnic_vic.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "vnic_vic.h"
|
||||
|
||||
struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui,
|
||||
const u8 type)
|
||||
{
|
||||
struct vic_provinfo *vp;
|
||||
|
||||
if (!oui)
|
||||
return NULL;
|
||||
|
||||
vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags);
|
||||
if (!vp)
|
||||
return NULL;
|
||||
|
||||
memcpy(vp->oui, oui, sizeof(vp->oui));
|
||||
vp->type = type;
|
||||
vp->length = htonl(sizeof(vp->num_tlvs));
|
||||
|
||||
return vp;
|
||||
}
|
||||
|
||||
void vic_provinfo_free(struct vic_provinfo *vp)
|
||||
{
|
||||
kfree(vp);
|
||||
}
|
||||
|
||||
int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
|
||||
const void *value)
|
||||
{
|
||||
struct vic_provinfo_tlv *tlv;
|
||||
|
||||
if (!vp || !value)
|
||||
return -EINVAL;
|
||||
|
||||
if (ntohl(vp->length) + offsetof(struct vic_provinfo_tlv, value) +
|
||||
length > VIC_PROVINFO_MAX_TLV_DATA)
|
||||
return -ENOMEM;
|
||||
|
||||
tlv = (struct vic_provinfo_tlv *)((u8 *)vp->tlv +
|
||||
ntohl(vp->length) - sizeof(vp->num_tlvs));
|
||||
|
||||
tlv->type = htons(type);
|
||||
tlv->length = htons(length);
|
||||
memcpy(tlv->value, value, length);
|
||||
|
||||
vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1);
|
||||
vp->length = htonl(ntohl(vp->length) +
|
||||
offsetof(struct vic_provinfo_tlv, value) + length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t vic_provinfo_size(struct vic_provinfo *vp)
|
||||
{
|
||||
return vp ? ntohl(vp->length) + sizeof(*vp) - sizeof(vp->num_tlvs) : 0;
|
||||
}
|
83
drivers/net/ethernet/cisco/enic/vnic_vic.h
Normal file
83
drivers/net/ethernet/cisco/enic/vnic_vic.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_VIC_H_
|
||||
#define _VNIC_VIC_H_
|
||||
|
||||
/* Note: All integer fields in NETWORK byte order */
|
||||
|
||||
/* Note: String field lengths include null char */
|
||||
|
||||
#define VIC_PROVINFO_CISCO_OUI { 0x00, 0x00, 0x0c }
|
||||
#define VIC_PROVINFO_GENERIC_TYPE 0x4
|
||||
|
||||
enum vic_generic_prov_tlv_type {
|
||||
VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR = 0,
|
||||
VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR = 1,
|
||||
VIC_GENERIC_PROV_TLV_CLIENT_NAME_STR = 2,
|
||||
VIC_GENERIC_PROV_TLV_CLUSTER_PORT_NAME_STR = 3,
|
||||
VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR = 4,
|
||||
VIC_GENERIC_PROV_TLV_CLUSTER_UUID_STR = 5,
|
||||
VIC_GENERIC_PROV_TLV_CLUSTER_NAME_STR = 7,
|
||||
VIC_GENERIC_PROV_TLV_HOST_UUID_STR = 8,
|
||||
VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR = 9,
|
||||
VIC_GENERIC_PROV_TLV_INCARNATION_NUMBER = 10,
|
||||
VIC_GENERIC_PROV_TLV_OS_TYPE = 11,
|
||||
VIC_GENERIC_PROV_TLV_OS_VENDOR = 12,
|
||||
VIC_GENERIC_PROV_TLV_CLIENT_TYPE = 15,
|
||||
};
|
||||
|
||||
enum vic_generic_prov_os_type {
|
||||
VIC_GENERIC_PROV_OS_TYPE_UNKNOWN = 0,
|
||||
VIC_GENERIC_PROV_OS_TYPE_ESX = 1,
|
||||
VIC_GENERIC_PROV_OS_TYPE_LINUX = 2,
|
||||
VIC_GENERIC_PROV_OS_TYPE_WINDOWS = 3,
|
||||
VIC_GENERIC_PROV_OS_TYPE_SOLARIS = 4,
|
||||
};
|
||||
|
||||
struct vic_provinfo {
|
||||
u8 oui[3]; /* OUI of data provider */
|
||||
u8 type; /* provider-specific type */
|
||||
u32 length; /* length of data below */
|
||||
u32 num_tlvs; /* number of tlvs */
|
||||
struct vic_provinfo_tlv {
|
||||
u16 type;
|
||||
u16 length;
|
||||
u8 value[0];
|
||||
} tlv[0];
|
||||
} __packed;
|
||||
|
||||
#define VIC_PROVINFO_ADD_TLV(vp, tlvtype, tlvlen, data) \
|
||||
do { \
|
||||
err = vic_provinfo_add_tlv(vp, tlvtype, tlvlen, data); \
|
||||
if (err) \
|
||||
goto add_tlv_failure; \
|
||||
} while (0)
|
||||
|
||||
#define VIC_PROVINFO_MAX_DATA 1385
|
||||
#define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \
|
||||
sizeof(struct vic_provinfo))
|
||||
|
||||
struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui,
|
||||
const u8 type);
|
||||
void vic_provinfo_free(struct vic_provinfo *vp);
|
||||
int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
|
||||
const void *value);
|
||||
size_t vic_provinfo_size(struct vic_provinfo *vp);
|
||||
|
||||
#endif /* _VNIC_VIC_H_ */
|
195
drivers/net/ethernet/cisco/enic/vnic_wq.c
Normal file
195
drivers/net/ethernet/cisco/enic/vnic_wq.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
|
||||
static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
|
||||
{
|
||||
struct vnic_wq_buf *buf;
|
||||
unsigned int i, j, count = wq->ring.desc_count;
|
||||
unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count);
|
||||
|
||||
for (i = 0; i < blks; i++) {
|
||||
wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ(count), GFP_ATOMIC);
|
||||
if (!wq->bufs[i])
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < blks; i++) {
|
||||
buf = wq->bufs[i];
|
||||
for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES(count); j++) {
|
||||
buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES(count) + j;
|
||||
buf->desc = (u8 *)wq->ring.descs +
|
||||
wq->ring.desc_size * buf->index;
|
||||
if (buf->index + 1 == count) {
|
||||
buf->next = wq->bufs[0];
|
||||
break;
|
||||
} else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES(count)) {
|
||||
buf->next = wq->bufs[i + 1];
|
||||
} else {
|
||||
buf->next = buf + 1;
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wq->to_use = wq->to_clean = wq->bufs[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_wq_free(struct vnic_wq *wq)
|
||||
{
|
||||
struct vnic_dev *vdev;
|
||||
unsigned int i;
|
||||
|
||||
vdev = wq->vdev;
|
||||
|
||||
vnic_dev_free_desc_ring(vdev, &wq->ring);
|
||||
|
||||
for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) {
|
||||
if (wq->bufs[i]) {
|
||||
kfree(wq->bufs[i]);
|
||||
wq->bufs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wq->ctrl = NULL;
|
||||
}
|
||||
|
||||
int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
wq->index = index;
|
||||
wq->vdev = vdev;
|
||||
|
||||
wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index);
|
||||
if (!wq->ctrl) {
|
||||
pr_err("Failed to hook WQ[%d] resource\n", index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vnic_wq_disable(wq);
|
||||
|
||||
err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = vnic_wq_alloc_bufs(wq);
|
||||
if (err) {
|
||||
vnic_wq_free(wq);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static 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;
|
||||
writeq(paddr, &wq->ctrl->ring_base);
|
||||
iowrite32(count, &wq->ctrl->ring_size);
|
||||
iowrite32(fetch_index, &wq->ctrl->fetch_index);
|
||||
iowrite32(posted_index, &wq->ctrl->posted_index);
|
||||
iowrite32(cq_index, &wq->ctrl->cq_index);
|
||||
iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable);
|
||||
iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset);
|
||||
iowrite32(0, &wq->ctrl->error_status);
|
||||
|
||||
wq->to_use = wq->to_clean =
|
||||
&wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES(count)]
|
||||
[fetch_index % VNIC_WQ_BUF_BLK_ENTRIES(count)];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
unsigned int vnic_wq_error_status(struct vnic_wq *wq)
|
||||
{
|
||||
return ioread32(&wq->ctrl->error_status);
|
||||
}
|
||||
|
||||
void vnic_wq_enable(struct vnic_wq *wq)
|
||||
{
|
||||
iowrite32(1, &wq->ctrl->enable);
|
||||
}
|
||||
|
||||
int vnic_wq_disable(struct vnic_wq *wq)
|
||||
{
|
||||
unsigned int wait;
|
||||
|
||||
iowrite32(0, &wq->ctrl->enable);
|
||||
|
||||
/* Wait for HW to ACK disable request */
|
||||
for (wait = 0; wait < 1000; wait++) {
|
||||
if (!(ioread32(&wq->ctrl->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,
|
||||
void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf))
|
||||
{
|
||||
struct vnic_wq_buf *buf;
|
||||
|
||||
buf = wq->to_clean;
|
||||
|
||||
while (vnic_wq_desc_used(wq) > 0) {
|
||||
|
||||
(*buf_clean)(wq, buf);
|
||||
|
||||
buf = wq->to_clean = buf->next;
|
||||
wq->ring.desc_avail++;
|
||||
}
|
||||
|
||||
wq->to_use = wq->to_clean = wq->bufs[0];
|
||||
|
||||
iowrite32(0, &wq->ctrl->fetch_index);
|
||||
iowrite32(0, &wq->ctrl->posted_index);
|
||||
iowrite32(0, &wq->ctrl->error_status);
|
||||
|
||||
vnic_dev_clear_desc_ring(&wq->ring);
|
||||
}
|
175
drivers/net/ethernet/cisco/enic/vnic_wq.h
Normal file
175
drivers/net/ethernet/cisco/enic/vnic_wq.h
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_WQ_H_
|
||||
#define _VNIC_WQ_H_
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_cq.h"
|
||||
|
||||
/* Work queue control */
|
||||
struct vnic_wq_ctrl {
|
||||
u64 ring_base; /* 0x00 */
|
||||
u32 ring_size; /* 0x08 */
|
||||
u32 pad0;
|
||||
u32 posted_index; /* 0x10 */
|
||||
u32 pad1;
|
||||
u32 cq_index; /* 0x18 */
|
||||
u32 pad2;
|
||||
u32 enable; /* 0x20 */
|
||||
u32 pad3;
|
||||
u32 running; /* 0x28 */
|
||||
u32 pad4;
|
||||
u32 fetch_index; /* 0x30 */
|
||||
u32 pad5;
|
||||
u32 dca_value; /* 0x38 */
|
||||
u32 pad6;
|
||||
u32 error_interrupt_enable; /* 0x40 */
|
||||
u32 pad7;
|
||||
u32 error_interrupt_offset; /* 0x48 */
|
||||
u32 pad8;
|
||||
u32 error_status; /* 0x50 */
|
||||
u32 pad9;
|
||||
};
|
||||
|
||||
struct vnic_wq_buf {
|
||||
struct vnic_wq_buf *next;
|
||||
dma_addr_t dma_addr;
|
||||
void *os_buf;
|
||||
unsigned int len;
|
||||
unsigned int index;
|
||||
int sop;
|
||||
void *desc;
|
||||
uint64_t wr_id; /* Cookie */
|
||||
uint8_t cq_entry; /* Gets completion event from hw */
|
||||
uint8_t desc_skip_cnt; /* Num descs to occupy */
|
||||
uint8_t compressed_send; /* Both hdr and payload in one desc */
|
||||
};
|
||||
|
||||
/* Break the vnic_wq_buf allocations into blocks of 32/64 entries */
|
||||
#define VNIC_WQ_BUF_MIN_BLK_ENTRIES 32
|
||||
#define VNIC_WQ_BUF_DFLT_BLK_ENTRIES 64
|
||||
#define VNIC_WQ_BUF_BLK_ENTRIES(entries) \
|
||||
((unsigned int)((entries < VNIC_WQ_BUF_DFLT_BLK_ENTRIES) ? \
|
||||
VNIC_WQ_BUF_MIN_BLK_ENTRIES : VNIC_WQ_BUF_DFLT_BLK_ENTRIES))
|
||||
#define VNIC_WQ_BUF_BLK_SZ(entries) \
|
||||
(VNIC_WQ_BUF_BLK_ENTRIES(entries) * sizeof(struct vnic_wq_buf))
|
||||
#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \
|
||||
DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES(entries))
|
||||
#define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096)
|
||||
|
||||
struct vnic_wq {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_wq_ctrl __iomem *ctrl; /* memory-mapped */
|
||||
struct vnic_dev_ring ring;
|
||||
struct vnic_wq_buf *bufs[VNIC_WQ_BUF_BLKS_MAX];
|
||||
struct vnic_wq_buf *to_use;
|
||||
struct vnic_wq_buf *to_clean;
|
||||
unsigned int pkts_outstanding;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline void *vnic_wq_next_desc(struct vnic_wq *wq)
|
||||
{
|
||||
return wq->to_use->desc;
|
||||
}
|
||||
|
||||
static inline void vnic_wq_post(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr,
|
||||
unsigned int len, int sop, int eop,
|
||||
uint8_t desc_skip_cnt, uint8_t cq_entry,
|
||||
uint8_t compressed_send, uint64_t wrid)
|
||||
{
|
||||
struct vnic_wq_buf *buf = wq->to_use;
|
||||
|
||||
buf->sop = sop;
|
||||
buf->cq_entry = cq_entry;
|
||||
buf->compressed_send = compressed_send;
|
||||
buf->desc_skip_cnt = desc_skip_cnt;
|
||||
buf->os_buf = eop ? os_buf : NULL;
|
||||
buf->dma_addr = dma_addr;
|
||||
buf->len = len;
|
||||
buf->wr_id = wrid;
|
||||
|
||||
buf = buf->next;
|
||||
if (eop) {
|
||||
/* Adding write memory barrier prevents compiler and/or CPU
|
||||
* reordering, thus avoiding descriptor posting before
|
||||
* descriptor is initialized. Otherwise, hardware can read
|
||||
* stale descriptor fields.
|
||||
*/
|
||||
wmb();
|
||||
iowrite32(buf->index, &wq->ctrl->posted_index);
|
||||
}
|
||||
wq->to_use = buf;
|
||||
|
||||
wq->ring.desc_avail -= desc_skip_cnt;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct vnic_wq_buf *buf;
|
||||
|
||||
buf = wq->to_clean;
|
||||
while (1) {
|
||||
|
||||
(*buf_service)(wq, cq_desc, buf, opaque);
|
||||
|
||||
wq->ring.desc_avail++;
|
||||
|
||||
wq->to_clean = buf->next;
|
||||
|
||||
if (buf->index == completed_index)
|
||||
break;
|
||||
|
||||
buf = wq->to_clean;
|
||||
}
|
||||
}
|
||||
|
||||
void vnic_wq_free(struct vnic_wq *wq);
|
||||
int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset);
|
||||
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,
|
||||
void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf));
|
||||
|
||||
#endif /* _VNIC_WQ_H_ */
|
98
drivers/net/ethernet/cisco/enic/wq_enet_desc.h
Normal file
98
drivers/net/ethernet/cisco/enic/wq_enet_desc.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_ */
|
Loading…
Add table
Add a link
Reference in a new issue