aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-02-06 12:27:52 -0500
committerBen Hutchings <bhutchings@solarflare.com>2012-02-15 19:11:30 -0500
commit3d885e39219095ec5788026a1256dff61c86fa29 (patch)
tree81e9c6a5c8c7b3d6a9a0bb410d47e2984bfc87c1 /drivers/net/ethernet/sfc
parentc274d65c949d0909fc8f4f19561ecb7c1d3d1559 (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.c63
-rw-r--r--drivers/net/ethernet/sfc/filter.h14
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
104static struct efx_filter_table * 106static 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
184static 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
182static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec, 207static 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,
333int efx_filter_set_eth_local(struct efx_filter_spec *spec, 358int 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
588u32 efx_filter_get_rx_id_limit(struct efx_nic *efx) 633u32 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 */
48enum efx_filter_priority { 49enum 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 */
68enum efx_filter_flags { 70enum 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
113static 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
110extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, 122extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto,
111 __be32 host, __be16 port); 123 __be32 host, __be16 port);
112extern int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec, 124extern int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec,