aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
authorPetri Gynther <pgynther@google.com>2015-03-13 17:45:00 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-15 22:04:17 -0400
commit0034de4193e4aad30bbbef4e74ca5e0631ba08a7 (patch)
treea9361ac774e5c2cb7661502afa9a04c8b753371b /drivers/net/ethernet
parent70006af955151042aa62958b92b53f4296030fe5 (diff)
net: bcmgenet: add support for Hardware Filter Block
Add support for Hardware Filter Block (HFB) so that incoming Rx traffic can be matched and directed to desired Rx queues. Signed-off-by: Petri Gynther <pgynther@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c175
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h1
2 files changed, 176 insertions, 0 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index e74ae628bbb9..12956b143b11 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -197,6 +197,14 @@ enum dma_reg {
197 DMA_PRIORITY_0, 197 DMA_PRIORITY_0,
198 DMA_PRIORITY_1, 198 DMA_PRIORITY_1,
199 DMA_PRIORITY_2, 199 DMA_PRIORITY_2,
200 DMA_INDEX2RING_0,
201 DMA_INDEX2RING_1,
202 DMA_INDEX2RING_2,
203 DMA_INDEX2RING_3,
204 DMA_INDEX2RING_4,
205 DMA_INDEX2RING_5,
206 DMA_INDEX2RING_6,
207 DMA_INDEX2RING_7,
200}; 208};
201 209
202static const u8 bcmgenet_dma_regs_v3plus[] = { 210static const u8 bcmgenet_dma_regs_v3plus[] = {
@@ -208,6 +216,14 @@ static const u8 bcmgenet_dma_regs_v3plus[] = {
208 [DMA_PRIORITY_0] = 0x30, 216 [DMA_PRIORITY_0] = 0x30,
209 [DMA_PRIORITY_1] = 0x34, 217 [DMA_PRIORITY_1] = 0x34,
210 [DMA_PRIORITY_2] = 0x38, 218 [DMA_PRIORITY_2] = 0x38,
219 [DMA_INDEX2RING_0] = 0x70,
220 [DMA_INDEX2RING_1] = 0x74,
221 [DMA_INDEX2RING_2] = 0x78,
222 [DMA_INDEX2RING_3] = 0x7C,
223 [DMA_INDEX2RING_4] = 0x80,
224 [DMA_INDEX2RING_5] = 0x84,
225 [DMA_INDEX2RING_6] = 0x88,
226 [DMA_INDEX2RING_7] = 0x8C,
211}; 227};
212 228
213static const u8 bcmgenet_dma_regs_v2[] = { 229static const u8 bcmgenet_dma_regs_v2[] = {
@@ -2283,6 +2299,160 @@ static void bcmgenet_enable_dma(struct bcmgenet_priv *priv, u32 dma_ctrl)
2283 bcmgenet_tdma_writel(priv, reg, DMA_CTRL); 2299 bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
2284} 2300}
2285 2301
2302static bool bcmgenet_hfb_is_filter_enabled(struct bcmgenet_priv *priv,
2303 u32 f_index)
2304{
2305 u32 offset;
2306 u32 reg;
2307
2308 offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
2309 reg = bcmgenet_hfb_reg_readl(priv, offset);
2310 return !!(reg & (1 << (f_index % 32)));
2311}
2312
2313static void bcmgenet_hfb_enable_filter(struct bcmgenet_priv *priv, u32 f_index)
2314{
2315 u32 offset;
2316 u32 reg;
2317
2318 offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
2319 reg = bcmgenet_hfb_reg_readl(priv, offset);
2320 reg |= (1 << (f_index % 32));
2321 bcmgenet_hfb_reg_writel(priv, reg, offset);
2322}
2323
2324static void bcmgenet_hfb_set_filter_rx_queue_mapping(struct bcmgenet_priv *priv,
2325 u32 f_index, u32 rx_queue)
2326{
2327 u32 offset;
2328 u32 reg;
2329
2330 offset = f_index / 8;
2331 reg = bcmgenet_rdma_readl(priv, DMA_INDEX2RING_0 + offset);
2332 reg &= ~(0xF << (4 * (f_index % 8)));
2333 reg |= ((rx_queue & 0xF) << (4 * (f_index % 8)));
2334 bcmgenet_rdma_writel(priv, reg, DMA_INDEX2RING_0 + offset);
2335}
2336
2337static void bcmgenet_hfb_set_filter_length(struct bcmgenet_priv *priv,
2338 u32 f_index, u32 f_length)
2339{
2340 u32 offset;
2341 u32 reg;
2342
2343 offset = HFB_FLT_LEN_V3PLUS +
2344 ((priv->hw_params->hfb_filter_cnt - 1 - f_index) / 4) *
2345 sizeof(u32);
2346 reg = bcmgenet_hfb_reg_readl(priv, offset);
2347 reg &= ~(0xFF << (8 * (f_index % 4)));
2348 reg |= ((f_length & 0xFF) << (8 * (f_index % 4)));
2349 bcmgenet_hfb_reg_writel(priv, reg, offset);
2350}
2351
2352static int bcmgenet_hfb_find_unused_filter(struct bcmgenet_priv *priv)
2353{
2354 u32 f_index;
2355
2356 for (f_index = 0; f_index < priv->hw_params->hfb_filter_cnt; f_index++)
2357 if (!bcmgenet_hfb_is_filter_enabled(priv, f_index))
2358 return f_index;
2359
2360 return -ENOMEM;
2361}
2362
2363/* bcmgenet_hfb_add_filter
2364 *
2365 * Add new filter to Hardware Filter Block to match and direct Rx traffic to
2366 * desired Rx queue.
2367 *
2368 * f_data is an array of unsigned 32-bit integers where each 32-bit integer
2369 * provides filter data for 2 bytes (4 nibbles) of Rx frame:
2370 *
2371 * bits 31:20 - unused
2372 * bit 19 - nibble 0 match enable
2373 * bit 18 - nibble 1 match enable
2374 * bit 17 - nibble 2 match enable
2375 * bit 16 - nibble 3 match enable
2376 * bits 15:12 - nibble 0 data
2377 * bits 11:8 - nibble 1 data
2378 * bits 7:4 - nibble 2 data
2379 * bits 3:0 - nibble 3 data
2380 *
2381 * Example:
2382 * In order to match:
2383 * - Ethernet frame type = 0x0800 (IP)
2384 * - IP version field = 4
2385 * - IP protocol field = 0x11 (UDP)
2386 *
2387 * The following filter is needed:
2388 * u32 hfb_filter_ipv4_udp[] = {
2389 * Rx frame offset 0x00: 0x00000000, 0x00000000, 0x00000000, 0x00000000,
2390 * Rx frame offset 0x08: 0x00000000, 0x00000000, 0x000F0800, 0x00084000,
2391 * Rx frame offset 0x10: 0x00000000, 0x00000000, 0x00000000, 0x00030011,
2392 * };
2393 *
2394 * To add the filter to HFB and direct the traffic to Rx queue 0, call:
2395 * bcmgenet_hfb_add_filter(priv, hfb_filter_ipv4_udp,
2396 * ARRAY_SIZE(hfb_filter_ipv4_udp), 0);
2397 */
2398int bcmgenet_hfb_add_filter(struct bcmgenet_priv *priv, u32 *f_data,
2399 u32 f_length, u32 rx_queue)
2400{
2401 int f_index;
2402 u32 i;
2403
2404 f_index = bcmgenet_hfb_find_unused_filter(priv);
2405 if (f_index < 0)
2406 return -ENOMEM;
2407
2408 if (f_length > priv->hw_params->hfb_filter_size)
2409 return -EINVAL;
2410
2411 for (i = 0; i < f_length; i++)
2412 bcmgenet_hfb_writel(priv, f_data[i],
2413 (f_index * priv->hw_params->hfb_filter_size + i) *
2414 sizeof(u32));
2415
2416 bcmgenet_hfb_set_filter_length(priv, f_index, 2 * f_length);
2417 bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f_index, rx_queue);
2418 bcmgenet_hfb_enable_filter(priv, f_index);
2419 bcmgenet_hfb_reg_writel(priv, 0x1, HFB_CTRL);
2420
2421 return 0;
2422}
2423
2424/* bcmgenet_hfb_clear
2425 *
2426 * Clear Hardware Filter Block and disable all filtering.
2427 */
2428static void bcmgenet_hfb_clear(struct bcmgenet_priv *priv)
2429{
2430 u32 i;
2431
2432 bcmgenet_hfb_reg_writel(priv, 0x0, HFB_CTRL);
2433 bcmgenet_hfb_reg_writel(priv, 0x0, HFB_FLT_ENABLE_V3PLUS);
2434 bcmgenet_hfb_reg_writel(priv, 0x0, HFB_FLT_ENABLE_V3PLUS + 4);
2435
2436 for (i = DMA_INDEX2RING_0; i <= DMA_INDEX2RING_7; i++)
2437 bcmgenet_rdma_writel(priv, 0x0, i);
2438
2439 for (i = 0; i < (priv->hw_params->hfb_filter_cnt / 4); i++)
2440 bcmgenet_hfb_reg_writel(priv, 0x0,
2441 HFB_FLT_LEN_V3PLUS + i * sizeof(u32));
2442
2443 for (i = 0; i < priv->hw_params->hfb_filter_cnt *
2444 priv->hw_params->hfb_filter_size; i++)
2445 bcmgenet_hfb_writel(priv, 0x0, i * sizeof(u32));
2446}
2447
2448static void bcmgenet_hfb_init(struct bcmgenet_priv *priv)
2449{
2450 if (GENET_IS_V1(priv) || GENET_IS_V2(priv))
2451 return;
2452
2453 bcmgenet_hfb_clear(priv);
2454}
2455
2286static void bcmgenet_netif_start(struct net_device *dev) 2456static void bcmgenet_netif_start(struct net_device *dev)
2287{ 2457{
2288 struct bcmgenet_priv *priv = netdev_priv(dev); 2458 struct bcmgenet_priv *priv = netdev_priv(dev);
@@ -2348,6 +2518,9 @@ static int bcmgenet_open(struct net_device *dev)
2348 /* Always enable ring 16 - descriptor ring */ 2518 /* Always enable ring 16 - descriptor ring */
2349 bcmgenet_enable_dma(priv, dma_ctrl); 2519 bcmgenet_enable_dma(priv, dma_ctrl);
2350 2520
2521 /* HFB init */
2522 bcmgenet_hfb_init(priv);
2523
2351 ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED, 2524 ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED,
2352 dev->name, priv); 2525 dev->name, priv);
2353 if (ret < 0) { 2526 if (ret < 0) {
@@ -2592,6 +2765,7 @@ static struct bcmgenet_hw_params bcmgenet_hw_params[] = {
2592 .bp_in_en_shift = 17, 2765 .bp_in_en_shift = 17,
2593 .bp_in_mask = 0x1ffff, 2766 .bp_in_mask = 0x1ffff,
2594 .hfb_filter_cnt = 48, 2767 .hfb_filter_cnt = 48,
2768 .hfb_filter_size = 128,
2595 .qtag_mask = 0x3F, 2769 .qtag_mask = 0x3F,
2596 .tbuf_offset = 0x0600, 2770 .tbuf_offset = 0x0600,
2597 .hfb_offset = 0x8000, 2771 .hfb_offset = 0x8000,
@@ -2609,6 +2783,7 @@ static struct bcmgenet_hw_params bcmgenet_hw_params[] = {
2609 .bp_in_en_shift = 17, 2783 .bp_in_en_shift = 17,
2610 .bp_in_mask = 0x1ffff, 2784 .bp_in_mask = 0x1ffff,
2611 .hfb_filter_cnt = 48, 2785 .hfb_filter_cnt = 48,
2786 .hfb_filter_size = 128,
2612 .qtag_mask = 0x3F, 2787 .qtag_mask = 0x3F,
2613 .tbuf_offset = 0x0600, 2788 .tbuf_offset = 0x0600,
2614 .hfb_offset = 0x8000, 2789 .hfb_offset = 0x8000,
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 2a8113898aed..1ea838946318 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -509,6 +509,7 @@ struct bcmgenet_hw_params {
509 u8 bp_in_en_shift; 509 u8 bp_in_en_shift;
510 u32 bp_in_mask; 510 u32 bp_in_mask;
511 u8 hfb_filter_cnt; 511 u8 hfb_filter_cnt;
512 u8 hfb_filter_size;
512 u8 qtag_mask; 513 u8 qtag_mask;
513 u16 tbuf_offset; 514 u16 tbuf_offset;
514 u32 hfb_offset; 515 u32 hfb_offset;