mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-29 07:34:06 +08:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc-next
This commit is contained in:
commit
d5df7c4156
@ -26,3 +26,11 @@ config SFC_MCDI_MON
|
||||
----help---
|
||||
This exposes the on-board firmware-managed sensors as a
|
||||
hardware monitor device.
|
||||
config SFC_SRIOV
|
||||
bool "Solarflare SFC9000-family SR-IOV support"
|
||||
depends on SFC && PCI_IOV
|
||||
default y
|
||||
---help---
|
||||
This enables support for the SFC9000 I/O Virtualization
|
||||
features, allowing accelerated network performance in
|
||||
virtualized environments.
|
||||
|
@ -4,5 +4,6 @@ sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \
|
||||
tenxpress.o txc43128_phy.o falcon_boards.o \
|
||||
mcdi.o mcdi_phy.o mcdi_mon.o
|
||||
sfc-$(CONFIG_SFC_MTD) += mtd.o
|
||||
sfc-$(CONFIG_SFC_SRIOV) += siena_sriov.o
|
||||
|
||||
obj-$(CONFIG_SFC) += sfc.o
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -95,6 +95,7 @@ static inline void efx_filter_rfs_expire(struct efx_channel *channel) {}
|
||||
#endif
|
||||
|
||||
/* Channels */
|
||||
extern int efx_channel_dummy_op_int(struct efx_channel *channel);
|
||||
extern void efx_process_channel_now(struct efx_channel *channel);
|
||||
extern int
|
||||
efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries);
|
||||
|
@ -808,11 +808,16 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
|
||||
return efx_reset(efx, rc);
|
||||
}
|
||||
|
||||
/* MAC address mask including only MC flag */
|
||||
static const u8 mac_addr_mc_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
|
||||
|
||||
static int efx_ethtool_get_class_rule(struct efx_nic *efx,
|
||||
struct ethtool_rx_flow_spec *rule)
|
||||
{
|
||||
struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;
|
||||
struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec;
|
||||
struct ethhdr *mac_entry = &rule->h_u.ether_spec;
|
||||
struct ethhdr *mac_mask = &rule->m_u.ether_spec;
|
||||
struct efx_filter_spec spec;
|
||||
u16 vid;
|
||||
u8 proto;
|
||||
@ -828,11 +833,18 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
|
||||
else
|
||||
rule->ring_cookie = spec.dmaq_id;
|
||||
|
||||
rc = efx_filter_get_eth_local(&spec, &vid,
|
||||
rule->h_u.ether_spec.h_dest);
|
||||
if (spec.type == EFX_FILTER_MC_DEF || spec.type == EFX_FILTER_UC_DEF) {
|
||||
rule->flow_type = ETHER_FLOW;
|
||||
memcpy(mac_mask->h_dest, mac_addr_mc_mask, ETH_ALEN);
|
||||
if (spec.type == EFX_FILTER_MC_DEF)
|
||||
memcpy(mac_entry->h_dest, mac_addr_mc_mask, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = efx_filter_get_eth_local(&spec, &vid, mac_entry->h_dest);
|
||||
if (rc == 0) {
|
||||
rule->flow_type = ETHER_FLOW;
|
||||
memset(rule->m_u.ether_spec.h_dest, ~0, ETH_ALEN);
|
||||
memset(mac_mask->h_dest, ~0, ETH_ALEN);
|
||||
if (vid != EFX_FILTER_VID_UNSPEC) {
|
||||
rule->flow_type |= FLOW_EXT;
|
||||
rule->h_ext.vlan_tci = htons(vid);
|
||||
@ -1001,27 +1013,40 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
|
||||
}
|
||||
|
||||
case ETHER_FLOW | FLOW_EXT:
|
||||
/* Must match all or none of VID */
|
||||
if (rule->m_ext.vlan_tci != htons(0xfff) &&
|
||||
rule->m_ext.vlan_tci != 0)
|
||||
return -EINVAL;
|
||||
case ETHER_FLOW:
|
||||
/* Must match all of destination */
|
||||
if (!is_broadcast_ether_addr(mac_mask->h_dest))
|
||||
return -EINVAL;
|
||||
/* and nothing else */
|
||||
case ETHER_FLOW: {
|
||||
u16 vlan_tag_mask = (rule->flow_type & FLOW_EXT ?
|
||||
ntohs(rule->m_ext.vlan_tci) : 0);
|
||||
|
||||
/* Must not match on source address or Ethertype */
|
||||
if (!is_zero_ether_addr(mac_mask->h_source) ||
|
||||
mac_mask->h_proto)
|
||||
return -EINVAL;
|
||||
|
||||
rc = efx_filter_set_eth_local(
|
||||
&spec,
|
||||
(rule->flow_type & FLOW_EXT && rule->m_ext.vlan_tci) ?
|
||||
ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC,
|
||||
mac_entry->h_dest);
|
||||
/* Is it a default UC or MC filter? */
|
||||
if (!compare_ether_addr(mac_mask->h_dest, mac_addr_mc_mask) &&
|
||||
vlan_tag_mask == 0) {
|
||||
if (is_multicast_ether_addr(mac_entry->h_dest))
|
||||
rc = efx_filter_set_mc_def(&spec);
|
||||
else
|
||||
rc = efx_filter_set_uc_def(&spec);
|
||||
}
|
||||
/* Otherwise, it must match all of destination and all
|
||||
* or none of VID.
|
||||
*/
|
||||
else if (is_broadcast_ether_addr(mac_mask->h_dest) &&
|
||||
(vlan_tag_mask == 0xfff || vlan_tag_mask == 0)) {
|
||||
rc = efx_filter_set_eth_local(
|
||||
&spec,
|
||||
vlan_tag_mask ?
|
||||
ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC,
|
||||
mac_entry->h_dest);
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -1060,7 +1085,8 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
|
||||
return (efx_nic_rev(efx) < EFX_REV_FALCON_B0 ?
|
||||
return ((efx_nic_rev(efx) < EFX_REV_FALCON_B0 ||
|
||||
efx->n_rx_channels == 1) ?
|
||||
0 : ARRAY_SIZE(efx->rx_indir_table));
|
||||
}
|
||||
|
||||
|
@ -1333,6 +1333,12 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void falcon_dimension_resources(struct efx_nic *efx)
|
||||
{
|
||||
efx->rx_dc_base = 0x20000;
|
||||
efx->tx_dc_base = 0x26000;
|
||||
}
|
||||
|
||||
/* Probe all SPI devices on the NIC */
|
||||
static void falcon_probe_spi_devices(struct efx_nic *efx)
|
||||
{
|
||||
@ -1749,6 +1755,7 @@ const struct efx_nic_type falcon_a1_nic_type = {
|
||||
.probe = falcon_probe_nic,
|
||||
.remove = falcon_remove_nic,
|
||||
.init = falcon_init_nic,
|
||||
.dimension_resources = falcon_dimension_resources,
|
||||
.fini = efx_port_dummy_op_void,
|
||||
.monitor = falcon_monitor,
|
||||
.map_reset_reason = falcon_map_reset_reason,
|
||||
@ -1783,8 +1790,6 @@ const struct efx_nic_type falcon_a1_nic_type = {
|
||||
.max_interrupt_mode = EFX_INT_MODE_MSI,
|
||||
.phys_addr_channels = 4,
|
||||
.timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH,
|
||||
.tx_dc_base = 0x130000,
|
||||
.rx_dc_base = 0x100000,
|
||||
.offload_features = NETIF_F_IP_CSUM,
|
||||
};
|
||||
|
||||
@ -1792,6 +1797,7 @@ const struct efx_nic_type falcon_b0_nic_type = {
|
||||
.probe = falcon_probe_nic,
|
||||
.remove = falcon_remove_nic,
|
||||
.init = falcon_init_nic,
|
||||
.dimension_resources = falcon_dimension_resources,
|
||||
.fini = efx_port_dummy_op_void,
|
||||
.monitor = falcon_monitor,
|
||||
.map_reset_reason = falcon_map_reset_reason,
|
||||
@ -1835,8 +1841,6 @@ const struct efx_nic_type falcon_b0_nic_type = {
|
||||
* interrupt handler only supports 32
|
||||
* channels */
|
||||
.timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH,
|
||||
.tx_dc_base = 0x130000,
|
||||
.rx_dc_base = 0x100000,
|
||||
.offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE,
|
||||
};
|
||||
|
||||
|
@ -35,9 +35,17 @@
|
||||
enum efx_filter_table_id {
|
||||
EFX_FILTER_TABLE_RX_IP = 0,
|
||||
EFX_FILTER_TABLE_RX_MAC,
|
||||
EFX_FILTER_TABLE_RX_DEF,
|
||||
EFX_FILTER_TABLE_TX_MAC,
|
||||
EFX_FILTER_TABLE_COUNT,
|
||||
};
|
||||
|
||||
enum efx_filter_index {
|
||||
EFX_FILTER_INDEX_UC_DEF,
|
||||
EFX_FILTER_INDEX_MC_DEF,
|
||||
EFX_FILTER_SIZE_RX_DEF,
|
||||
};
|
||||
|
||||
struct efx_filter_table {
|
||||
enum efx_filter_table_id id;
|
||||
u32 offset; /* address of table relative to BAR */
|
||||
@ -90,8 +98,9 @@ efx_filter_spec_table_id(const struct efx_filter_spec *spec)
|
||||
BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_UDP_WILD >> 2));
|
||||
BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_FULL >> 2));
|
||||
BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_WILD >> 2));
|
||||
BUILD_BUG_ON(EFX_FILTER_TABLE_TX_MAC != EFX_FILTER_TABLE_RX_MAC + 2);
|
||||
EFX_BUG_ON_PARANOID(spec->type == EFX_FILTER_UNSPEC);
|
||||
return spec->type >> 2;
|
||||
return (spec->type >> 2) + ((spec->flags & EFX_FILTER_FLAG_TX) ? 2 : 0);
|
||||
}
|
||||
|
||||
static struct efx_filter_table *
|
||||
@ -109,7 +118,7 @@ static void efx_filter_table_reset_search_depth(struct efx_filter_table *table)
|
||||
memset(table->search_depth, 0, sizeof(table->search_depth));
|
||||
}
|
||||
|
||||
static void efx_filter_push_rx_limits(struct efx_nic *efx)
|
||||
static void efx_filter_push_rx_config(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_filter_state *state = efx->filter_state;
|
||||
struct efx_filter_table *table;
|
||||
@ -143,9 +152,58 @@ static void efx_filter_push_rx_limits(struct efx_nic *efx)
|
||||
FILTER_CTL_SRCH_FUDGE_WILD);
|
||||
}
|
||||
|
||||
table = &state->table[EFX_FILTER_TABLE_RX_DEF];
|
||||
if (table->size) {
|
||||
EFX_SET_OWORD_FIELD(
|
||||
filter_ctl, FRF_CZ_UNICAST_NOMATCH_Q_ID,
|
||||
table->spec[EFX_FILTER_INDEX_UC_DEF].dmaq_id);
|
||||
EFX_SET_OWORD_FIELD(
|
||||
filter_ctl, FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED,
|
||||
!!(table->spec[EFX_FILTER_INDEX_UC_DEF].flags &
|
||||
EFX_FILTER_FLAG_RX_RSS));
|
||||
EFX_SET_OWORD_FIELD(
|
||||
filter_ctl, FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE,
|
||||
!!(table->spec[EFX_FILTER_INDEX_UC_DEF].flags &
|
||||
EFX_FILTER_FLAG_RX_OVERRIDE_IP));
|
||||
EFX_SET_OWORD_FIELD(
|
||||
filter_ctl, FRF_CZ_MULTICAST_NOMATCH_Q_ID,
|
||||
table->spec[EFX_FILTER_INDEX_MC_DEF].dmaq_id);
|
||||
EFX_SET_OWORD_FIELD(
|
||||
filter_ctl, FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED,
|
||||
!!(table->spec[EFX_FILTER_INDEX_MC_DEF].flags &
|
||||
EFX_FILTER_FLAG_RX_RSS));
|
||||
EFX_SET_OWORD_FIELD(
|
||||
filter_ctl, FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE,
|
||||
!!(table->spec[EFX_FILTER_INDEX_MC_DEF].flags &
|
||||
EFX_FILTER_FLAG_RX_OVERRIDE_IP));
|
||||
}
|
||||
|
||||
efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
|
||||
}
|
||||
|
||||
static void efx_filter_push_tx_limits(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_filter_state *state = efx->filter_state;
|
||||
struct efx_filter_table *table;
|
||||
efx_oword_t tx_cfg;
|
||||
|
||||
efx_reado(efx, &tx_cfg, FR_AZ_TX_CFG);
|
||||
|
||||
table = &state->table[EFX_FILTER_TABLE_TX_MAC];
|
||||
if (table->size) {
|
||||
EFX_SET_OWORD_FIELD(
|
||||
tx_cfg, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
|
||||
table->search_depth[EFX_FILTER_MAC_FULL] +
|
||||
FILTER_CTL_SRCH_FUDGE_FULL);
|
||||
EFX_SET_OWORD_FIELD(
|
||||
tx_cfg, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
|
||||
table->search_depth[EFX_FILTER_MAC_WILD] +
|
||||
FILTER_CTL_SRCH_FUDGE_WILD);
|
||||
}
|
||||
|
||||
efx_writeo(efx, &tx_cfg, FR_AZ_TX_CFG);
|
||||
}
|
||||
|
||||
static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec,
|
||||
__be32 host1, __be16 port1,
|
||||
__be32 host2, __be16 port2)
|
||||
@ -300,7 +358,8 @@ int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec,
|
||||
int efx_filter_set_eth_local(struct efx_filter_spec *spec,
|
||||
u16 vid, const u8 *addr)
|
||||
{
|
||||
EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX));
|
||||
EFX_BUG_ON_PARANOID(!(spec->flags &
|
||||
(EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
|
||||
|
||||
/* This cannot currently be combined with other filtering */
|
||||
if (spec->type != EFX_FILTER_UNSPEC)
|
||||
@ -319,6 +378,52 @@ int efx_filter_set_eth_local(struct efx_filter_spec *spec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_filter_set_uc_def - specify matching otherwise-unmatched unicast
|
||||
* @spec: Specification to initialise
|
||||
*/
|
||||
int efx_filter_set_uc_def(struct efx_filter_spec *spec)
|
||||
{
|
||||
EFX_BUG_ON_PARANOID(!(spec->flags &
|
||||
(EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
|
||||
|
||||
if (spec->type != EFX_FILTER_UNSPEC)
|
||||
return -EINVAL;
|
||||
|
||||
spec->type = EFX_FILTER_UC_DEF;
|
||||
memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_filter_set_mc_def - specify matching otherwise-unmatched multicast
|
||||
* @spec: Specification to initialise
|
||||
*/
|
||||
int efx_filter_set_mc_def(struct efx_filter_spec *spec)
|
||||
{
|
||||
EFX_BUG_ON_PARANOID(!(spec->flags &
|
||||
(EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
|
||||
|
||||
if (spec->type != EFX_FILTER_UNSPEC)
|
||||
return -EINVAL;
|
||||
|
||||
spec->type = EFX_FILTER_MC_DEF;
|
||||
memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void efx_filter_reset_rx_def(struct efx_nic *efx, unsigned filter_idx)
|
||||
{
|
||||
struct efx_filter_state *state = efx->filter_state;
|
||||
struct efx_filter_table *table = &state->table[EFX_FILTER_TABLE_RX_DEF];
|
||||
struct efx_filter_spec *spec = &table->spec[filter_idx];
|
||||
|
||||
efx_filter_init_rx(spec, EFX_FILTER_PRI_MANUAL,
|
||||
EFX_FILTER_FLAG_RX_RSS, 0);
|
||||
spec->type = EFX_FILTER_UC_DEF + filter_idx;
|
||||
table->used_bitmap[0] |= 1 << filter_idx;
|
||||
}
|
||||
|
||||
int efx_filter_get_eth_local(const struct efx_filter_spec *spec,
|
||||
u16 *vid, u8 *addr)
|
||||
{
|
||||
@ -366,6 +471,13 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
|
||||
break;
|
||||
}
|
||||
|
||||
case EFX_FILTER_TABLE_RX_DEF:
|
||||
/* One filter spec per type */
|
||||
BUILD_BUG_ON(EFX_FILTER_INDEX_UC_DEF != 0);
|
||||
BUILD_BUG_ON(EFX_FILTER_INDEX_MC_DEF !=
|
||||
EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF);
|
||||
return spec->type - EFX_FILTER_UC_DEF;
|
||||
|
||||
case EFX_FILTER_TABLE_RX_MAC: {
|
||||
bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
|
||||
EFX_POPULATE_OWORD_8(
|
||||
@ -385,6 +497,18 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
|
||||
break;
|
||||
}
|
||||
|
||||
case EFX_FILTER_TABLE_TX_MAC: {
|
||||
bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
|
||||
EFX_POPULATE_OWORD_5(*filter,
|
||||
FRF_CZ_TMFT_TXQ_ID, spec->dmaq_id,
|
||||
FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
|
||||
FRF_CZ_TMFT_SRC_MAC_HI, spec->data[2],
|
||||
FRF_CZ_TMFT_SRC_MAC_LO, spec->data[1],
|
||||
FRF_CZ_TMFT_VLAN_ID, spec->data[0]);
|
||||
data3 = is_wild | spec->dmaq_id << 1;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
@ -399,6 +523,10 @@ static bool efx_filter_equal(const struct efx_filter_spec *left,
|
||||
memcmp(left->data, right->data, sizeof(left->data)))
|
||||
return false;
|
||||
|
||||
if (left->flags & EFX_FILTER_FLAG_TX &&
|
||||
left->dmaq_id != right->dmaq_id)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -448,23 +576,40 @@ static int efx_filter_search(struct efx_filter_table *table,
|
||||
* MAC filters without overriding behaviour.
|
||||
*/
|
||||
|
||||
#define EFX_FILTER_MATCH_PRI_RX_MAC_OVERRIDE_IP 0
|
||||
#define EFX_FILTER_MATCH_PRI_RX_DEF_OVERRIDE_IP 1
|
||||
#define EFX_FILTER_MATCH_PRI_NORMAL_BASE 2
|
||||
|
||||
#define EFX_FILTER_INDEX_WIDTH 13
|
||||
#define EFX_FILTER_INDEX_MASK ((1 << EFX_FILTER_INDEX_WIDTH) - 1)
|
||||
|
||||
static inline u32 efx_filter_make_id(enum efx_filter_table_id table_id,
|
||||
unsigned int index, u8 flags)
|
||||
{
|
||||
return (table_id == EFX_FILTER_TABLE_RX_MAC &&
|
||||
flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP) ?
|
||||
index :
|
||||
(table_id + 1) << EFX_FILTER_INDEX_WIDTH | index;
|
||||
unsigned int match_pri = EFX_FILTER_MATCH_PRI_NORMAL_BASE + table_id;
|
||||
|
||||
if (flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP) {
|
||||
if (table_id == EFX_FILTER_TABLE_RX_MAC)
|
||||
match_pri = EFX_FILTER_MATCH_PRI_RX_MAC_OVERRIDE_IP;
|
||||
else if (table_id == EFX_FILTER_TABLE_RX_DEF)
|
||||
match_pri = EFX_FILTER_MATCH_PRI_RX_DEF_OVERRIDE_IP;
|
||||
}
|
||||
|
||||
return match_pri << EFX_FILTER_INDEX_WIDTH | index;
|
||||
}
|
||||
|
||||
static inline enum efx_filter_table_id efx_filter_id_table_id(u32 id)
|
||||
{
|
||||
return (id <= EFX_FILTER_INDEX_MASK) ?
|
||||
EFX_FILTER_TABLE_RX_MAC :
|
||||
(id >> EFX_FILTER_INDEX_WIDTH) - 1;
|
||||
unsigned int match_pri = id >> EFX_FILTER_INDEX_WIDTH;
|
||||
|
||||
switch (match_pri) {
|
||||
case EFX_FILTER_MATCH_PRI_RX_MAC_OVERRIDE_IP:
|
||||
return EFX_FILTER_TABLE_RX_MAC;
|
||||
case EFX_FILTER_MATCH_PRI_RX_DEF_OVERRIDE_IP:
|
||||
return EFX_FILTER_TABLE_RX_DEF;
|
||||
default:
|
||||
return match_pri - EFX_FILTER_MATCH_PRI_NORMAL_BASE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int efx_filter_id_index(u32 id)
|
||||
@ -474,23 +619,30 @@ static inline unsigned int efx_filter_id_index(u32 id)
|
||||
|
||||
static inline u8 efx_filter_id_flags(u32 id)
|
||||
{
|
||||
return (id <= EFX_FILTER_INDEX_MASK) ?
|
||||
EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_OVERRIDE_IP :
|
||||
EFX_FILTER_FLAG_RX;
|
||||
unsigned int match_pri = id >> EFX_FILTER_INDEX_WIDTH;
|
||||
|
||||
if (match_pri < EFX_FILTER_MATCH_PRI_NORMAL_BASE)
|
||||
return EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_OVERRIDE_IP;
|
||||
else if (match_pri <=
|
||||
EFX_FILTER_MATCH_PRI_NORMAL_BASE + EFX_FILTER_TABLE_RX_DEF)
|
||||
return EFX_FILTER_FLAG_RX;
|
||||
else
|
||||
return EFX_FILTER_FLAG_TX;
|
||||
}
|
||||
|
||||
u32 efx_filter_get_rx_id_limit(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_filter_state *state = efx->filter_state;
|
||||
unsigned int table_id = EFX_FILTER_TABLE_RX_DEF;
|
||||
|
||||
if (state->table[EFX_FILTER_TABLE_RX_MAC].size != 0)
|
||||
return ((EFX_FILTER_TABLE_RX_MAC + 1) << EFX_FILTER_INDEX_WIDTH)
|
||||
+ state->table[EFX_FILTER_TABLE_RX_MAC].size;
|
||||
else if (state->table[EFX_FILTER_TABLE_RX_IP].size != 0)
|
||||
return ((EFX_FILTER_TABLE_RX_IP + 1) << EFX_FILTER_INDEX_WIDTH)
|
||||
+ state->table[EFX_FILTER_TABLE_RX_IP].size;
|
||||
else
|
||||
return 0;
|
||||
do {
|
||||
if (state->table[table_id].size != 0)
|
||||
return ((EFX_FILTER_MATCH_PRI_NORMAL_BASE + table_id)
|
||||
<< EFX_FILTER_INDEX_WIDTH) +
|
||||
state->table[table_id].size;
|
||||
} while (table_id--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -548,12 +700,20 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
|
||||
}
|
||||
*saved_spec = *spec;
|
||||
|
||||
if (table->search_depth[spec->type] < depth) {
|
||||
table->search_depth[spec->type] = depth;
|
||||
efx_filter_push_rx_limits(efx);
|
||||
}
|
||||
if (table->id == EFX_FILTER_TABLE_RX_DEF) {
|
||||
efx_filter_push_rx_config(efx);
|
||||
} else {
|
||||
if (table->search_depth[spec->type] < depth) {
|
||||
table->search_depth[spec->type] = depth;
|
||||
if (spec->flags & EFX_FILTER_FLAG_TX)
|
||||
efx_filter_push_tx_limits(efx);
|
||||
else
|
||||
efx_filter_push_rx_config(efx);
|
||||
}
|
||||
|
||||
efx_writeo(efx, &filter, table->offset + table->step * filter_idx);
|
||||
efx_writeo(efx, &filter,
|
||||
table->offset + table->step * filter_idx);
|
||||
}
|
||||
|
||||
netif_vdbg(efx, hw, efx->net_dev,
|
||||
"%s: filter type %d index %d rxq %u set",
|
||||
@ -571,7 +731,11 @@ static void efx_filter_table_clear_entry(struct efx_nic *efx,
|
||||
{
|
||||
static efx_oword_t filter;
|
||||
|
||||
if (test_bit(filter_idx, table->used_bitmap)) {
|
||||
if (table->id == EFX_FILTER_TABLE_RX_DEF) {
|
||||
/* RX default filters must always exist */
|
||||
efx_filter_reset_rx_def(efx, filter_idx);
|
||||
efx_filter_push_rx_config(efx);
|
||||
} else if (test_bit(filter_idx, table->used_bitmap)) {
|
||||
__clear_bit(filter_idx, table->used_bitmap);
|
||||
--table->used;
|
||||
memset(&table->spec[filter_idx], 0, sizeof(table->spec[0]));
|
||||
@ -617,7 +781,8 @@ int efx_filter_remove_id_safe(struct efx_nic *efx,
|
||||
spin_lock_bh(&state->lock);
|
||||
|
||||
if (test_bit(filter_idx, table->used_bitmap) &&
|
||||
spec->priority == priority && spec->flags == filter_flags) {
|
||||
spec->priority == priority &&
|
||||
!((spec->flags ^ filter_flags) & EFX_FILTER_FLAG_RX_OVERRIDE_IP)) {
|
||||
efx_filter_table_clear_entry(efx, table, filter_idx);
|
||||
if (table->used == 0)
|
||||
efx_filter_table_reset_search_depth(table);
|
||||
@ -668,7 +833,8 @@ int efx_filter_get_filter_safe(struct efx_nic *efx,
|
||||
spin_lock_bh(&state->lock);
|
||||
|
||||
if (test_bit(filter_idx, table->used_bitmap) &&
|
||||
spec->priority == priority && spec->flags == filter_flags) {
|
||||
spec->priority == priority &&
|
||||
!((spec->flags ^ filter_flags) & EFX_FILTER_FLAG_RX_OVERRIDE_IP)) {
|
||||
*spec_buf = *spec;
|
||||
rc = 0;
|
||||
} else {
|
||||
@ -722,7 +888,7 @@ u32 efx_filter_count_rx_used(struct efx_nic *efx,
|
||||
spin_lock_bh(&state->lock);
|
||||
|
||||
for (table_id = EFX_FILTER_TABLE_RX_IP;
|
||||
table_id <= EFX_FILTER_TABLE_RX_MAC;
|
||||
table_id <= EFX_FILTER_TABLE_RX_DEF;
|
||||
table_id++) {
|
||||
table = &state->table[table_id];
|
||||
for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
|
||||
@ -750,7 +916,7 @@ s32 efx_filter_get_rx_ids(struct efx_nic *efx,
|
||||
spin_lock_bh(&state->lock);
|
||||
|
||||
for (table_id = EFX_FILTER_TABLE_RX_IP;
|
||||
table_id <= EFX_FILTER_TABLE_RX_MAC;
|
||||
table_id <= EFX_FILTER_TABLE_RX_DEF;
|
||||
table_id++) {
|
||||
table = &state->table[table_id];
|
||||
for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
|
||||
@ -785,6 +951,11 @@ void efx_restore_filters(struct efx_nic *efx)
|
||||
|
||||
for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
|
||||
table = &state->table[table_id];
|
||||
|
||||
/* Check whether this is a regular register table */
|
||||
if (table->step == 0)
|
||||
continue;
|
||||
|
||||
for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
|
||||
if (!test_bit(filter_idx, table->used_bitmap))
|
||||
continue;
|
||||
@ -794,7 +965,8 @@ void efx_restore_filters(struct efx_nic *efx)
|
||||
}
|
||||
}
|
||||
|
||||
efx_filter_push_rx_limits(efx);
|
||||
efx_filter_push_rx_config(efx);
|
||||
efx_filter_push_tx_limits(efx);
|
||||
|
||||
spin_unlock_bh(&state->lock);
|
||||
}
|
||||
@ -833,6 +1005,16 @@ int efx_probe_filters(struct efx_nic *efx)
|
||||
table->offset = FR_CZ_RX_MAC_FILTER_TBL0;
|
||||
table->size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
|
||||
table->step = FR_CZ_RX_MAC_FILTER_TBL0_STEP;
|
||||
|
||||
table = &state->table[EFX_FILTER_TABLE_RX_DEF];
|
||||
table->id = EFX_FILTER_TABLE_RX_DEF;
|
||||
table->size = EFX_FILTER_SIZE_RX_DEF;
|
||||
|
||||
table = &state->table[EFX_FILTER_TABLE_TX_MAC];
|
||||
table->id = EFX_FILTER_TABLE_TX_MAC;
|
||||
table->offset = FR_CZ_TX_MAC_FILTER_TBL0;
|
||||
table->size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
|
||||
table->step = FR_CZ_TX_MAC_FILTER_TBL0_STEP;
|
||||
}
|
||||
|
||||
for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
|
||||
@ -849,6 +1031,15 @@ int efx_probe_filters(struct efx_nic *efx)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (state->table[EFX_FILTER_TABLE_RX_DEF].size) {
|
||||
/* RX default filters must always exist */
|
||||
unsigned i;
|
||||
for (i = 0; i < EFX_FILTER_SIZE_RX_DEF; i++)
|
||||
efx_filter_reset_rx_def(efx, i);
|
||||
}
|
||||
|
||||
efx_filter_push_rx_config(efx);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
@ -20,6 +20,8 @@
|
||||
* @EFX_FILTER_UDP_WILD: Matching UDP/IPv4 destination (host, port)
|
||||
* @EFX_FILTER_MAC_FULL: Matching Ethernet destination MAC address, VID
|
||||
* @EFX_FILTER_MAC_WILD: Matching Ethernet destination MAC address
|
||||
* @EFX_FILTER_UC_DEF: Matching all otherwise unmatched unicast
|
||||
* @EFX_FILTER_MC_DEF: Matching all otherwise unmatched multicast
|
||||
* @EFX_FILTER_UNSPEC: Match type is unspecified
|
||||
*
|
||||
* Falcon NICs only support the TCP/IPv4 and UDP/IPv4 filter types.
|
||||
@ -31,6 +33,8 @@ enum efx_filter_type {
|
||||
EFX_FILTER_UDP_WILD,
|
||||
EFX_FILTER_MAC_FULL = 4,
|
||||
EFX_FILTER_MAC_WILD,
|
||||
EFX_FILTER_UC_DEF = 8,
|
||||
EFX_FILTER_MC_DEF,
|
||||
EFX_FILTER_TYPE_COUNT, /* number of specific types */
|
||||
EFX_FILTER_UNSPEC = 0xf,
|
||||
};
|
||||
@ -39,7 +43,8 @@ enum efx_filter_type {
|
||||
* enum efx_filter_priority - priority of a hardware filter specification
|
||||
* @EFX_FILTER_PRI_HINT: Performance hint
|
||||
* @EFX_FILTER_PRI_MANUAL: Manually configured filter
|
||||
* @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour
|
||||
* @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour (user-level
|
||||
* networking and SR-IOV)
|
||||
*/
|
||||
enum efx_filter_priority {
|
||||
EFX_FILTER_PRI_HINT = 0,
|
||||
@ -60,12 +65,14 @@ enum efx_filter_priority {
|
||||
* any IP filter that matches the same packet. By default, IP
|
||||
* filters take precedence.
|
||||
* @EFX_FILTER_FLAG_RX: Filter is for RX
|
||||
* @EFX_FILTER_FLAG_TX: Filter is for TX
|
||||
*/
|
||||
enum efx_filter_flags {
|
||||
EFX_FILTER_FLAG_RX_RSS = 0x01,
|
||||
EFX_FILTER_FLAG_RX_SCATTER = 0x02,
|
||||
EFX_FILTER_FLAG_RX_OVERRIDE_IP = 0x04,
|
||||
EFX_FILTER_FLAG_RX = 0x08,
|
||||
EFX_FILTER_FLAG_TX = 0x10,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -103,6 +110,15 @@ static inline void efx_filter_init_rx(struct efx_filter_spec *spec,
|
||||
spec->dmaq_id = rxq_id;
|
||||
}
|
||||
|
||||
static inline void efx_filter_init_tx(struct efx_filter_spec *spec,
|
||||
unsigned txq_id)
|
||||
{
|
||||
spec->type = EFX_FILTER_UNSPEC;
|
||||
spec->priority = EFX_FILTER_PRI_REQUIRED;
|
||||
spec->flags = EFX_FILTER_FLAG_TX;
|
||||
spec->dmaq_id = txq_id;
|
||||
}
|
||||
|
||||
extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto,
|
||||
__be32 host, __be16 port);
|
||||
extern int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec,
|
||||
@ -117,6 +133,8 @@ extern int efx_filter_set_eth_local(struct efx_filter_spec *spec,
|
||||
u16 vid, const u8 *addr);
|
||||
extern int efx_filter_get_eth_local(const struct efx_filter_spec *spec,
|
||||
u16 *vid, u8 *addr);
|
||||
extern int efx_filter_set_uc_def(struct efx_filter_spec *spec);
|
||||
extern int efx_filter_set_mc_def(struct efx_filter_spec *spec);
|
||||
enum {
|
||||
EFX_FILTER_VID_UNSPEC = 0xffff,
|
||||
};
|
||||
|
@ -560,6 +560,9 @@ void efx_mcdi_process_event(struct efx_channel *channel,
|
||||
case MCDI_EVENT_CODE_MAC_STATS_DMA:
|
||||
/* MAC stats are gather lazily. We can ignore this. */
|
||||
break;
|
||||
case MCDI_EVENT_CODE_FLR:
|
||||
efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
|
||||
break;
|
||||
|
||||
default:
|
||||
netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
|
||||
@ -1154,6 +1157,37 @@ fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int efx_mcdi_flush_rxqs(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_channel *channel;
|
||||
struct efx_rx_queue *rx_queue;
|
||||
__le32 *qid;
|
||||
int rc, count;
|
||||
|
||||
qid = kmalloc(EFX_MAX_CHANNELS * sizeof(*qid), GFP_KERNEL);
|
||||
if (qid == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
count = 0;
|
||||
efx_for_each_channel(channel, efx) {
|
||||
efx_for_each_channel_rx_queue(rx_queue, channel) {
|
||||
if (rx_queue->flush_pending) {
|
||||
rx_queue->flush_pending = false;
|
||||
atomic_dec(&efx->rxq_flush_pending);
|
||||
qid[count++] = cpu_to_le32(
|
||||
efx_rx_queue_index(rx_queue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, (u8 *)qid,
|
||||
count * sizeof(*qid), NULL, 0, NULL);
|
||||
WARN_ON(rc > 0);
|
||||
|
||||
kfree(qid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
|
||||
{
|
||||
|
@ -146,6 +146,8 @@ extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx,
|
||||
extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out);
|
||||
extern int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id);
|
||||
extern int efx_mcdi_wol_filter_reset(struct efx_nic *efx);
|
||||
extern int efx_mcdi_flush_rxqs(struct efx_nic *efx);
|
||||
extern int efx_mcdi_set_mac(struct efx_nic *efx);
|
||||
extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
|
||||
u32 dma_len, int enable, int clear);
|
||||
extern int efx_mcdi_mac_reconfigure(struct efx_nic *efx);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "mcdi.h"
|
||||
#include "mcdi_pcol.h"
|
||||
|
||||
static int efx_mcdi_set_mac(struct efx_nic *efx)
|
||||
int efx_mcdi_set_mac(struct efx_nic *efx)
|
||||
{
|
||||
u32 reject, fcntl;
|
||||
u8 cmdbytes[MC_CMD_SET_MAC_IN_LEN];
|
||||
@ -44,6 +44,8 @@ static int efx_mcdi_set_mac(struct efx_nic *efx)
|
||||
}
|
||||
if (efx->wanted_fc & EFX_FC_AUTO)
|
||||
fcntl = MC_CMD_FCNTL_AUTO;
|
||||
if (efx->fc_disable)
|
||||
fcntl = MC_CMD_FCNTL_OFF;
|
||||
|
||||
MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl);
|
||||
|
||||
|
@ -280,7 +280,7 @@ fail:
|
||||
--part;
|
||||
efx_mtd_remove_partition(part);
|
||||
}
|
||||
/* mtd_device_register() returns 1 if the MTD table is full */
|
||||
/* Failure is unlikely here, but probably means we're out of memory */
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
@ -52,8 +53,10 @@
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#define EFX_MAX_CHANNELS 32
|
||||
#define EFX_MAX_CHANNELS 32U
|
||||
#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
|
||||
#define EFX_EXTRA_CHANNEL_IOV 0
|
||||
#define EFX_MAX_EXTRA_CHANNELS 1U
|
||||
|
||||
/* Checksum generation is a per-queue option in hardware, so each
|
||||
* queue visible to the networking core is backed by two hardware TX
|
||||
@ -81,15 +84,8 @@ struct efx_special_buffer {
|
||||
void *addr;
|
||||
dma_addr_t dma_addr;
|
||||
unsigned int len;
|
||||
int index;
|
||||
int entries;
|
||||
};
|
||||
|
||||
enum efx_flush_state {
|
||||
FLUSH_NONE,
|
||||
FLUSH_PENDING,
|
||||
FLUSH_FAILED,
|
||||
FLUSH_DONE,
|
||||
unsigned int index;
|
||||
unsigned int entries;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -138,7 +134,6 @@ struct efx_tx_buffer {
|
||||
* @txd: The hardware descriptor ring
|
||||
* @ptr_mask: The size of the ring minus 1.
|
||||
* @initialised: Has hardware queue been initialised?
|
||||
* @flushed: Used when handling queue flushing
|
||||
* @read_count: Current read pointer.
|
||||
* This is the number of buffers that have been removed from both rings.
|
||||
* @old_write_count: The value of @write_count when last checked.
|
||||
@ -181,7 +176,6 @@ struct efx_tx_queue {
|
||||
struct efx_special_buffer txd;
|
||||
unsigned int ptr_mask;
|
||||
bool initialised;
|
||||
enum efx_flush_state flushed;
|
||||
|
||||
/* Members used mainly on the completion path */
|
||||
unsigned int read_count ____cacheline_aligned_in_smp;
|
||||
@ -249,6 +243,9 @@ struct efx_rx_page_state {
|
||||
* @buffer: The software buffer ring
|
||||
* @rxd: The hardware descriptor ring
|
||||
* @ptr_mask: The size of the ring minus 1.
|
||||
* @enabled: Receive queue enabled indicator.
|
||||
* @flush_pending: Set when a RX flush is pending. Has the same lifetime as
|
||||
* @rxq_flush_pending.
|
||||
* @added_count: Number of buffers added to the receive queue.
|
||||
* @notified_count: Number of buffers given to NIC (<= @added_count).
|
||||
* @removed_count: Number of buffers removed from the receive queue.
|
||||
@ -263,13 +260,14 @@ struct efx_rx_page_state {
|
||||
* @alloc_page_count: RX allocation strategy counter.
|
||||
* @alloc_skb_count: RX allocation strategy counter.
|
||||
* @slow_fill: Timer used to defer efx_nic_generate_fill_event().
|
||||
* @flushed: Use when handling queue flushing
|
||||
*/
|
||||
struct efx_rx_queue {
|
||||
struct efx_nic *efx;
|
||||
struct efx_rx_buffer *buffer;
|
||||
struct efx_special_buffer rxd;
|
||||
unsigned int ptr_mask;
|
||||
bool enabled;
|
||||
bool flush_pending;
|
||||
|
||||
int added_count;
|
||||
int notified_count;
|
||||
@ -283,8 +281,6 @@ struct efx_rx_queue {
|
||||
unsigned int alloc_skb_count;
|
||||
struct timer_list slow_fill;
|
||||
unsigned int slow_fill_count;
|
||||
|
||||
enum efx_flush_state flushed;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -318,6 +314,7 @@ enum efx_rx_alloc_method {
|
||||
*
|
||||
* @efx: Associated Efx NIC
|
||||
* @channel: Channel instance number
|
||||
* @type: Channel type definition
|
||||
* @enabled: Channel enabled indicator
|
||||
* @irq: IRQ number (MSI and MSI-X only)
|
||||
* @irq_moderation: IRQ moderation value (in hardware ticks)
|
||||
@ -348,6 +345,7 @@ enum efx_rx_alloc_method {
|
||||
struct efx_channel {
|
||||
struct efx_nic *efx;
|
||||
int channel;
|
||||
const struct efx_channel_type *type;
|
||||
bool enabled;
|
||||
int irq;
|
||||
unsigned int irq_moderation;
|
||||
@ -386,6 +384,26 @@ struct efx_channel {
|
||||
struct efx_tx_queue tx_queue[EFX_TXQ_TYPES];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct efx_channel_type - distinguishes traffic and extra channels
|
||||
* @handle_no_channel: Handle failure to allocate an extra channel
|
||||
* @pre_probe: Set up extra state prior to initialisation
|
||||
* @post_remove: Tear down extra state after finalisation, if allocated.
|
||||
* May be called on channels that have not been probed.
|
||||
* @get_name: Generate the channel's name (used for its IRQ handler)
|
||||
* @copy: Copy the channel state prior to reallocation. May be %NULL if
|
||||
* reallocation is not supported.
|
||||
* @keep_eventq: Flag for whether event queue should be kept initialised
|
||||
* while the device is stopped
|
||||
*/
|
||||
struct efx_channel_type {
|
||||
void (*handle_no_channel)(struct efx_nic *);
|
||||
int (*pre_probe)(struct efx_channel *);
|
||||
void (*get_name)(struct efx_channel *, char *buf, size_t len);
|
||||
struct efx_channel *(*copy)(const struct efx_channel *);
|
||||
bool keep_eventq;
|
||||
};
|
||||
|
||||
enum efx_led_mode {
|
||||
EFX_LED_OFF = 0,
|
||||
EFX_LED_ON = 1,
|
||||
@ -613,6 +631,8 @@ union efx_multicast_hash {
|
||||
};
|
||||
|
||||
struct efx_filter_state;
|
||||
struct efx_vf;
|
||||
struct vfdi_status;
|
||||
|
||||
/**
|
||||
* struct efx_nic - an Efx NIC
|
||||
@ -638,8 +658,13 @@ struct efx_filter_state;
|
||||
* @rx_queue: RX DMA queues
|
||||
* @channel: Channels
|
||||
* @channel_name: Names for channels and their IRQs
|
||||
* @extra_channel_types: Types of extra (non-traffic) channels that
|
||||
* should be allocated for this NIC
|
||||
* @rxq_entries: Size of receive queues requested by user.
|
||||
* @txq_entries: Size of transmit queues requested by user.
|
||||
* @tx_dc_base: Base qword address in SRAM of TX queue descriptor caches
|
||||
* @rx_dc_base: Base qword address in SRAM of RX queue descriptor caches
|
||||
* @sram_lim_qw: Qword address limit of SRAM
|
||||
* @next_buffer_table: First available buffer table id
|
||||
* @n_channels: Number of channels in use
|
||||
* @n_rx_channels: Number of channels used for RX (= number of RX queues)
|
||||
@ -677,10 +702,31 @@ struct efx_filter_state;
|
||||
* @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
|
||||
* @multicast_hash: Multicast hash table
|
||||
* @wanted_fc: Wanted flow control flags
|
||||
* @fc_disable: When non-zero flow control is disabled. Typically used to
|
||||
* ensure that network back pressure doesn't delay dma queue flushes.
|
||||
* Serialised by the rtnl lock.
|
||||
* @mac_work: Work item for changing MAC promiscuity and multicast hash
|
||||
* @loopback_mode: Loopback status
|
||||
* @loopback_modes: Supported loopback mode bitmask
|
||||
* @loopback_selftest: Offline self-test private state
|
||||
* @drain_pending: Count of RX and TX queues that haven't been flushed and drained.
|
||||
* @rxq_flush_pending: Count of number of receive queues that need to be flushed.
|
||||
* Decremented when the efx_flush_rx_queue() is called.
|
||||
* @rxq_flush_outstanding: Count of number of RX flushes started but not yet
|
||||
* completed (either success or failure). Not used when MCDI is used to
|
||||
* flush receive queues.
|
||||
* @flush_wq: wait queue used by efx_nic_flush_queues() to wait for flush completions.
|
||||
* @vf: Array of &struct efx_vf objects.
|
||||
* @vf_count: Number of VFs intended to be enabled.
|
||||
* @vf_init_count: Number of VFs that have been fully initialised.
|
||||
* @vi_scale: log2 number of vnics per VF.
|
||||
* @vf_buftbl_base: The zeroth buffer table index used to back VF queues.
|
||||
* @vfdi_status: Common VFDI status page to be dmad to VF address space.
|
||||
* @local_addr_list: List of local addresses. Protected by %local_lock.
|
||||
* @local_page_list: List of DMA addressable pages used to broadcast
|
||||
* %local_addr_list. Protected by %local_lock.
|
||||
* @local_lock: Mutex protecting %local_addr_list and %local_page_list.
|
||||
* @peer_work: Work item to broadcast peer addresses to VMs.
|
||||
* @monitor_work: Hardware monitor workitem
|
||||
* @biu_lock: BIU (bus interface unit) lock
|
||||
* @last_irq_cpu: Last CPU to handle a possible test interrupt. This
|
||||
@ -720,12 +766,18 @@ struct efx_nic {
|
||||
|
||||
struct efx_channel *channel[EFX_MAX_CHANNELS];
|
||||
char channel_name[EFX_MAX_CHANNELS][IFNAMSIZ + 6];
|
||||
const struct efx_channel_type *
|
||||
extra_channel_type[EFX_MAX_EXTRA_CHANNELS];
|
||||
|
||||
unsigned rxq_entries;
|
||||
unsigned txq_entries;
|
||||
unsigned tx_dc_base;
|
||||
unsigned rx_dc_base;
|
||||
unsigned sram_lim_qw;
|
||||
unsigned next_buffer_table;
|
||||
unsigned n_channels;
|
||||
unsigned n_rx_channels;
|
||||
unsigned rss_spread;
|
||||
unsigned tx_channel_offset;
|
||||
unsigned n_tx_channels;
|
||||
unsigned int rx_buffer_len;
|
||||
@ -769,6 +821,7 @@ struct efx_nic {
|
||||
bool promiscuous;
|
||||
union efx_multicast_hash multicast_hash;
|
||||
u8 wanted_fc;
|
||||
unsigned fc_disable;
|
||||
|
||||
atomic_t rx_reset;
|
||||
enum efx_loopback_mode loopback_mode;
|
||||
@ -778,6 +831,25 @@ struct efx_nic {
|
||||
|
||||
struct efx_filter_state *filter_state;
|
||||
|
||||
atomic_t drain_pending;
|
||||
atomic_t rxq_flush_pending;
|
||||
atomic_t rxq_flush_outstanding;
|
||||
wait_queue_head_t flush_wq;
|
||||
|
||||
#ifdef CONFIG_SFC_SRIOV
|
||||
struct efx_channel *vfdi_channel;
|
||||
struct efx_vf *vf;
|
||||
unsigned vf_count;
|
||||
unsigned vf_init_count;
|
||||
unsigned vi_scale;
|
||||
unsigned vf_buftbl_base;
|
||||
struct efx_buffer vfdi_status;
|
||||
struct list_head local_addr_list;
|
||||
struct list_head local_page_list;
|
||||
struct mutex local_lock;
|
||||
struct work_struct peer_work;
|
||||
#endif
|
||||
|
||||
/* The following fields may be written more often */
|
||||
|
||||
struct delayed_work monitor_work ____cacheline_aligned_in_smp;
|
||||
@ -803,6 +875,8 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
|
||||
* @probe: Probe the controller
|
||||
* @remove: Free resources allocated by probe()
|
||||
* @init: Initialise the controller
|
||||
* @dimension_resources: Dimension controller resources (buffer table,
|
||||
* and VIs once the available interrupt resources are clear)
|
||||
* @fini: Shut down the controller
|
||||
* @monitor: Periodic function for polling link state and hardware monitor
|
||||
* @map_reset_reason: Map ethtool reset reason to a reset method
|
||||
@ -842,8 +916,6 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
|
||||
* @phys_addr_channels: Number of channels with physically addressed
|
||||
* descriptors
|
||||
* @timer_period_max: Maximum period of interrupt timer (in ticks)
|
||||
* @tx_dc_base: Base address in SRAM of TX queue descriptor caches
|
||||
* @rx_dc_base: Base address in SRAM of RX queue descriptor caches
|
||||
* @offload_features: net_device feature flags for protocol offload
|
||||
* features implemented in hardware
|
||||
*/
|
||||
@ -851,6 +923,7 @@ struct efx_nic_type {
|
||||
int (*probe)(struct efx_nic *efx);
|
||||
void (*remove)(struct efx_nic *efx);
|
||||
int (*init)(struct efx_nic *efx);
|
||||
void (*dimension_resources)(struct efx_nic *efx);
|
||||
void (*fini)(struct efx_nic *efx);
|
||||
void (*monitor)(struct efx_nic *efx);
|
||||
enum reset_type (*map_reset_reason)(enum reset_type reason);
|
||||
@ -887,8 +960,6 @@ struct efx_nic_type {
|
||||
unsigned int max_interrupt_mode;
|
||||
unsigned int phys_addr_channels;
|
||||
unsigned int timer_period_max;
|
||||
unsigned int tx_dc_base;
|
||||
unsigned int rx_dc_base;
|
||||
netdev_features_t offload_features;
|
||||
};
|
||||
|
||||
@ -912,6 +983,13 @@ efx_get_channel(struct efx_nic *efx, unsigned index)
|
||||
_channel = (_channel->channel + 1 < (_efx)->n_channels) ? \
|
||||
(_efx)->channel[_channel->channel + 1] : NULL)
|
||||
|
||||
/* Iterate over all used channels in reverse */
|
||||
#define efx_for_each_channel_rev(_channel, _efx) \
|
||||
for (_channel = (_efx)->channel[(_efx)->n_channels - 1]; \
|
||||
_channel; \
|
||||
_channel = _channel->channel ? \
|
||||
(_efx)->channel[_channel->channel - 1] : NULL)
|
||||
|
||||
static inline struct efx_tx_queue *
|
||||
efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
|
||||
{
|
||||
@ -956,13 +1034,6 @@ static inline bool efx_tx_queue_used(struct efx_tx_queue *tx_queue)
|
||||
_tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \
|
||||
_tx_queue++)
|
||||
|
||||
static inline struct efx_rx_queue *
|
||||
efx_get_rx_queue(struct efx_nic *efx, unsigned index)
|
||||
{
|
||||
EFX_BUG_ON_PARANOID(index >= efx->n_rx_channels);
|
||||
return &efx->channel[index]->rx_queue;
|
||||
}
|
||||
|
||||
static inline bool efx_channel_has_rx_queue(struct efx_channel *channel)
|
||||
{
|
||||
return channel->channel < channel->efx->n_rx_channels;
|
||||
|
@ -49,24 +49,29 @@
|
||||
#define EFX_INT_ERROR_EXPIRE 3600
|
||||
#define EFX_MAX_INT_ERRORS 5
|
||||
|
||||
/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times
|
||||
*/
|
||||
#define EFX_FLUSH_INTERVAL 10
|
||||
#define EFX_FLUSH_POLL_COUNT 100
|
||||
|
||||
/* Size and alignment of special buffers (4KB) */
|
||||
#define EFX_BUF_SIZE 4096
|
||||
|
||||
/* Depth of RX flush request fifo */
|
||||
#define EFX_RX_FLUSH_COUNT 4
|
||||
|
||||
/* Generated event code for efx_generate_test_event() */
|
||||
#define EFX_CHANNEL_MAGIC_TEST(_channel) \
|
||||
(0x00010100 + (_channel)->channel)
|
||||
/* Driver generated events */
|
||||
#define _EFX_CHANNEL_MAGIC_TEST 0x000101
|
||||
#define _EFX_CHANNEL_MAGIC_FILL 0x000102
|
||||
#define _EFX_CHANNEL_MAGIC_RX_DRAIN 0x000103
|
||||
#define _EFX_CHANNEL_MAGIC_TX_DRAIN 0x000104
|
||||
|
||||
/* Generated event code for efx_generate_fill_event() */
|
||||
#define EFX_CHANNEL_MAGIC_FILL(_channel) \
|
||||
(0x00010200 + (_channel)->channel)
|
||||
#define _EFX_CHANNEL_MAGIC(_code, _data) ((_code) << 8 | (_data))
|
||||
#define _EFX_CHANNEL_MAGIC_CODE(_magic) ((_magic) >> 8)
|
||||
|
||||
#define EFX_CHANNEL_MAGIC_TEST(_channel) \
|
||||
_EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_TEST, (_channel)->channel)
|
||||
#define EFX_CHANNEL_MAGIC_FILL(_rx_queue) \
|
||||
_EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_FILL, \
|
||||
efx_rx_queue_index(_rx_queue))
|
||||
#define EFX_CHANNEL_MAGIC_RX_DRAIN(_rx_queue) \
|
||||
_EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_RX_DRAIN, \
|
||||
efx_rx_queue_index(_rx_queue))
|
||||
#define EFX_CHANNEL_MAGIC_TX_DRAIN(_tx_queue) \
|
||||
_EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_TX_DRAIN, \
|
||||
(_tx_queue)->queue)
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
@ -187,7 +192,7 @@ static void
|
||||
efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
|
||||
{
|
||||
efx_qword_t buf_desc;
|
||||
int index;
|
||||
unsigned int index;
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
@ -196,7 +201,7 @@ efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
|
||||
/* Write buffer descriptors to NIC */
|
||||
for (i = 0; i < buffer->entries; i++) {
|
||||
index = buffer->index + i;
|
||||
dma_addr = buffer->dma_addr + (i * 4096);
|
||||
dma_addr = buffer->dma_addr + (i * EFX_BUF_SIZE);
|
||||
netif_dbg(efx, probe, efx->net_dev,
|
||||
"mapping special buffer %d at %llx\n",
|
||||
index, (unsigned long long)dma_addr);
|
||||
@ -259,6 +264,10 @@ static int efx_alloc_special_buffer(struct efx_nic *efx,
|
||||
/* Select new buffer ID */
|
||||
buffer->index = efx->next_buffer_table;
|
||||
efx->next_buffer_table += buffer->entries;
|
||||
#ifdef CONFIG_SFC_SRIOV
|
||||
BUG_ON(efx_sriov_enabled(efx) &&
|
||||
efx->vf_buftbl_base < efx->next_buffer_table);
|
||||
#endif
|
||||
|
||||
netif_dbg(efx, probe, efx->net_dev,
|
||||
"allocating special buffers %d-%d at %llx+%x "
|
||||
@ -430,8 +439,6 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue)
|
||||
struct efx_nic *efx = tx_queue->efx;
|
||||
efx_oword_t reg;
|
||||
|
||||
tx_queue->flushed = FLUSH_NONE;
|
||||
|
||||
/* Pin TX descriptor ring */
|
||||
efx_init_special_buffer(efx, &tx_queue->txd);
|
||||
|
||||
@ -488,9 +495,6 @@ static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue)
|
||||
struct efx_nic *efx = tx_queue->efx;
|
||||
efx_oword_t tx_flush_descq;
|
||||
|
||||
tx_queue->flushed = FLUSH_PENDING;
|
||||
|
||||
/* Post a flush command */
|
||||
EFX_POPULATE_OWORD_2(tx_flush_descq,
|
||||
FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
|
||||
FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue);
|
||||
@ -502,9 +506,6 @@ void efx_nic_fini_tx(struct efx_tx_queue *tx_queue)
|
||||
struct efx_nic *efx = tx_queue->efx;
|
||||
efx_oword_t tx_desc_ptr;
|
||||
|
||||
/* The queue should have been flushed */
|
||||
WARN_ON(tx_queue->flushed != FLUSH_DONE);
|
||||
|
||||
/* Remove TX descriptor ring from card */
|
||||
EFX_ZERO_OWORD(tx_desc_ptr);
|
||||
efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
|
||||
@ -595,8 +596,6 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
|
||||
efx_rx_queue_index(rx_queue), rx_queue->rxd.index,
|
||||
rx_queue->rxd.index + rx_queue->rxd.entries - 1);
|
||||
|
||||
rx_queue->flushed = FLUSH_NONE;
|
||||
|
||||
/* Pin RX descriptor ring */
|
||||
efx_init_special_buffer(efx, &rx_queue->rxd);
|
||||
|
||||
@ -625,9 +624,6 @@ static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue)
|
||||
struct efx_nic *efx = rx_queue->efx;
|
||||
efx_oword_t rx_flush_descq;
|
||||
|
||||
rx_queue->flushed = FLUSH_PENDING;
|
||||
|
||||
/* Post a flush command */
|
||||
EFX_POPULATE_OWORD_2(rx_flush_descq,
|
||||
FRF_AZ_RX_FLUSH_DESCQ_CMD, 1,
|
||||
FRF_AZ_RX_FLUSH_DESCQ,
|
||||
@ -640,9 +636,6 @@ void efx_nic_fini_rx(struct efx_rx_queue *rx_queue)
|
||||
efx_oword_t rx_desc_ptr;
|
||||
struct efx_nic *efx = rx_queue->efx;
|
||||
|
||||
/* The queue should already have been flushed */
|
||||
WARN_ON(rx_queue->flushed != FLUSH_DONE);
|
||||
|
||||
/* Remove RX descriptor ring from card */
|
||||
EFX_ZERO_OWORD(rx_desc_ptr);
|
||||
efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
|
||||
@ -658,6 +651,103 @@ void efx_nic_remove_rx(struct efx_rx_queue *rx_queue)
|
||||
efx_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Flush handling
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/* efx_nic_flush_queues() must be woken up when all flushes are completed,
|
||||
* or more RX flushes can be kicked off.
|
||||
*/
|
||||
static bool efx_flush_wake(struct efx_nic *efx)
|
||||
{
|
||||
/* Ensure that all updates are visible to efx_nic_flush_queues() */
|
||||
smp_mb();
|
||||
|
||||
return (atomic_read(&efx->drain_pending) == 0 ||
|
||||
(atomic_read(&efx->rxq_flush_outstanding) < EFX_RX_FLUSH_COUNT
|
||||
&& atomic_read(&efx->rxq_flush_pending) > 0));
|
||||
}
|
||||
|
||||
/* Flush all the transmit queues, and continue flushing receive queues until
|
||||
* they're all flushed. Wait for the DRAIN events to be recieved so that there
|
||||
* are no more RX and TX events left on any channel. */
|
||||
int efx_nic_flush_queues(struct efx_nic *efx)
|
||||
{
|
||||
unsigned timeout = msecs_to_jiffies(5000); /* 5s for all flushes and drains */
|
||||
struct efx_channel *channel;
|
||||
struct efx_rx_queue *rx_queue;
|
||||
struct efx_tx_queue *tx_queue;
|
||||
int rc = 0;
|
||||
|
||||
efx->fc_disable++;
|
||||
efx->type->prepare_flush(efx);
|
||||
|
||||
efx_for_each_channel(channel, efx) {
|
||||
efx_for_each_channel_tx_queue(tx_queue, channel) {
|
||||
atomic_inc(&efx->drain_pending);
|
||||
efx_flush_tx_queue(tx_queue);
|
||||
}
|
||||
efx_for_each_channel_rx_queue(rx_queue, channel) {
|
||||
atomic_inc(&efx->drain_pending);
|
||||
rx_queue->flush_pending = true;
|
||||
atomic_inc(&efx->rxq_flush_pending);
|
||||
}
|
||||
}
|
||||
|
||||
while (timeout && atomic_read(&efx->drain_pending) > 0) {
|
||||
/* If SRIOV is enabled, then offload receive queue flushing to
|
||||
* the firmware (though we will still have to poll for
|
||||
* completion). If that fails, fall back to the old scheme.
|
||||
*/
|
||||
if (efx_sriov_enabled(efx)) {
|
||||
rc = efx_mcdi_flush_rxqs(efx);
|
||||
if (!rc)
|
||||
goto wait;
|
||||
}
|
||||
|
||||
/* The hardware supports four concurrent rx flushes, each of
|
||||
* which may need to be retried if there is an outstanding
|
||||
* descriptor fetch
|
||||
*/
|
||||
efx_for_each_channel(channel, efx) {
|
||||
efx_for_each_channel_rx_queue(rx_queue, channel) {
|
||||
if (atomic_read(&efx->rxq_flush_outstanding) >=
|
||||
EFX_RX_FLUSH_COUNT)
|
||||
break;
|
||||
|
||||
if (rx_queue->flush_pending) {
|
||||
rx_queue->flush_pending = false;
|
||||
atomic_dec(&efx->rxq_flush_pending);
|
||||
atomic_inc(&efx->rxq_flush_outstanding);
|
||||
efx_flush_rx_queue(rx_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wait:
|
||||
timeout = wait_event_timeout(efx->flush_wq, efx_flush_wake(efx),
|
||||
timeout);
|
||||
}
|
||||
|
||||
if (atomic_read(&efx->drain_pending)) {
|
||||
netif_err(efx, hw, efx->net_dev, "failed to flush %d queues "
|
||||
"(rx %d+%d)\n", atomic_read(&efx->drain_pending),
|
||||
atomic_read(&efx->rxq_flush_outstanding),
|
||||
atomic_read(&efx->rxq_flush_pending));
|
||||
rc = -ETIMEDOUT;
|
||||
|
||||
atomic_set(&efx->drain_pending, 0);
|
||||
atomic_set(&efx->rxq_flush_pending, 0);
|
||||
atomic_set(&efx->rxq_flush_outstanding, 0);
|
||||
}
|
||||
|
||||
efx->fc_disable--;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Event queue processing
|
||||
@ -682,7 +772,8 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel)
|
||||
}
|
||||
|
||||
/* Use HW to insert a SW defined event */
|
||||
static void efx_generate_event(struct efx_channel *channel, efx_qword_t *event)
|
||||
void efx_generate_event(struct efx_nic *efx, unsigned int evq,
|
||||
efx_qword_t *event)
|
||||
{
|
||||
efx_oword_t drv_ev_reg;
|
||||
|
||||
@ -692,8 +783,18 @@ static void efx_generate_event(struct efx_channel *channel, efx_qword_t *event)
|
||||
drv_ev_reg.u32[1] = event->u32[1];
|
||||
drv_ev_reg.u32[2] = 0;
|
||||
drv_ev_reg.u32[3] = 0;
|
||||
EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, channel->channel);
|
||||
efx_writeo(channel->efx, &drv_ev_reg, FR_AZ_DRV_EV);
|
||||
EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, evq);
|
||||
efx_writeo(efx, &drv_ev_reg, FR_AZ_DRV_EV);
|
||||
}
|
||||
|
||||
static void efx_magic_event(struct efx_channel *channel, u32 magic)
|
||||
{
|
||||
efx_qword_t event;
|
||||
|
||||
EFX_POPULATE_QWORD_2(event, FSF_AZ_EV_CODE,
|
||||
FSE_AZ_EV_CODE_DRV_GEN_EV,
|
||||
FSF_AZ_DRV_GEN_EV_MAGIC, magic);
|
||||
efx_generate_event(channel->efx, channel->channel, &event);
|
||||
}
|
||||
|
||||
/* Handle a transmit completion event
|
||||
@ -710,6 +811,9 @@ efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
|
||||
struct efx_nic *efx = channel->efx;
|
||||
int tx_packets = 0;
|
||||
|
||||
if (unlikely(ACCESS_ONCE(efx->reset_pending)))
|
||||
return 0;
|
||||
|
||||
if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) {
|
||||
/* Transmit completion */
|
||||
tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR);
|
||||
@ -851,6 +955,10 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
|
||||
bool rx_ev_pkt_ok;
|
||||
u16 flags;
|
||||
struct efx_rx_queue *rx_queue;
|
||||
struct efx_nic *efx = channel->efx;
|
||||
|
||||
if (unlikely(ACCESS_ONCE(efx->reset_pending)))
|
||||
return;
|
||||
|
||||
/* Basic packet information */
|
||||
rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT);
|
||||
@ -897,24 +1005,101 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
|
||||
efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, flags);
|
||||
}
|
||||
|
||||
/* If this flush done event corresponds to a &struct efx_tx_queue, then
|
||||
* send an %EFX_CHANNEL_MAGIC_TX_DRAIN event to drain the event queue
|
||||
* of all transmit completions.
|
||||
*/
|
||||
static void
|
||||
efx_handle_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
|
||||
{
|
||||
struct efx_tx_queue *tx_queue;
|
||||
int qid;
|
||||
|
||||
qid = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA);
|
||||
if (qid < EFX_TXQ_TYPES * efx->n_tx_channels) {
|
||||
tx_queue = efx_get_tx_queue(efx, qid / EFX_TXQ_TYPES,
|
||||
qid % EFX_TXQ_TYPES);
|
||||
|
||||
efx_magic_event(tx_queue->channel,
|
||||
EFX_CHANNEL_MAGIC_TX_DRAIN(tx_queue));
|
||||
}
|
||||
}
|
||||
|
||||
/* If this flush done event corresponds to a &struct efx_rx_queue: If the flush
|
||||
* was succesful then send an %EFX_CHANNEL_MAGIC_RX_DRAIN, otherwise add
|
||||
* the RX queue back to the mask of RX queues in need of flushing.
|
||||
*/
|
||||
static void
|
||||
efx_handle_rx_flush_done(struct efx_nic *efx, efx_qword_t *event)
|
||||
{
|
||||
struct efx_channel *channel;
|
||||
struct efx_rx_queue *rx_queue;
|
||||
int qid;
|
||||
bool failed;
|
||||
|
||||
qid = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
|
||||
failed = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
|
||||
if (qid >= efx->n_channels)
|
||||
return;
|
||||
channel = efx_get_channel(efx, qid);
|
||||
if (!efx_channel_has_rx_queue(channel))
|
||||
return;
|
||||
rx_queue = efx_channel_get_rx_queue(channel);
|
||||
|
||||
if (failed) {
|
||||
netif_info(efx, hw, efx->net_dev,
|
||||
"RXQ %d flush retry\n", qid);
|
||||
rx_queue->flush_pending = true;
|
||||
atomic_inc(&efx->rxq_flush_pending);
|
||||
} else {
|
||||
efx_magic_event(efx_rx_queue_channel(rx_queue),
|
||||
EFX_CHANNEL_MAGIC_RX_DRAIN(rx_queue));
|
||||
}
|
||||
atomic_dec(&efx->rxq_flush_outstanding);
|
||||
if (efx_flush_wake(efx))
|
||||
wake_up(&efx->flush_wq);
|
||||
}
|
||||
|
||||
static void
|
||||
efx_handle_drain_event(struct efx_channel *channel)
|
||||
{
|
||||
struct efx_nic *efx = channel->efx;
|
||||
|
||||
WARN_ON(atomic_read(&efx->drain_pending) == 0);
|
||||
atomic_dec(&efx->drain_pending);
|
||||
if (efx_flush_wake(efx))
|
||||
wake_up(&efx->flush_wq);
|
||||
}
|
||||
|
||||
static void
|
||||
efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
|
||||
{
|
||||
struct efx_nic *efx = channel->efx;
|
||||
unsigned code;
|
||||
struct efx_rx_queue *rx_queue =
|
||||
efx_channel_has_rx_queue(channel) ?
|
||||
efx_channel_get_rx_queue(channel) : NULL;
|
||||
unsigned magic, code;
|
||||
|
||||
code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
|
||||
if (code == EFX_CHANNEL_MAGIC_TEST(channel))
|
||||
; /* ignore */
|
||||
else if (code == EFX_CHANNEL_MAGIC_FILL(channel))
|
||||
magic = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
|
||||
code = _EFX_CHANNEL_MAGIC_CODE(magic);
|
||||
|
||||
if (magic == EFX_CHANNEL_MAGIC_TEST(channel)) {
|
||||
/* ignore */
|
||||
} else if (rx_queue && magic == EFX_CHANNEL_MAGIC_FILL(rx_queue)) {
|
||||
/* The queue must be empty, so we won't receive any rx
|
||||
* events, so efx_process_channel() won't refill the
|
||||
* queue. Refill it here */
|
||||
efx_fast_push_rx_descriptors(efx_channel_get_rx_queue(channel));
|
||||
else
|
||||
efx_fast_push_rx_descriptors(rx_queue);
|
||||
} else if (rx_queue && magic == EFX_CHANNEL_MAGIC_RX_DRAIN(rx_queue)) {
|
||||
rx_queue->enabled = false;
|
||||
efx_handle_drain_event(channel);
|
||||
} else if (code == _EFX_CHANNEL_MAGIC_TX_DRAIN) {
|
||||
efx_handle_drain_event(channel);
|
||||
} else {
|
||||
netif_dbg(efx, hw, efx->net_dev, "channel %d received "
|
||||
"generated event "EFX_QWORD_FMT"\n",
|
||||
channel->channel, EFX_QWORD_VAL(*event));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -931,10 +1116,14 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
|
||||
case FSE_AZ_TX_DESCQ_FLS_DONE_EV:
|
||||
netif_vdbg(efx, hw, efx->net_dev, "channel %d TXQ %d flushed\n",
|
||||
channel->channel, ev_sub_data);
|
||||
efx_handle_tx_flush_done(efx, event);
|
||||
efx_sriov_tx_flush_done(efx, event);
|
||||
break;
|
||||
case FSE_AZ_RX_DESCQ_FLS_DONE_EV:
|
||||
netif_vdbg(efx, hw, efx->net_dev, "channel %d RXQ %d flushed\n",
|
||||
channel->channel, ev_sub_data);
|
||||
efx_handle_rx_flush_done(efx, event);
|
||||
efx_sriov_rx_flush_done(efx, event);
|
||||
break;
|
||||
case FSE_AZ_EVQ_INIT_DONE_EV:
|
||||
netif_dbg(efx, hw, efx->net_dev,
|
||||
@ -966,16 +1155,24 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
|
||||
RESET_TYPE_DISABLE);
|
||||
break;
|
||||
case FSE_BZ_RX_DSC_ERROR_EV:
|
||||
netif_err(efx, rx_err, efx->net_dev,
|
||||
"RX DMA Q %d reports descriptor fetch error."
|
||||
" RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
|
||||
efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
|
||||
if (ev_sub_data < EFX_VI_BASE) {
|
||||
netif_err(efx, rx_err, efx->net_dev,
|
||||
"RX DMA Q %d reports descriptor fetch error."
|
||||
" RX Q %d is disabled.\n", ev_sub_data,
|
||||
ev_sub_data);
|
||||
efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
|
||||
} else
|
||||
efx_sriov_desc_fetch_err(efx, ev_sub_data);
|
||||
break;
|
||||
case FSE_BZ_TX_DSC_ERROR_EV:
|
||||
netif_err(efx, tx_err, efx->net_dev,
|
||||
"TX DMA Q %d reports descriptor fetch error."
|
||||
" TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
|
||||
efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
|
||||
if (ev_sub_data < EFX_VI_BASE) {
|
||||
netif_err(efx, tx_err, efx->net_dev,
|
||||
"TX DMA Q %d reports descriptor fetch error."
|
||||
" TX Q %d is disabled.\n", ev_sub_data,
|
||||
ev_sub_data);
|
||||
efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
|
||||
} else
|
||||
efx_sriov_desc_fetch_err(efx, ev_sub_data);
|
||||
break;
|
||||
default:
|
||||
netif_vdbg(efx, hw, efx->net_dev,
|
||||
@ -1035,6 +1232,9 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
|
||||
case FSE_AZ_EV_CODE_DRIVER_EV:
|
||||
efx_handle_driver_event(channel, &event);
|
||||
break;
|
||||
case FSE_CZ_EV_CODE_USER_EV:
|
||||
efx_sriov_event(channel, &event);
|
||||
break;
|
||||
case FSE_CZ_EV_CODE_MCDI_EV:
|
||||
efx_mcdi_process_event(channel, &event);
|
||||
break;
|
||||
@ -1135,161 +1335,13 @@ void efx_nic_remove_eventq(struct efx_channel *channel)
|
||||
|
||||
void efx_nic_generate_test_event(struct efx_channel *channel)
|
||||
{
|
||||
unsigned int magic = EFX_CHANNEL_MAGIC_TEST(channel);
|
||||
efx_qword_t test_event;
|
||||
|
||||
EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
|
||||
FSE_AZ_EV_CODE_DRV_GEN_EV,
|
||||
FSF_AZ_DRV_GEN_EV_MAGIC, magic);
|
||||
efx_generate_event(channel, &test_event);
|
||||
efx_magic_event(channel, EFX_CHANNEL_MAGIC_TEST(channel));
|
||||
}
|
||||
|
||||
void efx_nic_generate_fill_event(struct efx_channel *channel)
|
||||
void efx_nic_generate_fill_event(struct efx_rx_queue *rx_queue)
|
||||
{
|
||||
unsigned int magic = EFX_CHANNEL_MAGIC_FILL(channel);
|
||||
efx_qword_t test_event;
|
||||
|
||||
EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
|
||||
FSE_AZ_EV_CODE_DRV_GEN_EV,
|
||||
FSF_AZ_DRV_GEN_EV_MAGIC, magic);
|
||||
efx_generate_event(channel, &test_event);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Flush handling
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
static void efx_poll_flush_events(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_channel *channel = efx_get_channel(efx, 0);
|
||||
struct efx_tx_queue *tx_queue;
|
||||
struct efx_rx_queue *rx_queue;
|
||||
unsigned int read_ptr = channel->eventq_read_ptr;
|
||||
unsigned int end_ptr = read_ptr + channel->eventq_mask - 1;
|
||||
|
||||
do {
|
||||
efx_qword_t *event = efx_event(channel, read_ptr);
|
||||
int ev_code, ev_sub_code, ev_queue;
|
||||
bool ev_failed;
|
||||
|
||||
if (!efx_event_present(event))
|
||||
break;
|
||||
|
||||
ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE);
|
||||
ev_sub_code = EFX_QWORD_FIELD(*event,
|
||||
FSF_AZ_DRIVER_EV_SUBCODE);
|
||||
if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
|
||||
ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) {
|
||||
ev_queue = EFX_QWORD_FIELD(*event,
|
||||
FSF_AZ_DRIVER_EV_SUBDATA);
|
||||
if (ev_queue < EFX_TXQ_TYPES * efx->n_tx_channels) {
|
||||
tx_queue = efx_get_tx_queue(
|
||||
efx, ev_queue / EFX_TXQ_TYPES,
|
||||
ev_queue % EFX_TXQ_TYPES);
|
||||
tx_queue->flushed = FLUSH_DONE;
|
||||
}
|
||||
} else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
|
||||
ev_sub_code == FSE_AZ_RX_DESCQ_FLS_DONE_EV) {
|
||||
ev_queue = EFX_QWORD_FIELD(
|
||||
*event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
|
||||
ev_failed = EFX_QWORD_FIELD(
|
||||
*event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
|
||||
if (ev_queue < efx->n_rx_channels) {
|
||||
rx_queue = efx_get_rx_queue(efx, ev_queue);
|
||||
rx_queue->flushed =
|
||||
ev_failed ? FLUSH_FAILED : FLUSH_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* We're about to destroy the queue anyway, so
|
||||
* it's ok to throw away every non-flush event */
|
||||
EFX_SET_QWORD(*event);
|
||||
|
||||
++read_ptr;
|
||||
} while (read_ptr != end_ptr);
|
||||
|
||||
channel->eventq_read_ptr = read_ptr;
|
||||
}
|
||||
|
||||
/* Handle tx and rx flushes at the same time, since they run in
|
||||
* parallel in the hardware and there's no reason for us to
|
||||
* serialise them */
|
||||
int efx_nic_flush_queues(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_channel *channel;
|
||||
struct efx_rx_queue *rx_queue;
|
||||
struct efx_tx_queue *tx_queue;
|
||||
int i, tx_pending, rx_pending;
|
||||
|
||||
/* If necessary prepare the hardware for flushing */
|
||||
efx->type->prepare_flush(efx);
|
||||
|
||||
/* Flush all tx queues in parallel */
|
||||
efx_for_each_channel(channel, efx) {
|
||||
efx_for_each_possible_channel_tx_queue(tx_queue, channel) {
|
||||
if (tx_queue->initialised)
|
||||
efx_flush_tx_queue(tx_queue);
|
||||
}
|
||||
}
|
||||
|
||||
/* The hardware supports four concurrent rx flushes, each of which may
|
||||
* need to be retried if there is an outstanding descriptor fetch */
|
||||
for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) {
|
||||
rx_pending = tx_pending = 0;
|
||||
efx_for_each_channel(channel, efx) {
|
||||
efx_for_each_channel_rx_queue(rx_queue, channel) {
|
||||
if (rx_queue->flushed == FLUSH_PENDING)
|
||||
++rx_pending;
|
||||
}
|
||||
}
|
||||
efx_for_each_channel(channel, efx) {
|
||||
efx_for_each_channel_rx_queue(rx_queue, channel) {
|
||||
if (rx_pending == EFX_RX_FLUSH_COUNT)
|
||||
break;
|
||||
if (rx_queue->flushed == FLUSH_FAILED ||
|
||||
rx_queue->flushed == FLUSH_NONE) {
|
||||
efx_flush_rx_queue(rx_queue);
|
||||
++rx_pending;
|
||||
}
|
||||
}
|
||||
efx_for_each_possible_channel_tx_queue(tx_queue, channel) {
|
||||
if (tx_queue->initialised &&
|
||||
tx_queue->flushed != FLUSH_DONE)
|
||||
++tx_pending;
|
||||
}
|
||||
}
|
||||
|
||||
if (rx_pending == 0 && tx_pending == 0)
|
||||
return 0;
|
||||
|
||||
msleep(EFX_FLUSH_INTERVAL);
|
||||
efx_poll_flush_events(efx);
|
||||
}
|
||||
|
||||
/* Mark the queues as all flushed. We're going to return failure
|
||||
* leading to a reset, or fake up success anyway */
|
||||
efx_for_each_channel(channel, efx) {
|
||||
efx_for_each_possible_channel_tx_queue(tx_queue, channel) {
|
||||
if (tx_queue->initialised &&
|
||||
tx_queue->flushed != FLUSH_DONE)
|
||||
netif_err(efx, hw, efx->net_dev,
|
||||
"tx queue %d flush command timed out\n",
|
||||
tx_queue->queue);
|
||||
tx_queue->flushed = FLUSH_DONE;
|
||||
}
|
||||
efx_for_each_channel_rx_queue(rx_queue, channel) {
|
||||
if (rx_queue->flushed != FLUSH_DONE)
|
||||
netif_err(efx, hw, efx->net_dev,
|
||||
"rx queue %d flush command timed out\n",
|
||||
efx_rx_queue_index(rx_queue));
|
||||
rx_queue->flushed = FLUSH_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
efx_magic_event(efx_rx_queue_channel(rx_queue),
|
||||
EFX_CHANNEL_MAGIC_FILL(rx_queue));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@ -1315,18 +1367,10 @@ static inline void efx_nic_interrupts(struct efx_nic *efx,
|
||||
|
||||
void efx_nic_enable_interrupts(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_channel *channel;
|
||||
|
||||
EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
|
||||
wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
|
||||
|
||||
/* Enable interrupts */
|
||||
efx_nic_interrupts(efx, true, false);
|
||||
|
||||
/* Force processing of all the channels to get the EVQ RPTRs up to
|
||||
date */
|
||||
efx_for_each_channel(channel, efx)
|
||||
efx_schedule_channel(channel);
|
||||
}
|
||||
|
||||
void efx_nic_disable_interrupts(struct efx_nic *efx)
|
||||
@ -1593,6 +1637,58 @@ void efx_nic_fini_interrupt(struct efx_nic *efx)
|
||||
free_irq(efx->legacy_irq, efx);
|
||||
}
|
||||
|
||||
/* Looks at available SRAM resources and works out how many queues we
|
||||
* can support, and where things like descriptor caches should live.
|
||||
*
|
||||
* SRAM is split up as follows:
|
||||
* 0 buftbl entries for channels
|
||||
* efx->vf_buftbl_base buftbl entries for SR-IOV
|
||||
* efx->rx_dc_base RX descriptor caches
|
||||
* efx->tx_dc_base TX descriptor caches
|
||||
*/
|
||||
void efx_nic_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw)
|
||||
{
|
||||
unsigned vi_count, buftbl_min;
|
||||
|
||||
/* Account for the buffer table entries backing the datapath channels
|
||||
* and the descriptor caches for those channels.
|
||||
*/
|
||||
buftbl_min = ((efx->n_rx_channels * EFX_MAX_DMAQ_SIZE +
|
||||
efx->n_tx_channels * EFX_TXQ_TYPES * EFX_MAX_DMAQ_SIZE +
|
||||
efx->n_channels * EFX_MAX_EVQ_SIZE)
|
||||
* sizeof(efx_qword_t) / EFX_BUF_SIZE);
|
||||
vi_count = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES);
|
||||
|
||||
#ifdef CONFIG_SFC_SRIOV
|
||||
if (efx_sriov_wanted(efx)) {
|
||||
unsigned vi_dc_entries, buftbl_free, entries_per_vf, vf_limit;
|
||||
|
||||
efx->vf_buftbl_base = buftbl_min;
|
||||
|
||||
vi_dc_entries = RX_DC_ENTRIES + TX_DC_ENTRIES;
|
||||
vi_count = max(vi_count, EFX_VI_BASE);
|
||||
buftbl_free = (sram_lim_qw - buftbl_min -
|
||||
vi_count * vi_dc_entries);
|
||||
|
||||
entries_per_vf = ((vi_dc_entries + EFX_VF_BUFTBL_PER_VI) *
|
||||
efx_vf_size(efx));
|
||||
vf_limit = min(buftbl_free / entries_per_vf,
|
||||
(1024U - EFX_VI_BASE) >> efx->vi_scale);
|
||||
|
||||
if (efx->vf_count > vf_limit) {
|
||||
netif_err(efx, probe, efx->net_dev,
|
||||
"Reducing VF count from from %d to %d\n",
|
||||
efx->vf_count, vf_limit);
|
||||
efx->vf_count = vf_limit;
|
||||
}
|
||||
vi_count += efx->vf_count * efx_vf_size(efx);
|
||||
}
|
||||
#endif
|
||||
|
||||
efx->tx_dc_base = sram_lim_qw - vi_count * TX_DC_ENTRIES;
|
||||
efx->rx_dc_base = efx->tx_dc_base - vi_count * RX_DC_ENTRIES;
|
||||
}
|
||||
|
||||
u32 efx_nic_fpga_ver(struct efx_nic *efx)
|
||||
{
|
||||
efx_oword_t altera_build;
|
||||
@ -1605,11 +1701,9 @@ void efx_nic_init_common(struct efx_nic *efx)
|
||||
efx_oword_t temp;
|
||||
|
||||
/* Set positions of descriptor caches in SRAM. */
|
||||
EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR,
|
||||
efx->type->tx_dc_base / 8);
|
||||
EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, efx->tx_dc_base);
|
||||
efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG);
|
||||
EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR,
|
||||
efx->type->rx_dc_base / 8);
|
||||
EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR, efx->rx_dc_base);
|
||||
efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG);
|
||||
|
||||
/* Set TX descriptor cache size. */
|
||||
|
@ -65,6 +65,11 @@ enum {
|
||||
#define FALCON_GMAC_LOOPBACKS \
|
||||
(1 << LOOPBACK_GMAC)
|
||||
|
||||
/* Alignment of PCIe DMA boundaries (4KB) */
|
||||
#define EFX_PAGE_SIZE 4096
|
||||
/* Size and alignment of buffer table entries (same) */
|
||||
#define EFX_BUF_SIZE EFX_PAGE_SIZE
|
||||
|
||||
/**
|
||||
* struct falcon_board_type - board operations and type information
|
||||
* @id: Board type id, as found in NVRAM
|
||||
@ -164,6 +169,95 @@ static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On the SFC9000 family each port is associated with 1 PCI physical
|
||||
* function (PF) handled by sfc and a configurable number of virtual
|
||||
* functions (VFs) that may be handled by some other driver, often in
|
||||
* a VM guest. The queue pointer registers are mapped in both PF and
|
||||
* VF BARs such that an 8K region provides access to a single RX, TX
|
||||
* and event queue (collectively a Virtual Interface, VI or VNIC).
|
||||
*
|
||||
* The PF has access to all 1024 VIs while VFs are mapped to VIs
|
||||
* according to VI_BASE and VI_SCALE: VF i has access to VIs numbered
|
||||
* in range [VI_BASE + i << VI_SCALE, VI_BASE + i + 1 << VI_SCALE).
|
||||
* The number of VIs and the VI_SCALE value are configurable but must
|
||||
* be established at boot time by firmware.
|
||||
*/
|
||||
|
||||
/* Maximum VI_SCALE parameter supported by Siena */
|
||||
#define EFX_VI_SCALE_MAX 6
|
||||
/* Base VI to use for SR-IOV. Must be aligned to (1 << EFX_VI_SCALE_MAX),
|
||||
* so this is the smallest allowed value. */
|
||||
#define EFX_VI_BASE 128U
|
||||
/* Maximum number of VFs allowed */
|
||||
#define EFX_VF_COUNT_MAX 127
|
||||
/* Limit EVQs on VFs to be only 8k to reduce buffer table reservation */
|
||||
#define EFX_MAX_VF_EVQ_SIZE 8192UL
|
||||
/* The number of buffer table entries reserved for each VI on a VF */
|
||||
#define EFX_VF_BUFTBL_PER_VI \
|
||||
((EFX_MAX_VF_EVQ_SIZE + 2 * EFX_MAX_DMAQ_SIZE) * \
|
||||
sizeof(efx_qword_t) / EFX_BUF_SIZE)
|
||||
|
||||
#ifdef CONFIG_SFC_SRIOV
|
||||
|
||||
static inline bool efx_sriov_wanted(struct efx_nic *efx)
|
||||
{
|
||||
return efx->vf_count != 0;
|
||||
}
|
||||
static inline bool efx_sriov_enabled(struct efx_nic *efx)
|
||||
{
|
||||
return efx->vf_init_count != 0;
|
||||
}
|
||||
static inline unsigned int efx_vf_size(struct efx_nic *efx)
|
||||
{
|
||||
return 1 << efx->vi_scale;
|
||||
}
|
||||
|
||||
extern int efx_init_sriov(void);
|
||||
extern void efx_sriov_probe(struct efx_nic *efx);
|
||||
extern int efx_sriov_init(struct efx_nic *efx);
|
||||
extern void efx_sriov_mac_address_changed(struct efx_nic *efx);
|
||||
extern void efx_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event);
|
||||
extern void efx_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event);
|
||||
extern void efx_sriov_event(struct efx_channel *channel, efx_qword_t *event);
|
||||
extern void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq);
|
||||
extern void efx_sriov_flr(struct efx_nic *efx, unsigned flr);
|
||||
extern void efx_sriov_reset(struct efx_nic *efx);
|
||||
extern void efx_sriov_fini(struct efx_nic *efx);
|
||||
extern void efx_fini_sriov(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline bool efx_sriov_wanted(struct efx_nic *efx) { return false; }
|
||||
static inline bool efx_sriov_enabled(struct efx_nic *efx) { return false; }
|
||||
static inline unsigned int efx_vf_size(struct efx_nic *efx) { return 0; }
|
||||
|
||||
static inline int efx_init_sriov(void) { return 0; }
|
||||
static inline void efx_sriov_probe(struct efx_nic *efx) {}
|
||||
static inline int efx_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
|
||||
static inline void efx_sriov_mac_address_changed(struct efx_nic *efx) {}
|
||||
static inline void efx_sriov_tx_flush_done(struct efx_nic *efx,
|
||||
efx_qword_t *event) {}
|
||||
static inline void efx_sriov_rx_flush_done(struct efx_nic *efx,
|
||||
efx_qword_t *event) {}
|
||||
static inline void efx_sriov_event(struct efx_channel *channel,
|
||||
efx_qword_t *event) {}
|
||||
static inline void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq) {}
|
||||
static inline void efx_sriov_flr(struct efx_nic *efx, unsigned flr) {}
|
||||
static inline void efx_sriov_reset(struct efx_nic *efx) {}
|
||||
static inline void efx_sriov_fini(struct efx_nic *efx) {}
|
||||
static inline void efx_fini_sriov(void) {}
|
||||
|
||||
#endif
|
||||
|
||||
extern int efx_sriov_set_vf_mac(struct net_device *dev, int vf, u8 *mac);
|
||||
extern int efx_sriov_set_vf_vlan(struct net_device *dev, int vf,
|
||||
u16 vlan, u8 qos);
|
||||
extern int efx_sriov_get_vf_config(struct net_device *dev, int vf,
|
||||
struct ifla_vf_info *ivf);
|
||||
extern int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf,
|
||||
bool spoofchk);
|
||||
|
||||
extern const struct efx_nic_type falcon_a1_nic_type;
|
||||
extern const struct efx_nic_type falcon_b0_nic_type;
|
||||
extern const struct efx_nic_type siena_a0_nic_type;
|
||||
@ -190,6 +284,7 @@ extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_nic_generate_fill_event(struct efx_rx_queue *rx_queue);
|
||||
|
||||
/* Event data path */
|
||||
extern int efx_nic_probe_eventq(struct efx_channel *channel);
|
||||
@ -211,7 +306,6 @@ extern void falcon_update_stats_xmac(struct efx_nic *efx);
|
||||
extern int efx_nic_init_interrupt(struct efx_nic *efx);
|
||||
extern void efx_nic_enable_interrupts(struct efx_nic *efx);
|
||||
extern void efx_nic_generate_test_event(struct efx_channel *channel);
|
||||
extern void efx_nic_generate_fill_event(struct efx_channel *channel);
|
||||
extern void efx_nic_generate_interrupt(struct efx_nic *efx);
|
||||
extern void efx_nic_disable_interrupts(struct efx_nic *efx);
|
||||
extern void efx_nic_fini_interrupt(struct efx_nic *efx);
|
||||
@ -225,6 +319,8 @@ extern void falcon_start_nic_stats(struct efx_nic *efx);
|
||||
extern void falcon_stop_nic_stats(struct efx_nic *efx);
|
||||
extern void falcon_setup_xaui(struct efx_nic *efx);
|
||||
extern int falcon_reset_xaui(struct efx_nic *efx);
|
||||
extern void
|
||||
efx_nic_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw);
|
||||
extern void efx_nic_init_common(struct efx_nic *efx);
|
||||
extern void efx_nic_push_rx_indir_table(struct efx_nic *efx);
|
||||
|
||||
@ -278,8 +374,8 @@ extern void efx_nic_get_regs(struct efx_nic *efx, void *buf);
|
||||
#define MAC_DATA_LBN 0
|
||||
#define MAC_DATA_WIDTH 32
|
||||
|
||||
extern void efx_nic_generate_event(struct efx_channel *channel,
|
||||
efx_qword_t *event);
|
||||
extern void efx_generate_event(struct efx_nic *efx, unsigned int evq,
|
||||
efx_qword_t *event);
|
||||
|
||||
extern void falcon_poll_xmac(struct efx_nic *efx);
|
||||
|
||||
|
@ -2446,8 +2446,8 @@
|
||||
#define FRF_CZ_RMFT_RXQ_ID_WIDTH 12
|
||||
#define FRF_CZ_RMFT_WILDCARD_MATCH_LBN 60
|
||||
#define FRF_CZ_RMFT_WILDCARD_MATCH_WIDTH 1
|
||||
#define FRF_CZ_RMFT_DEST_MAC_LBN 16
|
||||
#define FRF_CZ_RMFT_DEST_MAC_WIDTH 44
|
||||
#define FRF_CZ_RMFT_DEST_MAC_LBN 12
|
||||
#define FRF_CZ_RMFT_DEST_MAC_WIDTH 48
|
||||
#define FRF_CZ_RMFT_VLAN_ID_LBN 0
|
||||
#define FRF_CZ_RMFT_VLAN_ID_WIDTH 12
|
||||
|
||||
@ -2523,8 +2523,8 @@
|
||||
#define FRF_CZ_TMFT_TXQ_ID_WIDTH 12
|
||||
#define FRF_CZ_TMFT_WILDCARD_MATCH_LBN 60
|
||||
#define FRF_CZ_TMFT_WILDCARD_MATCH_WIDTH 1
|
||||
#define FRF_CZ_TMFT_SRC_MAC_LBN 16
|
||||
#define FRF_CZ_TMFT_SRC_MAC_WIDTH 44
|
||||
#define FRF_CZ_TMFT_SRC_MAC_LBN 12
|
||||
#define FRF_CZ_TMFT_SRC_MAC_WIDTH 48
|
||||
#define FRF_CZ_TMFT_VLAN_ID_LBN 0
|
||||
#define FRF_CZ_TMFT_VLAN_ID_WIDTH 12
|
||||
|
||||
@ -2895,17 +2895,17 @@
|
||||
|
||||
/* RX_MAC_FILTER_TBL0 */
|
||||
/* RMFT_DEST_MAC is wider than 32 bits */
|
||||
#define FRF_CZ_RMFT_DEST_MAC_LO_LBN 12
|
||||
#define FRF_CZ_RMFT_DEST_MAC_LO_LBN FRF_CZ_RMFT_DEST_MAC_LBN
|
||||
#define FRF_CZ_RMFT_DEST_MAC_LO_WIDTH 32
|
||||
#define FRF_CZ_RMFT_DEST_MAC_HI_LBN 44
|
||||
#define FRF_CZ_RMFT_DEST_MAC_HI_WIDTH 16
|
||||
#define FRF_CZ_RMFT_DEST_MAC_HI_LBN (FRF_CZ_RMFT_DEST_MAC_LBN + 32)
|
||||
#define FRF_CZ_RMFT_DEST_MAC_HI_WIDTH (FRF_CZ_RMFT_DEST_MAC_WIDTH - 32)
|
||||
|
||||
/* TX_MAC_FILTER_TBL0 */
|
||||
/* TMFT_SRC_MAC is wider than 32 bits */
|
||||
#define FRF_CZ_TMFT_SRC_MAC_LO_LBN 12
|
||||
#define FRF_CZ_TMFT_SRC_MAC_LO_LBN FRF_CZ_TMFT_SRC_MAC_LBN
|
||||
#define FRF_CZ_TMFT_SRC_MAC_LO_WIDTH 32
|
||||
#define FRF_CZ_TMFT_SRC_MAC_HI_LBN 44
|
||||
#define FRF_CZ_TMFT_SRC_MAC_HI_WIDTH 16
|
||||
#define FRF_CZ_TMFT_SRC_MAC_HI_LBN (FRF_CZ_TMFT_SRC_MAC_LBN + 32)
|
||||
#define FRF_CZ_TMFT_SRC_MAC_HI_WIDTH (FRF_CZ_TMFT_SRC_MAC_WIDTH - 32)
|
||||
|
||||
/* TX_PACE_TBL */
|
||||
/* Values >20 are documented as reserved, but will result in a queue going
|
||||
|
@ -405,10 +405,9 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
|
||||
void efx_rx_slow_fill(unsigned long context)
|
||||
{
|
||||
struct efx_rx_queue *rx_queue = (struct efx_rx_queue *)context;
|
||||
struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
|
||||
|
||||
/* Post an event to cause NAPI to run and refill the queue */
|
||||
efx_nic_generate_fill_event(channel);
|
||||
efx_nic_generate_fill_event(rx_queue);
|
||||
++rx_queue->slow_fill_count;
|
||||
}
|
||||
|
||||
@ -706,6 +705,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
|
||||
rx_queue->fast_fill_limit = limit;
|
||||
|
||||
/* Set up RX descriptor ring */
|
||||
rx_queue->enabled = true;
|
||||
efx_nic_init_rx(rx_queue);
|
||||
}
|
||||
|
||||
@ -717,6 +717,9 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
|
||||
netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
|
||||
"shutting down RX queue %d\n", efx_rx_queue_index(rx_queue));
|
||||
|
||||
/* A flush failure might have left rx_queue->enabled */
|
||||
rx_queue->enabled = false;
|
||||
|
||||
del_timer_sync(&rx_queue->slow_fill);
|
||||
efx_nic_fini_rx(rx_queue);
|
||||
|
||||
|
@ -225,6 +225,15 @@ static int siena_probe_nvconfig(struct efx_nic *efx)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void siena_dimension_resources(struct efx_nic *efx)
|
||||
{
|
||||
/* Each port has a small block of internal SRAM dedicated to
|
||||
* the buffer table and descriptor caches. In theory we can
|
||||
* map both blocks to one port, but we don't.
|
||||
*/
|
||||
efx_nic_dimension_resources(efx, FR_CZ_BUF_FULL_TBL_ROWS / 2);
|
||||
}
|
||||
|
||||
static int siena_probe_nic(struct efx_nic *efx)
|
||||
{
|
||||
struct siena_nic_data *nic_data;
|
||||
@ -304,6 +313,8 @@ static int siena_probe_nic(struct efx_nic *efx)
|
||||
if (rc)
|
||||
goto fail5;
|
||||
|
||||
efx_sriov_probe(efx);
|
||||
|
||||
return 0;
|
||||
|
||||
fail5:
|
||||
@ -619,6 +630,7 @@ const struct efx_nic_type siena_a0_nic_type = {
|
||||
.probe = siena_probe_nic,
|
||||
.remove = siena_remove_nic,
|
||||
.init = siena_init_nic,
|
||||
.dimension_resources = siena_dimension_resources,
|
||||
.fini = efx_port_dummy_op_void,
|
||||
.monitor = NULL,
|
||||
.map_reset_reason = siena_map_reset_reason,
|
||||
@ -657,8 +669,6 @@ const struct efx_nic_type siena_a0_nic_type = {
|
||||
* interrupt handler only supports 32
|
||||
* channels */
|
||||
.timer_period_max = 1 << FRF_CZ_TC_TIMER_VAL_WIDTH,
|
||||
.tx_dc_base = 0x88000,
|
||||
.rx_dc_base = 0x68000,
|
||||
.offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
|
||||
NETIF_F_RXHASH | NETIF_F_NTUPLE),
|
||||
};
|
||||
|
1642
drivers/net/ethernet/sfc/siena_sriov.c
Normal file
1642
drivers/net/ethernet/sfc/siena_sriov.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -110,7 +110,7 @@ efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr)
|
||||
* little benefit from using descriptors that cross those
|
||||
* boundaries and we keep things simple by not doing so.
|
||||
*/
|
||||
unsigned len = (~dma_addr & 0xfff) + 1;
|
||||
unsigned len = (~dma_addr & (EFX_PAGE_SIZE - 1)) + 1;
|
||||
|
||||
/* Work around hardware bug for unaligned buffers. */
|
||||
if (EFX_WORKAROUND_5391(efx) && (dma_addr & 0xf))
|
||||
|
254
drivers/net/ethernet/sfc/vfdi.h
Normal file
254
drivers/net/ethernet/sfc/vfdi.h
Normal file
@ -0,0 +1,254 @@
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare Solarstorm network controllers and boards
|
||||
* Copyright 2010-2012 Solarflare Communications Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, incorporated herein by reference.
|
||||
*/
|
||||
#ifndef _VFDI_H
|
||||
#define _VFDI_H
|
||||
|
||||
/**
|
||||
* DOC: Virtual Function Driver Interface
|
||||
*
|
||||
* This file contains software structures used to form a two way
|
||||
* communication channel between the VF driver and the PF driver,
|
||||
* named Virtual Function Driver Interface (VFDI).
|
||||
*
|
||||
* For the purposes of VFDI, a page is a memory region with size and
|
||||
* alignment of 4K. All addresses are DMA addresses to be used within
|
||||
* the domain of the relevant VF.
|
||||
*
|
||||
* The only hardware-defined channels for a VF driver to communicate
|
||||
* with the PF driver are the event mailboxes (%FR_CZ_USR_EV
|
||||
* registers). Writing to these registers generates an event with
|
||||
* EV_CODE = EV_CODE_USR_EV, USER_QID set to the index of the mailbox
|
||||
* and USER_EV_REG_VALUE set to the value written. The PF driver may
|
||||
* direct or disable delivery of these events by setting
|
||||
* %FR_CZ_USR_EV_CFG.
|
||||
*
|
||||
* The PF driver can send arbitrary events to arbitrary event queues.
|
||||
* However, for consistency, VFDI events from the PF are defined to
|
||||
* follow the same form and be sent to the first event queue assigned
|
||||
* to the VF while that queue is enabled by the VF driver.
|
||||
*
|
||||
* The general form of the variable bits of VFDI events is:
|
||||
*
|
||||
* 0 16 24 31
|
||||
* | DATA | TYPE | SEQ |
|
||||
*
|
||||
* SEQ is a sequence number which should be incremented by 1 (modulo
|
||||
* 256) for each event. The sequence numbers used in each direction
|
||||
* are independent.
|
||||
*
|
||||
* The VF submits requests of type &struct vfdi_req by sending the
|
||||
* address of the request (ADDR) in a series of 4 events:
|
||||
*
|
||||
* 0 16 24 31
|
||||
* | ADDR[0:15] | VFDI_EV_TYPE_REQ_WORD0 | SEQ |
|
||||
* | ADDR[16:31] | VFDI_EV_TYPE_REQ_WORD1 | SEQ+1 |
|
||||
* | ADDR[32:47] | VFDI_EV_TYPE_REQ_WORD2 | SEQ+2 |
|
||||
* | ADDR[48:63] | VFDI_EV_TYPE_REQ_WORD3 | SEQ+3 |
|
||||
*
|
||||
* The address must be page-aligned. After receiving such a valid
|
||||
* series of events, the PF driver will attempt to read the request
|
||||
* and write a response to the same address. In case of an invalid
|
||||
* sequence of events or a DMA error, there will be no response.
|
||||
*
|
||||
* The VF driver may request that the PF driver writes status
|
||||
* information into its domain asynchronously. After writing the
|
||||
* status, the PF driver will send an event of the form:
|
||||
*
|
||||
* 0 16 24 31
|
||||
* | reserved | VFDI_EV_TYPE_STATUS | SEQ |
|
||||
*
|
||||
* In case the VF must be reset for any reason, the PF driver will
|
||||
* send an event of the form:
|
||||
*
|
||||
* 0 16 24 31
|
||||
* | reserved | VFDI_EV_TYPE_RESET | SEQ |
|
||||
*
|
||||
* It is then the responsibility of the VF driver to request
|
||||
* reinitialisation of its queues.
|
||||
*/
|
||||
#define VFDI_EV_SEQ_LBN 24
|
||||
#define VFDI_EV_SEQ_WIDTH 8
|
||||
#define VFDI_EV_TYPE_LBN 16
|
||||
#define VFDI_EV_TYPE_WIDTH 8
|
||||
#define VFDI_EV_TYPE_REQ_WORD0 0
|
||||
#define VFDI_EV_TYPE_REQ_WORD1 1
|
||||
#define VFDI_EV_TYPE_REQ_WORD2 2
|
||||
#define VFDI_EV_TYPE_REQ_WORD3 3
|
||||
#define VFDI_EV_TYPE_STATUS 4
|
||||
#define VFDI_EV_TYPE_RESET 5
|
||||
#define VFDI_EV_DATA_LBN 0
|
||||
#define VFDI_EV_DATA_WIDTH 16
|
||||
|
||||
struct vfdi_endpoint {
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
__be16 tci;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum vfdi_op - VFDI operation enumeration
|
||||
* @VFDI_OP_RESPONSE: Indicates a response to the request.
|
||||
* @VFDI_OP_INIT_EVQ: Initialize SRAM entries and initialize an EVQ.
|
||||
* @VFDI_OP_INIT_RXQ: Initialize SRAM entries and initialize an RXQ.
|
||||
* @VFDI_OP_INIT_TXQ: Initialize SRAM entries and initialize a TXQ.
|
||||
* @VFDI_OP_FINI_ALL_QUEUES: Flush all queues, finalize all queues, then
|
||||
* finalize the SRAM entries.
|
||||
* @VFDI_OP_INSERT_FILTER: Insert a MAC filter targetting the given RXQ.
|
||||
* @VFDI_OP_REMOVE_ALL_FILTERS: Remove all filters.
|
||||
* @VFDI_OP_SET_STATUS_PAGE: Set the DMA page(s) used for status updates
|
||||
* from PF and write the initial status.
|
||||
* @VFDI_OP_CLEAR_STATUS_PAGE: Clear the DMA page(s) used for status
|
||||
* updates from PF.
|
||||
*/
|
||||
enum vfdi_op {
|
||||
VFDI_OP_RESPONSE = 0,
|
||||
VFDI_OP_INIT_EVQ = 1,
|
||||
VFDI_OP_INIT_RXQ = 2,
|
||||
VFDI_OP_INIT_TXQ = 3,
|
||||
VFDI_OP_FINI_ALL_QUEUES = 4,
|
||||
VFDI_OP_INSERT_FILTER = 5,
|
||||
VFDI_OP_REMOVE_ALL_FILTERS = 6,
|
||||
VFDI_OP_SET_STATUS_PAGE = 7,
|
||||
VFDI_OP_CLEAR_STATUS_PAGE = 8,
|
||||
VFDI_OP_LIMIT,
|
||||
};
|
||||
|
||||
/* Response codes for VFDI operations. Other values may be used in future. */
|
||||
#define VFDI_RC_SUCCESS 0
|
||||
#define VFDI_RC_ENOMEM (-12)
|
||||
#define VFDI_RC_EINVAL (-22)
|
||||
#define VFDI_RC_EOPNOTSUPP (-95)
|
||||
#define VFDI_RC_ETIMEDOUT (-110)
|
||||
|
||||
/**
|
||||
* struct vfdi_req - Request from VF driver to PF driver
|
||||
* @op: Operation code or response indicator, taken from &enum vfdi_op.
|
||||
* @rc: Response code. Set to 0 on success or a negative error code on failure.
|
||||
* @u.init_evq.index: Index of event queue to create.
|
||||
* @u.init_evq.buf_count: Number of 4k buffers backing event queue.
|
||||
* @u.init_evq.addr: Array of length %u.init_evq.buf_count containing DMA
|
||||
* address of each page backing the event queue.
|
||||
* @u.init_rxq.index: Index of receive queue to create.
|
||||
* @u.init_rxq.buf_count: Number of 4k buffers backing receive queue.
|
||||
* @u.init_rxq.evq: Instance of event queue to target receive events at.
|
||||
* @u.init_rxq.label: Label used in receive events.
|
||||
* @u.init_rxq.flags: Unused.
|
||||
* @u.init_rxq.addr: Array of length %u.init_rxq.buf_count containing DMA
|
||||
* address of each page backing the receive queue.
|
||||
* @u.init_txq.index: Index of transmit queue to create.
|
||||
* @u.init_txq.buf_count: Number of 4k buffers backing transmit queue.
|
||||
* @u.init_txq.evq: Instance of event queue to target transmit completion
|
||||
* events at.
|
||||
* @u.init_txq.label: Label used in transmit completion events.
|
||||
* @u.init_txq.flags: Checksum offload flags.
|
||||
* @u.init_txq.addr: Array of length %u.init_txq.buf_count containing DMA
|
||||
* address of each page backing the transmit queue.
|
||||
* @u.mac_filter.rxq: Insert MAC filter at VF local address/VLAN targetting
|
||||
* all traffic at this receive queue.
|
||||
* @u.mac_filter.flags: MAC filter flags.
|
||||
* @u.set_status_page.dma_addr: Base address for the &struct vfdi_status.
|
||||
* This address must be such that the structure fits within a page.
|
||||
* @u.set_status_page.peer_page_count: Number of additional pages the VF
|
||||
* has provided into which peer addresses may be DMAd.
|
||||
* @u.set_status_page.peer_page_addr: Array of DMA addresses of pages.
|
||||
* If the number of peers exceeds 256, then the VF must provide
|
||||
* additional pages in this array. The PF will then DMA up to
|
||||
* 512 vfdi_endpoint structures into each page. These addresses
|
||||
* must be page-aligned.
|
||||
*/
|
||||
struct vfdi_req {
|
||||
u32 op;
|
||||
u32 reserved1;
|
||||
s32 rc;
|
||||
u32 reserved2;
|
||||
union {
|
||||
struct {
|
||||
u32 index;
|
||||
u32 buf_count;
|
||||
u64 addr[];
|
||||
} init_evq;
|
||||
struct {
|
||||
u32 index;
|
||||
u32 buf_count;
|
||||
u32 evq;
|
||||
u32 label;
|
||||
u32 flags;
|
||||
#define VFDI_RXQ_FLAG_SCATTER_EN 1
|
||||
u32 reserved;
|
||||
u64 addr[];
|
||||
} init_rxq;
|
||||
struct {
|
||||
u32 index;
|
||||
u32 buf_count;
|
||||
u32 evq;
|
||||
u32 label;
|
||||
u32 flags;
|
||||
#define VFDI_TXQ_FLAG_IP_CSUM_DIS 1
|
||||
#define VFDI_TXQ_FLAG_TCPUDP_CSUM_DIS 2
|
||||
u32 reserved;
|
||||
u64 addr[];
|
||||
} init_txq;
|
||||
struct {
|
||||
u32 rxq;
|
||||
u32 flags;
|
||||
#define VFDI_MAC_FILTER_FLAG_RSS 1
|
||||
#define VFDI_MAC_FILTER_FLAG_SCATTER 2
|
||||
} mac_filter;
|
||||
struct {
|
||||
u64 dma_addr;
|
||||
u64 peer_page_count;
|
||||
u64 peer_page_addr[];
|
||||
} set_status_page;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vfdi_status - Status provided by PF driver to VF driver
|
||||
* @generation_start: A generation count DMA'd to VF *before* the
|
||||
* rest of the structure.
|
||||
* @generation_end: A generation count DMA'd to VF *after* the
|
||||
* rest of the structure.
|
||||
* @version: Version of this structure; currently set to 1. Later
|
||||
* versions must either be layout-compatible or only be sent to VFs
|
||||
* that specifically request them.
|
||||
* @length: Total length of this structure including embedded tables
|
||||
* @vi_scale: log2 the number of VIs available on this VF. This quantity
|
||||
* is used by the hardware for register decoding.
|
||||
* @max_tx_channels: The maximum number of transmit queues the VF can use.
|
||||
* @rss_rxq_count: The number of receive queues present in the shared RSS
|
||||
* indirection table.
|
||||
* @peer_count: Total number of peers in the complete peer list. If larger
|
||||
* than ARRAY_SIZE(%peers), then the VF must provide sufficient
|
||||
* additional pages each of which is filled with vfdi_endpoint structures.
|
||||
* @local: The MAC address and outer VLAN tag of *this* VF
|
||||
* @peers: Table of peer addresses. The @tci fields in these structures
|
||||
* are currently unused and must be ignored. Additional peers are
|
||||
* written into any additional pages provided by the VF.
|
||||
* @timer_quantum_ns: Timer quantum (nominal period between timer ticks)
|
||||
* for interrupt moderation timers, in nanoseconds. This member is only
|
||||
* present if @length is sufficiently large.
|
||||
*/
|
||||
struct vfdi_status {
|
||||
u32 generation_start;
|
||||
u32 generation_end;
|
||||
u32 version;
|
||||
u32 length;
|
||||
u8 vi_scale;
|
||||
u8 max_tx_channels;
|
||||
u8 rss_rxq_count;
|
||||
u8 reserved1;
|
||||
u16 peer_count;
|
||||
u16 reserved2;
|
||||
struct vfdi_endpoint local;
|
||||
struct vfdi_endpoint peers[256];
|
||||
|
||||
/* Members below here extend version 1 of this structure */
|
||||
u32 timer_quantum_ns;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user