Commit e3a5e33f authored by Grygorii Strashko's avatar Grygorii Strashko Committed by David S. Miller

drivers: net: cpsw: ale: add broadcast/multicast rate limit support

The CPSW ALE supports feature to rate limit number ingress
broadcast(BC)/multicast(MC) packets per/sec which main purpose is BC/MC
storm prevention.

The ALE BC/MC packet rate limit configuration consist of two parts:
- global
  ALE_CONTROL.ENABLE_RATE_LIMIT bit 0 which enables rate limiting globally
  ALE_PRESCALE.PRESCALE specifies rate limiting interval
- per-port
  ALE_PORTCTLx.BCASTMCAST/_LIMIT specifies number of BC/MC packets allowed
  per rate limiting interval.
  When port.BCASTMCAST/_LIMIT is 0 rate limiting is disabled for Port.

When BC/MC packet rate limiting is enabled the number of allowed packets
per/sec is defined as:
  number_of_packets/sec = (Fclk / ALE_PRESCALE) * port.BCASTMCAST/_LIMIT

Hence, the ALE_PRESCALE configuration is common for all ports the 1ms
interval is selected and configured during ALE initialization while
port.BCAST/MCAST_LIMIT are configured per-port.
This allows to achieve:
 - min number_of_packets = 1000 when port.BCAST/MCAST_LIMIT = 1
 - max number_of_packets = 1000 * 255 = 255000
   when port.BCAST/MCAST_LIMIT = 0xFF

The ALE_CONTROL.ENABLE_RATE_LIMIT can also be enabled once during ALE
initialization as rate limiting enabled by non zero port.BCASTMCAST/_LIMIT
values.

This patch implements above logic in ALE and adds new ALE APIs
 cpsw_ale_rx_ratelimit_bc();
 cpsw_ale_rx_ratelimit_mc();
Signed-off-by: default avatarGrygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1a95e04e
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
/* ALE_AGING_TIMER */ /* ALE_AGING_TIMER */
#define ALE_AGING_TIMER_MASK GENMASK(23, 0) #define ALE_AGING_TIMER_MASK GENMASK(23, 0)
#define ALE_RATE_LIMIT_MIN_PPS 1000
/** /**
* struct ale_entry_fld - The ALE tbl entry field description * struct ale_entry_fld - The ALE tbl entry field description
* @start_bit: field start bit * @start_bit: field start bit
...@@ -1136,6 +1138,50 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) ...@@ -1136,6 +1138,50 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control)
return tmp & BITMASK(info->bits); return tmp & BITMASK(info->bits);
} }
int cpsw_ale_rx_ratelimit_mc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps)
{
int val = ratelimit_pps / ALE_RATE_LIMIT_MIN_PPS;
u32 remainder = ratelimit_pps % ALE_RATE_LIMIT_MIN_PPS;
if (ratelimit_pps && !val) {
dev_err(ale->params.dev, "ALE MC port:%d ratelimit min value 1000pps\n", port);
return -EINVAL;
}
if (remainder)
dev_info(ale->params.dev, "ALE port:%d MC ratelimit set to %dpps (requested %d)\n",
port, ratelimit_pps - remainder, ratelimit_pps);
cpsw_ale_control_set(ale, port, ALE_PORT_MCAST_LIMIT, val);
dev_dbg(ale->params.dev, "ALE port:%d MC ratelimit set %d\n",
port, val * ALE_RATE_LIMIT_MIN_PPS);
return 0;
}
int cpsw_ale_rx_ratelimit_bc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps)
{
int val = ratelimit_pps / ALE_RATE_LIMIT_MIN_PPS;
u32 remainder = ratelimit_pps % ALE_RATE_LIMIT_MIN_PPS;
if (ratelimit_pps && !val) {
dev_err(ale->params.dev, "ALE port:%d BC ratelimit min value 1000pps\n", port);
return -EINVAL;
}
if (remainder)
dev_info(ale->params.dev, "ALE port:%d BC ratelimit set to %dpps (requested %d)\n",
port, ratelimit_pps - remainder, ratelimit_pps);
cpsw_ale_control_set(ale, port, ALE_PORT_BCAST_LIMIT, val);
dev_dbg(ale->params.dev, "ALE port:%d BC ratelimit set %d\n",
port, val * ALE_RATE_LIMIT_MIN_PPS);
return 0;
}
static void cpsw_ale_timer(struct timer_list *t) static void cpsw_ale_timer(struct timer_list *t)
{ {
struct cpsw_ale *ale = from_timer(ale, t, timer); struct cpsw_ale *ale = from_timer(ale, t, timer);
...@@ -1199,6 +1245,26 @@ static void cpsw_ale_aging_stop(struct cpsw_ale *ale) ...@@ -1199,6 +1245,26 @@ static void cpsw_ale_aging_stop(struct cpsw_ale *ale)
void cpsw_ale_start(struct cpsw_ale *ale) void cpsw_ale_start(struct cpsw_ale *ale)
{ {
unsigned long ale_prescale;
/* configure Broadcast and Multicast Rate Limit
* number_of_packets = (Fclk / ALE_PRESCALE) * port.BCAST/MCAST_LIMIT
* ALE_PRESCALE width is 19bit and min value 0x10
* port.BCAST/MCAST_LIMIT is 8bit
*
* For multi port configuration support the ALE_PRESCALE is configured to 1ms interval,
* which allows to configure port.BCAST/MCAST_LIMIT per port and achieve:
* min number_of_packets = 1000 when port.BCAST/MCAST_LIMIT = 1
* max number_of_packets = 1000 * 255 = 255000 when port.BCAST/MCAST_LIMIT = 0xFF
*/
ale_prescale = ale->params.bus_freq / ALE_RATE_LIMIT_MIN_PPS;
writel((u32)ale_prescale, ale->params.ale_regs + ALE_PRESCALE);
/* Allow MC/BC rate limiting globally.
* The actual Rate Limit cfg enabled per-port by port.BCAST/MCAST_LIMIT
*/
cpsw_ale_control_set(ale, 0, ALE_RATE_LIMIT, 1);
cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1); cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1);
cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
......
...@@ -120,6 +120,8 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, ...@@ -120,6 +120,8 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
int reg_mcast, int unreg_mcast); int reg_mcast, int unreg_mcast);
int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port); int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port);
void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti, int port); void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti, int port);
int cpsw_ale_rx_ratelimit_bc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps);
int cpsw_ale_rx_ratelimit_mc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps);
int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control); int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int cpsw_ale_control_set(struct cpsw_ale *ale, int port,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment