Skip to content

Commit

Permalink
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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>
  • Loading branch information
David S. Miller committed Oct 2, 2012
2 parents d342894 + 6ac7ef1 commit d3d5df2
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 82 deletions.
22 changes: 11 additions & 11 deletions drivers/net/ethernet/sfc/bitfield.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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), \
Expand Down Expand Up @@ -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] \
Expand Down
11 changes: 4 additions & 7 deletions drivers/net/ethernet/sfc/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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 */
Expand All @@ -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);

Expand Down
108 changes: 53 additions & 55 deletions drivers/net/ethernet/sfc/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,21 +161,13 @@ static void efx_filter_push_rx_config(struct efx_nic *efx)
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);
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
7 changes: 1 addition & 6 deletions drivers/net/ethernet/sfc/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions drivers/net/ethernet/sfc/mcdi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/ethernet/sfc/selftest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/sfc/siena_sriov.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit d3d5df2

Please sign in to comment.