diff options
author | Mugunthan V N <mugunthanvnm@ti.com> | 2012-10-29 04:45:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-01 12:21:29 -0400 |
commit | 5c50a856d550b3bf6a731f6e33a794ed5c519817 (patch) | |
tree | 3435bb193aac26e54094a022f809cbe33079a4f0 /drivers/net/ethernet/ti | |
parent | 8ef29f8aae524bd51298fb10ac6a5ce6c4c5a3d8 (diff) |
drivers: net: ethernet: cpsw: add multicast address to ALE table
Adding multicast address to ALE table via netdev ops to subscribe, transmit
or receive multicast frames to and from the network
Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/ti')
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 27 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.c | 31 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.h | 1 |
3 files changed, 56 insertions, 3 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index df55e2403746..63b046fc2bba 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c | |||
@@ -70,6 +70,8 @@ do { \ | |||
70 | dev_notice(priv->dev, format, ## __VA_ARGS__); \ | 70 | dev_notice(priv->dev, format, ## __VA_ARGS__); \ |
71 | } while (0) | 71 | } while (0) |
72 | 72 | ||
73 | #define ALE_ALL_PORTS 0x7 | ||
74 | |||
73 | #define CPSW_MAJOR_VERSION(reg) (reg >> 8 & 0x7) | 75 | #define CPSW_MAJOR_VERSION(reg) (reg >> 8 & 0x7) |
74 | #define CPSW_MINOR_VERSION(reg) (reg & 0xff) | 76 | #define CPSW_MINOR_VERSION(reg) (reg & 0xff) |
75 | #define CPSW_RTL_VERSION(reg) ((reg >> 11) & 0x1f) | 77 | #define CPSW_RTL_VERSION(reg) ((reg >> 11) & 0x1f) |
@@ -228,6 +230,30 @@ struct cpsw_priv { | |||
228 | (func)((priv)->slaves + idx, ##arg); \ | 230 | (func)((priv)->slaves + idx, ##arg); \ |
229 | } while (0) | 231 | } while (0) |
230 | 232 | ||
233 | static void cpsw_ndo_set_rx_mode(struct net_device *ndev) | ||
234 | { | ||
235 | struct cpsw_priv *priv = netdev_priv(ndev); | ||
236 | |||
237 | if (ndev->flags & IFF_PROMISC) { | ||
238 | /* Enable promiscuous mode */ | ||
239 | dev_err(priv->dev, "Ignoring Promiscuous mode\n"); | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | /* Clear all mcast from ALE */ | ||
244 | cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port); | ||
245 | |||
246 | if (!netdev_mc_empty(ndev)) { | ||
247 | struct netdev_hw_addr *ha; | ||
248 | |||
249 | /* program multicast address list into ALE register */ | ||
250 | netdev_for_each_mc_addr(ha, ndev) { | ||
251 | cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr, | ||
252 | ALE_ALL_PORTS << priv->host_port, 0, 0); | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
231 | static void cpsw_intr_enable(struct cpsw_priv *priv) | 257 | static void cpsw_intr_enable(struct cpsw_priv *priv) |
232 | { | 258 | { |
233 | __raw_writel(0xFF, &priv->ss_regs->tx_en); | 259 | __raw_writel(0xFF, &priv->ss_regs->tx_en); |
@@ -673,6 +699,7 @@ static const struct net_device_ops cpsw_netdev_ops = { | |||
673 | .ndo_change_mtu = eth_change_mtu, | 699 | .ndo_change_mtu = eth_change_mtu, |
674 | .ndo_tx_timeout = cpsw_ndo_tx_timeout, | 700 | .ndo_tx_timeout = cpsw_ndo_tx_timeout, |
675 | .ndo_get_stats = cpsw_ndo_get_stats, | 701 | .ndo_get_stats = cpsw_ndo_get_stats, |
702 | .ndo_set_rx_mode = cpsw_ndo_set_rx_mode, | ||
676 | #ifdef CONFIG_NET_POLL_CONTROLLER | 703 | #ifdef CONFIG_NET_POLL_CONTROLLER |
677 | .ndo_poll_controller = cpsw_ndo_poll_controller, | 704 | .ndo_poll_controller = cpsw_ndo_poll_controller, |
678 | #endif | 705 | #endif |
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index ca0d48a7e508..0e9ccc2cf91f 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
21 | #include <linux/stat.h> | 21 | #include <linux/stat.h> |
22 | #include <linux/sysfs.h> | 22 | #include <linux/sysfs.h> |
23 | #include <linux/etherdevice.h> | ||
23 | 24 | ||
24 | #include "cpsw_ale.h" | 25 | #include "cpsw_ale.h" |
25 | 26 | ||
@@ -211,10 +212,34 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry, | |||
211 | mask &= ~port_mask; | 212 | mask &= ~port_mask; |
212 | 213 | ||
213 | /* free if only remaining port is host port */ | 214 | /* free if only remaining port is host port */ |
214 | if (mask == BIT(ale->params.ale_ports)) | 215 | if (mask) |
215 | cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); | ||
216 | else | ||
217 | cpsw_ale_set_port_mask(ale_entry, mask); | 216 | cpsw_ale_set_port_mask(ale_entry, mask); |
217 | else | ||
218 | cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); | ||
219 | } | ||
220 | |||
221 | int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask) | ||
222 | { | ||
223 | u32 ale_entry[ALE_ENTRY_WORDS]; | ||
224 | int ret, idx; | ||
225 | |||
226 | for (idx = 0; idx < ale->params.ale_entries; idx++) { | ||
227 | cpsw_ale_read(ale, idx, ale_entry); | ||
228 | ret = cpsw_ale_get_entry_type(ale_entry); | ||
229 | if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) | ||
230 | continue; | ||
231 | |||
232 | if (cpsw_ale_get_mcast(ale_entry)) { | ||
233 | u8 addr[6]; | ||
234 | |||
235 | cpsw_ale_get_addr(ale_entry, addr); | ||
236 | if (!is_broadcast_ether_addr(addr)) | ||
237 | cpsw_ale_flush_mcast(ale, ale_entry, port_mask); | ||
238 | } | ||
239 | |||
240 | cpsw_ale_write(ale, idx, ale_entry); | ||
241 | } | ||
242 | return 0; | ||
218 | } | 243 | } |
219 | 244 | ||
220 | static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry, | 245 | static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry, |
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index a95b37beb02d..2bd09cbce522 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h | |||
@@ -80,6 +80,7 @@ void cpsw_ale_stop(struct cpsw_ale *ale); | |||
80 | 80 | ||
81 | int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout); | 81 | int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout); |
82 | int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); | 82 | int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); |
83 | int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask); | ||
83 | int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags); | 84 | int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags); |
84 | int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port); | 85 | int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port); |
85 | int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, | 86 | int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |