From patchwork Tue Dec 18 03:31:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tristram.Ha@microchip.com X-Patchwork-Id: 1014941 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=microchip.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43Jk8C5gs7z9sC7 for ; Tue, 18 Dec 2018 14:31:23 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726549AbeLRDbV (ORCPT ); Mon, 17 Dec 2018 22:31:21 -0500 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:53788 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726296AbeLRDbV (ORCPT ); Mon, 17 Dec 2018 22:31:21 -0500 X-IronPort-AV: E=Sophos;i="5.56,367,1539673200"; d="scan'208";a="25382246" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 17 Dec 2018 20:31:20 -0700 Received: from localhost.localdomain (10.10.76.4) by chn-sv-exch04.mchp-main.com (10.10.76.105) with Microsoft SMTP Server id 14.3.352.0; Mon, 17 Dec 2018 20:31:33 -0700 From: To: Sergio Paracuellos , Andrew Lunn , Florian Fainelli , Pavel Machek , Marek Vasut CC: Tristram Ha , , , Subject: [PATCH net-next] net: dsa: microchip: fix VLAN filtering operation Date: Mon, 17 Dec 2018 19:31:21 -0800 Message-ID: <1545103881-28361-1-git-send-email-Tristram.Ha@microchip.com> X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Tristram Ha Fix VLAN filtering operation in kernel 4.15 and later. Fixes: b987e98e50ab90e5 ("dsa: add DSA switch driver for Microchip KSZ9477") Signed-off-by: Tristram Ha --- drivers/net/dsa/microchip/ksz9477.c | 44 ++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 57a146a..28e3fa5 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -496,19 +496,33 @@ static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag) { struct ksz_device *dev = ds->priv; + u32 vlan_table[3]; if (flag) { + vlan_table[0] = VLAN_VALID | 0; + vlan_table[1] = 0; + vlan_table[2] = dev->port_mask; + if (ksz9477_set_vlan_table(dev, 0, vlan_table)) { + dev_dbg(dev->dev, "Failed to set vlan table\n"); + return 0; + } ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, - PORT_VLAN_LOOKUP_VID_0, true); - ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, - true); + (PORT_VLAN_LOOKUP_VID_0 | PORT_INGRESS_FILTER), + true); ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, true); } else { + /* VLAN 1 entry is required to run properly. */ + vlan_table[0] = VLAN_VALID | 0; + vlan_table[1] = 0; + vlan_table[2] = dev->port_mask; + if (ksz9477_set_vlan_table(dev, 1, vlan_table)) { + dev_dbg(dev->dev, "Failed to set vlan table\n"); + return 0; + } ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, false); - ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, - false); ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, - PORT_VLAN_LOOKUP_VID_0, false); + (PORT_VLAN_LOOKUP_VID_0 | PORT_INGRESS_FILTER), + false); } return 0; @@ -521,6 +535,7 @@ static void ksz9477_port_vlan_add(struct dsa_switch *ds, int port, u32 vlan_table[3]; u16 vid; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { if (ksz9477_get_vlan_table(dev, vid, vlan_table)) { @@ -533,7 +548,12 @@ static void ksz9477_port_vlan_add(struct dsa_switch *ds, int port, vlan_table[1] |= BIT(port); else vlan_table[1] &= ~BIT(port); - vlan_table[1] &= ~(BIT(dev->cpu_port)); + + /* Keep host port untagged when setting pvid. */ + if (untagged && pvid) + vlan_table[1] |= BIT(dev->cpu_port); + else + vlan_table[1] &= ~(BIT(dev->cpu_port)); vlan_table[2] |= BIT(port) | BIT(dev->cpu_port); @@ -543,7 +563,7 @@ static void ksz9477_port_vlan_add(struct dsa_switch *ds, int port, } /* change PVID */ - if (vlan->flags & BRIDGE_VLAN_INFO_PVID) + if (pvid) ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vid); } } @@ -568,6 +588,10 @@ static int ksz9477_port_vlan_del(struct dsa_switch *ds, int port, vlan_table[2] &= ~BIT(port); + /* Remove VLAN entry if no longer used. */ + if (vid > 1 && !(vlan_table[2] & ~dev->host_mask)) + vlan_table[0] &= ~VLAN_VALID; + if (pvid == vid) pvid = 1; @@ -1130,6 +1154,10 @@ static int ksz9477_setup(struct dsa_switch *ds) return ret; } + /* Required for port partitioning. */ + ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, + true); + /* accept packet up to 2000bytes */ ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_LEGAL_PACKET_DISABLE, true);