aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-10-01 21:32:55 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-01 21:32:55 -0400
commitd3d5df2c4b86786ea792b073f0df9cd82f7efcaa (patch)
tree1b7658dbe2e5a8db6ba3d166812b153b2fabcb13
parentd342894c5d2f8c7df194c793ec4059656e09ca31 (diff)
parent6ac7ef1487a040483d89a95045efc5185a71268f (diff)
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc-next
Ben Hutchings says: ==================== Some bug fixes that should go into 3.7: 1. Fix oops when removing device with SR-IOV enabled. (This regression was introduced by the last set of changes, so the fix does not need to be applied to any earlier kernel versions.) 2. Fix firmware structure field lookup bug that resulted in missing sensor information. 3. Fix bug that makes self-test do very little in some configurations. 4. Fix the numbering of ethtool RX flow steering filters to reflect the real hardware priorities. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/sfc/bitfield.h22
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c11
-rw-r--r--drivers/net/ethernet/sfc/filter.c108
-rw-r--r--drivers/net/ethernet/sfc/filter.h7
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h6
-rw-r--r--drivers/net/ethernet/sfc/selftest.c3
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.c1
7 files changed, 76 insertions, 82 deletions
diff --git a/drivers/net/ethernet/sfc/bitfield.h b/drivers/net/ethernet/sfc/bitfield.h
index b26a954c27f..5400a33f254 100644
--- a/drivers/net/ethernet/sfc/bitfield.h
+++ b/drivers/net/ethernet/sfc/bitfield.h
@@ -120,10 +120,10 @@ typedef union efx_oword {
* [0,high-low), with garbage in bits [high-low+1,...).
*/
#define EFX_EXTRACT_NATIVE(native_element, min, max, low, high) \
- (((low > max) || (high < min)) ? 0 : \
- ((low > min) ? \
- ((native_element) >> (low - min)) : \
- ((native_element) << (min - low))))
+ ((low) > (max) || (high) < (min) ? 0 : \
+ (low) > (min) ? \
+ (native_element) >> ((low) - (min)) : \
+ (native_element) << ((min) - (low)))
/*
* Extract bit field portion [low,high) from the 64-bit little-endian
@@ -142,27 +142,27 @@ typedef union efx_oword {
#define EFX_EXTRACT_OWORD64(oword, low, high) \
((EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) | \
EFX_EXTRACT64((oword).u64[1], 64, 127, low, high)) & \
- EFX_MASK64(high + 1 - low))
+ EFX_MASK64((high) + 1 - (low)))
#define EFX_EXTRACT_QWORD64(qword, low, high) \
(EFX_EXTRACT64((qword).u64[0], 0, 63, low, high) & \
- EFX_MASK64(high + 1 - low))
+ EFX_MASK64((high) + 1 - (low)))
#define EFX_EXTRACT_OWORD32(oword, low, high) \
((EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) | \
EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) | \
EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) | \
EFX_EXTRACT32((oword).u32[3], 96, 127, low, high)) & \
- EFX_MASK32(high + 1 - low))
+ EFX_MASK32((high) + 1 - (low)))
#define EFX_EXTRACT_QWORD32(qword, low, high) \
((EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) | \
EFX_EXTRACT32((qword).u32[1], 32, 63, low, high)) & \
- EFX_MASK32(high + 1 - low))
+ EFX_MASK32((high) + 1 - (low)))
#define EFX_EXTRACT_DWORD(dword, low, high) \
(EFX_EXTRACT32((dword).u32[0], 0, 31, low, high) & \
- EFX_MASK32(high + 1 - low))
+ EFX_MASK32((high) + 1 - (low)))
#define EFX_OWORD_FIELD64(oword, field) \
EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), \
@@ -442,10 +442,10 @@ typedef union efx_oword {
cpu_to_le32(EFX_INSERT_NATIVE(min, max, low, high, value))
#define EFX_INPLACE_MASK64(min, max, low, high) \
- EFX_INSERT64(min, max, low, high, EFX_MASK64(high + 1 - low))
+ EFX_INSERT64(min, max, low, high, EFX_MASK64((high) + 1 - (low)))
#define EFX_INPLACE_MASK32(min, max, low, high) \
- EFX_INSERT32(min, max, low, high, EFX_MASK32(high + 1 - low))
+ EFX_INSERT32(min, max, low, high, EFX_MASK32((high) + 1 - (low)))
#define EFX_SET_OWORD64(oword, low, high, value) do { \
(oword).u64[0] = (((oword).u64[0] \
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 9df556c01b8..90f078eff8e 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -337,7 +337,8 @@ static int efx_fill_loopback_test(struct efx_nic *efx,
unsigned int test_index,
struct ethtool_string *strings, u64 *data)
{
- struct efx_channel *channel = efx_get_channel(efx, 0);
+ struct efx_channel *channel =
+ efx_get_channel(efx, efx->tx_channel_offset);
struct efx_tx_queue *tx_queue;
efx_for_each_channel_tx_queue(tx_queue, channel) {
@@ -960,9 +961,7 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
int rc;
/* Check that user wants us to choose the location */
- if (rule->location != RX_CLS_LOC_ANY &&
- rule->location != RX_CLS_LOC_FIRST &&
- rule->location != RX_CLS_LOC_LAST)
+ if (rule->location != RX_CLS_LOC_ANY)
return -EINVAL;
/* Range-check ring_cookie */
@@ -976,9 +975,7 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
rule->m_ext.data[1]))
return -EINVAL;
- efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL,
- (rule->location == RX_CLS_LOC_FIRST) ?
- EFX_FILTER_FLAG_RX_OVERRIDE_IP : 0,
+ efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, 0,
(rule->ring_cookie == RX_CLS_FLOW_DISC) ?
0xfff : rule->ring_cookie);
diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c
index c3fd61f0a95..8af42cd1fed 100644
--- a/drivers/net/ethernet/sfc/filter.c
+++ b/drivers/net/ethernet/sfc/filter.c
@@ -162,20 +162,12 @@ static void efx_filter_push_rx_config(struct efx_nic *efx)
!!(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);
@@ -480,14 +472,12 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
case EFX_FILTER_TABLE_RX_MAC: {
bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
- EFX_POPULATE_OWORD_8(
+ EFX_POPULATE_OWORD_7(
*filter,
FRF_CZ_RMFT_RSS_EN,
!!(spec->flags & EFX_FILTER_FLAG_RX_RSS),
FRF_CZ_RMFT_SCATTER_EN,
!!(spec->flags & EFX_FILTER_FLAG_RX_SCATTER),
- FRF_CZ_RMFT_IP_OVERRIDE,
- !!(spec->flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP),
FRF_CZ_RMFT_RXQ_ID, spec->dmaq_id,
FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
FRF_CZ_RMFT_DEST_MAC_HI, spec->data[2],
@@ -567,49 +557,62 @@ static int efx_filter_search(struct efx_filter_table *table,
}
/*
- * Construct/deconstruct external filter IDs. These must be ordered
- * by matching priority, for RX NFC semantics.
+ * Construct/deconstruct external filter IDs. At least the RX filter
+ * IDs must be ordered by matching priority, for RX NFC semantics.
*
- * Each RX MAC filter entry has a flag for whether it can override an
- * RX IP filter that also matches. So we assign locations for MAC
- * filters with overriding behaviour, then for IP filters, then for
- * MAC filters without overriding behaviour.
+ * Deconstruction needs to be robust against invalid IDs so that
+ * efx_filter_remove_id_safe() and efx_filter_get_filter_safe() can
+ * accept user-provided IDs.
*/
-#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_MATCH_PRI_COUNT 5
+
+static const u8 efx_filter_type_match_pri[EFX_FILTER_TYPE_COUNT] = {
+ [EFX_FILTER_TCP_FULL] = 0,
+ [EFX_FILTER_UDP_FULL] = 0,
+ [EFX_FILTER_TCP_WILD] = 1,
+ [EFX_FILTER_UDP_WILD] = 1,
+ [EFX_FILTER_MAC_FULL] = 2,
+ [EFX_FILTER_MAC_WILD] = 3,
+ [EFX_FILTER_UC_DEF] = 4,
+ [EFX_FILTER_MC_DEF] = 4,
+};
+
+static const enum efx_filter_table_id efx_filter_range_table[] = {
+ EFX_FILTER_TABLE_RX_IP, /* RX match pri 0 */
+ EFX_FILTER_TABLE_RX_IP,
+ EFX_FILTER_TABLE_RX_MAC,
+ EFX_FILTER_TABLE_RX_MAC,
+ EFX_FILTER_TABLE_RX_DEF, /* RX match pri 4 */
+ EFX_FILTER_TABLE_COUNT, /* TX match pri 0; invalid */
+ EFX_FILTER_TABLE_COUNT, /* invalid */
+ EFX_FILTER_TABLE_TX_MAC,
+ EFX_FILTER_TABLE_TX_MAC, /* TX match pri 3 */
+};
#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)
+static inline u32
+efx_filter_make_id(const struct efx_filter_spec *spec, unsigned int index)
{
- unsigned int match_pri = EFX_FILTER_MATCH_PRI_NORMAL_BASE + table_id;
+ unsigned int range;
- 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;
- }
+ range = efx_filter_type_match_pri[spec->type];
+ if (!(spec->flags & EFX_FILTER_FLAG_RX))
+ range += EFX_FILTER_MATCH_PRI_COUNT;
- return match_pri << EFX_FILTER_INDEX_WIDTH | index;
+ return range << EFX_FILTER_INDEX_WIDTH | index;
}
static inline enum efx_filter_table_id efx_filter_id_table_id(u32 id)
{
- unsigned int match_pri = id >> EFX_FILTER_INDEX_WIDTH;
+ unsigned int range = 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;
- }
+ if (range < ARRAY_SIZE(efx_filter_range_table))
+ return efx_filter_range_table[range];
+ else
+ return EFX_FILTER_TABLE_COUNT; /* invalid */
}
static inline unsigned int efx_filter_id_index(u32 id)
@@ -619,12 +622,9 @@ static inline unsigned int efx_filter_id_index(u32 id)
static inline u8 efx_filter_id_flags(u32 id)
{
- unsigned int match_pri = id >> EFX_FILTER_INDEX_WIDTH;
+ unsigned int range = 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)
+ if (range < EFX_FILTER_MATCH_PRI_COUNT)
return EFX_FILTER_FLAG_RX;
else
return EFX_FILTER_FLAG_TX;
@@ -633,14 +633,15 @@ static inline u8 efx_filter_id_flags(u32 id)
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;
+ unsigned int range = EFX_FILTER_MATCH_PRI_COUNT - 1;
+ enum efx_filter_table_id table_id;
do {
+ table_id = efx_filter_range_table[range];
if (state->table[table_id].size != 0)
- return ((EFX_FILTER_MATCH_PRI_NORMAL_BASE + table_id)
- << EFX_FILTER_INDEX_WIDTH) +
+ return range << EFX_FILTER_INDEX_WIDTH |
state->table[table_id].size;
- } while (table_id--);
+ } while (range--);
return 0;
}
@@ -718,7 +719,7 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
netif_vdbg(efx, hw, efx->net_dev,
"%s: filter type %d index %d rxq %u set",
__func__, spec->type, filter_idx, spec->dmaq_id);
- rc = efx_filter_make_id(table->id, filter_idx, spec->flags);
+ rc = efx_filter_make_id(spec, filter_idx);
out:
spin_unlock_bh(&state->lock);
@@ -781,8 +782,7 @@ 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) & EFX_FILTER_FLAG_RX_OVERRIDE_IP)) {
+ spec->priority == priority) {
efx_filter_table_clear_entry(efx, table, filter_idx);
if (table->used == 0)
efx_filter_table_reset_search_depth(table);
@@ -833,8 +833,7 @@ 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) & EFX_FILTER_FLAG_RX_OVERRIDE_IP)) {
+ spec->priority == priority) {
*spec_buf = *spec;
rc = 0;
} else {
@@ -927,8 +926,7 @@ s32 efx_filter_get_rx_ids(struct efx_nic *efx,
goto out;
}
buf[count++] = efx_filter_make_id(
- table_id, filter_idx,
- table->spec[filter_idx].flags);
+ &table->spec[filter_idx], filter_idx);
}
}
}
diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h
index 3c77802aed6..5cb54723b82 100644
--- a/drivers/net/ethernet/sfc/filter.h
+++ b/drivers/net/ethernet/sfc/filter.h
@@ -61,16 +61,12 @@ enum efx_filter_priority {
* according to the indirection table.
* @EFX_FILTER_FLAG_RX_SCATTER: Enable DMA scatter on the receiving
* queue.
- * @EFX_FILTER_FLAG_RX_OVERRIDE_IP: Enables a MAC filter to override
- * 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,
};
@@ -88,8 +84,7 @@ enum efx_filter_flags {
*
* The @priority field is used by software to determine whether a new
* filter may replace an old one. The hardware priority of a filter
- * depends on the filter type and %EFX_FILTER_FLAG_RX_OVERRIDE_IP
- * flag.
+ * depends on the filter type.
*/
struct efx_filter_spec {
u8 type:4;
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index dc25caaa398..3ba2e5b5a9c 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -113,11 +113,13 @@ extern void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
#define MCDI_EVENT_FIELD(_ev, _field) \
EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field)
#define MCDI_ARRAY_FIELD(_buf, _field1, _type, _index, _field2) \
- EFX_DWORD_FIELD( \
+ EFX_EXTRACT_DWORD( \
*((efx_dword_t *) \
(MCDI_ARRAY_PTR(_buf, _field1, _type, _index) + \
(MC_CMD_ ## _type ## _TYPEDEF_ ## _field2 ## _OFST & ~3))), \
- MC_CMD_ ## _type ## _TYPEDEF_ ## _field2)
+ MC_CMD_ ## _type ## _TYPEDEF_ ## _field2 ## _LBN & 0x1f, \
+ (MC_CMD_ ## _type ## _TYPEDEF_ ## _field2 ## _LBN & 0x1f) + \
+ MC_CMD_ ## _type ## _TYPEDEF_ ## _field2 ## _WIDTH - 1)
extern void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len);
extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c
index 96068d15b60..ce72ae4f399 100644
--- a/drivers/net/ethernet/sfc/selftest.c
+++ b/drivers/net/ethernet/sfc/selftest.c
@@ -614,7 +614,8 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
{
enum efx_loopback_mode mode;
struct efx_loopback_state *state;
- struct efx_channel *channel = efx_get_channel(efx, 0);
+ struct efx_channel *channel =
+ efx_get_channel(efx, efx->tx_channel_offset);
struct efx_tx_queue *tx_queue;
int rc = 0;
diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c
index a8f48a45584..d49b53dc2a5 100644
--- a/drivers/net/ethernet/sfc/siena_sriov.c
+++ b/drivers/net/ethernet/sfc/siena_sriov.c
@@ -1035,6 +1035,7 @@ efx_sriov_get_channel_name(struct efx_channel *channel, char *buf, size_t len)
static const struct efx_channel_type efx_sriov_channel_type = {
.handle_no_channel = efx_sriov_handle_no_channel,
.pre_probe = efx_sriov_probe_channel,
+ .post_remove = efx_channel_dummy_op_void,
.get_name = efx_sriov_get_channel_name,
/* no copy operation; channel must not be reallocated */
.keep_eventq = true,