From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BF007C433EF for ; Thu, 7 Oct 2021 15:13:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A72DC6113E for ; Thu, 7 Oct 2021 15:13:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242524AbhJGPPa (ORCPT ); Thu, 7 Oct 2021 11:15:30 -0400 Received: from esa.microchip.iphmx.com ([68.232.153.233]:8260 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242471AbhJGPPM (ORCPT ); Thu, 7 Oct 2021 11:15:12 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1633619598; x=1665155598; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=F8AdM2bQCohn5beRmiDST/s0/uszilKdA86p30O7lEw=; b=IzD0mu1g/rT6sufgiS/D53kyoUknwAPwS1UJBVdL66yGbjY+LsMCFhMG IGaLWa+yOEk6SmBRC/i61WHtMDuUc5AHgq+t8WODVN4q/IYqu5h1KVoq4 fxx2SW6Ph60LMibXpEVY6xJ4Xa2L82NCq78QXYQLzDCBcFkeJg43zMgDS aMQkXT1qKCJEBv3BGBQEMhjsL9KOcEa7fXKzBV5+NbpZtpqXIRgo5jXJc kxCztEfHz+fdghloiQNYLRXk2IskyG3HJJwfpVmmvWFK9tb+K9EjtMa6a U+vkUaouoJXQhhDXI3VgwkCC4NYDWUma5aPMqtAcrrFzTCTsqwdMJugTD w==; IronPort-SDR: MkGKzUC7AxLA0MUaSxHENuNq44veaNwnp2v1i+x6YaH28orBGd+ZC2aXiaL0DLoMob+Piwpmag u6DE5NXxqxKvOiW1FjWbj/qH9KbHGAOJIGZz1EEsgcJAaUZ+d0WB42e3S/QYE+O55e9lZX64b4 LwRZPZgiD8el8HQRUcBpvIuKS5/T/Zit3PE93/66ku0GqucXPSQ7n3mWKeoI/E4YxIewHBnUtL WXUVQpyXhbBV74YpRGrpWPsI2SEq3PuNLzBq6xfNgXFeR7s85HWDZFw3eukqoSWU1LjjrBknVT VCduOEg1k5liBuy2Dj8Gp/HR X-IronPort-AV: E=Sophos;i="5.85,355,1624345200"; d="scan'208";a="139412269" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa3.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 07 Oct 2021 08:13:17 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.14; Thu, 7 Oct 2021 08:13:17 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2176.14 via Frontend Transport; Thu, 7 Oct 2021 08:13:12 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v4 net-next 10/10] net: dsa: microchip: add support for vlan operations Date: Thu, 7 Oct 2021 20:42:00 +0530 Message-ID: <20211007151200.748944-11-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20211007151200.748944-1-prasanna.vengateshan@microchip.com> References: <20211007151200.748944-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Support for VLAN add, del, prepare and filtering operations. The VLAN aware is a global setting. Mixed vlan filterings are not supported. vlan_filtering_is_global is made as true in lan937x_setup function. Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/lan937x_main.c | 198 +++++++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index f55b2a037ad9..25fa352ec857 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -17,6 +17,14 @@ #include "ksz_common.h" #include "lan937x_dev.h" +static int lan937x_wait_vlan_ctrl_ready(struct ksz_device *dev) +{ + unsigned int val; + + return regmap_read_poll_timeout(dev->regmap[0], REG_SW_VLAN_CTRL, val, + !(val & VLAN_START), 10, 1000); +} + static u8 lan937x_get_fid(u16 vid) { if (vid > ALU_FID_SIZE) @@ -25,6 +33,97 @@ static u8 lan937x_get_fid(u16 vid) return vid; } +static int lan937x_get_vlan_table(struct ksz_device *dev, u16 vid, + struct lan937x_vlan *vlan_entry) +{ + u32 data; + int ret; + + mutex_lock(&dev->vlan_mutex); + + ret = ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + if (ret < 0) + goto exit; + + ret = ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START); + if (ret < 0) + goto exit; + + /* wait to be cleared */ + ret = lan937x_wait_vlan_ctrl_ready(dev); + if (ret < 0) + goto exit; + + ret = ksz_read32(dev, REG_SW_VLAN_ENTRY__4, &data); + if (ret < 0) + goto exit; + + vlan_entry->valid = !!(data & VLAN_VALID); + vlan_entry->fid = data & VLAN_FID_M; + + ret = ksz_read32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, + &vlan_entry->untag_prtmap); + if (ret < 0) + goto exit; + + ret = ksz_read32(dev, REG_SW_VLAN_ENTRY_PORTS__4, + &vlan_entry->fwd_map); + if (ret < 0) + goto exit; + + ret = ksz_write8(dev, REG_SW_VLAN_CTRL, 0); + if (ret < 0) + goto exit; + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + +static int lan937x_set_vlan_table(struct ksz_device *dev, u16 vid, + struct lan937x_vlan *vlan_entry) +{ + u32 data; + int ret; + + mutex_lock(&dev->vlan_mutex); + + data = vlan_entry->valid ? VLAN_VALID : 0; + data |= vlan_entry->fid; + + ret = ksz_write32(dev, REG_SW_VLAN_ENTRY__4, data); + if (ret < 0) + goto exit; + + ret = ksz_write32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, + vlan_entry->untag_prtmap); + if (ret < 0) + goto exit; + + ret = ksz_write32(dev, REG_SW_VLAN_ENTRY_PORTS__4, vlan_entry->fwd_map); + if (ret < 0) + goto exit; + + ret = ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + if (ret < 0) + goto exit; + + ret = ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE); + if (ret < 0) + goto exit; + + /* wait to be cleared */ + ret = lan937x_wait_vlan_ctrl_ready(dev); + if (ret < 0) + goto exit; + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + static int lan937x_read_table(struct ksz_device *dev, u32 *table) { int ret; @@ -193,6 +292,102 @@ static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, ksz_update_port_member(dev, port); } +static int lan937x_port_vlan_filtering(struct dsa_switch *ds, int port, + bool flag, + struct netlink_ext_ack *extack) +{ + struct ksz_device *dev = ds->priv; + int ret; + + ret = lan937x_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, + flag); + + return ret; +} + +static int lan937x_port_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct netlink_ext_ack *extack) +{ + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct ksz_device *dev = ds->priv; + struct lan937x_vlan vlan_entry; + int ret; + + ret = lan937x_get_vlan_table(dev, vlan->vid, &vlan_entry); + if (ret < 0) { + NL_SET_ERR_MSG_MOD(extack, "Failed to get vlan table"); + return ret; + } + + vlan_entry.fid = lan937x_get_fid(vlan->vid); + vlan_entry.valid = true; + + /* set/clear switch port when updating vlan table registers */ + if (untagged) + vlan_entry.untag_prtmap |= BIT(port); + else + vlan_entry.untag_prtmap &= ~BIT(port); + + vlan_entry.fwd_map |= BIT(port); + + ret = lan937x_set_vlan_table(dev, vlan->vid, &vlan_entry); + if (ret < 0) { + NL_SET_ERR_MSG_MOD(extack, "Failed to set vlan table"); + return ret; + } + + /* change PVID */ + if (vlan->flags & BRIDGE_VLAN_INFO_PVID) { + ret = lan937x_pwrite16(dev, port, REG_PORT_DEFAULT_VID, + vlan->vid); + if (ret < 0) { + NL_SET_ERR_MSG_MOD(extack, "Failed to set pvid"); + return ret; + } + } + + return 0; +} + +static int lan937x_port_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct ksz_device *dev = ds->priv; + struct lan937x_vlan vlan_entry; + u16 pvid; + int ret; + + lan937x_pread16(dev, port, REG_PORT_DEFAULT_VID, &pvid); + pvid &= 0xFFF; + + ret = lan937x_get_vlan_table(dev, vlan->vid, &vlan_entry); + if (ret < 0) { + dev_err(dev->dev, "Failed to get vlan table\n"); + return ret; + } + /* clear port fwd map */ + vlan_entry.fwd_map &= ~BIT(port); + + if (untagged) + vlan_entry.untag_prtmap &= ~BIT(port); + + ret = lan937x_set_vlan_table(dev, vlan->vid, &vlan_entry); + if (ret < 0) { + dev_err(dev->dev, "Failed to set vlan table\n"); + return ret; + } + + ret = lan937x_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid); + if (ret < 0) { + dev_err(dev->dev, "Failed to set pvid\n"); + return ret; + } + + return 0; +} + static int lan937x_port_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid) { @@ -1086,6 +1281,9 @@ const struct dsa_switch_ops lan937x_switch_ops = { .port_bridge_leave = ksz_port_bridge_leave, .port_stp_state_set = lan937x_port_stp_state_set, .port_fast_age = ksz_port_fast_age, + .port_vlan_filtering = lan937x_port_vlan_filtering, + .port_vlan_add = lan937x_port_vlan_add, + .port_vlan_del = lan937x_port_vlan_del, .port_fdb_dump = lan937x_port_fdb_dump, .port_fdb_add = lan937x_port_fdb_add, .port_fdb_del = lan937x_port_fdb_del, -- 2.27.0