From patchwork Mon Oct 29 18:45:11 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Cochran X-Patchwork-Id: 195117 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 1EB6C2C008F for ; Tue, 30 Oct 2012 05:45:40 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760492Ab2J2Spi (ORCPT ); Mon, 29 Oct 2012 14:45:38 -0400 Received: from mail-ea0-f174.google.com ([209.85.215.174]:37510 "EHLO mail-ea0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1760475Ab2J2Spf (ORCPT ); Mon, 29 Oct 2012 14:45:35 -0400 Received: by mail-ea0-f174.google.com with SMTP id c13so1826941eaa.19 for ; Mon, 29 Oct 2012 11:45:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :in-reply-to:references; bh=nv5X79U4EKWiSGaq2siXiCHzETHYI9znjf0Ri+zST1o=; b=pRrTvKiReoNGfHBcEccIDnrEiykeZgckln3b42io9Qxk9oOP0mTBgMKjmefipxqOqo +4m2hP20NztFWBBtdZ1CO0gAQN7qApr7RfRSuLoTFhZQ/Xig0jtDGL/X3weNVwNdX24L 9lBItE3ESGUn7E91I9kSl8T8DEDKNPUo+7PQKD23I/FMUNAoZkWIQVVV1Jhl8zJWuen0 4e9DcCexq7Fg6fDLsuGQP0koQADrzhtGtvf5AlK5cTHLn6UWE2XXeqwB2h2Ewwisd0p5 kEBcUJeyeUtw9D5/ZUIWnRDnOg34y2dEj8C2sw3Js5XhLp64vuXHATdiIMQt7Gn6sXlZ KVCA== Received: by 10.14.216.193 with SMTP id g41mr55213440eep.37.1351536334642; Mon, 29 Oct 2012 11:45:34 -0700 (PDT) Received: from localhost.localdomain (089144206154.atnat0015.highway.a1.net. [89.144.206.154]) by mx.google.com with ESMTPS id o49sm24364915eep.5.2012.10.29.11.45.32 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 29 Oct 2012 11:45:33 -0700 (PDT) From: Richard Cochran To: Cc: , David Miller , Cyril Chemparathy , Mugunthan V N Subject: [PATCH net-next V3 01/10] drivers: net: ethernet: cpsw: add multicast address to ALE table Date: Mon, 29 Oct 2012 19:45:11 +0100 Message-Id: X-Mailer: git-send-email 1.7.2.5 In-Reply-To: References: In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Mugunthan V N 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 Acked-by: Richard Cochran --- drivers/net/ethernet/ti/cpsw.c | 27 +++++++++++++++++++++++++++ drivers/net/ethernet/ti/cpsw_ale.c | 31 ++++++++++++++++++++++++++++--- 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 df55e24..63b046f 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -70,6 +70,8 @@ do { \ dev_notice(priv->dev, format, ## __VA_ARGS__); \ } while (0) +#define ALE_ALL_PORTS 0x7 + #define CPSW_MAJOR_VERSION(reg) (reg >> 8 & 0x7) #define CPSW_MINOR_VERSION(reg) (reg & 0xff) #define CPSW_RTL_VERSION(reg) ((reg >> 11) & 0x1f) @@ -228,6 +230,30 @@ struct cpsw_priv { (func)((priv)->slaves + idx, ##arg); \ } while (0) +static void cpsw_ndo_set_rx_mode(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + + if (ndev->flags & IFF_PROMISC) { + /* Enable promiscuous mode */ + dev_err(priv->dev, "Ignoring Promiscuous mode\n"); + return; + } + + /* Clear all mcast from ALE */ + cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port); + + if (!netdev_mc_empty(ndev)) { + struct netdev_hw_addr *ha; + + /* program multicast address list into ALE register */ + netdev_for_each_mc_addr(ha, ndev) { + cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr, + ALE_ALL_PORTS << priv->host_port, 0, 0); + } + } +} + static void cpsw_intr_enable(struct cpsw_priv *priv) { __raw_writel(0xFF, &priv->ss_regs->tx_en); @@ -673,6 +699,7 @@ static const struct net_device_ops cpsw_netdev_ops = { .ndo_change_mtu = eth_change_mtu, .ndo_tx_timeout = cpsw_ndo_tx_timeout, .ndo_get_stats = cpsw_ndo_get_stats, + .ndo_set_rx_mode = cpsw_ndo_set_rx_mode, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = cpsw_ndo_poll_controller, #endif diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index ca0d48a..0e9ccc2 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "cpsw_ale.h" @@ -211,10 +212,34 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry, mask &= ~port_mask; /* free if only remaining port is host port */ - if (mask == BIT(ale->params.ale_ports)) - cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); - else + if (mask) cpsw_ale_set_port_mask(ale_entry, mask); + else + cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); +} + +int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask) +{ + u32 ale_entry[ALE_ENTRY_WORDS]; + int ret, idx; + + for (idx = 0; idx < ale->params.ale_entries; idx++) { + cpsw_ale_read(ale, idx, ale_entry); + ret = cpsw_ale_get_entry_type(ale_entry); + if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) + continue; + + if (cpsw_ale_get_mcast(ale_entry)) { + u8 addr[6]; + + cpsw_ale_get_addr(ale_entry, addr); + if (!is_broadcast_ether_addr(addr)) + cpsw_ale_flush_mcast(ale, ale_entry, port_mask); + } + + cpsw_ale_write(ale, idx, ale_entry); + } + return 0; } 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 a95b37b..2bd09cb 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); int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout); int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); +int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask); int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags); int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port); int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,