Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/815498/?format=api
{ "id": 815498, "url": "http://patchwork.ozlabs.org/api/patches/815498/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/1505825158-8192-3-git-send-email-razvan.stefanescu@nxp.com/", "project": { "id": 7, "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api", "name": "Linux network development", "link_name": "netdev", "list_id": "netdev.vger.kernel.org", "list_email": "netdev@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1505825158-8192-3-git-send-email-razvan.stefanescu@nxp.com>", "list_archive_url": null, "date": "2017-09-19T12:45:54", "name": "[RESEND,2/6] staging: fsl-dpaa2/ethsw: Add Freescale DPAA2 Ethernet Switch driver", "commit_ref": null, "pull_url": null, "state": "not-applicable", "archived": true, "hash": "78cb48e36dca99b33c6187e8e0dff6858f9597e8", "submitter": { "id": 72391, "url": "http://patchwork.ozlabs.org/api/people/72391/?format=api", "name": "Razvan Stefanescu", "email": "razvan.stefanescu@nxp.com" }, "delegate": { "id": 34, "url": "http://patchwork.ozlabs.org/api/users/34/?format=api", "username": "davem", "first_name": "David", "last_name": "Miller", "email": "davem@davemloft.net" }, "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/1505825158-8192-3-git-send-email-razvan.stefanescu@nxp.com/mbox/", "series": [ { "id": 3864, "url": "http://patchwork.ozlabs.org/api/series/3864/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netdev/list/?series=3864", "date": "2017-09-19T12:45:58", "name": "staging: Introduce DPAA2 Ethernet Switch driver", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/3864/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/815498/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/815498/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<netdev-owner@vger.kernel.org>", "X-Original-To": "patchwork-incoming@ozlabs.org", "Delivered-To": "patchwork-incoming@ozlabs.org", "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xxN2v2x0fz9s82\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 19 Sep 2017 22:48:23 +1000 (AEST)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1752022AbdISMsE (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tTue, 19 Sep 2017 08:48:04 -0400", "from mail-sn1nam02on0063.outbound.protection.outlook.com\n\t([104.47.36.63]:15858\n\t\"EHLO NAM02-SN1-obe.outbound.protection.outlook.com\"\n\trhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP\n\tid S1751798AbdISMqL (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tTue, 19 Sep 2017 08:46:11 -0400", "from DM5PR03CA0044.namprd03.prod.outlook.com (10.174.189.161) by\n\tCO2PR03MB2357.namprd03.prod.outlook.com (10.166.93.17) with Microsoft\n\tSMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id\n\t15.20.56.11; Tue, 19 Sep 2017 12:46:08 +0000", "from BL2FFO11FD045.protection.gbl (2a01:111:f400:7c09::159) by\n\tDM5PR03CA0044.outlook.office365.com (2603:10b6:4:3b::33) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id\n\t15.20.56.8 via Frontend Transport; Tue, 19 Sep 2017 12:46:08 +0000", "from tx30smr01.am.freescale.net (192.88.168.50) by\n\tBL2FFO11FD045.mail.protection.outlook.com (10.173.161.207) with\n\tMicrosoft\n\tSMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id\n\t15.20.35.14 via Frontend Transport; Tue, 19 Sep 2017 12:46:08 +0000", "from fsr-ub1464-140.ea.freescale.net\n\t(fsr-ub1464-140.ea.freescale.net [10.171.73.107])\n\tby tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id\n\tv8JCjwWg016741; Tue, 19 Sep 2017 05:46:05 -0700" ], "Received-SPF": "Fail (protection.outlook.com: domain of nxp.com does not\n\tdesignate 192.88.168.50 as permitted sender)\n\treceiver=protection.outlook.com; \n\tclient-ip=192.88.168.50; helo=tx30smr01.am.freescale.net;", "From": "Razvan Stefanescu <razvan.stefanescu@nxp.com>", "To": "<gregkh@linuxfoundation.org>", "CC": "<devel@driverdev.osuosl.org>, <linux-kernel@vger.kernel.org>,\n\t<netdev@vger.kernel.org>, <agraf@suse.de>, <arnd@arndb.de>,\n\t<alexandru.marginean@nxp.com>, <bogdan.purcareata@nxp.com>,\n\t<ruxandra.radulescu@nxp.com>, <laurentiu.tudor@nxp.com>,\n\t<stuyoder@gmail.com>", "Subject": "[RESEND PATCH 2/6] staging: fsl-dpaa2/ethsw: Add Freescale DPAA2\n\tEthernet Switch driver", "Date": "Tue, 19 Sep 2017 15:45:54 +0300", "Message-ID": "<1505825158-8192-3-git-send-email-razvan.stefanescu@nxp.com>", "X-Mailer": "git-send-email 1.9.1", "In-Reply-To": "<1505825158-8192-1-git-send-email-razvan.stefanescu@nxp.com>", "References": "<1505825158-8192-1-git-send-email-razvan.stefanescu@nxp.com>", "X-EOPAttributedMessage": "0", "X-Matching-Connectors": "131502987683984343;\n\t(91ab9b29-cfa4-454e-5278-08d120cd25b8); ()", "X-Forefront-Antispam-Report": "CIP:192.88.168.50; IPV:NLI; CTRY:US; EFV:NLI;\n\tSFV:NSPM;\n\tSFS:(10009020)(6009001)(336005)(346002)(39380400002)(376002)(39860400002)(2980300002)(1109001)(1110001)(339900001)(51234002)(189002)(199003)(2950100002)(86362001)(6666003)(77096006)(2906002)(5660300001)(498600001)(47776003)(50986999)(316002)(36756003)(6916009)(16586007)(104016004)(76176999)(356003)(50226002)(8676002)(33646002)(105606002)(2351001)(305945005)(106466001)(81166006)(81156014)(48376002)(50466002)(97736004)(8936002)(68736007)(39060400002)(53936002)(53946003)(54906002)(7416002)(4326008)(5003940100001)(8656003)(189998001)(2004002)(217873001)(579004)(309714004);\n\tDIR:OUT; SFP:1101; SCL:1; SRVR:CO2PR03MB2357;\n\tH:tx30smr01.am.freescale.net; FPR:; SPF:Fail;\n\tPTR:InfoDomainNonexistent; MX:1; A:1; LANG:en; ", "X-Microsoft-Exchange-Diagnostics": [ "1; BL2FFO11FD045;\n\t1:oDiriyzZWNmANG3zHENTwIvADv0k1ZmO4hrkBus41WCMY5EMXHKtz7OkBTZqz1yTi+kg05xRh9uo6L+Us14LbV07VpfQ60PGf0ID50hD9VFpEuBXggOiD0JSAFNZxcWt", "1; CO2PR03MB2357;\n\t3:pDWogJXCOu9IAAjanslJ+Bpfkl6SVtdMLAi5LVoqP0JxSTmVcq15n9rQx+b9hN69eIFvOW2ua9I3H8EHFJAkO1DGwk8Ez6LKGW2iKDzYP7Bfs/1NLQE1dW1XUocfYNZZXKhmn46UOzslPQtNSpZ0BlbgY7hqyUwO+XblukVYvKAgKX3ACpnRt/CmiBVVv2+Em0/AH/rjeJCFwwcAFcypyxJLC23LbRftor+PDkQEwlxFmtnHRAveo/2S7xdTJ3KmFtU94RVm9UQk4nSwTorACHiFDhcT8FdfshNCXW/RNM1En/XJaxogS+4D5Ruo7a/iZ+1YThAjNVuIr9iaFiVSPUI4k7gtOsjQd1AkRtPzCJo=;\n\t25:k+Gv2vTuMot2YngMMuV0CpsJkEx/dyIS59eP8HjyTr8ZHjmlh1h6lESbO/mI0O2XXZ5c4kNOw/D6ugMI3lSlr/Poed9nwl/uoCD1AeAae97mdVqZe2Og2N2PTdJ5Mkl6NMJjiyoy5F+gBmrAgvv43/6ruxdgd9PUnjYaIZ9MhTA2D5BNe7jQTNnGt1/ldAZ1uVbw40E44ImalPwh8IppfmUFbhCNjmXcGlcXLgAPUCi4F0jFGgfn2edFvWrbacl7uHZ+39TRyc7vzjT9dK2aV2sKLA/IE2A3WAmkSOTbc7GeLDZaIHKeo5NHTIivZh3NAmQDbTIVJbGenmV3bp195g==", "1; CO2PR03MB2357;\n\t31:oQSz1Q7KKA1Tr1I2fqKXYz+WSq6oC26pkzCKY/OeVp9A9CA4B7KOs8+R8AUjFWUe/cusJOi6LTKVkpWKqcFjinHvJlauBFv+ZblTo9o5TTmK+pIlqYAK41d5kJcn3cF1LkznzII7+9lbwJYnpalBA+i1PYEVuA79otN35o5aV0PoVW5u30ZjZCbXzOsQ0Cf9z3losTMbQWJdIMG0EL6zhVD6qr5zxX+5/gjJRnoY9fI=;\n\t4:IDcNWqOKgq4zu4qH+XuT9dmrEZdw7PKGdjPXsnVcjsRisU0BWlc+pLbPSI30exGjykbj5wI2Me+xzpuFg5xbs6cZYIeEZDhFC37IumUZmI4pUzKiXhg74/YamTBOwBSutZ1OmbIWmGiecZIQ6VES9xxuaCqk1Mvahh9QroR1RpFi17VPeOzpAr7kPV9fPBVp5AoEimyJ+3GWqNLgsmoY+XkKOFKLKSHCNGfNRznso6jSkLL3lLqxPwIp0QBxgJUNk+Vlr+e+gGaP6HSl9guCKG6KmDjNuRoyxNLcuddWJX8=", "1; CO2PR03MB2357;\n\t23:10wGFUjxoKtx4BIc4uLUwPXS0DgQRVgxZjwz+n6P+TSsqYLQ2WDEmIbpaVkVLZl18TzxbnL/+0fQfbCB+NZWlbwc2P+6DsX9YEDftGw+DKvGulD5iCEP73z1GZLaBnrYQIU4Mfa9KK4jXKSau2+aTrsFClz5CNAzNafKyqgI0GihvbSteMpYa9y6g1tRRCEFNgN/nJJ/rskP/x7yXDK5DDwe21H26zORWCW3783hsI8wYuczKgGMnkpB7+jJCssN1eE0Wn14VxWrzuB59BTMqYEyIPDIBtTVpu6xp4aYK5lM8AYV+zKxTu//JCPYZlI1Fx1k7OcW+0j7LMEi1EXywfASDMpT/enkorp0iPrSiwriVF8uMBDCk4J7MzaIVMrEnO9HNnBeQQ6j1zSqXpLT3avlV5csZubB+7hL2hrqbIGLeATQxf4XTBQV33tPQk4oIfpOKrr+/1ugKYZ+qFOeuaW+B86r7FVnAbkmCdgK4Gk8gR5QKsNbmbBfyUkDhAipFrWPB9R4iuA7jjUlmtMbZjKzdjZfRaREX4Y1YFRd95nHakyyVjyclKB+5fiss5LnqtYqd4+bjPzbCsLmECHO78JGT3ZvWjU7sBclPRMOHPXOvEUpYslAExWXcY0lakg+5gzcXZPLKDysbDuU08faCBY7dZY4SGXdsHyLjb3wvfRrsXOPu8Wj3tIj4+gZ9pepI8Ugg+r/an6Jx5hsecdapk6rNoK3+nDaUyugZ332NkAEZFgKr1xn1grO4bNWa+Dn1HdhPR8GYkZ/ujb/XOi+LFD0A4Vimlxl1EPBIJgmDg6NN77pNnDifzJUrTGbza76L36ub2IgzP5mf4hls148Pg6/cMuPBofW2o6qMi4+PocSWISfhShmct0TfyMz4tosN9M5SQUtF7r+y2UgFJ2AndkfXg8ThhPdZGcBLFN6ecKz3KB5aZ6cm49sgXrrLi3uonc/EdYhE2NVfVye8js2hmtOcHaaViaxo1WXwjOnA05t99qrKizi27dCVuvTLXYeoPkmKHApMIyP4FRX1b0xy1OWz+d38Oqt5GrNfakfpNeKGrKCZe++lHKM6v0bKzuTQBtNZCOwD/uXzUV0cE7lyBx4eU5coaTrJXrVsvRd6uObvQWpg2ZAwDaDVfJdKOfvSbQTzFmuQBLw1xXwLZmkpF2f+PvDIRE8kIE+vhuB8h6Dw3Jgd+S0PWGH/FoBfQv+yC1nATzIqZ11HIzAim8DUHqNuYmFQLm3Y2GGdl+fhpmt5axDJmAnXCeyLYekW8r66ouSivt3ji+XO6b5bSR0oOH9uqfcRwyVHEByUC2DLD4=", "1; CO2PR03MB2357;\n\t6:SV3lOS/3Xp18X0qdnCa0Yc8QtYIO1mjOTXnpdsgjd31rMFps6BQZzJpBnfMxPA85w5jFpcKamqigmXFQaVeHVo4vJYbEbfp+kcJC5S90qzrxscZeOOeyq734qfRx77JvIq8UZDgZKQwFpSyljpJ/mz+rzZ32i1GHHBljVCkM0gHbhmQgyh3U8YMnVQTEoHlMSCB9zN8p9repb65wXZLWIWNJ4/8W6dfxFbT5sDlW3BXxSIoJAiGgjEBc88oXKU34pBCs1K5BCgZCdCSKKNJcjwoIn+BuH5f1uvilC4668QIdLWYvg1xqAjuFti4atNmGemSZ5/IguVgR3cYEcQaeFw==;\n\t5:35IUJrEIE/gIJbTa3zd5bmJVEqkPSGfhx3D5ynzXsN3cWpaZAtUixqzA0iMBIii8k6XKcyc75aDjailCpLc4qm0AAURrczF3+HUUMZZg3vEw3YRtojI/RHSHONQTM3fTuA3HED9M85E/eA7r8t9YNg==;\n\t24:3p5JRcH0eVlZebMD7epXDZlr8AQLPS0uM9DQUo9oEJyjjKsasfW6XLngKdHaizYnFdKMydD3g6i8A+VFX79SO6HrplJWw27hcnuIysiKgVw=;\n\t7:ZWSdsZWjsXAaHP1lRpLkPMWu9v/b1OlAU7FleGXqFAS1Ldvk5COrUXj8ozlN0UPvag9Pd1k/oE0wtJ5yJcEEtIAuqnXKMnKWyaUJpJhpa6XVFnnZuJM3muGW4IySPCw7QCbztLgA0yVZj/CcIEhZYmgJBRi0RXR2Qs2dPL2evpxvM/i9x7vMfPfrHLSF2IuW7SIIja4eYE/zn/E2YvHFfKP473EIf5LX6RwOaB32nXI=" ], "MIME-Version": "1.0", "Content-Type": "text/plain", "X-MS-PublicTrafficType": "Email", "X-MS-Office365-Filtering-Correlation-Id": "51f95bac-14e5-42c2-127a-08d4ff5c6643", "X-Microsoft-Antispam": "UriScan:; BCL:0; PCL:0;\n\tRULEID:(300000500095)(300135000095)(300000501095)(300135300095)(22001)(300000502095)(300135100095)(300000503095)(300135400095)(2017052603199)(201703131430075)(201703131517081)(300000504095)(300135200095)(300000505095)(300135600095)(300000506095)(300135500095);\n\tSRVR:CO2PR03MB2357; ", "X-MS-TrafficTypeDiagnostic": "CO2PR03MB2357:", "X-Exchange-Antispam-Report-Test": "UriScan:(185117386973197);", "X-Microsoft-Antispam-PRVS": "<CO2PR03MB2357907D6155B4FDE10F5B0DE6600@CO2PR03MB2357.namprd03.prod.outlook.com>", "X-Exchange-Antispam-Report-CFA-Test": "BCL:0; PCL:0;\n\tRULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6095135)(2401047)(5005006)(8121501046)(10201501046)(93006095)(93001095)(3002001)(100000703101)(100105400095)(6055026)(6096035)(20161123559100)(20161123556025)(20161123561025)(201703131430075)(201703131433075)(201703131448075)(201703161259150)(201703151042153)(20161123563025)(20161123565025)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);\n\tSRVR:CO2PR03MB2357; BCL:0; PCL:0;\n\tRULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(400006)(100000804101)(100110200095)(100000805101)(100110500095);\n\tSRVR:CO2PR03MB2357; ", "X-Forefront-PRVS": "04359FAD81", "SpamDiagnosticOutput": "1:99", "SpamDiagnosticMetadata": "NSPM", "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "19 Sep 2017 12:46:08.2268\n\t(UTC)", "X-MS-Exchange-CrossTenant-Id": "5afe0b00-7697-4969-b663-5eab37d5f47e", "X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp": "TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e;\n\tIp=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net]", "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem", "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "CO2PR03MB2357", "Sender": "netdev-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<netdev.vger.kernel.org>", "X-Mailing-List": "netdev@vger.kernel.org" }, "content": "Introduce the DPAA2 Ethernet Switch driver, which manages Datapath Switch\n(DPSW) objects discovered on the MC bus.\n\nSuggested-by: Alexandru Marginean <alexandru.marginean@nxp.com>\nSigned-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>\n---\n drivers/staging/fsl-dpaa2/ethsw/Makefile | 2 +-\n drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 1523 ++++++++++++++++++++++++++++++\n drivers/staging/fsl-dpaa2/ethsw/ethsw.h | 88 ++\n 3 files changed, 1612 insertions(+), 1 deletion(-)\n create mode 100644 drivers/staging/fsl-dpaa2/ethsw/ethsw.c\n create mode 100644 drivers/staging/fsl-dpaa2/ethsw/ethsw.h", "diff": "diff --git a/drivers/staging/fsl-dpaa2/ethsw/Makefile b/drivers/staging/fsl-dpaa2/ethsw/Makefile\nindex db137f7..a6d72d1 100644\n--- a/drivers/staging/fsl-dpaa2/ethsw/Makefile\n+++ b/drivers/staging/fsl-dpaa2/ethsw/Makefile\n@@ -4,4 +4,4 @@\n \n obj-$(CONFIG_FSL_DPAA2_ETHSW) += dpaa2-ethsw.o\n \n-dpaa2-ethsw-objs := dpsw.o\n+dpaa2-ethsw-objs := ethsw.o dpsw.o\ndiff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c\nnew file mode 100644\nindex 0000000..ae86078\n--- /dev/null\n+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c\n@@ -0,0 +1,1523 @@\n+/* Copyright 2014-2016 Freescale Semiconductor Inc.\n+ * Copyright 2017 NXP\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ * * Redistributions of source code must retain the above copyright\n+ *\t notice, this list of conditions and the following disclaimer.\n+ * * Redistributions in binary form must reproduce the above copyright\n+ *\t notice, this list of conditions and the following disclaimer in the\n+ *\t documentation and/or other materials provided with the distribution.\n+ * * Neither the name of the above-listed copyright holders nor the\n+ *\t names of any contributors may be used to endorse or promote products\n+ *\t derived from this software without specific prior written permission.\n+ *\n+ *\n+ * ALTERNATIVELY, this software may be distributed under the terms of the\n+ * GNU General Public License (\"GPL\") as published by the Free Software\n+ * Foundation, either version 2 of that License or (at your option) any\n+ * later version.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\n+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n+ * POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <linux/module.h>\n+\n+#include <linux/interrupt.h>\n+#include <linux/msi.h>\n+#include <linux/kthread.h>\n+#include <linux/workqueue.h>\n+\n+#include \"../../fsl-mc/include/mc.h\"\n+\n+#include \"ethsw.h\"\n+\n+static struct workqueue_struct *ethsw_owq;\n+\n+/* Minimal supported DPSW version */\n+#define DPSW_MIN_VER_MAJOR\t\t8\n+#define DPSW_MIN_VER_MINOR\t\t0\n+\n+#define DEFAULT_VLAN_ID\t\t\t1\n+\n+static int ethsw_add_vlan(struct ethsw_core *ethsw, u16 vid)\n+{\n+\tint err;\n+\n+\tstruct dpsw_vlan_cfg\tvcfg = {\n+\t\t.fdb_id = 0,\n+\t};\n+\n+\tif (ethsw->vlans[vid]) {\n+\t\tdev_err(ethsw->dev, \"VLAN already configured\\n\");\n+\t\treturn -EEXIST;\n+\t}\n+\n+\terr = dpsw_vlan_add(ethsw->mc_io, 0,\n+\t\t\t ethsw->dpsw_handle, vid, &vcfg);\n+\tif (err) {\n+\t\tdev_err(ethsw->dev, \"dpsw_vlan_add err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\tethsw->vlans[vid] = ETHSW_VLAN_MEMBER;\n+\n+\treturn 0;\n+}\n+\n+static int ethsw_port_add_vlan(struct ethsw_port_priv *port_priv,\n+\t\t\t u16 vid, u16 flags)\n+{\n+\tstruct ethsw_core *ethsw = port_priv->ethsw_data;\n+\tstruct net_device *netdev = port_priv->netdev;\n+\tstruct dpsw_vlan_if_cfg vcfg;\n+\tbool is_oper;\n+\tint err, err2;\n+\n+\tif (port_priv->vlans[vid]) {\n+\t\tnetdev_warn(netdev, \"VLAN %d already configured\\n\", vid);\n+\t\treturn -EEXIST;\n+\t}\n+\n+\tvcfg.num_ifs = 1;\n+\tvcfg.if_id[0] = port_priv->idx;\n+\terr = dpsw_vlan_add_if(ethsw->mc_io, 0, ethsw->dpsw_handle, vid, &vcfg);\n+\tif (err) {\n+\t\tnetdev_err(netdev, \"dpsw_vlan_add_if err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\tport_priv->vlans[vid] = ETHSW_VLAN_MEMBER;\n+\n+\tif (flags & BRIDGE_VLAN_INFO_UNTAGGED) {\n+\t\terr = dpsw_vlan_add_if_untagged(ethsw->mc_io, 0,\n+\t\t\t\t\t\tethsw->dpsw_handle,\n+\t\t\t\t\t\tvid, &vcfg);\n+\t\tif (err) {\n+\t\t\tnetdev_err(netdev,\n+\t\t\t\t \"dpsw_vlan_add_if_untagged err %d\\n\", err);\n+\t\t\treturn err;\n+\t\t}\n+\t\tport_priv->vlans[vid] |= ETHSW_VLAN_UNTAGGED;\n+\t}\n+\n+\tif (flags & BRIDGE_VLAN_INFO_PVID) {\n+\t\tstruct dpsw_tci_cfg tci_cfg = {\n+\t\t\t.pcp = 0,\n+\t\t\t.dei = 0,\n+\t\t\t.vlan_id = vid,\n+\t\t};\n+\n+\t\t/* Interface needs to be down to change PVID */\n+\t\tis_oper = netif_oper_up(netdev);\n+\t\tif (is_oper) {\n+\t\t\terr = dpsw_if_disable(ethsw->mc_io, 0,\n+\t\t\t\t\t ethsw->dpsw_handle,\n+\t\t\t\t\t port_priv->idx);\n+\t\t\tif (err) {\n+\t\t\t\tnetdev_err(netdev,\n+\t\t\t\t\t \"dpsw_if_disable err %d\\n\", err);\n+\t\t\t\treturn err;\n+\t\t\t}\n+\t\t}\n+\n+\t\terr = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\t port_priv->idx, &tci_cfg);\n+\t\tif (!err) {\n+\t\t\t/* Delete previous PVID info and mark the new one */\n+\t\t\tif (port_priv->pvid)\n+\t\t\t\tport_priv->vlans[port_priv->pvid]\n+\t\t\t\t\t\t ^= ETHSW_VLAN_PVID;\n+\n+\t\t\tport_priv->vlans[vid] |= ETHSW_VLAN_PVID;\n+\t\t\tport_priv->pvid = vid;\n+\t\t} else {\n+\t\t\tnetdev_err(netdev, \"dpsw_if_set_tci err %d\\n\", err);\n+\t\t}\n+\n+\t\tif (is_oper) {\n+\t\t\terr2 = dpsw_if_enable(ethsw->mc_io, 0,\n+\t\t\t\t\t ethsw->dpsw_handle,\n+\t\t\t\t\t port_priv->idx);\n+\t\t\tif (err2) {\n+\t\t\t\tnetdev_err(netdev,\n+\t\t\t\t\t \"dpsw_if_enable err %d\\n\", err2);\n+\t\t\t\treturn err2;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn err;\n+}\n+\n+static int ethsw_set_learning(struct ethsw_core *ethsw, u8 flag)\n+{\n+\tenum dpsw_fdb_learning_mode learn_mode;\n+\tint err;\n+\n+\tif (flag)\n+\t\tlearn_mode = DPSW_FDB_LEARNING_MODE_HW;\n+\telse\n+\t\tlearn_mode = DPSW_FDB_LEARNING_MODE_DIS;\n+\n+\terr = dpsw_fdb_set_learning_mode(ethsw->mc_io, 0, ethsw->dpsw_handle, 0,\n+\t\t\t\t\t learn_mode);\n+\tif (err) {\n+\t\tdev_err(ethsw->dev, \"dpsw_fdb_set_learning_mode err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\tethsw->learning = !!flag;\n+\n+\treturn 0;\n+}\n+\n+static int ethsw_port_set_flood(struct ethsw_port_priv *port_priv, u8 flag)\n+{\n+\tint err;\n+\n+\terr = dpsw_if_set_flooding(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t port_priv->idx, (int)flag);\n+\tif (err) {\n+\t\tnetdev_err(port_priv->netdev,\n+\t\t\t \"dpsw_fdb_set_learning_mode err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\tport_priv->flood = !!flag;\n+\n+\treturn 0;\n+}\n+\n+static int ethsw_port_set_stp_state(struct ethsw_port_priv *port_priv, u8 state)\n+{\n+\tstruct dpsw_stp_cfg stp_cfg = {\n+\t\t.vlan_id = DEFAULT_VLAN_ID,\n+\t\t.state = state,\n+\t};\n+\tint err;\n+\n+\tif (!netif_oper_up(port_priv->netdev) || state == port_priv->stp_state)\n+\t\treturn 0;\t/* Nothing to do */\n+\n+\terr = dpsw_if_set_stp(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t port_priv->idx, &stp_cfg);\n+\tif (err) {\n+\t\tnetdev_err(port_priv->netdev,\n+\t\t\t \"dpsw_if_set_stp err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\tport_priv->stp_state = state;\n+\n+\treturn 0;\n+}\n+\n+static int ethsw_dellink_switch(struct ethsw_core *ethsw, u16 vid)\n+{\n+\tstruct ethsw_port_priv *ppriv_local = NULL;\n+\tint i, err;\n+\n+\tif (!ethsw->vlans[vid])\n+\t\treturn -ENOENT;\n+\n+\terr = dpsw_vlan_remove(ethsw->mc_io, 0, ethsw->dpsw_handle, vid);\n+\tif (err) {\n+\t\tdev_err(ethsw->dev, \"dpsw_vlan_remove err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\tethsw->vlans[vid] = 0;\n+\n+\tfor (i = 0; i < ethsw->sw_attr.num_ifs; i++) {\n+\t\tppriv_local = ethsw->ports[i];\n+\t\tppriv_local->vlans[vid] = 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int ethsw_port_fdb_add_uc(struct ethsw_port_priv *port_priv,\n+\t\t\t\t const unsigned char *addr)\n+{\n+\tstruct dpsw_fdb_unicast_cfg entry = {0};\n+\tint err;\n+\n+\tentry.if_egress = port_priv->idx;\n+\tentry.type = DPSW_FDB_ENTRY_STATIC;\n+\tether_addr_copy(entry.mac_addr, addr);\n+\n+\terr = dpsw_fdb_add_unicast(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t 0, &entry);\n+\tif (err)\n+\t\tnetdev_err(port_priv->netdev,\n+\t\t\t \"dpsw_fdb_add_unicast err %d\\n\", err);\n+\treturn err;\n+}\n+\n+static int ethsw_port_fdb_del_uc(struct ethsw_port_priv *port_priv,\n+\t\t\t\t const unsigned char *addr)\n+{\n+\tstruct dpsw_fdb_unicast_cfg entry = {0};\n+\tint err;\n+\n+\tentry.if_egress = port_priv->idx;\n+\tentry.type = DPSW_FDB_ENTRY_STATIC;\n+\tether_addr_copy(entry.mac_addr, addr);\n+\n+\terr = dpsw_fdb_remove_unicast(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t 0, &entry);\n+\tif (err)\n+\t\tnetdev_err(port_priv->netdev,\n+\t\t\t \"dpsw_fdb_remove_unicast err %d\\n\", err);\n+\treturn err;\n+}\n+\n+static int ethsw_port_fdb_add_mc(struct ethsw_port_priv *port_priv,\n+\t\t\t\t const unsigned char *addr)\n+{\n+\tstruct dpsw_fdb_multicast_cfg entry = {0};\n+\tint err;\n+\n+\tether_addr_copy(entry.mac_addr, addr);\n+\tentry.type = DPSW_FDB_ENTRY_STATIC;\n+\tentry.num_ifs = 1;\n+\tentry.if_id[0] = port_priv->idx;\n+\n+\terr = dpsw_fdb_add_multicast(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t 0, &entry);\n+\tif (err)\n+\t\tnetdev_err(port_priv->netdev, \"dpsw_fdb_add_multicast err %d\\n\",\n+\t\t\t err);\n+\treturn err;\n+}\n+\n+static int ethsw_port_fdb_del_mc(struct ethsw_port_priv *port_priv,\n+\t\t\t\t const unsigned char *addr)\n+{\n+\tstruct dpsw_fdb_multicast_cfg entry = {0};\n+\tint err;\n+\n+\tether_addr_copy(entry.mac_addr, addr);\n+\tentry.type = DPSW_FDB_ENTRY_STATIC;\n+\tentry.num_ifs = 1;\n+\tentry.if_id[0] = port_priv->idx;\n+\n+\terr = dpsw_fdb_remove_multicast(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t\tport_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t\t0, &entry);\n+\tif (err)\n+\t\tnetdev_err(port_priv->netdev,\n+\t\t\t \"dpsw_fdb_remove_multicast err %d\\n\", err);\n+\treturn err;\n+}\n+\n+static void port_get_stats(struct net_device *netdev,\n+\t\t\t struct rtnl_link_stats64 *stats)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tu64 tmp;\n+\tint err;\n+\n+\terr = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t port_priv->idx,\n+\t\t\t\t DPSW_CNT_ING_FRAME, &stats->rx_packets);\n+\tif (err)\n+\t\tgoto error;\n+\n+\terr = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t port_priv->idx,\n+\t\t\t\t DPSW_CNT_EGR_FRAME, &stats->tx_packets);\n+\tif (err)\n+\t\tgoto error;\n+\n+\terr = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t port_priv->idx,\n+\t\t\t\t DPSW_CNT_ING_BYTE, &stats->rx_bytes);\n+\tif (err)\n+\t\tgoto error;\n+\n+\terr = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t port_priv->idx,\n+\t\t\t\t DPSW_CNT_EGR_BYTE, &stats->tx_bytes);\n+\tif (err)\n+\t\tgoto error;\n+\n+\terr = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t port_priv->idx,\n+\t\t\t\t DPSW_CNT_ING_FRAME_DISCARD,\n+\t\t\t\t &stats->rx_dropped);\n+\tif (err)\n+\t\tgoto error;\n+\n+\terr = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t port_priv->idx,\n+\t\t\t\t DPSW_CNT_ING_FLTR_FRAME,\n+\t\t\t\t &tmp);\n+\tif (err)\n+\t\tgoto error;\n+\tstats->rx_dropped += tmp;\n+\n+\terr = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t port_priv->idx,\n+\t\t\t\t DPSW_CNT_EGR_FRAME_DISCARD,\n+\t\t\t\t &stats->tx_dropped);\n+\tif (err)\n+\t\tgoto error;\n+\n+\treturn;\n+\n+error:\n+\tnetdev_err(netdev, \"dpsw_if_get_counter err %d\\n\", err);\n+}\n+\n+static bool port_has_offload_stats(const struct net_device *netdev,\n+\t\t\t\t int attr_id)\n+{\n+\treturn (attr_id == IFLA_OFFLOAD_XSTATS_CPU_HIT);\n+}\n+\n+static int port_get_offload_stats(int attr_id,\n+\t\t\t\t const struct net_device *netdev,\n+\t\t\t\t void *sp)\n+{\n+\tswitch (attr_id) {\n+\tcase IFLA_OFFLOAD_XSTATS_CPU_HIT:\n+\t\tport_get_stats((struct net_device *)netdev, sp);\n+\t\treturn 0;\n+\t}\n+\n+\treturn -EINVAL;\n+}\n+\n+static int port_change_mtu(struct net_device *netdev, int mtu)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tint err;\n+\n+\terr = dpsw_if_set_max_frame_length(port_priv->ethsw_data->mc_io,\n+\t\t\t\t\t 0,\n+\t\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t\t port_priv->idx,\n+\t\t\t\t\t (u16)ETHSW_L2_MAX_FRM(mtu));\n+\tif (err) {\n+\t\tnetdev_err(netdev,\n+\t\t\t \"dpsw_if_set_max_frame_length() err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\tnetdev->mtu = mtu;\n+\treturn 0;\n+}\n+\n+static int port_carrier_state_sync(struct net_device *netdev)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tstruct dpsw_link_state state;\n+\tint err;\n+\n+\terr = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t\t port_priv->idx, &state);\n+\tif (err) {\n+\t\tnetdev_err(netdev, \"dpsw_if_get_link_state() err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\tWARN_ONCE(state.up > 1, \"Garbage read into link_state\");\n+\n+\tif (state.up != port_priv->link_state) {\n+\t\tif (state.up)\n+\t\t\tnetif_carrier_on(netdev);\n+\t\telse\n+\t\t\tnetif_carrier_off(netdev);\n+\t\tport_priv->link_state = state.up;\n+\t}\n+\treturn 0;\n+}\n+\n+static int port_open(struct net_device *netdev)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tint err;\n+\n+\t/* No need to allow Tx as control interface is disabled */\n+\tnetif_tx_stop_all_queues(netdev);\n+\n+\terr = dpsw_if_enable(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t port_priv->idx);\n+\tif (err) {\n+\t\tnetdev_err(netdev, \"dpsw_if_enable err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\t/* sync carrier state */\n+\terr = port_carrier_state_sync(netdev);\n+\tif (err) {\n+\t\tnetdev_err(netdev,\n+\t\t\t \"port_carrier_state_sync err %d\\n\", err);\n+\t\tgoto err_carrier_sync;\n+\t}\n+\n+\treturn 0;\n+\n+err_carrier_sync:\n+\tdpsw_if_disable(port_priv->ethsw_data->mc_io, 0,\n+\t\t\tport_priv->ethsw_data->dpsw_handle,\n+\t\t\tport_priv->idx);\n+\treturn err;\n+}\n+\n+static int port_stop(struct net_device *netdev)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tint err;\n+\n+\terr = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0,\n+\t\t\t port_priv->ethsw_data->dpsw_handle,\n+\t\t\t port_priv->idx);\n+\tif (err) {\n+\t\tnetdev_err(netdev, \"dpsw_if_disable err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static netdev_tx_t port_dropframe(struct sk_buff *skb,\n+\t\t\t\t struct net_device *netdev)\n+{\n+\t/* we don't support I/O for now, drop the frame */\n+\tdev_kfree_skb_any(skb);\n+\n+\treturn NETDEV_TX_OK;\n+}\n+\n+static const struct net_device_ops ethsw_port_ops = {\n+\t.ndo_open\t\t= port_open,\n+\t.ndo_stop\t\t= port_stop,\n+\n+\t.ndo_set_mac_address\t= eth_mac_addr,\n+\t.ndo_change_mtu\t\t= port_change_mtu,\n+\t.ndo_has_offload_stats\t= port_has_offload_stats,\n+\t.ndo_get_offload_stats\t= port_get_offload_stats,\n+\n+\t.ndo_start_xmit\t\t= port_dropframe,\n+};\n+\n+static void ethsw_links_state_update(struct ethsw_core *ethsw)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ethsw->sw_attr.num_ifs; i++)\n+\t\tport_carrier_state_sync(ethsw->ports[i]->netdev);\n+}\n+\n+static irqreturn_t ethsw_irq0_handler(int irq_num, void *arg)\n+{\n+\treturn IRQ_WAKE_THREAD;\n+}\n+\n+static irqreturn_t ethsw_irq0_handler_thread(int irq_num, void *arg)\n+{\n+\tstruct device *dev = (struct device *)arg;\n+\tstruct ethsw_core *ethsw = dev_get_drvdata(dev);\n+\n+\t/* Mask the events and the if_id reserved bits to be cleared on read */\n+\tu32 status = DPSW_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000;\n+\tint err;\n+\n+\terr = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\t DPSW_IRQ_INDEX_IF, &status);\n+\tif (err) {\n+\t\tdev_err(dev, \"Can't get irq status (err %d)\", err);\n+\n+\t\terr = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\t\t DPSW_IRQ_INDEX_IF, 0xFFFFFFFF);\n+\t\tif (err)\n+\t\t\tdev_err(dev, \"Can't clear irq status (err %d)\", err);\n+\t\tgoto out;\n+\t}\n+\n+\tif (status & DPSW_IRQ_EVENT_LINK_CHANGED)\n+\t\tethsw_links_state_update(ethsw);\n+\n+out:\n+\treturn IRQ_HANDLED;\n+}\n+\n+static int ethsw_setup_irqs(struct fsl_mc_device *sw_dev)\n+{\n+\tstruct device *dev = &sw_dev->dev;\n+\tstruct ethsw_core *ethsw = dev_get_drvdata(dev);\n+\tu32 mask = DPSW_IRQ_EVENT_LINK_CHANGED;\n+\tstruct fsl_mc_device_irq *irq;\n+\tint err;\n+\n+\terr = fsl_mc_allocate_irqs(sw_dev);\n+\tif (err) {\n+\t\tdev_err(dev, \"MC irqs allocation failed\\n\");\n+\t\treturn err;\n+\t}\n+\n+\tif (WARN_ON(sw_dev->obj_desc.irq_count != DPSW_IRQ_NUM)) {\n+\t\terr = -EINVAL;\n+\t\tgoto free_irq;\n+\t}\n+\n+\terr = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\t DPSW_IRQ_INDEX_IF, 0);\n+\tif (err) {\n+\t\tdev_err(dev, \"dpsw_set_irq_enable err %d\\n\", err);\n+\t\tgoto free_irq;\n+\t}\n+\n+\tirq = sw_dev->irqs[DPSW_IRQ_INDEX_IF];\n+\n+\terr = devm_request_threaded_irq(dev, irq->msi_desc->irq,\n+\t\t\t\t\tethsw_irq0_handler,\n+\t\t\t\t\tethsw_irq0_handler_thread,\n+\t\t\t\t\tIRQF_NO_SUSPEND | IRQF_ONESHOT,\n+\t\t\t\t\tdev_name(dev), dev);\n+\tif (err) {\n+\t\tdev_err(dev, \"devm_request_threaded_irq(): %d\", err);\n+\t\tgoto free_irq;\n+\t}\n+\n+\terr = dpsw_set_irq_mask(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\tDPSW_IRQ_INDEX_IF, mask);\n+\tif (err) {\n+\t\tdev_err(dev, \"dpsw_set_irq_mask(): %d\", err);\n+\t\tgoto free_devm_irq;\n+\t}\n+\n+\terr = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\t DPSW_IRQ_INDEX_IF, 1);\n+\tif (err) {\n+\t\tdev_err(dev, \"dpsw_set_irq_enable(): %d\", err);\n+\t\tgoto free_devm_irq;\n+\t}\n+\n+\treturn 0;\n+\n+free_devm_irq:\n+\tdevm_free_irq(dev, irq->msi_desc->irq, dev);\n+free_irq:\n+\tfsl_mc_free_irqs(sw_dev);\n+\treturn err;\n+}\n+\n+static void ethsw_teardown_irqs(struct fsl_mc_device *sw_dev)\n+{\n+\tstruct device *dev = &sw_dev->dev;\n+\tstruct ethsw_core *ethsw = dev_get_drvdata(dev);\n+\tstruct fsl_mc_device_irq *irq;\n+\n+\tirq = sw_dev->irqs[DPSW_IRQ_INDEX_IF];\n+\tdpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t DPSW_IRQ_INDEX_IF, 0);\n+\tfsl_mc_free_irqs(sw_dev);\n+}\n+\n+static int swdev_port_attr_get(struct net_device *netdev,\n+\t\t\t struct switchdev_attr *attr)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\n+\tswitch (attr->id) {\n+\tcase SWITCHDEV_ATTR_ID_PORT_PARENT_ID:\n+\t\tattr->u.ppid.id_len = 1;\n+\t\tattr->u.ppid.id[0] = port_priv->ethsw_data->dev_id;\n+\t\tbreak;\n+\tcase SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:\n+\t\tattr->u.brport_flags =\n+\t\t\t(port_priv->ethsw_data->learning ? BR_LEARNING : 0) |\n+\t\t\t(port_priv->flood ? BR_FLOOD : 0);\n+\t\tbreak;\n+\tcase SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT:\n+\t\tattr->u.brport_flags_support = BR_LEARNING | BR_FLOOD;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int port_attr_stp_state_set(struct net_device *netdev,\n+\t\t\t\t struct switchdev_trans *trans,\n+\t\t\t\t u8 state)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\n+\tif (switchdev_trans_ph_prepare(trans))\n+\t\treturn 0;\n+\n+\treturn ethsw_port_set_stp_state(port_priv, state);\n+}\n+\n+static int port_attr_br_flags_set(struct net_device *netdev,\n+\t\t\t\t struct switchdev_trans *trans,\n+\t\t\t\t unsigned long flags)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tint err = 0;\n+\n+\tif (switchdev_trans_ph_prepare(trans))\n+\t\treturn 0;\n+\n+\t/* Learning is enabled per switch */\n+\terr = ethsw_set_learning(port_priv->ethsw_data, flags & BR_LEARNING);\n+\tif (err)\n+\t\tgoto exit;\n+\n+\terr = ethsw_port_set_flood(port_priv, flags & BR_FLOOD);\n+\n+exit:\n+\treturn err;\n+}\n+\n+static int swdev_port_attr_set(struct net_device *netdev,\n+\t\t\t const struct switchdev_attr *attr,\n+\t\t\t struct switchdev_trans *trans)\n+{\n+\tint err = 0;\n+\n+\tswitch (attr->id) {\n+\tcase SWITCHDEV_ATTR_ID_PORT_STP_STATE:\n+\t\terr = port_attr_stp_state_set(netdev, trans,\n+\t\t\t\t\t attr->u.stp_state);\n+\t\tbreak;\n+\tcase SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:\n+\t\terr = port_attr_br_flags_set(netdev, trans,\n+\t\t\t\t\t attr->u.brport_flags);\n+\t\tbreak;\n+\tcase SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:\n+\t\t/* VLANs are supported by default */\n+\t\tbreak;\n+\tdefault:\n+\t\terr = -EOPNOTSUPP;\n+\t\tbreak;\n+\t}\n+\n+\treturn err;\n+}\n+\n+static int port_vlans_add(struct net_device *netdev,\n+\t\t\t const struct switchdev_obj_port_vlan *vlan,\n+\t\t\t struct switchdev_trans *trans)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tint vid, err;\n+\n+\tif (switchdev_trans_ph_prepare(trans))\n+\t\treturn 0;\n+\n+\tfor (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {\n+\t\tif (!port_priv->ethsw_data->vlans[vid]) {\n+\t\t\t/* this is a new VLAN */\n+\t\t\terr = ethsw_add_vlan(port_priv->ethsw_data, vid);\n+\t\t\tif (err)\n+\t\t\t\treturn err;\n+\n+\t\t\tport_priv->ethsw_data->vlans[vid] |= ETHSW_VLAN_GLOBAL;\n+\t\t}\n+\t\terr = ethsw_port_add_vlan(port_priv, vid, vlan->flags);\n+\t\tif (err)\n+\t\t\tbreak;\n+\t}\n+\n+\treturn err;\n+}\n+\n+static int port_lookup_address(struct net_device *netdev, int is_uc,\n+\t\t\t const unsigned char *addr)\n+{\n+\tstruct netdev_hw_addr_list *list = (is_uc) ? &netdev->uc : &netdev->mc;\n+\tstruct netdev_hw_addr *ha;\n+\n+\tnetif_addr_lock_bh(netdev);\n+\tlist_for_each_entry(ha, &list->list, list) {\n+\t\tif (ether_addr_equal(ha->addr, addr)) {\n+\t\t\tnetif_addr_unlock_bh(netdev);\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+\tnetif_addr_unlock_bh(netdev);\n+\treturn 0;\n+}\n+\n+static int port_mdb_add(struct net_device *netdev,\n+\t\t\tconst struct switchdev_obj_port_mdb *mdb,\n+\t\t\tstruct switchdev_trans *trans)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tint err;\n+\n+\tif (switchdev_trans_ph_prepare(trans))\n+\t\treturn 0;\n+\n+\t/* Check if address is already set on this port */\n+\tif (port_lookup_address(netdev, 0, mdb->addr))\n+\t\treturn -EEXIST;\n+\n+\terr = ethsw_port_fdb_add_mc(port_priv, mdb->addr);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = dev_mc_add(netdev, mdb->addr);\n+\tif (err)\n+\t\tnetdev_err(netdev, \"dev_mc_add err %d\\n\", err);\n+\n+\treturn err;\n+}\n+\n+static int swdev_port_obj_add(struct net_device *netdev,\n+\t\t\t const struct switchdev_obj *obj,\n+\t\t\t struct switchdev_trans *trans)\n+{\n+\tint err;\n+\n+\tswitch (obj->id) {\n+\tcase SWITCHDEV_OBJ_ID_PORT_VLAN:\n+\t\terr = port_vlans_add(netdev,\n+\t\t\t\t SWITCHDEV_OBJ_PORT_VLAN(obj),\n+\t\t\t\t trans);\n+\t\tbreak;\n+\tcase SWITCHDEV_OBJ_ID_PORT_MDB:\n+\t\terr = port_mdb_add(netdev,\n+\t\t\t\t SWITCHDEV_OBJ_PORT_MDB(obj),\n+\t\t\t\t trans);\n+\t\tbreak;\n+\tdefault:\n+\t\terr = -EOPNOTSUPP;\n+\t\tbreak;\n+\t}\n+\n+\treturn err;\n+}\n+\n+static int ethsw_port_del_vlan(struct ethsw_port_priv *port_priv, u16 vid)\n+{\n+\tstruct ethsw_core *ethsw = port_priv->ethsw_data;\n+\tstruct net_device *netdev = port_priv->netdev;\n+\tstruct dpsw_vlan_if_cfg vcfg;\n+\tint i, err, err2;\n+\tbool is_oper;\n+\n+\tif (!port_priv->vlans[vid])\n+\t\treturn -ENOENT;\n+\n+\tif (port_priv->vlans[vid] & ETHSW_VLAN_PVID) {\n+\t\tstruct dpsw_tci_cfg tci_cfg = { 0 };\n+\t\t/* Interface needs to be down to change PVID */\n+\t\tis_oper = netif_oper_up(netdev);\n+\n+\t\tif (is_oper) {\n+\t\t\terr = dpsw_if_disable(ethsw->mc_io, 0,\n+\t\t\t\t\t ethsw->dpsw_handle,\n+\t\t\t\t\t port_priv->idx);\n+\t\t\tif (err) {\n+\t\t\t\tnetdev_err(netdev, \"dpsw_if_disable err %d\\n\",\n+\t\t\t\t\t err);\n+\t\t\t\tgoto exit_err;\n+\t\t\t}\n+\t\t}\n+\n+\t\terr = dpsw_if_set_tci(ethsw->mc_io, 0,\n+\t\t\t\t ethsw->dpsw_handle,\n+\t\t\t\t port_priv->idx, &tci_cfg);\n+\t\tif (!err) {\n+\t\t\tport_priv->vlans[vid] &= ~ETHSW_VLAN_PVID;\n+\t\t\tport_priv->pvid = 0;\n+\t\t} else {\n+\t\t\tnetdev_err(netdev, \"dpsw_if_set_tci err %d\\n\", err);\n+\t\t}\n+\n+\t\tif (is_oper) {\n+\t\t\terr2 = dpsw_if_enable(ethsw->mc_io, 0,\n+\t\t\t\t\t ethsw->dpsw_handle,\n+\t\t\t\t\t port_priv->idx);\n+\t\t\tif (err2) {\n+\t\t\t\tnetdev_err(netdev, \"dpsw_if_enable err %d\\n\",\n+\t\t\t\t\t err2);\n+\t\t\t\treturn err2;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (err)\n+\t\t\tgoto exit_err;\n+\t}\n+\n+\tvcfg.num_ifs = 1;\n+\tvcfg.if_id[0] = port_priv->idx;\n+\tif (port_priv->vlans[vid] & ETHSW_VLAN_UNTAGGED) {\n+\t\terr = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0,\n+\t\t\t\t\t\t ethsw->dpsw_handle,\n+\t\t\t\t\t\t vid, &vcfg);\n+\t\tif (err) {\n+\t\t\tnetdev_err(netdev,\n+\t\t\t\t \"dpsw_vlan_remove_if_untagged err %d\\n\",\n+\t\t\t\t err);\n+\t\t}\n+\t\tport_priv->vlans[vid] &= ~ETHSW_VLAN_UNTAGGED;\n+\t}\n+\n+\tif (port_priv->vlans[vid] & ETHSW_VLAN_MEMBER) {\n+\t\terr = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\t\t vid, &vcfg);\n+\t\tif (err) {\n+\t\t\tnetdev_err(netdev,\n+\t\t\t\t \"dpsw_vlan_remove_if err %d\\n\", err);\n+\t\t\treturn err;\n+\t\t}\n+\t\tport_priv->vlans[vid] &= ~ETHSW_VLAN_MEMBER;\n+\n+\t\t/* Delete VLAN from switch if it is no longer configured on\n+\t\t * any port\n+\t\t */\n+\t\tfor (i = 0; i < ethsw->sw_attr.num_ifs; i++)\n+\t\t\tif (ethsw->ports[i]->vlans[vid] & ETHSW_VLAN_MEMBER)\n+\t\t\t\treturn 0; /* Found a port member in VID */\n+\n+\t\tethsw->vlans[vid] &= ~ETHSW_VLAN_GLOBAL;\n+\n+\t\terr = ethsw_dellink_switch(ethsw, vid);\n+\t\tif (err)\n+\t\t\tgoto exit_err;\n+\t}\n+\n+\treturn 0;\n+exit_err:\n+\treturn err;\n+}\n+\n+static int port_vlans_del(struct net_device *netdev,\n+\t\t\t const struct switchdev_obj_port_vlan *vlan)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tint vid, err;\n+\n+\tfor (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {\n+\t\terr = ethsw_port_del_vlan(port_priv, vid);\n+\t\tif (err)\n+\t\t\tbreak;\n+\t}\n+\n+\treturn err;\n+}\n+\n+static int port_mdb_del(struct net_device *netdev,\n+\t\t\tconst struct switchdev_obj_port_mdb *mdb)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\tint err;\n+\n+\tif (!port_lookup_address(netdev, 0, mdb->addr))\n+\t\treturn -ENOENT;\n+\n+\terr = ethsw_port_fdb_del_mc(port_priv, mdb->addr);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = dev_mc_del(netdev, mdb->addr);\n+\tif (err) {\n+\t\tnetdev_err(netdev, \"dev_mc_del err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\treturn err;\n+}\n+\n+static int swdev_port_obj_del(struct net_device *netdev,\n+\t\t\t const struct switchdev_obj *obj)\n+{\n+\tint err;\n+\n+\tswitch (obj->id) {\n+\tcase SWITCHDEV_OBJ_ID_PORT_VLAN:\n+\t\terr = port_vlans_del(netdev, SWITCHDEV_OBJ_PORT_VLAN(obj));\n+\t\tbreak;\n+\tcase SWITCHDEV_OBJ_ID_PORT_MDB:\n+\t\terr = port_mdb_del(netdev, SWITCHDEV_OBJ_PORT_MDB(obj));\n+\t\tbreak;\n+\tdefault:\n+\t\terr = -EOPNOTSUPP;\n+\t\tbreak;\n+\t}\n+\treturn err;\n+}\n+\n+static const struct switchdev_ops ethsw_port_switchdev_ops = {\n+\t.switchdev_port_attr_get\t= swdev_port_attr_get,\n+\t.switchdev_port_attr_set\t= swdev_port_attr_set,\n+\t.switchdev_port_obj_add\t\t= swdev_port_obj_add,\n+\t.switchdev_port_obj_del\t\t= swdev_port_obj_del,\n+};\n+\n+/* For the moment, only flood setting needs to be updated */\n+static int port_bridge_join(struct net_device *netdev)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\n+\t/* Enable flooding */\n+\treturn ethsw_port_set_flood(port_priv, 1);\n+}\n+\n+static int port_bridge_leave(struct net_device *netdev)\n+{\n+\tstruct ethsw_port_priv *port_priv = netdev_priv(netdev);\n+\n+\t/* Disable flooding */\n+\treturn ethsw_port_set_flood(port_priv, 0);\n+}\n+\n+static int port_netdevice_event(struct notifier_block *unused,\n+\t\t\t\tunsigned long event, void *ptr)\n+{\n+\tstruct net_device *netdev = netdev_notifier_info_to_dev(ptr);\n+\tstruct netdev_notifier_changeupper_info *info = ptr;\n+\tstruct net_device *upper_dev;\n+\tint err = 0;\n+\n+\tif (netdev->netdev_ops != ðsw_port_ops)\n+\t\treturn NOTIFY_DONE;\n+\n+\t/* Handle just upper dev link/unlink for the moment */\n+\tif (event == NETDEV_CHANGEUPPER) {\n+\t\tupper_dev = info->upper_dev;\n+\t\tif (netif_is_bridge_master(upper_dev)) {\n+\t\t\tif (info->linking)\n+\t\t\t\terr = port_bridge_join(netdev);\n+\t\t\telse\n+\t\t\t\terr = port_bridge_leave(netdev);\n+\t\t}\n+\t}\n+\n+\treturn notifier_from_errno(err);\n+}\n+\n+static struct notifier_block port_nb __read_mostly = {\n+\t.notifier_call = port_netdevice_event,\n+};\n+\n+struct ethsw_switchdev_event_work {\n+\tstruct work_struct work;\n+\tstruct switchdev_notifier_fdb_info fdb_info;\n+\tstruct net_device *dev;\n+\tunsigned long event;\n+};\n+\n+static void ethsw_switchdev_event_work(struct work_struct *work)\n+{\n+\tstruct ethsw_switchdev_event_work *switchdev_work =\n+\t\tcontainer_of(work, struct ethsw_switchdev_event_work, work);\n+\tstruct net_device *dev = switchdev_work->dev;\n+\tstruct switchdev_notifier_fdb_info *fdb_info;\n+\tstruct ethsw_port_priv *port_priv;\n+\n+\trtnl_lock();\n+\tport_priv = netdev_priv(dev);\n+\tfdb_info = &switchdev_work->fdb_info;\n+\n+\tswitch (switchdev_work->event) {\n+\tcase SWITCHDEV_FDB_ADD_TO_DEVICE:\n+\t\tethsw_port_fdb_add_uc(netdev_priv(dev), fdb_info->addr);\n+\t\tbreak;\n+\tcase SWITCHDEV_FDB_DEL_TO_DEVICE:\n+\t\tethsw_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr);\n+\t\tbreak;\n+\t}\n+\n+\trtnl_unlock();\n+\tkfree(switchdev_work->fdb_info.addr);\n+\tkfree(switchdev_work);\n+\tdev_put(dev);\n+}\n+\n+/* Called under rcu_read_lock() */\n+static int port_switchdev_event(struct notifier_block *unused,\n+\t\t\t\tunsigned long event, void *ptr)\n+{\n+\tstruct net_device *dev = switchdev_notifier_info_to_dev(ptr);\n+\tstruct ethsw_switchdev_event_work *switchdev_work;\n+\tstruct switchdev_notifier_fdb_info *fdb_info = ptr;\n+\n+\tswitchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);\n+\tif (!switchdev_work)\n+\t\treturn NOTIFY_BAD;\n+\n+\tINIT_WORK(&switchdev_work->work, ethsw_switchdev_event_work);\n+\tswitchdev_work->dev = dev;\n+\tswitchdev_work->event = event;\n+\n+\tswitch (event) {\n+\tcase SWITCHDEV_FDB_ADD_TO_DEVICE:\n+\tcase SWITCHDEV_FDB_DEL_TO_DEVICE:\n+\t\tmemcpy(&switchdev_work->fdb_info, ptr,\n+\t\t sizeof(switchdev_work->fdb_info));\n+\t\tswitchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);\n+\t\tif (!switchdev_work->fdb_info.addr)\n+\t\t\tgoto err_addr_alloc;\n+\n+\t\tether_addr_copy((u8 *)switchdev_work->fdb_info.addr,\n+\t\t\t\tfdb_info->addr);\n+\n+\t\t/* Take a reference on the device to avoid being freed. */\n+\t\tdev_hold(dev);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn NOTIFY_DONE;\n+\t}\n+\n+\tqueue_work(ethsw_owq, &switchdev_work->work);\n+\n+\treturn NOTIFY_DONE;\n+\n+err_addr_alloc:\n+\tkfree(switchdev_work);\n+\treturn NOTIFY_BAD;\n+}\n+\n+static struct notifier_block port_switchdev_nb = {\n+\t.notifier_call = port_switchdev_event,\n+};\n+\n+static int ethsw_register_notifier(struct device *dev)\n+{\n+\tint err;\n+\n+\terr = register_netdevice_notifier(&port_nb);\n+\tif (err) {\n+\t\tdev_err(dev, \"Failed to register netdev notifier\\n\");\n+\t\treturn err;\n+\t}\n+\n+\terr = register_switchdev_notifier(&port_switchdev_nb);\n+\tif (err) {\n+\t\tdev_err(dev, \"Failed to register switchdev notifier\\n\");\n+\t\tgoto err_switchdev_nb;\n+\t}\n+\n+\treturn 0;\n+\n+err_switchdev_nb:\n+\tunregister_netdevice_notifier(&port_nb);\n+\treturn err;\n+}\n+\n+static int ethsw_open(struct ethsw_core\t*ethsw)\n+{\n+\tstruct ethsw_port_priv *port_priv = NULL;\n+\tint i, err;\n+\n+\terr = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle);\n+\tif (err) {\n+\t\tdev_err(ethsw->dev, \"dpsw_enable err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\tfor (i = 0; i < ethsw->sw_attr.num_ifs; i++) {\n+\t\tport_priv = ethsw->ports[i];\n+\t\terr = dev_open(port_priv->netdev);\n+\t\tif (err) {\n+\t\t\tnetdev_err(port_priv->netdev, \"dev_open err %d\\n\", err);\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int ethsw_stop(struct ethsw_core\t*ethsw)\n+{\n+\tstruct ethsw_port_priv *port_priv = NULL;\n+\tint i, err;\n+\n+\tdestroy_workqueue(ethsw_owq);\n+\n+\tfor (i = 0; i < ethsw->sw_attr.num_ifs; i++) {\n+\t\tport_priv = ethsw->ports[i];\n+\t\tdev_close(port_priv->netdev);\n+\t}\n+\n+\terr = dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle);\n+\tif (err) {\n+\t\tdev_err(ethsw->dev, \"dpsw_disable err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int ethsw_init(struct fsl_mc_device *sw_dev)\n+{\n+\tstruct device *dev = &sw_dev->dev;\n+\tstruct ethsw_core *ethsw = dev_get_drvdata(dev);\n+\tu16 version_major, version_minor, i;\n+\tstruct dpsw_stp_cfg stp_cfg;\n+\tint err;\n+\n+\tethsw->dev_id = sw_dev->obj_desc.id;\n+\n+\terr = dpsw_open(ethsw->mc_io, 0, ethsw->dev_id, ðsw->dpsw_handle);\n+\tif (err) {\n+\t\tdev_err(dev, \"dpsw_open err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\terr = dpsw_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\t ðsw->sw_attr);\n+\tif (err) {\n+\t\tdev_err(dev, \"dpsw_get_attributes err %d\\n\", err);\n+\t\tgoto err_close;\n+\t}\n+\n+\terr = dpsw_get_api_version(ethsw->mc_io, 0,\n+\t\t\t\t &version_major,\n+\t\t\t\t &version_minor);\n+\tif (err) {\n+\t\tdev_err(dev, \"dpsw_get_api_version err %d\\n\", err);\n+\t\tgoto err_close;\n+\t}\n+\n+\t/* Minimum supported DPSW version check */\n+\tif (version_major < DPSW_MIN_VER_MAJOR ||\n+\t (version_major == DPSW_MIN_VER_MAJOR &&\n+\t version_minor < DPSW_MIN_VER_MINOR)) {\n+\t\tdev_err(dev, \"DPSW version %d:%d not supported. Use %d.%d or greater.\\n\",\n+\t\t\tversion_major,\n+\t\t\tversion_minor,\n+\t\t\tDPSW_MIN_VER_MAJOR, DPSW_MIN_VER_MINOR);\n+\t\terr = -ENOTSUPP;\n+\t\tgoto err_close;\n+\t}\n+\n+\terr = dpsw_reset(ethsw->mc_io, 0, ethsw->dpsw_handle);\n+\tif (err) {\n+\t\tdev_err(dev, \"dpsw_reset err %d\\n\", err);\n+\t\tgoto err_close;\n+\t}\n+\n+\terr = dpsw_fdb_set_learning_mode(ethsw->mc_io, 0, ethsw->dpsw_handle, 0,\n+\t\t\t\t\t DPSW_FDB_LEARNING_MODE_HW);\n+\tif (err) {\n+\t\tdev_err(dev, \"dpsw_fdb_set_learning_mode err %d\\n\", err);\n+\t\tgoto err_close;\n+\t}\n+\n+\tstp_cfg.vlan_id = DEFAULT_VLAN_ID;\n+\tstp_cfg.state = DPSW_STP_STATE_FORWARDING;\n+\n+\tfor (i = 0; i < ethsw->sw_attr.num_ifs; i++) {\n+\t\terr = dpsw_if_set_stp(ethsw->mc_io, 0, ethsw->dpsw_handle, i,\n+\t\t\t\t &stp_cfg);\n+\t\tif (err) {\n+\t\t\tdev_err(dev, \"dpsw_if_set_stp err %d for port %d\\n\",\n+\t\t\t\terr, i);\n+\t\t\tgoto err_close;\n+\t\t}\n+\n+\t\terr = dpsw_if_set_broadcast(ethsw->mc_io, 0,\n+\t\t\t\t\t ethsw->dpsw_handle, i, 1);\n+\t\tif (err) {\n+\t\t\tdev_err(dev,\n+\t\t\t\t\"dpsw_if_set_broadcast err %d for port %d\\n\",\n+\t\t\t\terr, i);\n+\t\t\tgoto err_close;\n+\t\t}\n+\t}\n+\n+\tethsw_owq = alloc_ordered_workqueue(\"%s_ordered\", WQ_MEM_RECLAIM,\n+\t\t\t\t\t \"ethsw\");\n+\tif (!ethsw_owq) {\n+\t\terr = -ENOMEM;\n+\t\tgoto err_close;\n+\t}\n+\n+\terr = ethsw_register_notifier(dev);\n+\tif (err)\n+\t\tgoto err_destroy_ordered_workqueue;\n+\n+\treturn 0;\n+\n+err_destroy_ordered_workqueue:\n+\tdestroy_workqueue(ethsw_owq);\n+\n+err_close:\n+\tdpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle);\n+\treturn err;\n+}\n+\n+static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)\n+{\n+\tconst char def_mcast[ETH_ALEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x01};\n+\tstruct net_device *netdev = port_priv->netdev;\n+\tstruct ethsw_core *ethsw = port_priv->ethsw_data;\n+\tstruct dpsw_tci_cfg tci_cfg = {0};\n+\tstruct dpsw_vlan_if_cfg vcfg;\n+\tint err;\n+\n+\t/* Switch starts with all ports configured to VLAN 1. Need to\n+\t * remove this setting to allow configuration at bridge join\n+\t */\n+\tvcfg.num_ifs = 1;\n+\tvcfg.if_id[0] = port_priv->idx;\n+\n+\terr = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\t\t DEFAULT_VLAN_ID, &vcfg);\n+\tif (err) {\n+\t\tnetdev_err(netdev, \"dpsw_vlan_remove_if_untagged err %d\\n\",\n+\t\t\t err);\n+\t\treturn err;\n+\t}\n+\n+\terr = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t port_priv->idx, &tci_cfg);\n+\tif (err) {\n+\t\tnetdev_err(netdev, \"dpsw_if_set_tci err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\terr = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle,\n+\t\t\t\t DEFAULT_VLAN_ID, &vcfg);\n+\tif (err) {\n+\t\tnetdev_err(netdev, \"dpsw_vlan_remove_if err %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\terr = ethsw_port_fdb_add_mc(port_priv, def_mcast);\n+\n+\treturn err;\n+}\n+\n+static void ethsw_takedown(struct fsl_mc_device *sw_dev)\n+{\n+\tstruct device *dev = &sw_dev->dev;\n+\tstruct ethsw_core *ethsw = dev_get_drvdata(dev);\n+\tint err;\n+\n+\terr = unregister_switchdev_notifier(&port_switchdev_nb);\n+\tif (err)\n+\t\tdev_err(dev,\n+\t\t\t\"Failed to unregister switchdev notifier (%d)\\n\", err);\n+\n+\terr = unregister_netdevice_notifier(&port_nb);\n+\tif (err)\n+\t\tdev_err(dev,\n+\t\t\t\"Failed to unregister netdev notifier (%d)\\n\", err);\n+\n+\terr = dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle);\n+\tif (err)\n+\t\tdev_warn(dev, \"dpsw_close err %d\\n\", err);\n+}\n+\n+static int ethsw_remove(struct fsl_mc_device *sw_dev)\n+{\n+\tstruct ethsw_port_priv *port_priv;\n+\tstruct ethsw_core *ethsw;\n+\tstruct device *dev;\n+\tint i;\n+\n+\tdev = &sw_dev->dev;\n+\tethsw = dev_get_drvdata(dev);\n+\n+\tethsw_teardown_irqs(sw_dev);\n+\n+\trtnl_lock();\n+\tethsw_stop(ethsw);\n+\trtnl_unlock();\n+\n+\tfor (i = 0; i < ethsw->sw_attr.num_ifs; i++) {\n+\t\tport_priv = ethsw->ports[i];\n+\t\tunregister_netdev(port_priv->netdev);\n+\t\tfree_netdev(port_priv->netdev);\n+\t}\n+\tkfree(ethsw->ports);\n+\n+\tethsw_takedown(sw_dev);\n+\tfsl_mc_portal_free(ethsw->mc_io);\n+\n+\tkfree(ethsw);\n+\n+\tdev_set_drvdata(dev, NULL);\n+\n+\treturn 0;\n+}\n+\n+static int ethsw_probe_port(struct ethsw_core *ethsw, u16 port_idx)\n+{\n+\tstruct ethsw_port_priv *port_priv;\n+\tstruct device *dev = ethsw->dev;\n+\tstruct net_device *port_netdev;\n+\tint err;\n+\n+\tport_netdev = alloc_etherdev(sizeof(struct ethsw_port_priv));\n+\tif (!port_netdev) {\n+\t\tdev_err(dev, \"alloc_etherdev error\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tport_priv = netdev_priv(port_netdev);\n+\tport_priv->netdev = port_netdev;\n+\tport_priv->ethsw_data = ethsw;\n+\n+\tport_priv->idx = port_idx;\n+\tport_priv->stp_state = BR_STATE_FORWARDING;\n+\n+\t/* Flooding is implicitly enabled */\n+\tport_priv->flood = true;\n+\n+\tSET_NETDEV_DEV(port_netdev, dev);\n+\tport_netdev->netdev_ops = ðsw_port_ops;\n+\tport_netdev->switchdev_ops = ðsw_port_switchdev_ops;\n+\n+\t/* Set MTU limits */\n+\tport_netdev->min_mtu = ETH_MIN_MTU;\n+\tport_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH;\n+\n+\terr = register_netdev(port_netdev);\n+\tif (err < 0) {\n+\t\tdev_err(dev, \"register_netdev error %d\\n\", err);\n+\t\t\tfree_netdev(port_netdev);\n+\t\t\treturn err;\n+\t\t}\n+\n+\tethsw->ports[port_idx] = port_priv;\n+\n+\treturn ethsw_port_init(port_priv, port_idx);\n+}\n+\n+static int ethsw_probe(struct fsl_mc_device *sw_dev)\n+{\n+\tstruct device *dev = &sw_dev->dev;\n+\tstruct ethsw_core *ethsw;\n+\tint err;\n+\tu16 i, j;\n+\n+\t/* Allocate switch core*/\n+\tethsw = kzalloc(sizeof(*ethsw), GFP_KERNEL);\n+\n+\tif (!ethsw)\n+\t\treturn -ENOMEM;\n+\n+\tethsw->dev = dev;\n+\tdev_set_drvdata(dev, ethsw);\n+\n+\terr = fsl_mc_portal_allocate(sw_dev, 0, ðsw->mc_io);\n+\tif (err) {\n+\t\tdev_err(dev, \"fsl_mc_portal_allocate err %d\\n\", err);\n+\t\tgoto err_free_drvdata;\n+\t}\n+\n+\terr = ethsw_init(sw_dev);\n+\tif (err)\n+\t\tgoto err_free_cmdport;\n+\n+\t/* DEFAULT_VLAN_ID is implicitly configured on the switch */\n+\tethsw->vlans[DEFAULT_VLAN_ID] = ETHSW_VLAN_MEMBER;\n+\n+\t/* Learning is implicitly enabled */\n+\tethsw->learning = true;\n+\n+\tethsw->ports = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->ports),\n+\t\t\t GFP_KERNEL);\n+\tif (!(ethsw->ports)) {\n+\t\terr = -ENOMEM;\n+\t\tgoto err_takedown;\n+\t}\n+\n+\tfor (i = 0; i < ethsw->sw_attr.num_ifs; i++) {\n+\t\terr = ethsw_probe_port(ethsw, i);\n+\t\tif (err) {\n+\t\t\t/* Cleanup previous ports only */\n+\t\t\tfor (j = 0; j < i; j++) {\n+\t\t\t\tunregister_netdev(ethsw->ports[j]->netdev);\n+\t\t\t\tfree_netdev(ethsw->ports[j]->netdev);\n+\t\t\t}\n+\t\t\tgoto err_takedown;\n+\t\t}\n+\t}\n+\n+\t/* Switch starts up enabled */\n+\trtnl_lock();\n+\terr = ethsw_open(ethsw);\n+\trtnl_unlock();\n+\tif (err)\n+\t\tgoto err_free_ports;\n+\n+\t/* Setup IRQs */\n+\terr = ethsw_setup_irqs(sw_dev);\n+\tif (err)\n+\t\tgoto err_stop;\n+\n+\tdev_info(dev, \"probed %d port switch\\n\", ethsw->sw_attr.num_ifs);\n+\treturn 0;\n+\n+err_stop:\n+\trtnl_lock();\n+\tethsw_stop(ethsw);\n+\trtnl_unlock();\n+\n+err_free_ports:\n+\tfor (i = 0; i < ethsw->sw_attr.num_ifs; i++) {\n+\t\tunregister_netdev(ethsw->ports[i]->netdev);\n+\t\tfree_netdev(ethsw->ports[i]->netdev);\n+\t}\n+\tkfree(ethsw->ports);\n+\n+err_takedown:\n+\tethsw_takedown(sw_dev);\n+\n+err_free_cmdport:\n+\tfsl_mc_portal_free(ethsw->mc_io);\n+\n+err_free_drvdata:\n+\tkfree(ethsw);\n+\tdev_set_drvdata(dev, NULL);\n+\n+\treturn err;\n+}\n+\n+static const struct fsl_mc_device_id ethsw_match_id_table[] = {\n+\t{\n+\t\t.vendor = FSL_MC_VENDOR_FREESCALE,\n+\t\t.obj_type = \"dpsw\",\n+\t},\n+\t{ .vendor = 0x0 }\n+};\n+MODULE_DEVICE_TABLE(fslmc, ethsw_match_id_table);\n+\n+static struct fsl_mc_driver eth_sw_drv = {\n+\t.driver = {\n+\t\t.name = KBUILD_MODNAME,\n+\t\t.owner = THIS_MODULE,\n+\t},\n+\t.probe = ethsw_probe,\n+\t.remove = ethsw_remove,\n+\t.match_id_table = ethsw_match_id_table\n+};\n+\n+module_fsl_mc_driver(eth_sw_drv);\n+\n+MODULE_LICENSE(\"Dual BSD/GPL\");\n+MODULE_DESCRIPTION(\"DPAA2 Ethernet Switch Driver\");\ndiff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h\nnew file mode 100644\nindex 0000000..8c1d645\n--- /dev/null\n+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h\n@@ -0,0 +1,88 @@\n+/* Copyright 2014-2017 Freescale Semiconductor Inc.\n+ * Copyright 2017 NXP\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ * * Redistributions of source code must retain the above copyright\n+ *\t notice, this list of conditions and the following disclaimer.\n+ * * Redistributions in binary form must reproduce the above copyright\n+ *\t notice, this list of conditions and the following disclaimer in the\n+ *\t documentation and/or other materials provided with the distribution.\n+ * * Neither the name of the above-listed copyright holders nor the\n+ *\t names of any contributors may be used to endorse or promote products\n+ *\t derived from this software without specific prior written permission.\n+ *\n+ *\n+ * ALTERNATIVELY, this software may be distributed under the terms of the\n+ * GNU General Public License (\"GPL\") as published by the Free Software\n+ * Foundation, either version 2 of that License or (at your option) any\n+ * later version.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\n+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n+ * POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef __ETHSW_H\n+#define __ETHSW_H\n+\n+#include <linux/netdevice.h>\n+#include <linux/etherdevice.h>\n+#include <linux/rtnetlink.h>\n+#include <linux/if_vlan.h>\n+#include <uapi/linux/if_bridge.h>\n+#include <net/switchdev.h>\n+#include <linux/if_bridge.h>\n+\n+#include \"dpsw.h\"\n+\n+/* Number of IRQs supported */\n+#define DPSW_IRQ_NUM\t2\n+\n+#define ETHSW_VLAN_MEMBER\t1\n+#define ETHSW_VLAN_UNTAGGED\t2\n+#define ETHSW_VLAN_PVID\t\t4\n+#define ETHSW_VLAN_GLOBAL\t8\n+\n+/* Maximum Frame Length supported by HW (currently 10k) */\n+#define DPAA2_MFL\t\t(10 * 1024)\n+#define ETHSW_MAX_FRAME_LENGTH\t(DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN)\n+#define ETHSW_L2_MAX_FRM(mtu)\t((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN)\n+\n+struct ethsw_core;\n+\n+/* Per port private data */\n+struct ethsw_port_priv {\n+\tstruct net_device\t*netdev;\n+\tu16\t\t\tidx;\n+\tstruct ethsw_core\t*ethsw_data;\n+\tu8\t\t\tlink_state;\n+\tu8\t\t\tstp_state;\n+\tbool\t\t\tflood;\n+\n+\tu8\t\t\tvlans[VLAN_VID_MASK + 1];\n+\tu16\t\t\tpvid;\n+};\n+\n+/* Switch data */\n+struct ethsw_core {\n+\tstruct device\t\t\t*dev;\n+\tstruct fsl_mc_io\t\t*mc_io;\n+\tu16\t\t\t\tdpsw_handle;\n+\tstruct dpsw_attr\t\tsw_attr;\n+\tint\t\t\t\tdev_id;\n+\tstruct ethsw_port_priv\t\t**ports;\n+\n+\tu8\t\t\t\tvlans[VLAN_VID_MASK + 1];\n+\tbool\t\t\t\tlearning;\n+};\n+\n+#endif\t/* __ETHSW_H */\n", "prefixes": [ "RESEND", "2/6" ] }