diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-02-06 12:27:52 -0500 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-02-15 19:11:30 -0500 |
commit | 3d885e39219095ec5788026a1256dff61c86fa29 (patch) | |
tree | 81e9c6a5c8c7b3d6a9a0bb410d47e2984bfc87c1 /drivers/net/ethernet/sfc | |
parent | c274d65c949d0909fc8f4f19561ecb7c1d3d1559 (diff) |
sfc: Add support for TX MAC filters
On Siena each TX queue can be configured to send only packets for
which there is a TX MAC filter that matches the source MAC address,
queue ID, and optionally VID. This will be used to implement the
'spoofchk' feature for SR-IOV virtual functions.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet/sfc')
-rw-r--r-- | drivers/net/ethernet/sfc/filter.c | 63 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/filter.h | 14 |
2 files changed, 72 insertions, 5 deletions
diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c index 92517ea42715..fea7f7300675 100644 --- a/drivers/net/ethernet/sfc/filter.c +++ b/drivers/net/ethernet/sfc/filter.c | |||
@@ -36,6 +36,7 @@ enum efx_filter_table_id { | |||
36 | EFX_FILTER_TABLE_RX_IP = 0, | 36 | EFX_FILTER_TABLE_RX_IP = 0, |
37 | EFX_FILTER_TABLE_RX_MAC, | 37 | EFX_FILTER_TABLE_RX_MAC, |
38 | EFX_FILTER_TABLE_RX_DEF, | 38 | EFX_FILTER_TABLE_RX_DEF, |
39 | EFX_FILTER_TABLE_TX_MAC, | ||
39 | EFX_FILTER_TABLE_COUNT, | 40 | EFX_FILTER_TABLE_COUNT, |
40 | }; | 41 | }; |
41 | 42 | ||
@@ -97,8 +98,9 @@ efx_filter_spec_table_id(const struct efx_filter_spec *spec) | |||
97 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_UDP_WILD >> 2)); | 98 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_UDP_WILD >> 2)); |
98 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_FULL >> 2)); | 99 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_FULL >> 2)); |
99 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_WILD >> 2)); | 100 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_WILD >> 2)); |
101 | BUILD_BUG_ON(EFX_FILTER_TABLE_TX_MAC != EFX_FILTER_TABLE_RX_MAC + 2); | ||
100 | EFX_BUG_ON_PARANOID(spec->type == EFX_FILTER_UNSPEC); | 102 | EFX_BUG_ON_PARANOID(spec->type == EFX_FILTER_UNSPEC); |
101 | return spec->type >> 2; | 103 | return (spec->type >> 2) + ((spec->flags & EFX_FILTER_FLAG_TX) ? 2 : 0); |
102 | } | 104 | } |
103 | 105 | ||
104 | static struct efx_filter_table * | 106 | static struct efx_filter_table * |
@@ -179,6 +181,29 @@ static void efx_filter_push_rx_config(struct efx_nic *efx) | |||
179 | efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL); | 181 | efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL); |
180 | } | 182 | } |
181 | 183 | ||
184 | static void efx_filter_push_tx_limits(struct efx_nic *efx) | ||
185 | { | ||
186 | struct efx_filter_state *state = efx->filter_state; | ||
187 | struct efx_filter_table *table; | ||
188 | efx_oword_t tx_cfg; | ||
189 | |||
190 | efx_reado(efx, &tx_cfg, FR_AZ_TX_CFG); | ||
191 | |||
192 | table = &state->table[EFX_FILTER_TABLE_TX_MAC]; | ||
193 | if (table->size) { | ||
194 | EFX_SET_OWORD_FIELD( | ||
195 | tx_cfg, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE, | ||
196 | table->search_depth[EFX_FILTER_MAC_FULL] + | ||
197 | FILTER_CTL_SRCH_FUDGE_FULL); | ||
198 | EFX_SET_OWORD_FIELD( | ||
199 | tx_cfg, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE, | ||
200 | table->search_depth[EFX_FILTER_MAC_WILD] + | ||
201 | FILTER_CTL_SRCH_FUDGE_WILD); | ||
202 | } | ||
203 | |||
204 | efx_writeo(efx, &tx_cfg, FR_AZ_TX_CFG); | ||
205 | } | ||
206 | |||
182 | static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec, | 207 | static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec, |
183 | __be32 host1, __be16 port1, | 208 | __be32 host1, __be16 port1, |
184 | __be32 host2, __be16 port2) | 209 | __be32 host2, __be16 port2) |
@@ -333,7 +358,8 @@ int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec, | |||
333 | int efx_filter_set_eth_local(struct efx_filter_spec *spec, | 358 | int efx_filter_set_eth_local(struct efx_filter_spec *spec, |
334 | u16 vid, const u8 *addr) | 359 | u16 vid, const u8 *addr) |
335 | { | 360 | { |
336 | EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX)); | 361 | EFX_BUG_ON_PARANOID(!(spec->flags & |
362 | (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX))); | ||
337 | 363 | ||
338 | /* This cannot currently be combined with other filtering */ | 364 | /* This cannot currently be combined with other filtering */ |
339 | if (spec->type != EFX_FILTER_UNSPEC) | 365 | if (spec->type != EFX_FILTER_UNSPEC) |
@@ -471,6 +497,18 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec) | |||
471 | break; | 497 | break; |
472 | } | 498 | } |
473 | 499 | ||
500 | case EFX_FILTER_TABLE_TX_MAC: { | ||
501 | bool is_wild = spec->type == EFX_FILTER_MAC_WILD; | ||
502 | EFX_POPULATE_OWORD_5(*filter, | ||
503 | FRF_CZ_TMFT_TXQ_ID, spec->dmaq_id, | ||
504 | FRF_CZ_TMFT_WILDCARD_MATCH, is_wild, | ||
505 | FRF_CZ_TMFT_SRC_MAC_HI, spec->data[2], | ||
506 | FRF_CZ_TMFT_SRC_MAC_LO, spec->data[1], | ||
507 | FRF_CZ_TMFT_VLAN_ID, spec->data[0]); | ||
508 | data3 = is_wild | spec->dmaq_id << 1; | ||
509 | break; | ||
510 | } | ||
511 | |||
474 | default: | 512 | default: |
475 | BUG(); | 513 | BUG(); |
476 | } | 514 | } |
@@ -485,6 +523,10 @@ static bool efx_filter_equal(const struct efx_filter_spec *left, | |||
485 | memcmp(left->data, right->data, sizeof(left->data))) | 523 | memcmp(left->data, right->data, sizeof(left->data))) |
486 | return false; | 524 | return false; |
487 | 525 | ||
526 | if (left->flags & EFX_FILTER_FLAG_TX && | ||
527 | left->dmaq_id != right->dmaq_id) | ||
528 | return false; | ||
529 | |||
488 | return true; | 530 | return true; |
489 | } | 531 | } |
490 | 532 | ||
@@ -581,8 +623,11 @@ static inline u8 efx_filter_id_flags(u32 id) | |||
581 | 623 | ||
582 | if (match_pri < EFX_FILTER_MATCH_PRI_NORMAL_BASE) | 624 | if (match_pri < EFX_FILTER_MATCH_PRI_NORMAL_BASE) |
583 | return EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_OVERRIDE_IP; | 625 | return EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_OVERRIDE_IP; |
584 | else | 626 | else if (match_pri <= |
627 | EFX_FILTER_MATCH_PRI_NORMAL_BASE + EFX_FILTER_TABLE_RX_DEF) | ||
585 | return EFX_FILTER_FLAG_RX; | 628 | return EFX_FILTER_FLAG_RX; |
629 | else | ||
630 | return EFX_FILTER_FLAG_TX; | ||
586 | } | 631 | } |
587 | 632 | ||
588 | u32 efx_filter_get_rx_id_limit(struct efx_nic *efx) | 633 | u32 efx_filter_get_rx_id_limit(struct efx_nic *efx) |
@@ -660,7 +705,10 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec, | |||
660 | } else { | 705 | } else { |
661 | if (table->search_depth[spec->type] < depth) { | 706 | if (table->search_depth[spec->type] < depth) { |
662 | table->search_depth[spec->type] = depth; | 707 | table->search_depth[spec->type] = depth; |
663 | efx_filter_push_rx_config(efx); | 708 | if (spec->flags & EFX_FILTER_FLAG_TX) |
709 | efx_filter_push_tx_limits(efx); | ||
710 | else | ||
711 | efx_filter_push_rx_config(efx); | ||
664 | } | 712 | } |
665 | 713 | ||
666 | efx_writeo(efx, &filter, | 714 | efx_writeo(efx, &filter, |
@@ -918,6 +966,7 @@ void efx_restore_filters(struct efx_nic *efx) | |||
918 | } | 966 | } |
919 | 967 | ||
920 | efx_filter_push_rx_config(efx); | 968 | efx_filter_push_rx_config(efx); |
969 | efx_filter_push_tx_limits(efx); | ||
921 | 970 | ||
922 | spin_unlock_bh(&state->lock); | 971 | spin_unlock_bh(&state->lock); |
923 | } | 972 | } |
@@ -960,6 +1009,12 @@ int efx_probe_filters(struct efx_nic *efx) | |||
960 | table = &state->table[EFX_FILTER_TABLE_RX_DEF]; | 1009 | table = &state->table[EFX_FILTER_TABLE_RX_DEF]; |
961 | table->id = EFX_FILTER_TABLE_RX_DEF; | 1010 | table->id = EFX_FILTER_TABLE_RX_DEF; |
962 | table->size = EFX_FILTER_SIZE_RX_DEF; | 1011 | table->size = EFX_FILTER_SIZE_RX_DEF; |
1012 | |||
1013 | table = &state->table[EFX_FILTER_TABLE_TX_MAC]; | ||
1014 | table->id = EFX_FILTER_TABLE_TX_MAC; | ||
1015 | table->offset = FR_CZ_TX_MAC_FILTER_TBL0; | ||
1016 | table->size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS; | ||
1017 | table->step = FR_CZ_TX_MAC_FILTER_TBL0_STEP; | ||
963 | } | 1018 | } |
964 | 1019 | ||
965 | for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) { | 1020 | for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) { |
diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h index 451997841dc9..3c77802aed6c 100644 --- a/drivers/net/ethernet/sfc/filter.h +++ b/drivers/net/ethernet/sfc/filter.h | |||
@@ -43,7 +43,8 @@ enum efx_filter_type { | |||
43 | * enum efx_filter_priority - priority of a hardware filter specification | 43 | * enum efx_filter_priority - priority of a hardware filter specification |
44 | * @EFX_FILTER_PRI_HINT: Performance hint | 44 | * @EFX_FILTER_PRI_HINT: Performance hint |
45 | * @EFX_FILTER_PRI_MANUAL: Manually configured filter | 45 | * @EFX_FILTER_PRI_MANUAL: Manually configured filter |
46 | * @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour | 46 | * @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour (user-level |
47 | * networking and SR-IOV) | ||
47 | */ | 48 | */ |
48 | enum efx_filter_priority { | 49 | enum efx_filter_priority { |
49 | EFX_FILTER_PRI_HINT = 0, | 50 | EFX_FILTER_PRI_HINT = 0, |
@@ -64,12 +65,14 @@ enum efx_filter_priority { | |||
64 | * any IP filter that matches the same packet. By default, IP | 65 | * any IP filter that matches the same packet. By default, IP |
65 | * filters take precedence. | 66 | * filters take precedence. |
66 | * @EFX_FILTER_FLAG_RX: Filter is for RX | 67 | * @EFX_FILTER_FLAG_RX: Filter is for RX |
68 | * @EFX_FILTER_FLAG_TX: Filter is for TX | ||
67 | */ | 69 | */ |
68 | enum efx_filter_flags { | 70 | enum efx_filter_flags { |
69 | EFX_FILTER_FLAG_RX_RSS = 0x01, | 71 | EFX_FILTER_FLAG_RX_RSS = 0x01, |
70 | EFX_FILTER_FLAG_RX_SCATTER = 0x02, | 72 | EFX_FILTER_FLAG_RX_SCATTER = 0x02, |
71 | EFX_FILTER_FLAG_RX_OVERRIDE_IP = 0x04, | 73 | EFX_FILTER_FLAG_RX_OVERRIDE_IP = 0x04, |
72 | EFX_FILTER_FLAG_RX = 0x08, | 74 | EFX_FILTER_FLAG_RX = 0x08, |
75 | EFX_FILTER_FLAG_TX = 0x10, | ||
73 | }; | 76 | }; |
74 | 77 | ||
75 | /** | 78 | /** |
@@ -107,6 +110,15 @@ static inline void efx_filter_init_rx(struct efx_filter_spec *spec, | |||
107 | spec->dmaq_id = rxq_id; | 110 | spec->dmaq_id = rxq_id; |
108 | } | 111 | } |
109 | 112 | ||
113 | static inline void efx_filter_init_tx(struct efx_filter_spec *spec, | ||
114 | unsigned txq_id) | ||
115 | { | ||
116 | spec->type = EFX_FILTER_UNSPEC; | ||
117 | spec->priority = EFX_FILTER_PRI_REQUIRED; | ||
118 | spec->flags = EFX_FILTER_FLAG_TX; | ||
119 | spec->dmaq_id = txq_id; | ||
120 | } | ||
121 | |||
110 | extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, | 122 | extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, |
111 | __be32 host, __be16 port); | 123 | __be32 host, __be16 port); |
112 | extern int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec, | 124 | extern int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec, |