From patchwork Mon Mar 9 22:07:28 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Krzysztof Halasa X-Patchwork-Id: 448275 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 C13901401AD for ; Tue, 10 Mar 2015 09:14:23 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750933AbbCIWOU (ORCPT ); Mon, 9 Mar 2015 18:14:20 -0400 Received: from inx.pm.waw.pl ([195.116.170.130]:40850 "EHLO inx.pm.waw.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752377AbbCIWOS convert rfc822-to-8bit (ORCPT ); Mon, 9 Mar 2015 18:14:18 -0400 X-Greylist: delayed 406 seconds by postgrey-1.27 at vger.kernel.org; Mon, 09 Mar 2015 18:14:18 EDT Received: by inx.pm.waw.pl (Postfix, from userid 2530) id 2489429938; Mon, 9 Mar 2015 23:07:26 +0100 (CET) From: Krzysztof Halasa To: netdev@vger.kernel.org Subject: [PATCH] Fix IXP4xx Ethernet RX with both IFF_ALLMULTI and IFF_PROMISC. Date: Mon, 09 Mar 2015 23:07:28 +0100 Message-ID: MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This long standing bug caused IFF_PROMISC to be ignored when IFF_ALLMULTI was requested. Also, without any multicast address configured, the driver will use device MAC address for the multicast filter, instead of accepting all inbound traffic. Signed-off-by: Krzysztof HaƂasa --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -933,40 +933,42 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) static void eth_set_mcast_list(struct net_device *dev) { struct port *port = netdev_priv(dev); - struct netdev_hw_addr *ha; - u8 diffs[ETH_ALEN], *addr; int i; static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; - if (dev->flags & IFF_ALLMULTI) { - for (i = 0; i < ETH_ALEN; i++) { - __raw_writel(allmulti[i], &port->regs->mcast_addr[i]); - __raw_writel(allmulti[i], &port->regs->mcast_mask[i]); - } - __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN, - &port->regs->rx_control[0]); - return; - } - - if ((dev->flags & IFF_PROMISC) || netdev_mc_empty(dev)) { + if (dev->flags & IFF_PROMISC) { __raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN, &port->regs->rx_control[0]); return; } - memset(diffs, 0, ETH_ALEN); + if (dev->flags & IFF_ALLMULTI) { + for (i = 0; i < ETH_ALEN; i++) { + __raw_writel(allmulti[i], &port->regs->mcast_addr[i]); + __raw_writel(allmulti[i], &port->regs->mcast_mask[i]); + } + } else { + struct netdev_hw_addr *ha; + u8 diffs[ETH_ALEN], *addr = NULL; + + memset(diffs, 0, ETH_ALEN); + + /* calculate bits which differ between multicast addresses */ + netdev_for_each_mc_addr(ha, dev) { + if (!addr) + addr = ha->addr; /* first multicast address */ + else + for (i = 0; i < ETH_ALEN; i++) + diffs[i] |= addr[i] ^ ha->addr[i]; + } - addr = NULL; - netdev_for_each_mc_addr(ha, dev) { - if (!addr) - addr = ha->addr; /* first MAC address */ - for (i = 0; i < ETH_ALEN; i++) - diffs[i] |= addr[i] ^ ha->addr[i]; - } + if (!addr) /* use device MAC address instead */ + addr = dev->dev_addr; - for (i = 0; i < ETH_ALEN; i++) { - __raw_writel(addr[i], &port->regs->mcast_addr[i]); - __raw_writel(~diffs[i], &port->regs->mcast_mask[i]); + for (i = 0; i < ETH_ALEN; i++) { + __raw_writel(addr[i], &port->regs->mcast_addr[i]); + __raw_writel(~diffs[i], &port->regs->mcast_mask[i]); + } } __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN,