aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/ti
diff options
context:
space:
mode:
authorMugunthan V N <mugunthanvnm@ti.com>2012-10-29 04:45:11 -0400
committerDavid S. Miller <davem@davemloft.net>2012-11-01 12:21:29 -0400
commit5c50a856d550b3bf6a731f6e33a794ed5c519817 (patch)
tree3435bb193aac26e54094a022f809cbe33079a4f0 /drivers/net/ethernet/ti
parent8ef29f8aae524bd51298fb10ac6a5ce6c4c5a3d8 (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.c27
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c31
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.h1
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
233static 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
231static void cpsw_intr_enable(struct cpsw_priv *priv) 257static 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
221int 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
220static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry, 245static 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
81int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout); 81int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);
82int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); 82int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask);
83int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask);
83int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags); 84int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags);
84int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port); 85int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port);
85int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, 86int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,