From a869d5488f8a61a6a6472eb072948cae7a2e9dc9 Mon Sep 17 00:00:00 2001 From: Dominik Tacke Date: Tue, 24 Mar 2026 16:44:32 +0100 Subject: [PATCH 01/18] UPSTREAM: chore: change annotation for documentation commit aa46f97580ac03c4fa008c83ad4d8c724c5ace6b upstream. Updated the REUSE.toml to annotate documentation according to the zephyr charter with the CC-BY-4.0 license Signed-off-by: Dominik Tacke Signed-off-by: Siddharth Vadapalli --- LICENSES/CC-BY-4.0.txt | 156 +++++++++++++++++++++++++++++++++++++++++ REUSE.toml | 6 +- 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 LICENSES/CC-BY-4.0.txt diff --git a/LICENSES/CC-BY-4.0.txt b/LICENSES/CC-BY-4.0.txt new file mode 100644 index 000000000000..13ca539f377d --- /dev/null +++ b/LICENSES/CC-BY-4.0.txt @@ -0,0 +1,156 @@ +Creative Commons Attribution 4.0 International + + Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. + +Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors. + +Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public. + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + + a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + + d. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + + g. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + + i. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part; and + + B. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; + + b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + + a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + + b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + + c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + + a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + + d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + + e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + + a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + + c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + + d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/REUSE.toml b/REUSE.toml index 83f6d8fed7dd..0796e2952d3e 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -10,7 +10,6 @@ path = [ "**/*.ecl", "**/*.html", "**/*.json", - "**/*.rst", "**/*.yaml", "**/*.yml", "**/*_defconfig", @@ -24,3 +23,8 @@ path = [ ] SPDX-License-Identifier = "Apache-2.0" SPDX-FileCopyrightText = "Copyright The Zephyr Project Contributors" + +[[annotations]] +path = "**/*.rst" +SPDX-License-Identifier = "CC-BY-4.0" +SPDX-FileCopyrightText = "Copyright The Zephyr Project Contributors" From f36fa63c3747130d38e3b0a20351f4ba2b7725be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 9 Jul 2026 20:43:18 +0200 Subject: [PATCH 02/18] UPSTREAM: doc: licensing: add the exceptions section to REUSE.toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c9dc69bd18624ce12c0cd224a2b9749cef8e6431 upstream. Zephyr is Apache-2.0 as a whole but reuses a few components under other licenses. Introduce the exceptions section in REUSE.toml and document the Zephyr-Description/-Origin/-Kconfig-Condition keys the licensing page is generated from. Per-component entries follow. Signed-off-by: Benjamin Cabé Assisted-by: Claude:opus-4.8 Signed-off-by: Siddharth Vadapalli --- REUSE.toml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/REUSE.toml b/REUSE.toml index 0796e2952d3e..17a0387a20e3 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -28,3 +28,26 @@ SPDX-FileCopyrightText = "Copyright The Zephyr Project Contributors" path = "**/*.rst" SPDX-License-Identifier = "CC-BY-4.0" SPDX-FileCopyrightText = "Copyright The Zephyr Project Contributors" + +# ----------------------------------------------------------------------------- +# Licensing exceptions +# ----------------------------------------------------------------------------- +# +# Zephyr as a whole is Apache-2.0 licensed, but it imports or reuses a few +# components that use other licenses. Each such component is described below as +# a single REUSE annotation and is rendered on the licensing documentation page +# (see doc/LICENSING.rst) by the "zephyr.licensing" Sphinx extension. +# +# The license metadata is standard REUSE/SPDX and the standard SPDX-FileComment +# holds the free-text rationale ("Impact"). SPDX has no non-deprecated file-level +# field for an upstream URL (the ArtifactOf* file tags were deprecated in favour +# of relationships, which REUSE.toml cannot express, and Package* fields are not +# valid on files), so three Zephyr-specific keys are used (the `reuse` tool +# ignores keys it does not know about): +# +# Zephyr-Description Short human description of the component, used as +# its title on the page. Its presence promotes a +# plain REUSE annotation to a documented exception. +# Zephyr-Origin URL of the upstream project the files come from. +# Zephyr-Kconfig-Condition Kconfig option(s) gating whether the files end up in +# a build, rendered as :kconfig:option: references. From 8c58c78df2b640c42357344f71a7e18b6f443f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 9 Jul 2026 20:43:18 +0200 Subject: [PATCH 03/18] UPSTREAM: doc: licensing: document the Bootstrap dashboard files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ecbec6263a90d381a812190ed6ae95bafc1103c9 upstream. Bootstrap ships the dashboard's CSS and JavaScript under MIT. Add a REUSE.toml exception so the component appears on the licensing page and is accepted by the compliance guard. Signed-off-by: Benjamin Cabé Assisted-by: Claude:opus-4.8 Signed-off-by: Siddharth Vadapalli --- LICENSES/MIT.txt | 21 +++++++++++++++++++++ REUSE.toml | 10 ++++++++++ 2 files changed, 31 insertions(+) create mode 100644 LICENSES/MIT.txt diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 000000000000..8aa26455d23a --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/REUSE.toml b/REUSE.toml index 17a0387a20e3..4cd6b186e62b 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -51,3 +51,13 @@ SPDX-FileCopyrightText = "Copyright The Zephyr Project Contributors" # Zephyr-Origin URL of the upstream project the files come from. # Zephyr-Kconfig-Condition Kconfig option(s) gating whether the files end up in # a build, rendered as :kconfig:option: references. + +[[annotations]] +path = [ + "scripts/dashboard/static/css/bootstrap-chop.css", + "scripts/dashboard/static/js/bootstrap-chop.js", +] +SPDX-License-Identifier = "MIT" +SPDX-FileComment = "Used by the dashboard tool only and never linked into a Zephyr firmware image." +Zephyr-Description = "Bootstrap JavaScript and CSS Files" +Zephyr-Origin = "https://getbootstrap.com/" From 08072fd7064a791a1ad59cf34029a3bd37069463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 9 Jul 2026 20:43:18 +0200 Subject: [PATCH 04/18] UPSTREAM: doc: licensing: document the Bosch BMI08x sensor config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1ec3a57d6fbc73fc72892fe652b6cb39240c1f26 upstream. The BMI08x sensor configuration blob is imported from the Bosch Sensortec BMI08x API under BSD-3-Clause. Add a REUSE.toml exception so the component appears on the licensing page and is accepted by the compliance guard. Signed-off-by: Benjamin Cabé Assisted-by: Claude:opus-4.8 Signed-off-by: Siddharth Vadapalli --- LICENSES/BSD-3-Clause.txt | 28 ++++++++++++++++++++++++++++ REUSE.toml | 8 ++++++++ 2 files changed, 36 insertions(+) create mode 100644 LICENSES/BSD-3-Clause.txt diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt new file mode 100644 index 000000000000..ddd44f66e975 --- /dev/null +++ b/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) [year], [fullname] + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/REUSE.toml b/REUSE.toml index 4cd6b186e62b..a960a71d159f 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -61,3 +61,11 @@ SPDX-License-Identifier = "MIT" SPDX-FileComment = "Used by the dashboard tool only and never linked into a Zephyr firmware image." Zephyr-Description = "Bootstrap JavaScript and CSS Files" Zephyr-Origin = "https://getbootstrap.com/" + +[[annotations]] +path = "drivers/sensor/bosch/bmi08x/bmi08x_config_file.h" +SPDX-License-Identifier = "BSD-3-Clause" +SPDX-FileComment = "Sensor configuration data compiled into the firmware only when the BMI08x driver is enabled." +Zephyr-Description = "Bosch BMI08x Sensor Configuration File" +Zephyr-Origin = "https://github.com/BoschSensortec/BMI08x-Sensor-API" +Zephyr-Kconfig-Condition = "CONFIG_BMI08X" From c2853f5f94997159ed87cfa686b67438405327d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Wed, 20 May 2026 10:06:26 +0200 Subject: [PATCH 05/18] UPSTREAM: dts: add dependency-mode prop key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e29a7d2a226a5456e9e99633fe6275bd3f5a8872 upstream. add dependency-mode prop key, so it can be changed what dependency a phandle in the dt introduces. With this it can be set in the dt binding that a phandle is f.e. ignored when the dt ordinal is calculated. Signed-off-by: Fin Maaß Signed-off-by: Siddharth Vadapalli --- .../src/devicetree/edtlib.py | 54 +++++++++++++++++-- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/scripts/dts/python-devicetree/src/devicetree/edtlib.py b/scripts/dts/python-devicetree/src/devicetree/edtlib.py index 3f035b96a3ac..0b3a2613221c 100644 --- a/scripts/dts/python-devicetree/src/devicetree/edtlib.py +++ b/scripts/dts/python-devicetree/src/devicetree/edtlib.py @@ -495,7 +495,8 @@ def _check_properties(self) -> None: ok_prop_keys = {"description", "type", "required", "enum", "const", "default", "deprecated", - "specifier-space", "min", "max"} + "specifier-space", "min", "max", "min-len", "max-len", + "dependency-mode"} for prop_name, options in raw["properties"].items(): for key in options: @@ -593,6 +594,20 @@ class PropertySpec: max: The maximum value the property may take as given in the binding, or None. Only applicable to 'int' and 'array' type properties. + + min_len: + The minimum length of the array itself as given in the binding, or None. + Corresponds to the binding key 'min-len:'. + Only applicable to array type properties. + + max_len: + The maximum length of the array itself as given in the binding, or None. + Corresponds to the binding key 'max-len:'. + Only applicable to array type properties. + + dependency_mode: + Specifies how the dependency graph should handle this property. + Can be "ignore", "child-ignore", "reverse", "normal" or None. """ def __init__(self, name: str, binding: Binding): @@ -674,6 +689,11 @@ def deprecated(self) -> bool: "See the class docstring" return self._raw.get("deprecated", False) + @property + def dependency_mode(self) -> Optional[str]: + "See the class docstring" + return self._raw.get("dependency-mode") + @property def specifier_space(self) -> Optional[str]: "See the class docstring" @@ -2427,6 +2447,26 @@ def scc_order(self) -> list[list[Node]]: except Exception as e: raise EDTError(e) from None + def _apply_dependency_mode(self, root_node: Node, dep_node: Node, prop: Property) -> None: + match prop.spec.dependency_mode: + case None | "normal": + self._graph.add_edge(root_node, dep_node) + case "reverse": + self._graph.add_edge(dep_node, root_node) + case "ignore": + pass + case "child-ignore": + def _is_child(child_node: Optional[Node]) -> bool: + if child_node is None: + return False + if root_node is child_node: + return True + return _is_child(child_node.parent) + if TYPE_CHECKING: + assert isinstance(prop.val, Node) + if not _is_child(dep_node): + self._graph.add_edge(root_node, dep_node) + def _process_properties_r(self, root_node: Node, props_node: Node) -> None: """ Process props_node properties for dependencies, and add those as @@ -2456,12 +2496,16 @@ def _is_child(parent_node: Node, child_node: Optional[Node]) -> bool: assert isinstance(prop.val, Node) if _is_child(props_node, prop.val): continue - self._graph.add_edge(root_node, prop.val) + if TYPE_CHECKING: + assert isinstance(prop.val, Node) + self._apply_dependency_mode(root_node, prop.val, prop) elif prop.type == 'phandles': if TYPE_CHECKING: assert isinstance(prop.val, list) for phandle_node in prop.val: - self._graph.add_edge(root_node, phandle_node) + if TYPE_CHECKING: + assert isinstance(phandle_node, Node) + self._apply_dependency_mode(root_node, phandle_node, prop) elif prop.type == 'phandle-array': if TYPE_CHECKING: assert isinstance(prop.val, list) @@ -2470,7 +2514,7 @@ def _is_child(parent_node: Node, child_node: Optional[Node]) -> bool: continue if TYPE_CHECKING: assert isinstance(cd, ControllerAndData) - self._graph.add_edge(root_node, cd.controller) + self._apply_dependency_mode(root_node, cd.controller, prop) # A Node depends on whatever supports the interrupts it # generates. @@ -2976,7 +3020,7 @@ def _bad_overwrite(to_dict: dict, from_dict: dict, prop: str, return False # These are overridden deliberately - if prop in {"title", "description", "compatible", "examples"}: + if prop in {"title", "description", "compatible", "examples", "dependency-mode"}: return False if prop == "required": From b5f37817be31303f649ac276f11377c34bb68a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Wed, 6 May 2026 16:50:24 +0200 Subject: [PATCH 06/18] UPSTREAM: dts: bindings: ethernet: update values for phy-connection-type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8434550bc205a7134d3e7f666e4aedb39a060551 upstream. Add all predefined values for phy-connection-type from the devicetree specification (Table 4.13). Signed-off-by: Fin Maaß Signed-off-by: Siddharth Vadapalli --- dts/bindings/ethernet/ethernet-controller.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dts/bindings/ethernet/ethernet-controller.yaml b/dts/bindings/ethernet/ethernet-controller.yaml index 7b929df79c47..b91f1ee16f44 100644 --- a/dts/bindings/ethernet/ethernet-controller.yaml +++ b/dts/bindings/ethernet/ethernet-controller.yaml @@ -46,6 +46,18 @@ properties: - "rmii" - "gmii" - "rgmii" + - "rgmii-id" + - "rgmii-txid" + - "rgmii-rxid" + - "tbi" + - "rtbi" + - "smii" + - "sgmii" + - "rev-mii" + - "xgmii" + - "moca" + - "qsgmii" + - "trgmii" - "internal" ptp-clock: From c632faf47e2ea2f73424914cf8f26cdad369f546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Wed, 20 May 2026 10:08:01 +0200 Subject: [PATCH 07/18] UPSTREAM: dts: ethernet: use dependency-mode for phy-handle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8d3f74699457d6fd07c40c017979000d25e74be1 upstream. Move `phy-handle` to use the dependency-mode prop key instead of the hardcoded code. Because all ethernet drivers only need to use the phy-handle in the iface init, we can ignore the phy-handle dependency completly instead of only ignoring it if the phy-handle pointing to a child node of the ethernet node. Signed-off-by: Fin Maaß Signed-off-by: Siddharth Vadapalli --- dts/bindings/ethernet/ethernet-controller.yaml | 1 + .../python-devicetree/src/devicetree/edtlib.py | 16 ---------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/dts/bindings/ethernet/ethernet-controller.yaml b/dts/bindings/ethernet/ethernet-controller.yaml index b91f1ee16f44..688af318a6e6 100644 --- a/dts/bindings/ethernet/ethernet-controller.yaml +++ b/dts/bindings/ethernet/ethernet-controller.yaml @@ -34,6 +34,7 @@ properties: phy-handle: type: phandle + dependency-mode: ignore description: | Specifies a reference to a node representing a PHY device. diff --git a/scripts/dts/python-devicetree/src/devicetree/edtlib.py b/scripts/dts/python-devicetree/src/devicetree/edtlib.py index 0b3a2613221c..35f54cd2bd84 100644 --- a/scripts/dts/python-devicetree/src/devicetree/edtlib.py +++ b/scripts/dts/python-devicetree/src/devicetree/edtlib.py @@ -2480,22 +2480,6 @@ def _process_properties_r(self, root_node: Node, props_node: Node) -> None: # 'phandles', or 'phandle-array' property values. for prop in props_node.props.values(): if prop.type == 'phandle': - # According to the DT spec, a property named 'phy-handle' is required when - # the Ethernet device is connected a physical layer device (PHY). - # But the 'phy-handle' property can point to a child node of the Ethernet device, - # so we need to check for that and not add a dependency in that case, otherwise - # we'll get a cycle in the graph. - if prop.name == "phy-handle": - def _is_child(parent_node: Node, child_node: Optional[Node]) -> bool: - if child_node is None: - return False - if parent_node is child_node: - return True - return _is_child(parent_node, child_node.parent) - if TYPE_CHECKING: - assert isinstance(prop.val, Node) - if _is_child(props_node, prop.val): - continue if TYPE_CHECKING: assert isinstance(prop.val, Node) self._apply_dependency_mode(root_node, prop.val, prop) From 0e463dd21dcaa24dfe61f322b4a1ec405dd85dcc Mon Sep 17 00:00:00 2001 From: Muhammad Waleed Badar Date: Thu, 7 May 2026 21:46:19 +0500 Subject: [PATCH 08/18] UPSTREAM: net: pkt: add NET_PKT_FRAG_FOR_EACH() macro commit 9907556e19c09814a583f5b858c0e1a2b8c1fee4 upstream. Add a macro to iterate over all fragments in a network packet. Signed-off-by: Muhammad Waleed Badar Signed-off-by: Siddharth Vadapalli --- include/zephyr/net/net_pkt.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index 5ac666fc1f3d..6546676d8280 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -52,6 +52,30 @@ extern "C" { struct net_context; +/** + * @brief Iterate over all fragments in a network packet. + * + * @details Traverses the fragment chain of a @ref net_pkt buffer. + * + * @param _pkt Pointer to the head @ref net_pkt buffer whose fragment + * chain is to be traversed. + * @param _var Name of the iterator variable. The macro declares + * this variable internally as struct net_buf * + * and updates it on each iteration. + * + * @note Iteration starts from the first fragment buffer (_pkt)->frags; + * + * Example usage: + * @code{.c} + * NET_PKT_FRAG_FOR_EACH(pkt, frag) { + * do_something(frag->data, frag->len); + * } + * @endcode + */ +#define NET_PKT_FRAG_FOR_EACH(_pkt, _var) \ + for (struct net_buf *_var = (_pkt)->frags; _var != NULL; \ + _var = _var->frags) + /** @cond INTERNAL_HIDDEN */ #if defined(CONFIG_NET_PKT_ALLOC_STATS) From c53629fccca74e923caa6173b3db85661c0da9d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Mon, 19 Oct 2026 12:23:28 +0530 Subject: [PATCH 09/18] UPSTREAM: net: l2: ethernet: add struct net_if to arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit db984ee196be90f2406a0e6c8afd98f834d2958b upstream. add struct net_if to arguments Signed-off-by: Fin Maaß Signed-off-by: Siddharth Vadapalli --- drivers/ethernet/dwc_xgmac/eth_dwc_xgmac.c | 15 ++-- drivers/ethernet/eth_adin2111.c | 8 ++- drivers/ethernet/eth_cyclonev.c | 22 +++--- drivers/ethernet/eth_dm9051.c | 15 ++-- drivers/ethernet/eth_dwmac.c | 11 ++- drivers/ethernet/eth_e1000.c | 7 +- drivers/ethernet/eth_enc28j60.c | 4 +- drivers/ethernet/eth_enc424j600.c | 10 +-- drivers/ethernet/eth_esp32.c | 9 +-- drivers/ethernet/eth_gecko.c | 7 +- drivers/ethernet/eth_ivshmem.c | 11 +-- drivers/ethernet/eth_lan865x.c | 16 +++-- drivers/ethernet/eth_lan9250.c | 9 +-- drivers/ethernet/eth_litex_liteeth.c | 15 ++-- drivers/ethernet/eth_native_tap.c | 11 +-- drivers/ethernet/eth_numaker.c | 8 ++- drivers/ethernet/eth_nxp_enet.c | 19 +++-- .../eth_nxp_enet_qos/eth_nxp_enet_qos_mac.c | 7 +- drivers/ethernet/eth_nxp_s32_gmac.c | 15 ++-- drivers/ethernet/eth_nxp_s32_netc.c | 9 +-- drivers/ethernet/eth_nxp_s32_netc_priv.h | 6 +- drivers/ethernet/eth_nxp_s32_netc_psi.c | 3 +- drivers/ethernet/eth_renesas_ra.c | 8 +-- drivers/ethernet/eth_renesas_ra_rmac.c | 11 +-- drivers/ethernet/eth_sam_gmac.c | 13 ++-- drivers/ethernet/eth_sensry_sy1xx_mac.c | 18 +++-- drivers/ethernet/eth_slip_tap.c | 9 +-- drivers/ethernet/eth_smsc911x.c | 7 +- drivers/ethernet/eth_smsc91x.c | 8 +-- drivers/ethernet/eth_stellaris.c | 3 +- drivers/ethernet/eth_stm32_hal_common.c | 15 ++-- drivers/ethernet/eth_stm32_hal_priv.h | 7 +- drivers/ethernet/eth_stm32_hal_ptp.c | 3 +- drivers/ethernet/eth_stm32_hal_v1.c | 9 +-- drivers/ethernet/eth_stm32_hal_v2.c | 9 +-- drivers/ethernet/eth_test.c | 24 ++++--- drivers/ethernet/eth_virtio_net.c | 3 +- drivers/ethernet/eth_w5500.c | 12 ++-- drivers/ethernet/eth_w6100.c | 12 ++-- drivers/ethernet/eth_wch.c | 18 ++--- .../ethernet/eth_xilinx_axi_ethernet_lite.c | 10 ++- drivers/ethernet/eth_xilinx_axienet.c | 69 +++++++++++++++++-- drivers/ethernet/eth_xlnx_gem.c | 19 +++-- drivers/ethernet/eth_xmc4xxx.c | 16 +++-- drivers/ethernet/intel/eth_intel_igc.c | 13 ++-- .../ethernet/nxp_imx_netc/eth_nxp_imx_netc.c | 15 ++-- .../nxp_imx_netc/eth_nxp_imx_netc_priv.h | 8 +-- .../nxp_imx_netc/eth_nxp_imx_netc_psi.c | 3 +- drivers/wifi/esp32/src/esp_wifi_drv.c | 4 +- drivers/wifi/infineon/airoc_wifi.c | 9 ++- drivers/wifi/nrf_wifi/inc/net_if.h | 8 ++- drivers/wifi/nrf_wifi/src/net_if.c | 5 +- drivers/wifi/nxp/nxp_wifi_drv.c | 5 +- drivers/wifi/siwx91x/siwx91x_wifi.c | 6 +- include/zephyr/net/ethernet.h | 19 ++--- subsys/net/l2/ethernet/dsa/dsa_port.c | 19 +++-- subsys/net/l2/ethernet/eth_stats.h | 4 +- subsys/net/l2/ethernet/ethernet.c | 10 +-- subsys/net/l2/ethernet/ethernet_mgmt.c | 49 ++++++------- subsys/net/l2/ethernet/ethernet_stats.c | 8 +-- subsys/net/lib/shell/stats.c | 8 +-- subsys/usb/device_next/class/usbd_cdc_ecm.c | 16 ++--- subsys/usb/device_next/class/usbd_cdc_ncm.c | 14 ++-- tests/net/bridge/src/main.c | 4 +- tests/net/checksum_offload/src/main.c | 6 +- tests/net/ethernet_mgmt/src/main.c | 5 +- tests/net/iface/src/main.c | 4 +- tests/net/promiscuous/src/main.c | 4 +- tests/net/ptp/clock/src/main.c | 6 +- tests/net/socket/net_mgmt/src/main.c | 6 +- tests/net/tx_timestamp/src/main.c | 3 +- tests/net/virtual/src/main.c | 3 +- tests/net/vlan/src/main.c | 6 +- 73 files changed, 506 insertions(+), 304 deletions(-) diff --git a/drivers/ethernet/dwc_xgmac/eth_dwc_xgmac.c b/drivers/ethernet/dwc_xgmac/eth_dwc_xgmac.c index 7e45ccd852bf..89eb8928ab7d 100644 --- a/drivers/ethernet/dwc_xgmac/eth_dwc_xgmac.c +++ b/drivers/ethernet/dwc_xgmac/eth_dwc_xgmac.c @@ -1189,7 +1189,7 @@ static void eth_dwc_xgmac_iface_init(struct net_if *iface) * @param dev Pointer to the ethernet device * @retval 0 upon successful completion */ -static int eth_dwc_xgmac_start_device(const struct device *dev) +static int eth_dwc_xgmac_start_device(const struct device *dev, struct net_if *iface __unused) { const struct eth_dwc_xgmac_config *dev_conf = (struct eth_dwc_xgmac_config *)dev->config; struct eth_dwc_xgmac_dev_data *dev_data = (struct eth_dwc_xgmac_dev_data *)dev->data; @@ -1267,7 +1267,7 @@ static int eth_dwc_xgmac_start_device(const struct device *dev) * @param dev Pointer to the ethernet device * @retval 0 upon successful completion */ -static int eth_dwc_xgmac_stop_device(const struct device *dev) +static int eth_dwc_xgmac_stop_device(const struct device *dev, struct net_if *iface __unused) { const struct eth_dwc_xgmac_config *dev_conf = (struct eth_dwc_xgmac_config *)dev->config; struct eth_dwc_xgmac_dev_data *dev_data = (struct eth_dwc_xgmac_dev_data *)dev->data; @@ -1521,7 +1521,9 @@ static inline void disable_filter_for_mac_addr(const struct device *dev, uint8_t * (1) if existing configuration is equals to input configuration * -ENOTSUP for invalid config type */ -static int eth_dwc_xgmac_set_config(const struct device *dev, enum ethernet_config_type type, +static int eth_dwc_xgmac_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct eth_dwc_xgmac_dev_data *dev_data = (struct eth_dwc_xgmac_dev_data *)dev->data; @@ -1592,9 +1594,9 @@ static int eth_dwc_xgmac_set_config(const struct device *dev, enum ethernet_conf * @param dev Pointer to the ethernet device * @return Enumeration containing the current XGMAC device's capabilities */ -static enum ethernet_hw_caps eth_dwc_xgmac_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_dwc_xgmac_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); enum ethernet_hw_caps caps = (enum ethernet_hw_caps)0; caps = (ETHERNET_LINK_1000BASE | ETHERNET_LINK_100BASE | ETHERNET_LINK_10BASE); @@ -1626,7 +1628,8 @@ static enum ethernet_hw_caps eth_dwc_xgmac_get_capabilities(const struct device * @param dev Pointer to the ethernet device * @return Pointer to the current XGMAC device's statistics data */ -static struct net_stats_eth *eth_dwc_xgmac_stats(const struct device *dev) +static struct net_stats_eth *eth_dwc_xgmac_stats(const struct device *dev, + struct net_if *iface __unused) { struct eth_dwc_xgmac_dev_data *dev_data = (struct eth_dwc_xgmac_dev_data *)dev->data; diff --git a/drivers/ethernet/eth_adin2111.c b/drivers/ethernet/eth_adin2111.c index cb781e172b33..1e292a254e6b 100644 --- a/drivers/ethernet/eth_adin2111.c +++ b/drivers/ethernet/eth_adin2111.c @@ -1216,9 +1216,9 @@ static void adin2111_port_iface_init(struct net_if *iface) } } -static enum ethernet_hw_caps adin2111_port_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps adin2111_port_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); return ETHERNET_LINK_10BASE | ETHERNET_HW_FILTERING #if defined(CONFIG_NET_LLDP) @@ -1228,6 +1228,7 @@ static enum ethernet_hw_caps adin2111_port_get_capabilities(const struct device } static int adin2111_port_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -1273,7 +1274,8 @@ static int adin2111_port_set_config(const struct device *dev, } #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *adin2111_port_get_stats(const struct device *dev) +static struct net_stats_eth *adin2111_port_get_stats(const struct device *dev, + struct net_if *iface __unused) { struct adin2111_port_data *data = dev->data; diff --git a/drivers/ethernet/eth_cyclonev.c b/drivers/ethernet/eth_cyclonev.c index 9717e83378f2..af8a31683a26 100644 --- a/drivers/ethernet/eth_cyclonev.c +++ b/drivers/ethernet/eth_cyclonev.c @@ -46,13 +46,14 @@ void eth_cyclonev_isr(const struct device *dev); int set_mac_conf_status(int instance, uint32_t *mac_config_reg_settings, struct eth_cyclonev_priv *p); int eth_cyclonev_probe(const struct device *dev); -static int eth_cyclonev_start(const struct device *dev); -static int eth_cyclonev_stop(const struct device *dev); +static int eth_cyclonev_start(const struct device *dev, struct net_if *iface); +static int eth_cyclonev_stop(const struct device *dev, struct net_if *iface); static void eth_cyclonev_receive(struct eth_cyclonev_priv *p); static void eth_cyclonev_tx_release(struct eth_cyclonev_priv *p); -static int eth_cyclonev_set_config(const struct device *dev, enum ethernet_config_type type, - const struct ethernet_config *config); -static enum ethernet_hw_caps eth_cyclonev_caps(const struct device *dev); +static int eth_cyclonev_set_config(const struct device *dev, struct net_if *iface, + enum ethernet_config_type type, + const struct ethernet_config *config); +static enum ethernet_hw_caps eth_cyclonev_caps(const struct device *dev, struct net_if *iface); /** Device config */ struct eth_cyclonev_config { @@ -311,7 +312,9 @@ static void eth_cyclonev_iface_init(struct net_if *iface) * @retval ret 0 if successful */ -static int eth_cyclonev_set_config(const struct device *dev, enum ethernet_config_type type, +static int eth_cyclonev_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct eth_cyclonev_priv *p = dev->data; @@ -359,7 +362,8 @@ static int eth_cyclonev_set_config(const struct device *dev, enum ethernet_confi * @retval caps Enumerated capabilities of device */ -static enum ethernet_hw_caps eth_cyclonev_caps(const struct device *dev) +static enum ethernet_hw_caps eth_cyclonev_caps(const struct device *dev, + struct net_if *iface __unused) { struct eth_cyclonev_priv *p = dev->data; enum ethernet_hw_caps caps = 0; @@ -1046,7 +1050,7 @@ int eth_cyclonev_probe(const struct device *dev) * @retval 0 */ -static int eth_cyclonev_start(const struct device *dev) +static int eth_cyclonev_start(const struct device *dev, struct net_if *iface __unused) { struct eth_cyclonev_priv *p = dev->data; @@ -1089,7 +1093,7 @@ static int eth_cyclonev_start(const struct device *dev) * @retval 0 if successful, -1 otherwise */ -static int eth_cyclonev_stop(const struct device *dev) +static int eth_cyclonev_stop(const struct device *dev, struct net_if *iface __unused) { struct eth_cyclonev_priv *p = dev->data; diff --git a/drivers/ethernet/eth_dm9051.c b/drivers/ethernet/eth_dm9051.c index 24a42c7e974b..67334ce64b8e 100644 --- a/drivers/ethernet/eth_dm9051.c +++ b/drivers/ethernet/eth_dm9051.c @@ -358,7 +358,7 @@ static int eth_dm9051_nsr_poll(const struct device *dev, k_timeout_t timeout) return -ETIMEDOUT; } -static int eth_dm9051_hw_start(const struct device *dev) +static int eth_dm9051_hw_start(const struct device *dev, struct net_if *iface __unused) { const uint8_t imr = DM9051_IMR_PRI | DM9051_IMR_PTI | DM9051_IMR_LNKCHGI | DM9051_IMR_PAR; const uint8_t rcr = DM9051_RCR_RXEN | DM9051_RCR_DIS_CRC | DM9051_RCR_DIS_LONG; @@ -416,7 +416,7 @@ static int eth_dm9051_hw_start(const struct device *dev) return eth_dm9051_spi_write_reg(dev, DM9051_IMR, imr); } -static int eth_dm9051_hw_stop(const struct device *dev) +static int eth_dm9051_hw_stop(const struct device *dev, struct net_if *iface __unused) { int ret; @@ -524,7 +524,7 @@ static struct net_pkt *eth_dm9051_recv_pkt(const struct device *dev) rx_len, NET_ETH_MAX_FRAME_SIZE); } - (void)eth_dm9051_hw_start(dev); + (void)eth_dm9051_hw_start(dev, data->iface); return NULL; } @@ -715,10 +715,9 @@ static void eth_dm9051_iface_init(struct net_if *iface) k_thread_name_set(&data->rx_thread, "eth_dm9051"); } -static enum ethernet_hw_caps eth_dm9051_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_dm9051_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE #if defined(CONFIG_NET_PROMISCUOUS_MODE) | ETHERNET_PROMISC_MODE @@ -727,6 +726,7 @@ static enum ethernet_hw_caps eth_dm9051_get_capabilities(const struct device *de } static int eth_dm9051_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -771,7 +771,8 @@ static int eth_dm9051_set_config(const struct device *dev, } } -static const struct device *eth_dm9051_get_phy(const struct device *dev) +static const struct device *eth_dm9051_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct eth_dm9051_config *config = dev->config; diff --git a/drivers/ethernet/eth_dwmac.c b/drivers/ethernet/eth_dwmac.c index f1acb4e93115..7972e2e4d322 100644 --- a/drivers/ethernet/eth_dwmac.c +++ b/drivers/ethernet/eth_dwmac.c @@ -97,7 +97,7 @@ static inline uint32_t phys_lo32(void *addr) return lo32((uintptr_t)addr); } -static enum ethernet_hw_caps dwmac_caps(const struct device *dev) +static enum ethernet_hw_caps dwmac_caps(const struct device *dev, struct net_if *iface __unused) { struct dwmac_priv *p = dev->data; enum ethernet_hw_caps caps = 0; @@ -468,6 +468,7 @@ static void dwmac_set_mac_addr(struct dwmac_priv *p, uint8_t *addr, int n) } static int dwmac_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -558,6 +559,14 @@ static void phy_link_state_changed(const struct device *phy_dev, } } +static const struct device *dwmac_get_phy(const struct device *dev, struct net_if *iface __unused) +{ + const struct dwmac_config *cfg = dev->config; + + return cfg->phy_dev; +} + + static void dwmac_iface_init(struct net_if *iface) { struct dwmac_priv *p = net_if_get_device(iface)->data; diff --git a/drivers/ethernet/eth_e1000.c b/drivers/ethernet/eth_e1000.c index 3e60d145cb64..c2513c97d95d 100644 --- a/drivers/ethernet/eth_e1000.c +++ b/drivers/ethernet/eth_e1000.c @@ -74,7 +74,7 @@ static struct net_if *get_iface(struct e1000_dev *ctx) return ctx->iface; } -static enum ethernet_hw_caps e1000_caps(const struct device *dev) +static enum ethernet_hw_caps e1000_caps(const struct device *dev, struct net_if *iface __unused) { return #if defined(CONFIG_NET_VLAN) @@ -92,7 +92,8 @@ static enum ethernet_hw_caps e1000_caps(const struct device *dev) } #if defined(CONFIG_ETH_E1000_PTP_CLOCK) -static const struct device *e1000_get_ptp_clock(const struct device *dev) +static const struct device *e1000_get_ptp_clock(const struct device *dev, + struct net_if *iface __unused) { struct e1000_dev *ctx = dev->data; @@ -287,7 +288,7 @@ static void e1000_iface_init(struct net_if *iface) } #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *get_stats(const struct device *dev) +static struct net_stats_eth *get_stats(const struct device *dev, struct net_if *iface __unused) { struct e1000_dev *ctx = dev->data; diff --git a/drivers/ethernet/eth_enc28j60.c b/drivers/ethernet/eth_enc28j60.c index ed842d45e162..ce8c7b9d7ecf 100644 --- a/drivers/ethernet/eth_enc28j60.c +++ b/drivers/ethernet/eth_enc28j60.c @@ -733,7 +733,8 @@ static void eth_enc28j60_rx_thread(void *p1, void *p2, void *p3) } } -static enum ethernet_hw_caps eth_enc28j60_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_enc28j60_get_capabilities(const struct device *dev, + struct net_if *iface __unused) { ARG_UNUSED(dev); @@ -745,6 +746,7 @@ static enum ethernet_hw_caps eth_enc28j60_get_capabilities(const struct device * } static int eth_enc28j60_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { diff --git a/drivers/ethernet/eth_enc424j600.c b/drivers/ethernet/eth_enc424j600.c index c5f0caa92464..9afbbad1d77b 100644 --- a/drivers/ethernet/eth_enc424j600.c +++ b/drivers/ethernet/eth_enc424j600.c @@ -496,14 +496,14 @@ static void enc424j600_rx_thread(void *p1, void *p2, void *p3) } } -static enum ethernet_hw_caps enc424j600_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps enc424j600_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE; } static int enc424j600_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -559,7 +559,7 @@ static void enc424j600_iface_init(struct net_if *iface) 0, K_NO_WAIT); } -static int enc424j600_start_device(const struct device *dev) +static int enc424j600_start_device(const struct device *dev, struct net_if *iface __unused) { struct enc424j600_runtime *context = dev->data; uint16_t tmp; @@ -589,7 +589,7 @@ static int enc424j600_start_device(const struct device *dev) return 0; } -static int enc424j600_stop_device(const struct device *dev) +static int enc424j600_stop_device(const struct device *dev, struct net_if *iface __unused) { struct enc424j600_runtime *context = dev->data; uint16_t tmp; diff --git a/drivers/ethernet/eth_esp32.c b/drivers/ethernet/eth_esp32.c index 545f971ae520..c352ba380bf9 100644 --- a/drivers/ethernet/eth_esp32.c +++ b/drivers/ethernet/eth_esp32.c @@ -336,13 +336,14 @@ static void eth_esp32_iomux_init_mii(void) } } -static enum ethernet_hw_caps eth_esp32_caps(const struct device *dev) +static enum ethernet_hw_caps eth_esp32_caps(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE; } static int eth_esp32_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -589,9 +590,9 @@ int eth_esp32_initialize(const struct device *dev) return res; } -static const struct device *eth_esp32_phy_get(const struct device *dev) +static const struct device *eth_esp32_phy_get(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); return eth_esp32_phy_dev; } diff --git a/drivers/ethernet/eth_gecko.c b/drivers/ethernet/eth_gecko.c index 843208872b5f..9cd6999b7840 100644 --- a/drivers/ethernet/eth_gecko.c +++ b/drivers/ethernet/eth_gecko.c @@ -627,11 +627,10 @@ static void eth_iface_init(struct net_if *iface) 0, K_NO_WAIT); } -static enum ethernet_hw_caps eth_gecko_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_gecko_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - - return (ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE); + return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE; } static const struct ethernet_api eth_api = { diff --git a/drivers/ethernet/eth_ivshmem.c b/drivers/ethernet/eth_ivshmem.c index 9414b64b07ef..b5c842734aa3 100644 --- a/drivers/ethernet/eth_ivshmem.c +++ b/drivers/ethernet/eth_ivshmem.c @@ -53,7 +53,8 @@ struct eth_ivshmem_cfg_data { }; #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *eth_ivshmem_get_stats(const struct device *dev) +static struct net_stats_eth *eth_ivshmem_get_stats(const struct device *dev, + struct net_if *iface __unused) { struct eth_ivshmem_dev_data *dev_data = dev->data; @@ -61,7 +62,7 @@ static struct net_stats_eth *eth_ivshmem_get_stats(const struct device *dev) } #endif -static int eth_ivshmem_start(const struct device *dev) +static int eth_ivshmem_start(const struct device *dev, struct net_if *iface __unused) { struct eth_ivshmem_dev_data *dev_data = dev->data; @@ -73,7 +74,7 @@ static int eth_ivshmem_start(const struct device *dev) return 0; } -static int eth_ivshmem_stop(const struct device *dev) +static int eth_ivshmem_stop(const struct device *dev, struct net_if *iface __unused) { struct eth_ivshmem_dev_data *dev_data = dev->data; @@ -85,9 +86,9 @@ static int eth_ivshmem_stop(const struct device *dev) return 0; } -static enum ethernet_hw_caps eth_ivshmem_caps(const struct device *dev) +static enum ethernet_hw_caps eth_ivshmem_caps(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_LINK_1000BASE; } diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 4340a0f3878e..cbaf578156eb 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -105,15 +105,21 @@ static void lan865x_iface_init(struct net_if *iface) ctx->iface_initialized = true; } -static enum ethernet_hw_caps lan865x_port_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps lan865x_port_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_PROMISC_MODE; + return ETHERNET_LINK_10BASE | ETHERNET_PROMISC_MODE +#if defined(CONFIG_NET_VLAN) + | ETHERNET_HW_VLAN +#endif + ; } static int lan865x_gpio_reset(const struct device *dev); static void lan865x_write_macaddress(const struct device *dev); -static int lan865x_set_config(const struct device *dev, enum ethernet_config_type type, +static int lan865x_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { const struct lan865x_config *cfg = dev->config; @@ -458,7 +464,7 @@ static int lan865x_port_send(const struct device *dev, struct net_pkt *pkt) return 0; } -const struct device *lan865x_get_phy(const struct device *dev) +const struct device *lan865x_get_phy(const struct device *dev, struct net_if *iface __unused) { const struct lan865x_config *cfg = dev->config; diff --git a/drivers/ethernet/eth_lan9250.c b/drivers/ethernet/eth_lan9250.c index 3242bff103c9..7f2f9ff5a7ea 100644 --- a/drivers/ethernet/eth_lan9250.c +++ b/drivers/ethernet/eth_lan9250.c @@ -760,10 +760,9 @@ static void lan9250_thread(void *p1, void *p2, void *p3) } } -static enum ethernet_hw_caps lan9250_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps lan9250_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE #if defined(CONFIG_NET_PROMISCUOUS_MODE) | ETHERNET_PROMISC_MODE @@ -789,7 +788,9 @@ static void lan9250_iface_init(struct net_if *iface) K_PRIO_COOP(CONFIG_ETH_LAN9250_RX_THREAD_PRIO), 0, K_NO_WAIT); } -static int lan9250_set_config(const struct device *dev, enum ethernet_config_type type, +static int lan9250_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct lan9250_runtime *ctx = dev->data; diff --git a/drivers/ethernet/eth_litex_liteeth.c b/drivers/ethernet/eth_litex_liteeth.c index 69561bdc7a44..15161a946ae9 100644 --- a/drivers/ethernet/eth_litex_liteeth.c +++ b/drivers/ethernet/eth_litex_liteeth.c @@ -169,7 +169,9 @@ static void eth_irq_handler(const struct device *port) } } -static int eth_set_config(const struct device *dev, enum ethernet_config_type type, +static int eth_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct eth_litex_dev_data *context = dev->data; @@ -185,7 +187,7 @@ static int eth_set_config(const struct device *dev, enum ethernet_config_type ty return -ENOTSUP; } -static int eth_start(const struct device *dev) +static int eth_start(const struct device *dev, struct net_if *iface __unused) { struct eth_litex_dev_data *context = dev->data; const struct eth_litex_config *config = dev->config; @@ -203,7 +205,7 @@ static int eth_start(const struct device *dev) return 0; } -static int eth_stop(const struct device *dev) +static int eth_stop(const struct device *dev, struct net_if *iface __unused) { const struct eth_litex_config *config = dev->config; @@ -213,7 +215,7 @@ static int eth_stop(const struct device *dev) return 0; } -static const struct device *eth_get_phy(const struct device *dev) +static const struct device *eth_get_phy(const struct device *dev, struct net_if *iface __unused) { const struct eth_litex_config *config = dev->config; @@ -269,10 +271,9 @@ static void eth_iface_init(struct net_if *iface) } } -static enum ethernet_hw_caps eth_caps(const struct device *dev) +static enum ethernet_hw_caps eth_caps(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return #ifdef CONFIG_NET_VLAN ETHERNET_HW_VLAN | diff --git a/drivers/ethernet/eth_native_tap.c b/drivers/ethernet/eth_native_tap.c index 4f31c5ffbfd4..62e312d5f05e 100644 --- a/drivers/ethernet/eth_native_tap.c +++ b/drivers/ethernet/eth_native_tap.c @@ -397,10 +397,9 @@ static void eth_iface_init(struct net_if *iface) } } -static enum ethernet_hw_caps eth_native_tap_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_native_tap_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_TXTIME #if defined(CONFIG_NET_VLAN) | ETHERNET_HW_VLAN @@ -421,7 +420,8 @@ static enum ethernet_hw_caps eth_native_tap_get_capabilities(const struct device } #if defined(CONFIG_ETH_NATIVE_TAP_PTP_CLOCK) -static const struct device *eth_get_ptp_clock(const struct device *dev) +static const struct device *eth_get_ptp_clock(const struct device *dev, + struct net_if *iface __unused) { struct eth_context *context = dev->data; @@ -430,7 +430,7 @@ static const struct device *eth_get_ptp_clock(const struct device *dev) #endif #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *get_stats(const struct device *dev) +static struct net_stats_eth *get_stats(const struct device *dev, struct net_if *iface __unused) { struct eth_context *context = dev->data; @@ -439,6 +439,7 @@ static struct net_stats_eth *get_stats(const struct device *dev) #endif static int set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { diff --git a/drivers/ethernet/eth_numaker.c b/drivers/ethernet/eth_numaker.c index 24934c1b19ac..6de4b76a0a50 100644 --- a/drivers/ethernet/eth_numaker.c +++ b/drivers/ethernet/eth_numaker.c @@ -523,7 +523,9 @@ static void numaker_eth_if_init(struct net_if *iface) m_numaker_gmacdev_enable(gmacdev); } -static int numaker_eth_set_config(const struct device *dev, enum ethernet_config_type type, +static int numaker_eth_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct eth_numaker_data *data = dev->data; @@ -541,9 +543,9 @@ static int numaker_eth_set_config(const struct device *dev, enum ethernet_config } } -static enum ethernet_hw_caps numaker_eth_get_cap(const struct device *dev) +static enum ethernet_hw_caps numaker_eth_get_cap(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); #if defined(NU_USING_HW_CHECKSUM) return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_HW_RX_CHKSUM_OFFLOAD; #else diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c index 67564db6c0c6..946debe90da4 100644 --- a/drivers/ethernet/eth_nxp_enet.c +++ b/drivers/ethernet/eth_nxp_enet.c @@ -200,7 +200,8 @@ static inline void eth_wait_for_ptp_ts(const struct device *dev, struct net_pkt #endif /* CONFIG_PTP_CLOCK_NXP_ENET */ #ifdef CONFIG_PTP_CLOCK -static const struct device *eth_nxp_enet_get_ptp_clock(const struct device *dev) +static const struct device *eth_nxp_enet_get_ptp_clock(const struct device *dev, + struct net_if *iface __unused) { const struct nxp_enet_mac_config *config = dev->config; @@ -243,7 +244,8 @@ static int eth_nxp_enet_tx(const struct device *dev, struct net_pkt *pkt) return 0; } -static enum ethernet_hw_caps eth_nxp_enet_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_nxp_enet_get_capabilities(const struct device *dev, + struct net_if *iface __unused) { #if defined(CONFIG_ETH_NXP_ENET_1G) const struct nxp_enet_mac_config *config = dev->config; @@ -278,8 +280,9 @@ static enum ethernet_hw_caps eth_nxp_enet_get_capabilities(const struct device * } static int eth_nxp_enet_set_config(const struct device *dev, - enum ethernet_config_type type, - const struct ethernet_config *cfg) + struct net_if *iface __unused, + enum ethernet_config_type type, + const struct ethernet_config *cfg) { struct nxp_enet_mac_data *data = dev->data; @@ -321,8 +324,9 @@ static int eth_nxp_enet_set_config(const struct device *dev, } static int eth_nxp_enet_get_config(const struct device *dev, - enum ethernet_config_type type, - struct ethernet_config *cfg) + struct net_if *iface __unused, + enum ethernet_config_type type, + struct ethernet_config *cfg) { switch (type) { case ETHERNET_CONFIG_TYPE_RX_CHECKSUM_SUPPORT: @@ -589,7 +593,8 @@ static void eth_nxp_enet_isr(const struct device *dev) irq_unlock(irq_lock_key); } -static const struct device *eth_nxp_enet_get_phy(const struct device *dev) +static const struct device *eth_nxp_enet_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct nxp_enet_mac_config *config = dev->config; diff --git a/drivers/ethernet/eth_nxp_enet_qos/eth_nxp_enet_qos_mac.c b/drivers/ethernet/eth_nxp_enet_qos/eth_nxp_enet_qos_mac.c index f138d6874830..df33d759751e 100644 --- a/drivers/ethernet/eth_nxp_enet_qos/eth_nxp_enet_qos_mac.c +++ b/drivers/ethernet/eth_nxp_enet_qos/eth_nxp_enet_qos_mac.c @@ -224,7 +224,8 @@ static void tx_dma_done(const struct device *dev) k_thread_name_get(k_current_get())); } -static enum ethernet_hw_caps eth_nxp_enet_qos_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_nxp_enet_qos_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_LINK_100BASE | ETHERNET_LINK_10BASE | @@ -778,7 +779,8 @@ static int eth_nxp_enet_qos_mac_init(const struct device *dev) return ret; } -static const struct device *eth_nxp_enet_qos_get_phy(const struct device *dev) +static const struct device *eth_nxp_enet_qos_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct nxp_enet_qos_mac_config *config = dev->config; @@ -788,6 +790,7 @@ static const struct device *eth_nxp_enet_qos_get_phy(const struct device *dev) static int eth_nxp_enet_qos_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *cfg) { diff --git a/drivers/ethernet/eth_nxp_s32_gmac.c b/drivers/ethernet/eth_nxp_s32_gmac.c index c0bb4e9d0c1f..80ecdc7d9338 100644 --- a/drivers/ethernet/eth_nxp_s32_gmac.c +++ b/drivers/ethernet/eth_nxp_s32_gmac.c @@ -125,7 +125,8 @@ static void phy_link_state_changed(const struct device *pdev, } } -static const struct device *eth_nxp_s32_get_phy(const struct device *dev) +static const struct device *eth_nxp_s32_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct eth_nxp_s32_config *cfg = dev->config; @@ -217,7 +218,8 @@ static int eth_nxp_s32_init(const struct device *dev) return 0; } -static int eth_nxp_s32_start(const struct device *dev) +static int eth_nxp_s32_start(const struct device *dev + struct net_if *iface __unused) { const struct eth_nxp_s32_config *cfg = dev->config; @@ -231,7 +233,8 @@ static int eth_nxp_s32_start(const struct device *dev) return 0; } -static int eth_nxp_s32_stop(const struct device *dev) +static int eth_nxp_s32_stop(const struct device *dev + struct net_if *iface __unused) { const struct eth_nxp_s32_config *cfg = dev->config; Gmac_Ip_StatusType status; @@ -455,6 +458,7 @@ static void eth_nxp_s32_rx_thread(void *arg1, void *unused1, void *unused2) } static int eth_nxp_s32_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -506,10 +510,9 @@ static int eth_nxp_s32_set_config(const struct device *dev, return res; } -static enum ethernet_hw_caps eth_nxp_s32_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_nxp_s32_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return (ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE #if (FEATURE_GMAC_RGMII_EN == 1U) diff --git a/drivers/ethernet/eth_nxp_s32_netc.c b/drivers/ethernet/eth_nxp_s32_netc.c index bf97c7a4b5a1..93a3901565c2 100644 --- a/drivers/ethernet/eth_nxp_s32_netc.c +++ b/drivers/ethernet/eth_nxp_s32_netc.c @@ -258,10 +258,9 @@ static void nxp_s32_eth_rx_thread(void *arg1, void *unused1, void *unused2) } } -enum ethernet_hw_caps nxp_s32_eth_get_capabilities(const struct device *dev) +enum ethernet_hw_caps nxp_s32_eth_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return (ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_LINK_1000BASE @@ -276,7 +275,9 @@ enum ethernet_hw_caps nxp_s32_eth_get_capabilities(const struct device *dev) ); } -int nxp_s32_eth_set_config(const struct device *dev, enum ethernet_config_type type, +int nxp_s32_eth_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct nxp_s32_eth_data *ctx = dev->data; diff --git a/drivers/ethernet/eth_nxp_s32_netc_priv.h b/drivers/ethernet/eth_nxp_s32_netc_priv.h index 33d335231b52..736aec487113 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_priv.h +++ b/drivers/ethernet/eth_nxp_s32_netc_priv.h @@ -129,9 +129,11 @@ struct nxp_s32_eth_data { int nxp_s32_eth_initialize_common(const struct device *dev); int nxp_s32_eth_tx(const struct device *dev, struct net_pkt *pkt); -enum ethernet_hw_caps nxp_s32_eth_get_capabilities(const struct device *dev); +enum ethernet_hw_caps nxp_s32_eth_get_capabilities(const struct device *dev, struct net_if *iface); void nxp_s32_eth_mcast_filter(const struct device *dev, const struct ethernet_filter *filter); -int nxp_s32_eth_set_config(const struct device *dev, enum ethernet_config_type type, +int nxp_s32_eth_set_config(const struct device *dev, + struct net_if *iface, + enum ethernet_config_type type, const struct ethernet_config *config); extern void Netc_Eth_Ip_MSIX_Rx(uint8_t si_idx); diff --git a/drivers/ethernet/eth_nxp_s32_netc_psi.c b/drivers/ethernet/eth_nxp_s32_netc_psi.c index 6d16d2afa911..05d31b57bec1 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_psi.c +++ b/drivers/ethernet/eth_nxp_s32_netc_psi.c @@ -76,7 +76,8 @@ static void phy_link_state_changed(const struct device *pdev, } } -static const struct device *nxp_s32_eth_get_phy(const struct device *dev) +static const struct device *nxp_s32_eth_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct nxp_s32_eth_config *cfg = dev->config; diff --git a/drivers/ethernet/eth_renesas_ra.c b/drivers/ethernet/eth_renesas_ra.c index 7ff53f7f4226..62f819aebae0 100644 --- a/drivers/ethernet/eth_renesas_ra.c +++ b/drivers/ethernet/eth_renesas_ra.c @@ -147,10 +147,9 @@ static struct renesas_ra_eth_config eth_0_config = { .p_cfg = &g_ether0_cfg, .phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, phy_handle))}; /* Driver functions */ -static enum ethernet_hw_caps renesas_ra_eth_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps renesas_ra_eth_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE; } @@ -308,7 +307,8 @@ static int renesas_ra_eth_tx(const struct device *dev, struct net_pkt *pkt) return -1; } -static const struct device *renesas_ra_eth_get_phy(const struct device *dev) +static const struct device *renesas_ra_eth_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct renesas_ra_eth_config *config = dev->config; diff --git a/drivers/ethernet/eth_renesas_ra_rmac.c b/drivers/ethernet/eth_renesas_ra_rmac.c index 220d3f6f47a7..250aa3c4b3ad 100644 --- a/drivers/ethernet/eth_renesas_ra_rmac.c +++ b/drivers/ethernet/eth_renesas_ra_rmac.c @@ -239,10 +239,9 @@ static void phy_type_setting(const struct device *dev) } } -static enum ethernet_hw_caps eth_renesas_ra_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_renesas_ra_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_LINK_1000BASE; } @@ -354,7 +353,8 @@ static void eth_renesas_ra_init_iface(struct net_if *iface) } #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *eth_renesas_ra_get_stats(const struct device *dev) +static struct net_stats_eth *eth_renesas_ra_get_stats(const struct device *dev, + struct net_if *iface __unused) { struct eth_renesas_ra_data *data = dev->data; @@ -363,7 +363,8 @@ static struct net_stats_eth *eth_renesas_ra_get_stats(const struct device *dev) #endif /* CONFIG_NET_STATISTICS_ETHERNET */ -const struct device *eth_renesas_ra_get_phy(const struct device *dev) +const struct device *eth_renesas_ra_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct eth_renesas_ra_config *config = dev->config; diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c index 9e3a5909ec50..8765cecd7a62 100644 --- a/drivers/ethernet/eth_sam_gmac.c +++ b/drivers/ethernet/eth_sam_gmac.c @@ -1721,7 +1721,8 @@ static void phy_link_state_changed(const struct device *pdev, } } -static const struct device *eth_sam_gmac_get_phy(const struct device *dev) +static const struct device *eth_sam_gmac_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct eth_sam_dev_cfg *const cfg = dev->config; @@ -1841,10 +1842,9 @@ static void eth_iface_init(struct net_if *iface) } } -static enum ethernet_hw_caps eth_sam_gmac_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_sam_gmac_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | #if defined(CONFIG_NET_VLAN) ETHERNET_HW_VLAN | @@ -1903,6 +1903,7 @@ static int eth_sam_gmac_set_qav_param(const struct device *dev, #endif static int eth_sam_gmac_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -1992,6 +1993,7 @@ static int eth_sam_gmac_get_qav_param(const struct device *dev, #endif static int eth_sam_gmac_get_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, struct ethernet_config *config) { @@ -2011,7 +2013,8 @@ static int eth_sam_gmac_get_config(const struct device *dev, } #if defined(CONFIG_PTP_CLOCK_SAM_GMAC) -static const struct device *eth_sam_gmac_get_ptp_clock(const struct device *dev) +static const struct device *eth_sam_gmac_get_ptp_clock(const struct device *dev, + struct net_if *iface __unused) { const struct eth_sam_dev_cfg *const cfg = dev->config; diff --git a/drivers/ethernet/eth_sensry_sy1xx_mac.c b/drivers/ethernet/eth_sensry_sy1xx_mac.c index 8cc4d7f83184..3305c2d0e123 100644 --- a/drivers/ethernet/eth_sensry_sy1xx_mac.c +++ b/drivers/ethernet/eth_sensry_sy1xx_mac.c @@ -103,7 +103,9 @@ struct sy1xx_mac_dev_data { /* prototypes */ static int sy1xx_mac_set_mac_addr(const struct device *dev); static int sy1xx_mac_set_promiscuous_mode(const struct device *dev, bool promiscuous_mode); -static int sy1xx_mac_set_config(const struct device *dev, enum ethernet_config_type type, +static int sy1xx_mac_set_config(const struct device *dev, + struct net_if *iface, + enum ethernet_config_type type, const struct ethernet_config *config); static void sy1xx_mac_rx_thread_entry(void *p1, void *p2, void *p3); @@ -183,7 +185,7 @@ static int sy1xx_mac_set_mac_addr(const struct device *dev) return 0; } -static int sy1xx_mac_start(const struct device *dev) +static int sy1xx_mac_start(const struct device *dev, struct net_if *iface __unused) { struct sy1xx_mac_dev_config *cfg = (struct sy1xx_mac_dev_config *)dev->config; struct sy1xx_mac_dev_data *data = (struct sy1xx_mac_dev_data *)dev->data; @@ -208,7 +210,7 @@ static int sy1xx_mac_start(const struct device *dev) return 0; } -static int sy1xx_mac_stop(const struct device *dev) +static int sy1xx_mac_stop(const struct device *dev, struct net_if *iface __unused) { struct sy1xx_mac_dev_data *data = (struct sy1xx_mac_dev_data *)dev->data; @@ -321,7 +323,8 @@ static void sy1xx_mac_iface_init(struct net_if *iface) } } -static enum ethernet_hw_caps sy1xx_mac_get_caps(const struct device *dev) +static enum ethernet_hw_caps sy1xx_mac_get_caps(const struct device *dev __unused, + struct net_if *iface __unused) { enum ethernet_hw_caps supported = 0; @@ -333,7 +336,9 @@ static enum ethernet_hw_caps sy1xx_mac_get_caps(const struct device *dev) return supported; } -static int sy1xx_mac_set_config(const struct device *dev, enum ethernet_config_type type, +static int sy1xx_mac_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct sy1xx_mac_dev_data *data = (struct sy1xx_mac_dev_data *)dev->data; @@ -355,7 +360,8 @@ static int sy1xx_mac_set_config(const struct device *dev, enum ethernet_config_t return ret; } -static const struct device *sy1xx_mac_get_phy(const struct device *dev) +static const struct device *sy1xx_mac_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct sy1xx_mac_dev_config *const cfg = dev->config; diff --git a/drivers/ethernet/eth_slip_tap.c b/drivers/ethernet/eth_slip_tap.c index dbbb6f5a747b..4055be41980c 100644 --- a/drivers/ethernet/eth_slip_tap.c +++ b/drivers/ethernet/eth_slip_tap.c @@ -16,10 +16,9 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); static struct slip_context slip_context_data; -static enum ethernet_hw_caps eth_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_HW_VLAN #if defined(CONFIG_NET_LLDP) | ETHERNET_LLDP @@ -30,7 +29,9 @@ static enum ethernet_hw_caps eth_capabilities(const struct device *dev) ; } -static int eth_slip_tap_set_config(const struct device *dev, enum ethernet_config_type type, +static int eth_slip_tap_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct slip_context *slip = dev->data; diff --git a/drivers/ethernet/eth_smsc911x.c b/drivers/ethernet/eth_smsc911x.c index 66a63524e4a0..5980d48be7ab 100644 --- a/drivers/ethernet/eth_smsc911x.c +++ b/drivers/ethernet/eth_smsc911x.c @@ -412,15 +412,14 @@ int smsc_init(void) /* Driver functions */ -static enum ethernet_hw_caps eth_smsc911x_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_smsc911x_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE; } #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *get_stats(const struct device *dev) +static struct net_stats_eth *get_stats(const struct device *dev, struct net_if *iface __unused) { struct eth_context *context = dev->data; diff --git a/drivers/ethernet/eth_smsc91x.c b/drivers/ethernet/eth_smsc91x.c index c150db14c11e..e15f15d1e4ff 100644 --- a/drivers/ethernet/eth_smsc91x.c +++ b/drivers/ethernet/eth_smsc91x.c @@ -664,7 +664,7 @@ static int smsc_init(struct smsc_data *sc) return 0; } -static const struct device *eth_get_phy(const struct device *dev) +static const struct device *eth_get_phy(const struct device *dev, struct net_if *iface __unused) { const struct eth_config *cfg = dev->config; @@ -684,10 +684,9 @@ static void phy_link_state_changed(const struct device *phy_dev, struct phy_link } } -static enum ethernet_hw_caps eth_smsc_get_caps(const struct device *dev) +static enum ethernet_hw_caps eth_smsc_get_caps(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return (ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE #if defined(CONFIG_NET_PROMISCUOUS_MODE) @@ -712,6 +711,7 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) } static int eth_smsc_set_config(const struct device *dev, + struct net_if *iface __unused enum ethernet_config_type type, const struct ethernet_config *config) { diff --git a/drivers/ethernet/eth_stellaris.c b/drivers/ethernet/eth_stellaris.c index c6949d6e9e60..5c39fb387974 100644 --- a/drivers/ethernet/eth_stellaris.c +++ b/drivers/ethernet/eth_stellaris.c @@ -303,7 +303,8 @@ static void eth_stellaris_init(struct net_if *iface) } #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *eth_stellaris_stats(const struct device *dev) +static struct net_stats_eth *eth_stellaris_stats(const struct device *dev, + struct net_if *iface __unused) { struct eth_stellaris_runtime *dev_data = dev->data; diff --git a/drivers/ethernet/eth_stm32_hal_common.c b/drivers/ethernet/eth_stm32_hal_common.c index be97dfac15fc..3f0179dd0591 100644 --- a/drivers/ethernet/eth_stm32_hal_common.c +++ b/drivers/ethernet/eth_stm32_hal_common.c @@ -238,10 +238,10 @@ static void phy_link_state_changed(const struct device *phy_dev, struct phy_link /* The hal also needs to be stopped before changing the MAC config. * The speed can change without receiving a link down callback before. */ - eth_stm32_hal_stop(dev); + eth_stm32_hal_stop(dev, dev_data->iface); if (state->is_up) { eth_stm32_set_mac_config(dev, state); - eth_stm32_hal_start(dev); + eth_stm32_hal_start(dev, dev_data->iface); net_eth_carrier_on(dev_data->iface); } else { net_eth_carrier_off(dev_data->iface); @@ -292,10 +292,9 @@ static void eth_iface_init(struct net_if *iface) k_thread_name_set(&dev_data->rx_thread, "stm_eth"); } -static enum ethernet_hw_caps eth_stm32_hal_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_stm32_hal_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE #if defined(CONFIG_NET_VLAN) | ETHERNET_HW_VLAN @@ -319,14 +318,16 @@ static enum ethernet_hw_caps eth_stm32_hal_get_capabilities(const struct device ; } -static const struct device *eth_stm32_hal_get_phy(const struct device *dev) +static const struct device *eth_stm32_hal_get_phy(const struct device *dev, + struct net_if *iface __unused) { ARG_UNUSED(dev); return eth_stm32_phy_dev; } #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *eth_stm32_hal_get_stats(const struct device *dev) +static struct net_stats_eth *eth_stm32_hal_get_stats(const struct device *dev, + struct net_if *iface __unused) { struct eth_stm32_hal_dev_data *dev_data = dev->data; diff --git a/drivers/ethernet/eth_stm32_hal_priv.h b/drivers/ethernet/eth_stm32_hal_priv.h index 02297f9bab07..dbd6c22a3b17 100644 --- a/drivers/ethernet/eth_stm32_hal_priv.h +++ b/drivers/ethernet/eth_stm32_hal_priv.h @@ -145,9 +145,10 @@ void eth_stm32_set_mac_config(const struct device *dev, struct phy_link_state *s int eth_stm32_tx(const struct device *dev, struct net_pkt *pkt); struct net_pkt *eth_stm32_rx(const struct device *dev); int eth_stm32_hal_init(const struct device *dev); -int eth_stm32_hal_start(const struct device *dev); -int eth_stm32_hal_stop(const struct device *dev); +int eth_stm32_hal_start(const struct device *dev, struct net_if *iface); +int eth_stm32_hal_stop(const struct device *dev, struct net_if *iface); int eth_stm32_hal_set_config(const struct device *dev, + struct net_if *iface, enum ethernet_config_type type, const struct ethernet_config *config); struct net_if *eth_stm32_get_iface(struct eth_stm32_hal_dev_data *ctx); @@ -158,7 +159,7 @@ void eth_stm32_mcast_filter(const struct device *dev, #endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */ #ifdef CONFIG_PTP_CLOCK_STM32_HAL -const struct device *eth_stm32_get_ptp_clock(const struct device *dev); +const struct device *eth_stm32_get_ptp_clock(const struct device *dev, struct net_if *iface); bool eth_stm32_is_ptp_pkt(struct net_if *iface, struct net_pkt *pkt); #endif /* CONFIG_PTP_CLOCK_STM32_HAL */ diff --git a/drivers/ethernet/eth_stm32_hal_ptp.c b/drivers/ethernet/eth_stm32_hal_ptp.c index 82e1df811cee..2386de8ef6f5 100644 --- a/drivers/ethernet/eth_stm32_hal_ptp.c +++ b/drivers/ethernet/eth_stm32_hal_ptp.c @@ -48,7 +48,8 @@ void HAL_ETH_TxPtpCallback(uint32_t *buff, ETH_TimeStampTypeDef *timestamp) net_if_add_tx_timestamp(ctx->pkt); } -const struct device *eth_stm32_get_ptp_clock(const struct device *dev) +const struct device *eth_stm32_get_ptp_clock(const struct device *dev, + struct net_if *iface __unused) { struct eth_stm32_hal_dev_data *dev_data = dev->data; diff --git a/drivers/ethernet/eth_stm32_hal_v1.c b/drivers/ethernet/eth_stm32_hal_v1.c index fbc4a401040d..a3c97aace6eb 100644 --- a/drivers/ethernet/eth_stm32_hal_v1.c +++ b/drivers/ethernet/eth_stm32_hal_v1.c @@ -217,7 +217,7 @@ void eth_stm32_set_mac_config(const struct device *dev, struct phy_link_state *s } } -int eth_stm32_hal_start(const struct device *dev) +int eth_stm32_hal_start(const struct device *dev, struct net_if *iface __unused) { struct eth_stm32_hal_dev_data *dev_data = dev->data; ETH_HandleTypeDef *heth = &dev_data->heth; @@ -234,7 +234,7 @@ int eth_stm32_hal_start(const struct device *dev) return 0; } -int eth_stm32_hal_stop(const struct device *dev) +int eth_stm32_hal_stop(const struct device *dev, struct net_if *iface __unused) { struct eth_stm32_hal_dev_data *dev_data = dev->data; ETH_HandleTypeDef *heth = &dev_data->heth; @@ -253,8 +253,9 @@ int eth_stm32_hal_stop(const struct device *dev) } int eth_stm32_hal_set_config(const struct device *dev, - enum ethernet_config_type type, - const struct ethernet_config *config) + struct net_if *iface __unused, + enum ethernet_config_type type, + const struct ethernet_config *config) { struct eth_stm32_hal_dev_data *dev_data = dev->data; ETH_HandleTypeDef *heth = &dev_data->heth; diff --git a/drivers/ethernet/eth_stm32_hal_v2.c b/drivers/ethernet/eth_stm32_hal_v2.c index 71211867e936..f06437b1ae2e 100644 --- a/drivers/ethernet/eth_stm32_hal_v2.c +++ b/drivers/ethernet/eth_stm32_hal_v2.c @@ -710,7 +710,7 @@ void eth_stm32_setup_mac_filter(ETH_HandleTypeDef *heth) k_sleep(K_MSEC(1)); } -int eth_stm32_hal_start(const struct device *dev) +int eth_stm32_hal_start(const struct device *dev, struct net_if *iface __unused) { struct eth_stm32_hal_dev_data *dev_data = dev->data; ETH_HandleTypeDef *heth = &dev_data->heth; @@ -727,7 +727,7 @@ int eth_stm32_hal_start(const struct device *dev) return 0; } -int eth_stm32_hal_stop(const struct device *dev) +int eth_stm32_hal_stop(const struct device *dev, struct net_if *iface __unused) { struct eth_stm32_hal_dev_data *dev_data = dev->data; ETH_HandleTypeDef *heth = &dev_data->heth; @@ -746,8 +746,9 @@ int eth_stm32_hal_stop(const struct device *dev) } int eth_stm32_hal_set_config(const struct device *dev, - enum ethernet_config_type type, - const struct ethernet_config *config) + struct net_if *iface __unused, + enum ethernet_config_type type, + const struct ethernet_config *config) { struct eth_stm32_hal_dev_data *dev_data = dev->data; ETH_HandleTypeDef *heth = &dev_data->heth; diff --git a/drivers/ethernet/eth_test.c b/drivers/ethernet/eth_test.c index 1854eb97c7e2..e0e42b1879fc 100644 --- a/drivers/ethernet/eth_test.c +++ b/drivers/ethernet/eth_test.c @@ -15,7 +15,8 @@ #define DT_DRV_COMPAT vnd_ethernet #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *vnd_ethernet_get_stats(const struct device *dev) +static struct net_stats_eth *vnd_ethernet_get_stats(const struct device *dev, + struct net_if *iface __unused) { ARG_UNUSED(dev); @@ -23,28 +24,31 @@ static struct net_stats_eth *vnd_ethernet_get_stats(const struct device *dev) } #endif -static int vnd_ethernet_start(const struct device *dev) +static int vnd_ethernet_start(const struct device *dev, struct net_if *iface __unused) { ARG_UNUSED(dev); return -ENOTSUP; } -static int vnd_ethernet_stop(const struct device *dev) +static int vnd_ethernet_stop(const struct device *dev, struct net_if *iface __unused) { ARG_UNUSED(dev); return -ENOTSUP; } -static enum ethernet_hw_caps vnd_ethernet_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps vnd_ethernet_get_capabilities(const struct device *dev, + struct net_if *iface __unused) { ARG_UNUSED(dev); return 0; } -static int vnd_ethernet_set_config(const struct device *dev, enum ethernet_config_type type, +static int vnd_ethernet_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { ARG_UNUSED(dev); @@ -54,7 +58,9 @@ static int vnd_ethernet_set_config(const struct device *dev, enum ethernet_confi return -ENOTSUP; } -static int vnd_ethernet_get_config(const struct device *dev, enum ethernet_config_type type, +static int vnd_ethernet_get_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, struct ethernet_config *config) { ARG_UNUSED(dev); @@ -79,7 +85,8 @@ static int vnd_ethernet_vlan_setup(const struct device *dev, struct net_if *ifac #endif /* CONFIG_NET_VLAN */ #if defined(CONFIG_PTP_CLOCK) -static const struct device *vnd_ethernet_get_ptp_clock(const struct device *dev) +static const struct device *vnd_ethernet_get_ptp_clock(const struct device *dev, + struct net_if *iface __unused) { ARG_UNUSED(dev); @@ -87,7 +94,8 @@ static const struct device *vnd_ethernet_get_ptp_clock(const struct device *dev) } #endif /* CONFIG_PTP_CLOCK */ -static const struct device *vnd_ethernet_get_phy(const struct device *dev) +static const struct device *vnd_ethernet_get_phy(const struct device *dev, + struct net_if *iface __unused) { ARG_UNUSED(dev); diff --git a/drivers/ethernet/eth_virtio_net.c b/drivers/ethernet/eth_virtio_net.c index b93ec100eb1c..14f3a4d2f2b2 100644 --- a/drivers/ethernet/eth_virtio_net.c +++ b/drivers/ethernet/eth_virtio_net.c @@ -123,7 +123,8 @@ static uint16_t virtnet_enum_queues_cb(uint16_t q_index, uint16_t q_size_max, vo } } -static enum ethernet_hw_caps virtnet_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps virtnet_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_LINK_1000BASE | ETHERNET_LINK_2500BASE | ETHERNET_LINK_5000BASE; diff --git a/drivers/ethernet/eth_w5500.c b/drivers/ethernet/eth_w5500.c index e405832721d7..aba50b21d2ae 100644 --- a/drivers/ethernet/eth_w5500.c +++ b/drivers/ethernet/eth_w5500.c @@ -393,10 +393,9 @@ static void w5500_iface_init(struct net_if *iface) k_thread_name_set(&ctx->thread, "eth_w5500"); } -static enum ethernet_hw_caps w5500_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps w5500_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE #if defined(CONFIG_NET_PROMISCUOUS_MODE) | ETHERNET_PROMISC_MODE @@ -405,6 +404,7 @@ static enum ethernet_hw_caps w5500_get_capabilities(const struct device *dev) } static int w5500_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -455,7 +455,7 @@ static int w5500_set_config(const struct device *dev, } } -static int w5500_hw_start(const struct device *dev) +static int w5500_hw_start(const struct device *dev, struct net_if *iface __unused) { uint8_t mode = S0_MR_MACRAW | BIT(W5500_S0_MR_MF); uint8_t mask = IR_S0; @@ -470,7 +470,7 @@ static int w5500_hw_start(const struct device *dev) return 0; } -static int w5500_hw_stop(const struct device *dev) +static int w5500_hw_stop(const struct device *dev, struct net_if *iface __unused) { uint8_t mask = 0; @@ -481,7 +481,7 @@ static int w5500_hw_stop(const struct device *dev) return 0; } -static const struct device *w5500_get_phy(const struct device *dev) +static const struct device *w5500_get_phy(const struct device *dev, struct net_if *iface __unused) { const struct w5500_config *config = dev->config; diff --git a/drivers/ethernet/eth_w6100.c b/drivers/ethernet/eth_w6100.c index b5e6f27eb72e..54ec1a06e1f5 100644 --- a/drivers/ethernet/eth_w6100.c +++ b/drivers/ethernet/eth_w6100.c @@ -374,10 +374,9 @@ static void w6100_iface_init(struct net_if *iface) k_thread_name_set(&ctx->thread, "eth_w6100"); } -static enum ethernet_hw_caps w6100_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps w6100_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_HW_FILTERING #if defined(CONFIG_NET_PROMISCUOUS_MODE) | ETHERNET_PROMISC_MODE @@ -386,6 +385,7 @@ static enum ethernet_hw_caps w6100_get_capabilities(const struct device *dev) } static int w6100_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -441,7 +441,7 @@ static int w6100_set_config(const struct device *dev, } } -static int w6100_hw_start(const struct device *dev) +static int w6100_hw_start(const struct device *dev, struct net_if *iface __unused) { uint8_t mode = S0_MR_MACRAW | BIT(W6100_S0_MR_MF); uint8_t mask = IR_S0; @@ -455,7 +455,7 @@ static int w6100_hw_start(const struct device *dev) return 0; } -static int w6100_hw_stop(const struct device *dev) +static int w6100_hw_stop(const struct device *dev, struct net_if *iface __unused) { uint8_t mask = 0; @@ -466,7 +466,7 @@ static int w6100_hw_stop(const struct device *dev) return 0; } -static const struct device *w6100_get_phy(const struct device *dev) +static const struct device *w6100_get_phy(const struct device *dev, struct net_if *iface __unused) { const struct w6100_config *config = dev->config; diff --git a/drivers/ethernet/eth_wch.c b/drivers/ethernet/eth_wch.c index 48da259d927f..b10b966431c6 100644 --- a/drivers/ethernet/eth_wch.c +++ b/drivers/ethernet/eth_wch.c @@ -397,7 +397,7 @@ static void eth_isr(const struct device *dev) } } -static int eth_wch_start(const struct device *dev) +static int eth_wch_start(const struct device *dev, struct net_if *iface __unused) { const struct eth_wch_config *config = dev->config; ETH_TypeDef *eth = config->regs; @@ -410,7 +410,7 @@ static int eth_wch_start(const struct device *dev) return 0; } -static int eth_wch_stop(const struct device *dev) +static int eth_wch_stop(const struct device *dev, struct net_if *iface __unused) { const struct eth_wch_config *config = dev->config; ETH_TypeDef *eth = config->regs; @@ -553,10 +553,9 @@ static void eth_wch_iface_init(struct net_if *iface) } } -static enum ethernet_hw_caps eth_wch_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_wch_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE #if defined(CONFIG_ETH_WCH_HW_CHECKSUM) | ETHERNET_HW_RX_CHKSUM_OFFLOAD @@ -576,7 +575,9 @@ static enum ethernet_hw_caps eth_wch_get_capabilities(const struct device *dev) ; } -static int eth_wch_set_config(const struct device *dev, enum ethernet_config_type type, +static int eth_wch_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct eth_wch_data *data = dev->data; @@ -609,7 +610,7 @@ static int eth_wch_set_config(const struct device *dev, enum ethernet_config_typ return -ENOTSUP; } -static const struct device *eth_wch_get_phy(const struct device *dev) +static const struct device *eth_wch_get_phy(const struct device *dev, struct net_if *iface __unused) { const struct eth_wch_config *config = dev->config; @@ -617,7 +618,8 @@ static const struct device *eth_wch_get_phy(const struct device *dev) } #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *eth_wch_get_stats(const struct device *dev) +static struct net_stats_eth *eth_wch_get_stats(const struct device *dev, + struct net_if *iface __unused) { struct eth_wch_data *data = dev->data; diff --git a/drivers/ethernet/eth_xilinx_axi_ethernet_lite.c b/drivers/ethernet/eth_xilinx_axi_ethernet_lite.c index 11d9013960ab..292319a256d6 100644 --- a/drivers/ethernet/eth_xilinx_axi_ethernet_lite.c +++ b/drivers/ethernet/eth_xilinx_axi_ethernet_lite.c @@ -156,14 +156,16 @@ static inline void axi_eth_lite_program_mac_address(const struct axi_eth_lite_co axi_eth_lite_wait_complete(config); } -static const struct device *axi_eth_lite_get_phy(const struct device *dev) +static const struct device *axi_eth_lite_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct axi_eth_lite_config *config = dev->config; return config->phy; } -static enum ethernet_hw_caps axi_eth_lite_get_caps(const struct device *dev) +static enum ethernet_hw_caps axi_eth_lite_get_caps(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE; } @@ -229,7 +231,9 @@ static void axi_eth_lite_iface_init(struct net_if *iface) LOG_DBG("Interface initialized!"); } -static int axi_eth_lite_set_config(const struct device *dev, enum ethernet_config_type type, +static int axi_eth_lite_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct axi_eth_lite_data *data = dev->data; diff --git a/drivers/ethernet/eth_xilinx_axienet.c b/drivers/ethernet/eth_xilinx_axienet.c index a3fd1c3d2d53..b41bece85110 100644 --- a/drivers/ethernet/eth_xilinx_axienet.c +++ b/drivers/ethernet/eth_xilinx_axienet.c @@ -362,7 +362,8 @@ static void xilinx_axienet_isr(const struct device *dev) } } -static enum ethernet_hw_caps xilinx_axienet_caps(const struct device *dev) +static enum ethernet_hw_caps xilinx_axienet_caps(const struct device *dev, + struct net_if *iface __unused) { const struct xilinx_axienet_config *config = dev->config; enum ethernet_hw_caps ret = ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | @@ -378,14 +379,17 @@ static enum ethernet_hw_caps xilinx_axienet_caps(const struct device *dev) return ret; } -static const struct device *xilinx_axienet_get_phy(const struct device *dev) +static const struct device *xilinx_axienet_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct xilinx_axienet_config *config = dev->config; return config->phy; } -static int xilinx_axienet_get_config(const struct device *dev, enum ethernet_config_type type, +static int xilinx_axienet_get_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, struct ethernet_config *config) { const struct xilinx_axienet_config *dev_config = dev->config; @@ -430,7 +434,9 @@ static void xilinx_axienet_set_mac_address(const struct xilinx_axienet_config *c (data->mac_addr[4]) | (data->mac_addr[5] << 8)); } -static int xilinx_axienet_set_config(const struct device *dev, enum ethernet_config_type type, +static int xilinx_axienet_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { const struct xilinx_axienet_config *dev_config = dev->config; @@ -544,6 +550,61 @@ static int xilinx_axienet_probe(const struct device *dev) xilinx_axienet_set_mac_address(config, data); + config->config_func(data); + + return 0; +} + +static int xilinx_axienet_stop(const struct device *dev, struct net_if *iface __unused) +{ + const struct xilinx_axienet_config *config = dev->config; + struct xilinx_axienet_data *data = dev->data; + uint32_t status; + int err; + + /* Disable AXIENET RX */ + status = xilinx_axienet_read_register( + config, XILINX_AXIENET_RECEIVER_CONFIGURATION_WORD_1_REG_OFFSET); + status &= ~XILINX_AXIENET_RECEIVER_CONFIGURATION_WORD_1_REG_RX_EN_MASK; + xilinx_axienet_write_register( + config, XILINX_AXIENET_RECEIVER_CONFIGURATION_WORD_1_REG_OFFSET, status); + + /* Stop the RX DMA channel */ + err = dma_stop(config->dma, XILINX_AXI_DMA_RX_CHANNEL_NUM); + if (err) { + LOG_ERR("%s: failed to stop RX DMA: %d", dev->name, err); + } + + /* Stop the TX DMA channel */ + err = dma_stop(config->dma, XILINX_AXI_DMA_TX_CHANNEL_NUM); + if (err) { + LOG_ERR("%s: failed to stop TX DMA: %d", dev->name, err); + } + + /* Disable AXIENET TX */ + status = xilinx_axienet_read_register(config, XILINX_AXIENET_TX_CONTROL_REG_OFFSET); + status &= ~XILINX_AXIENET_TX_CONTROL_TX_EN_MASK; + xilinx_axienet_write_register(config, XILINX_AXIENET_TX_CONTROL_REG_OFFSET, status); + + data->dma_is_configured_rx = false; + data->dma_is_configured_tx = false; + data->rx_populated_buffer_index = 0; + data->rx_completed_buffer_index = 0; + data->tx_populated_buffer_index = 0; + data->tx_completed_buffer_index = 0; + + LOG_INF("%s: AxiEnet stopped", dev->name); + return 0; +} + +static int xilinx_axienet_start(const struct device *dev, struct net_if *iface __unused) +{ + const struct xilinx_axienet_config *config = dev->config; + struct xilinx_axienet_data *data = dev->data; + uint32_t status; + int err; + + for (int i = 0; i < CONFIG_ETH_XILINX_AXIENET_BUFFER_NUM_RX - 1; i++) { setup_dma_rx_transfer(dev, config, data); } diff --git a/drivers/ethernet/eth_xlnx_gem.c b/drivers/ethernet/eth_xlnx_gem.c index 135b6825c2ac..f126a02960f9 100644 --- a/drivers/ethernet/eth_xlnx_gem.c +++ b/drivers/ethernet/eth_xlnx_gem.c @@ -43,18 +43,21 @@ static int eth_xlnx_gem_dev_init(const struct device *dev); static void eth_xlnx_gem_iface_init(struct net_if *iface); static void eth_xlnx_gem_isr(const struct device *dev); static int eth_xlnx_gem_send(const struct device *dev, struct net_pkt *pkt); -static int eth_xlnx_gem_start_device(const struct device *dev); -static int eth_xlnx_gem_stop_device(const struct device *dev); +static int eth_xlnx_gem_start_device(const struct device *dev, struct net_if *iface); +static int eth_xlnx_gem_stop_device(const struct device *dev, struct net_if *iface); static enum ethernet_hw_caps - eth_xlnx_gem_get_capabilities(const struct device *dev); + eth_xlnx_gem_get_capabilities(const struct device *dev, struct net_if *iface); static int eth_xlnx_gem_get_config(const struct device *dev, + struct net_if *iface, enum ethernet_config_type type, struct ethernet_config *config); static int eth_xlnx_gem_set_config(const struct device *dev, + struct net_if *iface, enum ethernet_config_type type, const struct ethernet_config *config); #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *eth_xlnx_gem_stats(const struct device *dev); +static struct net_stats_eth *eth_xlnx_gem_stats(const struct device *dev, + struct net_if *iface); #endif static void eth_xlnx_gem_reset_hw(const struct device *dev); @@ -630,7 +633,8 @@ static int eth_xlnx_gem_stop_device(const struct device *dev) * @return Enumeration containing the current GEM device's capabilities */ static enum ethernet_hw_caps eth_xlnx_gem_get_capabilities( - const struct device *dev) + const struct device *dev, + struct net_if *iface __unused) { const struct eth_xlnx_gem_dev_cfg *dev_conf = dev->config; enum ethernet_hw_caps caps = (enum ethernet_hw_caps)0; @@ -686,6 +690,7 @@ static enum ethernet_hw_caps eth_xlnx_gem_get_capabilities( * is not supported by this function. */ static int eth_xlnx_gem_get_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, struct ethernet_config *config) { @@ -734,6 +739,7 @@ static int eth_xlnx_gem_get_config(const struct device *dev, * is not supported by this function. */ static int eth_xlnx_gem_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -772,7 +778,8 @@ static int eth_xlnx_gem_set_config(const struct device *dev, * @param dev Pointer to the device data * @return Pointer to the current GEM device's statistics data */ -static struct net_stats_eth *eth_xlnx_gem_stats(const struct device *dev) +static struct net_stats_eth *eth_xlnx_gem_stats(const struct device *dev, + struct net_if *iface __unused) { struct eth_xlnx_gem_dev_data *dev_data = dev->data; diff --git a/drivers/ethernet/eth_xmc4xxx.c b/drivers/ethernet/eth_xmc4xxx.c index 718183ff8443..8009691d859a 100644 --- a/drivers/ethernet/eth_xmc4xxx.c +++ b/drivers/ethernet/eth_xmc4xxx.c @@ -855,7 +855,8 @@ static void phy_link_state_changed(const struct device *phy_dev, struct phy_link } } -static const struct device *eth_xmc4xxx_get_phy(const struct device *dev) +static const struct device *eth_xmc4xxx_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct eth_xmc4xxx_config *dev_cfg = dev->config; @@ -889,7 +890,8 @@ static void eth_xmc4xxx_iface_init(struct net_if *iface) } #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *eth_xmc4xxx_stats(const struct device *dev) +static struct net_stats_eth *eth_xmc4xxx_stats(const struct device *dev, + struct net_if *iface __unused) { struct eth_xmc4xxx_data *dev_data = dev->data; @@ -1107,7 +1109,8 @@ static int eth_xmc4xxx_init(const struct device *dev) return 0; } -static enum ethernet_hw_caps eth_xmc4xxx_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_xmc4xxx_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { ARG_UNUSED(dev); enum ethernet_hw_caps caps = ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | @@ -1128,7 +1131,9 @@ static enum ethernet_hw_caps eth_xmc4xxx_capabilities(const struct device *dev) return caps; } -static int eth_xmc4xxx_set_config(const struct device *dev, enum ethernet_config_type type, +static int eth_xmc4xxx_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct eth_xmc4xxx_data *dev_data = dev->data; @@ -1172,7 +1177,8 @@ static void eth_xmc4xxx_irq_config(void) } #if defined(CONFIG_PTP_CLOCK_XMC4XXX) -static const struct device *eth_xmc4xxx_get_ptp_clock(const struct device *dev) +static const struct device *eth_xmc4xxx_get_ptp_clock(const struct device *dev, + struct net_if *iface __unused) { const struct eth_xmc4xxx_config *dev_cfg = dev->config; diff --git a/drivers/ethernet/intel/eth_intel_igc.c b/drivers/ethernet/intel/eth_intel_igc.c index 4a71dae75b54..ece8082b1a20 100644 --- a/drivers/ethernet/intel/eth_intel_igc.c +++ b/drivers/ethernet/intel/eth_intel_igc.c @@ -472,14 +472,17 @@ static void eth_intel_igc_iface_init(struct net_if *iface) eth_intel_igc_intr_enable(dev); } -static enum ethernet_hw_caps eth_intel_igc_get_caps(const struct device *dev) +static enum ethernet_hw_caps eth_intel_igc_get_caps(const struct device *dev, + struct net_if *iface __unused) { ARG_UNUSED(dev); return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_LINK_1000BASE; } -static int eth_intel_igc_set_config(const struct device *dev, enum ethernet_config_type type, +static int eth_intel_igc_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *eth_cfg) { struct eth_intel_igc_mac_data *data = dev->data; @@ -493,7 +496,8 @@ static int eth_intel_igc_set_config(const struct device *dev, enum ethernet_conf return -ENOTSUP; } -static const struct device *eth_intel_igc_get_phy(const struct device *dev) +static const struct device *eth_intel_igc_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct eth_intel_igc_mac_cfg *cfg = dev->config; @@ -501,7 +505,8 @@ static const struct device *eth_intel_igc_get_phy(const struct device *dev) } #if defined(CONFIG_NET_STATISTICS_ETHERNET) -static struct net_stats_eth *eth_intel_igc_get_stats(const struct device *dev) +static struct net_stats_eth *eth_intel_igc_get_stats(const struct device *dev, + struct net_if *iface __unused) { struct eth_intel_igc_mac_data *data = dev->data; const struct eth_intel_igc_mac_cfg *cfg = dev->config; diff --git a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc.c b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc.c index d0f7ec786272..5a05501d5348 100644 --- a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc.c +++ b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc.c @@ -56,7 +56,7 @@ static void netc_eth_pkt_get_timestamp(struct net_pkt *pkt, const struct device pkt->timestamp.second = time_ns / NSEC_PER_SEC; } -const struct device *netc_eth_get_ptp_clock(const struct device *dev) +const struct device *netc_eth_get_ptp_clock(const struct device *dev, struct net_if *iface __unused) { const struct netc_eth_config *cfg = dev->config; @@ -184,7 +184,7 @@ static int netc_eth_rx(const struct device *dev) #ifdef NETC_PTP_TIMESTAMPING_SUPPORT if (attr.isTsAvail) { - const struct device *ptp_dev = netc_eth_get_ptp_clock(dev); + const struct device *ptp_dev = netc_eth_get_ptp_clock(dev, data->iface); #if defined(NETC_SWITCH_NO_TAG_DRIVER_SUPPORT) if (ctx->dsa_port == DSA_CONDUIT_PORT) { @@ -481,7 +481,7 @@ int netc_eth_tx(const struct device *dev, struct net_pkt *pkt) #ifdef NETC_PTP_TIMESTAMPING_SUPPORT pkt_is_gptp = net_ntohs(NET_ETH_HDR(pkt)->type) == NET_ETH_PTYPE_PTP; if ((pkt_is_gptp || net_pkt_is_tx_timestamping(pkt)) && - (netc_eth_get_ptp_clock(dev) != NULL)) { + (netc_eth_get_ptp_clock(dev, data->iface) != NULL)) { opt.flags |= kEP_TX_OPT_REQ_TS; } #endif @@ -564,7 +564,8 @@ int netc_eth_tx(const struct device *dev, struct net_pkt *pkt) return ret; } -enum ethernet_hw_caps netc_eth_get_capabilities(const struct device *dev) +enum ethernet_hw_caps netc_eth_get_capabilities(const struct device *dev __maybe_unused, + struct net_if *iface __maybe_unused) { uint32_t caps; @@ -579,15 +580,15 @@ enum ethernet_hw_caps netc_eth_get_capabilities(const struct device *dev) ); #if defined(NETC_PTP_TIMESTAMPING_SUPPORT) - if (netc_eth_get_ptp_clock(dev) != NULL) { + if (netc_eth_get_ptp_clock(dev, iface) != NULL) { caps |= ETHERNET_PTP; } #endif return caps; } -int netc_eth_set_config(const struct device *dev, enum ethernet_config_type type, - const struct ethernet_config *config) +int netc_eth_set_config(const struct device *dev, struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct netc_eth_data *data = dev->data; const struct netc_eth_config *cfg = dev->config; diff --git a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_priv.h b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_priv.h index c58ae57f0ef3..72669346a048 100644 --- a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_priv.h +++ b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_priv.h @@ -136,10 +136,10 @@ struct netc_eth_data { int netc_eth_init_common(const struct device *dev); int netc_eth_tx(const struct device *dev, struct net_pkt *pkt); -enum ethernet_hw_caps netc_eth_get_capabilities(const struct device *dev); -int netc_eth_set_config(const struct device *dev, enum ethernet_config_type type, - const struct ethernet_config *config); +enum ethernet_hw_caps netc_eth_get_capabilities(const struct device *dev, struct net_if *iface); +int netc_eth_set_config(const struct device *dev, struct net_if *iface, + enum ethernet_config_type type, const struct ethernet_config *config); #ifdef NETC_PTP_TIMESTAMPING_SUPPORT -const struct device *netc_eth_get_ptp_clock(const struct device *dev); +const struct device *netc_eth_get_ptp_clock(const struct device *dev, struct net_if *iface); #endif #endif /* ZEPHYR_DRIVERS_ETHERNET_ETH_NXP_IMX_NETC_PRIV_H_ */ diff --git a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_psi.c b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_psi.c index 4f26deb52e34..9fea495929c2 100644 --- a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_psi.c +++ b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_psi.c @@ -116,7 +116,8 @@ static int netc_eth_init(const struct device *dev) return netc_eth_init_common(dev); } -static const struct device *netc_eth_get_phy(const struct device *dev) +static const struct device *netc_eth_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct netc_eth_config *cfg = dev->config; diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index d96c3bfd85db..80cfc4abfcfa 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -1076,7 +1076,9 @@ static int esp32_wifi_dev_init(const struct device *dev) return 0; } -static int esp32_wifi_set_config(const struct device *dev, enum ethernet_config_type type, +static int esp32_wifi_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct esp32_wifi_runtime *dev_data = dev->data; diff --git a/drivers/wifi/infineon/airoc_wifi.c b/drivers/wifi/infineon/airoc_wifi.c index 0ae92330a5f9..8437a160d9c5 100644 --- a/drivers/wifi/infineon/airoc_wifi.c +++ b/drivers/wifi/infineon/airoc_wifi.c @@ -445,18 +445,17 @@ static void airoc_wifi_network_process_ethernet_data(whd_interface_t interface, } } -static enum ethernet_hw_caps airoc_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps airoc_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_HW_FILTERING; } -static int airoc_set_config(const struct device *dev, +static int airoc_set_config(const struct device *dev __unused, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { - ARG_UNUSED(dev); whd_mac_t whd_mac_addr; switch (type) { diff --git a/drivers/wifi/nrf_wifi/inc/net_if.h b/drivers/wifi/nrf_wifi/inc/net_if.h index b6c48e00598d..aa078e95c2ff 100644 --- a/drivers/wifi/nrf_wifi/inc/net_if.h +++ b/drivers/wifi/nrf_wifi/inc/net_if.h @@ -23,19 +23,21 @@ void nrf_wifi_if_init_zep(struct net_if *iface); -int nrf_wifi_if_start_zep(const struct device *dev); +int nrf_wifi_if_start_zep(const struct device *dev, struct net_if *iface); -int nrf_wifi_if_stop_zep(const struct device *dev); +int nrf_wifi_if_stop_zep(const struct device *dev, struct net_if *iface); int nrf_wifi_if_set_config_zep(const struct device *dev, + struct net_if *iface, enum ethernet_config_type type, const struct ethernet_config *config); int nrf_wifi_if_get_config_zep(const struct device *dev, + struct net_if *iface, enum ethernet_config_type type, struct ethernet_config *config); -enum ethernet_hw_caps nrf_wifi_if_caps_get(const struct device *dev); +enum ethernet_hw_caps nrf_wifi_if_caps_get(const struct device *dev, struct net_if *iface); int nrf_wifi_if_send(const struct device *dev, struct net_pkt *pkt); diff --git a/drivers/wifi/nrf_wifi/src/net_if.c b/drivers/wifi/nrf_wifi/src/net_if.c index f6482a8e06f5..7c1f6b53ef0c 100644 --- a/drivers/wifi/nrf_wifi/src/net_if.c +++ b/drivers/wifi/nrf_wifi/src/net_if.c @@ -951,7 +951,7 @@ int nrf_wifi_if_start_zep(const struct device *dev) } -int nrf_wifi_if_stop_zep(const struct device *dev) +int nrf_wifi_if_stop_zep(const struct device *dev, struct net_if *iface __unused) { enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; @@ -1040,6 +1040,7 @@ int nrf_wifi_if_stop_zep(const struct device *dev) } int nrf_wifi_if_get_config_zep(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, struct ethernet_config *config) { @@ -1114,6 +1115,7 @@ int nrf_wifi_if_get_config_zep(const struct device *dev, } int nrf_wifi_if_set_config_zep(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -1242,6 +1244,7 @@ int nrf_wifi_if_set_config_zep(const struct device *dev, #ifdef CONFIG_NET_STATISTICS_ETHERNET struct net_stats_eth *nrf_wifi_eth_stats_get_type(const struct device *dev, + struct net_if *iface __unused, uint32_t type) { struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; diff --git a/drivers/wifi/nxp/nxp_wifi_drv.c b/drivers/wifi/nxp/nxp_wifi_drv.c index 1bf68f6ae89c..3cb02ca60f3a 100644 --- a/drivers/wifi/nxp/nxp_wifi_drv.c +++ b/drivers/wifi/nxp/nxp_wifi_drv.c @@ -2179,7 +2179,9 @@ static int nxp_wifi_dev_init(const struct device *dev) return 0; } -static int nxp_wifi_set_config(const struct device *dev, enum ethernet_config_type type, +static int nxp_wifi_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct interface *if_handle = (struct interface *)dev->data; @@ -2212,6 +2214,7 @@ static int nxp_wifi_set_config(const struct device *dev, enum ethernet_config_ty } static int nxp_wifi_get_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, struct ethernet_config *config) { diff --git a/drivers/wifi/siwx91x/siwx91x_wifi.c b/drivers/wifi/siwx91x/siwx91x_wifi.c index 1b5a9c00004c..a2683b4f1a23 100644 --- a/drivers/wifi/siwx91x/siwx91x_wifi.c +++ b/drivers/wifi/siwx91x/siwx91x_wifi.c @@ -305,14 +305,14 @@ sl_status_t sl_si91x_host_process_data_frame(sl_wifi_interface_t interface, return SL_STATUS_FAIL; } -static enum ethernet_hw_caps siwx91x_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps siwx91x_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_HW_FILTERING; } static int siwx91x_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index 2833bbb0c488..0c508e4fd49f 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -547,7 +547,7 @@ struct ethernet_api { * for that driver. */ #if defined(CONFIG_NET_STATISTICS_ETHERNET) - struct net_stats_eth *(*get_stats)(const struct device *dev); + struct net_stats_eth *(*get_stats)(const struct device *dev, struct net_if *iface); /** Optional function to collect ethernet specific statistics with * type filter. If NULL, get_stats() will be called instead, which @@ -555,25 +555,28 @@ struct ethernet_api { * @param type Bitmask of ethernet_stats_type values. */ struct net_stats_eth *(*get_stats_type)(const struct device *dev, + struct net_if *iface, uint32_t type); #endif /** Start the device */ - int (*start)(const struct device *dev); + int (*start)(const struct device *dev, struct net_if *iface); /** Stop the device */ - int (*stop)(const struct device *dev); + int (*stop)(const struct device *dev, struct net_if *iface); /** Get the device capabilities */ - enum ethernet_hw_caps (*get_capabilities)(const struct device *dev); + enum ethernet_hw_caps (*get_capabilities)(const struct device *dev, struct net_if *iface); /** Set specific hardware configuration */ int (*set_config)(const struct device *dev, + struct net_if *iface, enum ethernet_config_type type, const struct ethernet_config *config); /** Get hardware specific configuration */ int (*get_config)(const struct device *dev, + struct net_if *iface, enum ethernet_config_type type, struct ethernet_config *config); @@ -589,11 +592,11 @@ struct ethernet_api { /** Return ptp_clock device that is tied to this ethernet device */ #if defined(CONFIG_PTP_CLOCK) - const struct device *(*get_ptp_clock)(const struct device *dev); + const struct device *(*get_ptp_clock)(const struct device *dev, struct net_if *iface); #endif /* CONFIG_PTP_CLOCK */ /** Return PHY device that is tied to this ethernet device */ - const struct device *(*get_phy)(const struct device *dev); + const struct device *(*get_phy)(const struct device *dev, struct net_if *iface); /** Send a network packet */ int (*send)(const struct device *dev, struct net_pkt *pkt); @@ -929,7 +932,7 @@ enum ethernet_hw_caps net_eth_get_hw_capabilities(struct net_if *iface) return caps; } - return (enum ethernet_hw_caps)(caps | api->get_capabilities(dev)); + return (enum ethernet_hw_caps)(caps | api->get_capabilities(dev, iface)); } /** @@ -952,7 +955,7 @@ int net_eth_get_hw_config(struct net_if *iface, enum ethernet_config_type type, return -ENOTSUP; } - return eth->get_config(dev, type, config); + return eth->get_config(dev, iface, type, config); } diff --git a/subsys/net/l2/ethernet/dsa/dsa_port.c b/subsys/net/l2/ethernet/dsa/dsa_port.c index 234671006e09..45852e255499 100644 --- a/subsys/net/l2/ethernet/dsa/dsa_port.c +++ b/subsys/net/l2/ethernet/dsa/dsa_port.c @@ -118,7 +118,8 @@ static void dsa_port_iface_init(struct net_if *iface) phy_link_callback_set(cfg->phy_dev, dsa_switch_ctx->dapi->port_phylink_change, (void *)dev); } -static const struct device *dsa_port_get_phy(const struct device *dev) +static const struct device *dsa_port_get_phy(const struct device *dev, + struct net_if *iface __unused) { const struct dsa_port_config *cfg = dev->config; @@ -126,7 +127,8 @@ static const struct device *dsa_port_get_phy(const struct device *dev) } #ifdef CONFIG_NET_L2_PTP -const struct device *dsa_port_get_ptp_clock(const struct device *dev) +const struct device *dsa_port_get_ptp_clock(const struct device *dev, + struct net_if *iface __unused) { const struct dsa_port_config *cfg = dev->config; @@ -134,13 +136,14 @@ const struct device *dsa_port_get_ptp_clock(const struct device *dev) } #endif -enum ethernet_hw_caps dsa_port_get_capabilities(const struct device *dev) +enum ethernet_hw_caps dsa_port_get_capabilities(const struct device *dev, + struct net_if *iface __maybe_unused) { struct dsa_switch_context *dsa_switch_ctx = dev->data; uint32_t caps = 0; #ifdef CONFIG_NET_L2_PTP - if (dsa_port_get_ptp_clock(dev) != NULL) { + if (dsa_port_get_ptp_clock(dev, iface) != NULL) { caps |= ETHERNET_PTP; } #endif @@ -152,7 +155,9 @@ enum ethernet_hw_caps dsa_port_get_capabilities(const struct device *dev) return caps; } -static int dsa_set_config(const struct device *dev, enum ethernet_config_type type, +static int dsa_set_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, const struct ethernet_config *config) { struct dsa_switch_context *dsa_switch_ctx = dev->data; @@ -164,7 +169,9 @@ static int dsa_set_config(const struct device *dev, enum ethernet_config_type ty return dsa_switch_ctx->dapi->set_config(dev, type, config); } -static int dsa_get_config(const struct device *dev, enum ethernet_config_type type, +static int dsa_get_config(const struct device *dev, + struct net_if *iface __unused, + enum ethernet_config_type type, struct ethernet_config *config) { struct dsa_switch_context *dsa_switch_ctx = dev->data; diff --git a/subsys/net/l2/ethernet/eth_stats.h b/subsys/net/l2/ethernet/eth_stats.h index 837cdebb9d2a..0a2b5ef57643 100644 --- a/subsys/net/l2/ethernet/eth_stats.h +++ b/subsys/net/l2/ethernet/eth_stats.h @@ -20,11 +20,11 @@ static inline struct net_stats_eth *eth_stats_get_common(struct net_if *iface) const struct ethernet_api *api = dev->api; if (api->get_stats_type != NULL) { - return api->get_stats_type(dev, ETHERNET_STATS_TYPE_COMMON); + return api->get_stats_type(dev, iface, ETHERNET_STATS_TYPE_COMMON); } if (api->get_stats != NULL) { - return api->get_stats(dev); + return api->get_stats(dev, iface); } return NULL; diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c index 9e82bacb9f28..fd0e5366a19f 100644 --- a/subsys/net/l2/ethernet/ethernet.c +++ b/subsys/net/l2/ethernet/ethernet.c @@ -251,7 +251,7 @@ static void ethernet_mcast_monitor_cb(struct net_if *iface, const struct net_add return; } - api->set_config(dev, ETHERNET_CONFIG_TYPE_FILTER, &cfg); + api->set_config(dev, iface, ETHERNET_CONFIG_TYPE_FILTER, &cfg); } #endif @@ -822,11 +822,11 @@ static inline int ethernet_enable(struct net_if *iface, bool state) net_arp_clear_cache(iface); if (eth->stop) { - return eth->stop(dev); + return eth->stop(dev, iface); } } else { if (eth->start) { - return eth->start(dev); + return eth->start(dev, iface); } } @@ -928,7 +928,7 @@ const struct device *net_eth_get_phy(struct net_if *iface) return NULL; } - return api->get_phy(dev); + return api->get_phy(dev, iface); } #if defined(CONFIG_PTP_CLOCK) @@ -953,7 +953,7 @@ const struct device *net_eth_get_ptp_clock(struct net_if *iface) return NULL; } - return api->get_ptp_clock(dev); + return api->get_ptp_clock(dev, iface); } #endif /* CONFIG_PTP_CLOCK */ diff --git a/subsys/net/l2/ethernet/ethernet_mgmt.c b/subsys/net/l2/ethernet/ethernet_mgmt.c index 7da7b9aa1d34..25ad751fdf0b 100644 --- a/subsys/net/l2/ethernet/ethernet_mgmt.c +++ b/subsys/net/l2/ethernet/ethernet_mgmt.c @@ -14,15 +14,16 @@ LOG_MODULE_REGISTER(net_ethernet_mgmt, CONFIG_NET_L2_ETHERNET_LOG_LEVEL); #include static inline bool is_hw_caps_supported(const struct device *dev, + struct net_if *iface, enum ethernet_hw_caps caps) { const struct ethernet_api *api = dev->api; - if (!api || !api->get_capabilities) { + if (!api->get_capabilities) { return false; } - return ((api->get_capabilities(dev) & caps) != 0); + return ((api->get_capabilities(dev, iface) & caps) != 0); } static int ethernet_set_config(uint64_t mgmt_request, @@ -74,7 +75,7 @@ static int ethernet_set_config(uint64_t mgmt_request, sizeof(struct net_eth_addr)); type = ETHERNET_CONFIG_TYPE_MAC_ADDRESS; - ret = api->set_config(dev, type, &config); + ret = api->set_config(dev, iface, type, &config); if (ret < 0) { return ret; } @@ -84,7 +85,7 @@ static int ethernet_set_config(uint64_t mgmt_request, } if (mgmt_request == NET_REQUEST_ETHERNET_SET_QAV_PARAM) { - if (!is_hw_caps_supported(dev, ETHERNET_QAV)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_QAV)) { return -ENOTSUP; } @@ -108,7 +109,7 @@ static int ethernet_set_config(uint64_t mgmt_request, sizeof(struct ethernet_qav_param)); type = ETHERNET_CONFIG_TYPE_QAV_PARAM; } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_QBV_PARAM) { - if (!is_hw_caps_supported(dev, ETHERNET_QBV)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_QBV)) { return -ENOTSUP; } @@ -128,7 +129,7 @@ static int ethernet_set_config(uint64_t mgmt_request, sizeof(struct ethernet_qbv_param)); type = ETHERNET_CONFIG_TYPE_QBV_PARAM; } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_QBU_PARAM) { - if (!is_hw_caps_supported(dev, ETHERNET_QBU)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_QBU)) { return -ENOTSUP; } @@ -144,7 +145,7 @@ static int ethernet_set_config(uint64_t mgmt_request, sizeof(struct ethernet_qbu_param)); type = ETHERNET_CONFIG_TYPE_QBU_PARAM; } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_TXTIME_PARAM) { - if (!is_hw_caps_supported(dev, ETHERNET_TXTIME)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_TXTIME)) { return -ENOTSUP; } @@ -156,7 +157,7 @@ static int ethernet_set_config(uint64_t mgmt_request, sizeof(struct ethernet_txtime_param)); type = ETHERNET_CONFIG_TYPE_TXTIME_PARAM; } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_PROMISC_MODE) { - if (!is_hw_caps_supported(dev, ETHERNET_PROMISC_MODE)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_PROMISC_MODE)) { return -ENOTSUP; } @@ -171,14 +172,14 @@ static int ethernet_set_config(uint64_t mgmt_request, sizeof(struct ethernet_t1s_param)); type = ETHERNET_CONFIG_TYPE_T1S_PARAM; } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE) { - if (!is_hw_caps_supported(dev, ETHERNET_TXINJECTION_MODE)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_TXINJECTION_MODE)) { return -ENOTSUP; } config.txinjection_mode = params->txinjection_mode; type = ETHERNET_CONFIG_TYPE_TXINJECTION_MODE; } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_MAC_FILTER) { - if (!is_hw_caps_supported(dev, ETHERNET_HW_FILTERING)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_HW_FILTERING)) { return -ENOTSUP; } @@ -188,7 +189,7 @@ static int ethernet_set_config(uint64_t mgmt_request, return -EINVAL; } - return api->set_config(dev, type, &config); + return api->set_config(dev, iface, type, &config); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_MAC_ADDRESS, @@ -242,20 +243,20 @@ static int ethernet_get_config(uint64_t mgmt_request, } if (mgmt_request == NET_REQUEST_ETHERNET_GET_PRIORITY_QUEUES_NUM) { - if (!is_hw_caps_supported(dev, ETHERNET_PRIORITY_QUEUES)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_PRIORITY_QUEUES)) { return -ENOTSUP; } type = ETHERNET_CONFIG_TYPE_PRIORITY_QUEUES_NUM; - ret = api->get_config(dev, type, &config); + ret = api->get_config(dev, iface, type, &config); if (ret) { return ret; } params->priority_queues_num = config.priority_queues_num; } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_QAV_PARAM) { - if (!is_hw_caps_supported(dev, ETHERNET_QAV)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_QAV)) { return -ENOTSUP; } @@ -264,7 +265,7 @@ static int ethernet_get_config(uint64_t mgmt_request, type = ETHERNET_CONFIG_TYPE_QAV_PARAM; - ret = api->get_config(dev, type, &config); + ret = api->get_config(dev, iface, type, &config); if (ret) { return ret; } @@ -294,7 +295,7 @@ static int ethernet_get_config(uint64_t mgmt_request, } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_PORTS_NUM) { type = ETHERNET_CONFIG_TYPE_PORTS_NUM; - ret = api->get_config(dev, type, &config); + ret = api->get_config(dev, iface, type, &config); if (ret) { return ret; } @@ -302,7 +303,7 @@ static int ethernet_get_config(uint64_t mgmt_request, params->ports_num = config.ports_num; } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_QBV_PARAM) { - if (!is_hw_caps_supported(dev, ETHERNET_QBV)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_QBV)) { return -ENOTSUP; } @@ -318,7 +319,7 @@ static int ethernet_get_config(uint64_t mgmt_request, type = ETHERNET_CONFIG_TYPE_QBV_PARAM; - ret = api->get_config(dev, type, &config); + ret = api->get_config(dev, iface, type, &config); if (ret) { return ret; } @@ -349,7 +350,7 @@ static int ethernet_get_config(uint64_t mgmt_request, } } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_QBU_PARAM) { - if (!is_hw_caps_supported(dev, ETHERNET_QBU)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_QBU)) { return -ENOTSUP; } @@ -358,7 +359,7 @@ static int ethernet_get_config(uint64_t mgmt_request, type = ETHERNET_CONFIG_TYPE_QBU_PARAM; - ret = api->get_config(dev, type, &config); + ret = api->get_config(dev, iface, type, &config); if (ret) { return ret; } @@ -391,7 +392,7 @@ static int ethernet_get_config(uint64_t mgmt_request, } } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_TXTIME_PARAM) { - if (!is_hw_caps_supported(dev, ETHERNET_TXTIME)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_TXTIME)) { return -ENOTSUP; } @@ -400,7 +401,7 @@ static int ethernet_get_config(uint64_t mgmt_request, type = ETHERNET_CONFIG_TYPE_TXTIME_PARAM; - ret = api->get_config(dev, type, &config); + ret = api->get_config(dev, iface, type, &config); if (ret) { return ret; } @@ -412,13 +413,13 @@ static int ethernet_get_config(uint64_t mgmt_request, break; } } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE) { - if (!is_hw_caps_supported(dev, ETHERNET_TXINJECTION_MODE)) { + if (!is_hw_caps_supported(dev, iface, ETHERNET_TXINJECTION_MODE)) { return -ENOTSUP; } type = ETHERNET_CONFIG_TYPE_TXINJECTION_MODE; - ret = api->get_config(dev, type, &config); + ret = api->get_config(dev, iface, type, &config); if (ret) { return ret; } diff --git a/subsys/net/l2/ethernet/ethernet_stats.c b/subsys/net/l2/ethernet/ethernet_stats.c index 3dd211e4cf7d..140ff51d0fd5 100644 --- a/subsys/net/l2/ethernet/ethernet_stats.c +++ b/subsys/net/l2/ethernet/ethernet_stats.c @@ -22,6 +22,7 @@ static int eth_stats_get(uint64_t mgmt_request, struct net_if *iface, { size_t len_chk = 0; void *src = NULL; + const struct device *dev = net_if_get_device(iface); const struct ethernet_api *eth; switch (NET_MGMT_GET_COMMAND(mgmt_request)) { @@ -30,7 +31,7 @@ static int eth_stats_get(uint64_t mgmt_request, struct net_if *iface, return -ENOENT; } - eth = net_if_get_device(iface)->api; + eth = dev->api; if (eth == NULL || (eth->get_stats == NULL && eth->get_stats_type == NULL)) { return -ENOENT; @@ -38,10 +39,9 @@ static int eth_stats_get(uint64_t mgmt_request, struct net_if *iface, len_chk = sizeof(struct net_stats_eth); if (eth->get_stats_type != NULL) { - src = eth->get_stats_type(net_if_get_device(iface), - ETHERNET_STATS_TYPE_ALL); + src = eth->get_stats_type(dev, iface, ETHERNET_STATS_TYPE_ALL); } else { - src = eth->get_stats(net_if_get_device(iface)); + src = eth->get_stats(dev, iface); } break; } diff --git a/subsys/net/lib/shell/stats.c b/subsys/net/lib/shell/stats.c index 06aa1c4ffa95..72ba258d3ae2 100644 --- a/subsys/net/lib/shell/stats.c +++ b/subsys/net/lib/shell/stats.c @@ -638,7 +638,8 @@ static void net_shell_print_statistics(struct net_if *iface, void *user_data) #if defined(CONFIG_NET_STATISTICS_ETHERNET) && \ defined(CONFIG_NET_STATISTICS_USER_API) if (iface && net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) { - const struct ethernet_api *eth_api; + const struct device *dev = net_if_get_device(iface); + const struct ethernet_api *eth_api = dev->api; struct net_stats_eth *eth_data = NULL; uint32_t type = ETHERNET_STATS_TYPE_ALL; @@ -648,15 +649,14 @@ static void net_shell_print_statistics(struct net_if *iface, void *user_data) type = opts->type; } - eth_api = net_if_get_device(iface)->api; if (eth_api != NULL) { /* Use get_stats_type if available for type filtering */ if (eth_api->get_stats_type != NULL) { eth_data = eth_api->get_stats_type( - net_if_get_device(iface), type); + dev, iface, type); } else if (eth_api->get_stats != NULL) { eth_data = eth_api->get_stats( - net_if_get_device(iface)); + dev, iface); } } diff --git a/subsys/usb/device_next/class/usbd_cdc_ecm.c b/subsys/usb/device_next/class/usbd_cdc_ecm.c index 8193896b2df4..2c477e75b9d7 100644 --- a/subsys/usb/device_next/class/usbd_cdc_ecm.c +++ b/subsys/usb/device_next/class/usbd_cdc_ecm.c @@ -543,6 +543,7 @@ static int cdc_ecm_send(const struct device *dev, struct net_pkt *const pkt) } static int cdc_ecm_set_config(const struct device *dev, + struct net_if *iface __unused, const enum ethernet_config_type type, const struct ethernet_config *config) { @@ -561,23 +562,22 @@ static int cdc_ecm_set_config(const struct device *dev, } } -static enum ethernet_hw_caps cdc_ecm_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps cdc_ecm_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE | ETHERNET_PROMISC_MODE; } -static int cdc_ecm_iface_start(const struct device *dev) +static int cdc_ecm_iface_start(const struct device *dev, struct net_if *iface) { struct cdc_ecm_eth_data *data = dev->data; - LOG_DBG("Start interface %p", data->iface); + LOG_DBG("Start interface %p", iface); atomic_set_bit(&data->state, CDC_ECM_IFACE_UP); if (atomic_test_bit(&data->state, CDC_ECM_DATA_IFACE_ENABLED)) { - net_if_carrier_on(data->iface); + net_if_carrier_on(iface); if (cdc_ecm_send_notification(dev, true)) { LOG_ERR("Failed to send connected notification"); } @@ -586,11 +586,11 @@ static int cdc_ecm_iface_start(const struct device *dev) return 0; } -static int cdc_ecm_iface_stop(const struct device *dev) +static int cdc_ecm_iface_stop(const struct device *dev, struct net_if *iface) { struct cdc_ecm_eth_data *data = dev->data; - LOG_DBG("Stop interface %p", data->iface); + LOG_DBG("Stop interface %p", iface); atomic_clear_bit(&data->state, CDC_ECM_IFACE_UP); diff --git a/subsys/usb/device_next/class/usbd_cdc_ncm.c b/subsys/usb/device_next/class/usbd_cdc_ncm.c index 7bd04a42b068..19f966fb009b 100644 --- a/subsys/usb/device_next/class/usbd_cdc_ncm.c +++ b/subsys/usb/device_next/class/usbd_cdc_ncm.c @@ -1094,6 +1094,7 @@ static int cdc_ncm_send(const struct device *dev, struct net_pkt *const pkt) } static int cdc_ncm_set_config(const struct device *dev, + struct net_if *iface __unused, const enum ethernet_config_type type, const struct ethernet_config *config) { @@ -1112,21 +1113,22 @@ static int cdc_ncm_set_config(const struct device *dev, } } -static enum ethernet_hw_caps cdc_ncm_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps cdc_ncm_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { ARG_UNUSED(dev); return ETHERNET_LINK_10BASE | ETHERNET_PROMISC_MODE; } -static int cdc_ncm_iface_start(const struct device *dev) +static int cdc_ncm_iface_start(const struct device *dev, struct net_if *iface) { struct cdc_ncm_eth_data *data = dev->data; - LOG_DBG("Start interface %d", net_if_get_by_iface(data->iface)); + LOG_DBG("Start interface %d", net_if_get_by_iface(iface)); atomic_set_bit(&data->state, CDC_NCM_IFACE_UP); - net_if_carrier_on(data->iface); + net_if_carrier_on(iface); if (atomic_test_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED)) { (void)k_work_reschedule(&data->notif_work, K_MSEC(1)); @@ -1135,11 +1137,11 @@ static int cdc_ncm_iface_start(const struct device *dev) return 0; } -static int cdc_ncm_iface_stop(const struct device *dev) +static int cdc_ncm_iface_stop(const struct device *dev, struct net_if *iface) { struct cdc_ncm_eth_data *data = dev->data; - LOG_DBG("Stop interface %d", net_if_get_by_iface(data->iface)); + LOG_DBG("Stop interface %d", net_if_get_by_iface(iface)); atomic_clear_bit(&data->state, CDC_NCM_IFACE_UP); diff --git a/tests/net/bridge/src/main.c b/tests/net/bridge/src/main.c index 7e6ab43c58e0..e5c9ef85fbd0 100644 --- a/tests/net/bridge/src/main.c +++ b/tests/net/bridge/src/main.c @@ -92,12 +92,14 @@ static int eth_fake_send(const struct device *dev, return 0; } -static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev, + struct net_if *iface __unused) { return ETHERNET_PROMISC_MODE; } static int eth_fake_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { diff --git a/tests/net/checksum_offload/src/main.c b/tests/net/checksum_offload/src/main.c index 0bf1ca0996a0..43db3bac8d6b 100644 --- a/tests/net/checksum_offload/src/main.c +++ b/tests/net/checksum_offload/src/main.c @@ -413,13 +413,15 @@ static int eth_tx_offloading_enabled(const struct device *dev, return 0; } -static enum ethernet_hw_caps eth_offloading_enabled(const struct device *dev) +static enum ethernet_hw_caps eth_offloading_enabled(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_HW_TX_CHKSUM_OFFLOAD | ETHERNET_HW_RX_CHKSUM_OFFLOAD; } -static enum ethernet_hw_caps eth_offloading_disabled(const struct device *dev) +static enum ethernet_hw_caps eth_offloading_disabled(const struct device *dev __unused, + struct net_if *iface __unused) { return 0; } diff --git a/tests/net/ethernet_mgmt/src/main.c b/tests/net/ethernet_mgmt/src/main.c index b49659954798..db9996315b69 100644 --- a/tests/net/ethernet_mgmt/src/main.c +++ b/tests/net/ethernet_mgmt/src/main.c @@ -95,7 +95,8 @@ static int eth_fake_send(const struct device *dev, return 0; } -static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_QAV | ETHERNET_PROMISC_MODE | ETHERNET_PRIORITY_QUEUES | @@ -140,6 +141,7 @@ static void eth_fake_recalc_qav_idle_slopes(struct eth_fake_context *ctx) } static int eth_fake_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -297,6 +299,7 @@ static int eth_fake_set_config(const struct device *dev, } static int eth_fake_get_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, struct ethernet_config *config) { diff --git a/tests/net/iface/src/main.c b/tests/net/iface/src/main.c index f9278b571779..e00c14c95535 100644 --- a/tests/net/iface/src/main.c +++ b/tests/net/iface/src/main.c @@ -228,12 +228,14 @@ static int eth_fake_send(const struct device *dev, return 0; } -static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_PROMISC_MODE; } static int eth_fake_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { diff --git a/tests/net/promiscuous/src/main.c b/tests/net/promiscuous/src/main.c index ccf76404b437..8f97aa7d3cf7 100644 --- a/tests/net/promiscuous/src/main.c +++ b/tests/net/promiscuous/src/main.c @@ -97,12 +97,14 @@ static int eth_fake_send(const struct device *dev, return 0; } -static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_PROMISC_MODE; } static int eth_fake_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { diff --git a/tests/net/ptp/clock/src/main.c b/tests/net/ptp/clock/src/main.c index f036e42759a0..bf1ef26ebf38 100644 --- a/tests/net/ptp/clock/src/main.c +++ b/tests/net/ptp/clock/src/main.c @@ -119,12 +119,14 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) return 0; } -static enum ethernet_hw_caps eth_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_PTP; } -static const struct device *eth_get_ptp_clock(const struct device *dev) +static const struct device *eth_get_ptp_clock(const struct device *dev, + struct net_if *iface __unused) { struct eth_context *context = dev->data; diff --git a/tests/net/socket/net_mgmt/src/main.c b/tests/net/socket/net_mgmt/src/main.c index aaf00aa4a900..914d007e1d90 100644 --- a/tests/net/socket/net_mgmt/src/main.c +++ b/tests/net/socket/net_mgmt/src/main.c @@ -124,6 +124,7 @@ static void eth_fake_recalc_qav_idle_slopes(struct eth_fake_context *ctx) } static int eth_fake_set_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, const struct ethernet_config *config) { @@ -171,6 +172,7 @@ static int eth_fake_set_config(const struct device *dev, } static int eth_fake_get_config(const struct device *dev, + struct net_if *iface __unused, enum ethernet_config_type type, struct ethernet_config *config) { @@ -220,9 +222,9 @@ static int eth_fake_get_config(const struct device *dev, return 0; } -static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { - ARG_UNUSED(dev); return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_QAV | ETHERNET_PROMISC_MODE | ETHERNET_PRIORITY_QUEUES; } diff --git a/tests/net/tx_timestamp/src/main.c b/tests/net/tx_timestamp/src/main.c index 3fe5700f0745..907610bc3010 100644 --- a/tests/net/tx_timestamp/src/main.c +++ b/tests/net/tx_timestamp/src/main.c @@ -121,7 +121,8 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) return 0; } -static enum ethernet_hw_caps eth_get_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_get_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return 0; } diff --git a/tests/net/virtual/src/main.c b/tests/net/virtual/src/main.c index 113fcaa0cfec..df4a23fb81ef 100644 --- a/tests/net/virtual/src/main.c +++ b/tests/net/virtual/src/main.c @@ -155,7 +155,8 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) return 0; } -static enum ethernet_hw_caps eth_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return 0; } diff --git a/tests/net/vlan/src/main.c b/tests/net/vlan/src/main.c index b0cd1ec21c84..5b7d8925e8e9 100644 --- a/tests/net/vlan/src/main.c +++ b/tests/net/vlan/src/main.c @@ -235,7 +235,8 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) return ret; } -static enum ethernet_hw_caps eth_vlan_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_vlan_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_HW_VLAN; } @@ -300,7 +301,8 @@ static int eth_tx_embed_ll_hdr(const struct device *dev, struct net_pkt *pkt) return 0; } -static enum ethernet_hw_caps eth_vlan_embed_ll_hdr_capabilities(const struct device *dev) +static enum ethernet_hw_caps eth_vlan_embed_ll_hdr_capabilities(const struct device *dev __unused, + struct net_if *iface __unused) { return ETHERNET_HW_VLAN; } From 54d0e9ba300664b8db4e12abc51ad1a0f08234c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Wed, 25 Mar 2026 23:11:05 +0100 Subject: [PATCH 10/18] UPSTREAM: net: net_if: add helper macros to add ifaces to a dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit bb2ac26fddfa3ef60f82054893a7585339039a9f upstream. add helper macros to add more than one iface to a device. Signed-off-by: Fin Maaß Signed-off-by: Siddharth Vadapalli --- include/zephyr/net/net_if.h | 71 +++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 4578ccb9446b..23c19c5a23f2 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -3551,6 +3551,11 @@ extern int net_stats_prometheus_scrape(struct prometheus_collector *collector, #define NET_IF_DECLARE(dev_id, inst) \ static struct net_if NET_IF_GET_NAME(dev_id, inst)[NET_IF_MAX_CONFIGS] +#define Z_NET_DEVICE_IF_INIT_INSTANCE(dev_id, instance, l2, \ + l2_ctx_type, mtu) \ + NET_L2_DATA_INIT(dev_id, instance, l2_ctx_type); \ + NET_IF_INIT(dev_id, instance, l2, mtu, NET_IF_MAX_CONFIGS) + #define Z_NET_DEVICE_INIT_INSTANCE(node_id, dev_id, name, instance, \ init_fn, pm, data, config, prio, \ api, l2, l2_ctx_type, mtu) \ @@ -3559,8 +3564,8 @@ extern int net_stats_prometheus_scrape(struct prometheus_collector *collector, Z_DEVICE_DT_FLAGS(node_id), pm, data, \ config, POST_KERNEL, prio, api, \ &Z_DEVICE_STATE_NAME(dev_id)); \ - NET_L2_DATA_INIT(dev_id, instance, l2_ctx_type); \ - NET_IF_INIT(dev_id, instance, l2, mtu, NET_IF_MAX_CONFIGS) + Z_NET_DEVICE_IF_INIT_INSTANCE(dev_id, instance, l2, \ + l2_ctx_type, mtu) #define Z_NET_DEVICE_INIT(node_id, dev_id, name, init_fn, pm, data, \ config, prio, api, l2, l2_ctx_type, mtu) \ @@ -3568,6 +3573,43 @@ extern int net_stats_prometheus_scrape(struct prometheus_collector *collector, pm, data, config, prio, api, l2, \ l2_ctx_type, mtu) +/** + * @brief Forward declaration of a network interface + * + * @param node_id Device node identifier + * @param instance Instance identifier + */ +#define NET_IF_DT_DECLARE(node_id, instance) \ + NET_IF_DECLARE(Z_DEVICE_DT_DEV_ID(node_id), instance) + +/** + * @brief Forward declaration of a network interface + * + * @param inst instance number. This is replaced by + * DT_DRV_COMPAT(inst) in the call to NET_DEVICE_DT_ADD_IFACE. + * @param ... other parameters as expected by NET_DEVICE_DT_ADD_IFACE. + */ +#define NET_IF_DT_INST_DECLARE(inst, ...) NET_IF_DT_DECLARE(DT_DRV_INST(inst), __VA_ARGS__) + +/** + * @brief Get a network interface that was created with NET_DEVICE_DT_DEFINE or + * NET_DEVICE_DT_ADD_IFACE. + * + * @param node_id Device node identifier + * @param instance Instance identifier + */ +#define NET_IF_DT_GET(node_id, instance) NET_IF_GET(Z_DEVICE_DT_DEV_ID(node_id), instance) + +/** + * @brief Get a network interface that was created with NET_DEVICE_DT_DEFINE or + * NET_DEVICE_DT_ADD_IFACE. + * + * @param inst instance number. This is replaced by + * DT_DRV_COMPAT(inst) in the call to NET_IF_DT_GET. + * @param ... other parameters as expected by NET_DEVICE_DT_ADD_IFACE. + */ +#define NET_IF_DT_INST_GET(inst, ...) NET_IF_DT_GET(DT_DRV_INST(inst), __VA_ARGS__) + /** * @brief Create a network interface and bind it to network device. * @@ -3592,6 +3634,31 @@ extern int net_stats_prometheus_scrape(struct prometheus_collector *collector, Z_NET_DEVICE_INIT(DT_INVALID_NODE, dev_id, name, init_fn, pm, \ data, config, prio, api, l2, l2_ctx_type, mtu) +/** + * @brief Adds a second (or more) network interface(s) to a network device created with + * NET_DEVICE_DT_DEFINE. + * + * @param node_id The devicetree node identifier. + * @param l2 Network L2 layer for this network interface. + * @param l2_ctx_type Type of L2 context data. + * @param mtu Maximum transfer unit in bytes for this network interface. + * @param instance Instance identifier (0 is reserved for the first interface, created with + * NET_DEVICE_DT_DEFINE, start from 1 for additional interfaces). + */ +#define NET_DEVICE_DT_ADD_IFACE(node_id, l2, l2_ctx_type, mtu, instance) \ + Z_NET_DEVICE_IF_INIT_INSTANCE(Z_DEVICE_DT_DEV_ID(node_id), instance, l2, l2_ctx_type, mtu) + +/** + * @brief Like NET_DEVICE_DT_ADD_IFACE for an instance of a DT_DRV_COMPAT compatible + * + * @param inst instance number. This is replaced by + * DT_DRV_COMPAT(inst) in the call to NET_DEVICE_DT_ADD_IFACE. + * + * @param ... other parameters as expected by NET_DEVICE_DT_ADD_IFACE. + */ +#define NET_DEVICE_DT_INST_ADD_IFACE(inst, ...) \ + NET_DEVICE_DT_ADD_IFACE(DT_DRV_INST(inst), __VA_ARGS__) + /** * @brief Like NET_DEVICE_INIT but taking metadata from a devicetree node. * Create a network interface and bind it to network device. From 3bc7e94459d2391ada33927cc6341e827778c032 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Thu, 14 May 2026 11:00:32 +0530 Subject: [PATCH 11/18] UPSTREAM-PEND: dts: bindings: dma: introduce AM62L PKTDMA (Packet DMA) PR: 122457 The Texas Instruments AM62L SoC [0] includes the Packet DMA Controller which is a packet-oriented DMA Engine. PKTDMA can perform data movement operations between memory and PSI-L (Packet Streaming Interface Link) peripherals. Add the bindings for PKTDMA. [0]: https://www.ti.com/product/AM62L Signed-off-by: Siddharth Vadapalli --- dts/bindings/dma/ti,am62l-pktdma.yaml | 58 +++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 dts/bindings/dma/ti,am62l-pktdma.yaml diff --git a/dts/bindings/dma/ti,am62l-pktdma.yaml b/dts/bindings/dma/ti,am62l-pktdma.yaml new file mode 100644 index 000000000000..67cc8e754df3 --- /dev/null +++ b/dts/bindings/dma/ti,am62l-pktdma.yaml @@ -0,0 +1,58 @@ +# Copyright (c) 2026 Texas Instruments Incorporated +# Author: Siddharth Vadapalli +# SPDX-License-Identifier: Apache-2.0 + +description: TI AM62L PKTDMA (Packet DMA) + +compatible: "ti,am62l-pktdma" + +include: [dma-controller.yaml, interrupt-nexus.yaml] + +properties: + reg: + required: true + description: | + Global Configuration Registers region + Realtime Channel Configuration Registers region + Realtime Ring Configuration Registers region + + reg-names: + required: true + description: | + Register names "gcfg", "chanrt" and "ringrt" corresponding to + the Global Configuration Registers region, the Realtime Channel + Configuration Registers region and the Realtime Ring Configuration + Registers region respectively. + + power-domains: + required: true + + "#address-cells": + required: true + const: 0 + + "#dma-cells": + required: true + const: 2 + + "#interrupt-cells": + required: true + const: 1 + + interrupt-map: + required: true + description: | + Mapping of PKTDMA Channel IDs to GIC interrupt numbers. + Each entry has 7 cells: + 1. channel_id + 2. gic_phandle + 3. gic_addr + 4. gic_irq_type (SPI/PPI) + 5. gic_irq_number + 6. gic_irq_flags + 7. gic_irq_priority + +# Parameter syntax +dma-cells: + - channel_id + - asel From ace9a2b2e28985117ea00dc7c55fadb8dfd3b3b3 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Sun, 17 May 2026 17:54:30 +0530 Subject: [PATCH 12/18] UPSTREAM-PEND: soc: ti: am62l: introduce AM62L PKTDMA (Packet DMA) driver PR: 122457 The Texas Instruments AM62L SoC [0] includes the Packet DMA Controller which is a packet-oriented DMA Engine. PKTDMA can perform data movement operations between memory and PSI-L (Packet Streaming Interface Link) peripherals. Since the PKTDMA Hardware supports additional vendor-specific features, an SoC-specific driver is required. Add the PKTDMA driver to enable DMA functionality on the AM62L SoC. [0]: https://www.ti.com/product/AM62L Signed-off-by: Siddharth Vadapalli --- soc/ti/k3/CMakeLists.txt | 4 + soc/ti/k3/am62lx/CMakeLists.txt | 5 + soc/ti/k3/am62lx/Kconfig | 2 + soc/ti/k3/am62lx/dma/CMakeLists.txt | 4 + soc/ti/k3/am62lx/dma/Kconfig | 13 + soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.c | 627 +++++++++++++++++++++ soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.h | 53 ++ 7 files changed, 708 insertions(+) create mode 100644 soc/ti/k3/am62lx/CMakeLists.txt create mode 100644 soc/ti/k3/am62lx/dma/CMakeLists.txt create mode 100644 soc/ti/k3/am62lx/dma/Kconfig create mode 100644 soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.c create mode 100644 soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.h diff --git a/soc/ti/k3/CMakeLists.txt b/soc/ti/k3/CMakeLists.txt index 92e71a11d6e6..db8da32b404e 100644 --- a/soc/ti/k3/CMakeLists.txt +++ b/soc/ti/k3/CMakeLists.txt @@ -248,3 +248,7 @@ if(CONFIG_SOC_FAMILY_TI_K3_BUILD_TISPL) endif() add_subdirectory(./common) + +if(CONFIG_SOC_SERIES_AM62LX) + add_subdirectory(am62lx) +endif() diff --git a/soc/ti/k3/am62lx/CMakeLists.txt b/soc/ti/k3/am62lx/CMakeLists.txt new file mode 100644 index 000000000000..a0b0a5dcb131 --- /dev/null +++ b/soc/ti/k3/am62lx/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2026 Texas Instruments Incorporated +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(dma) +add_subdirectory(dma) diff --git a/soc/ti/k3/am62lx/Kconfig b/soc/ti/k3/am62lx/Kconfig index 05ce23f9bb34..cb422e7867f8 100644 --- a/soc/ti/k3/am62lx/Kconfig +++ b/soc/ti/k3/am62lx/Kconfig @@ -2,6 +2,8 @@ # Copyright (c) 2026 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 +rsource "dma/Kconfig" + config SOC_SERIES_AM62LX_A53 select ARM64 select CPU_CORTEX_A53 diff --git a/soc/ti/k3/am62lx/dma/CMakeLists.txt b/soc/ti/k3/am62lx/dma/CMakeLists.txt new file mode 100644 index 000000000000..31eecbea3f20 --- /dev/null +++ b/soc/ti/k3/am62lx/dma/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2026 Texas Instruments Incorporated +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_DMA_TI_AM62L_PKTDMA dma_ti_am62l_pktdma.c) diff --git a/soc/ti/k3/am62lx/dma/Kconfig b/soc/ti/k3/am62lx/dma/Kconfig new file mode 100644 index 000000000000..4365b2e594c3 --- /dev/null +++ b/soc/ti/k3/am62lx/dma/Kconfig @@ -0,0 +1,13 @@ +# TI AM62L PKTDMA driver configuration + +# Copyright (c) 2026 Texas Instruments Incorporated +# SPDX-License-Identifier: Apache-2.0 + +config DMA_TI_AM62L_PKTDMA + bool "TI AM62L PKTDMA (Packet DMA) driver" + default y + depends on DMA && DT_HAS_TI_AM62L_PKTDMA_ENABLED + select DMA_64BIT + help + Enable the TI AM62L Packet DMA functionality for PSI-L + peripherals in the AM62L SoC. diff --git a/soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.c b/soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.c new file mode 100644 index 000000000000..6f37b56629aa --- /dev/null +++ b/soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.c @@ -0,0 +1,627 @@ +/* TI AM62L PKTDMA (Packet DMA) driver + * + * Copyright (c) 2026 Texas Instruments Incorporated + * Author: Siddharth Vadapalli + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_am62l_pktdma + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dma_ti_am62l_pktdma.h" + +LOG_MODULE_REGISTER(dma_ti_am62l_pktdma, CONFIG_DMA_LOG_LEVEL); + +/* Channel realtime (chanrt) register region */ +#define PKTDMA_CHANRT_CTL 0x0U +#define PKTDMA_CHANRT_CTL_EN BIT(31) +#define PKTDMA_CHANRT_CTL_TDOWN BIT(30) +#define PKTDMA_CHANRT_CTL_AUTOPAIR BIT(23) +#define PKTDMA_CHANRT_CTL_PAIR_TIMEOUT BIT(17) +#define PKTDMA_CHANRT_CTL_PAIR_COMPLETE BIT(16) +#define PKTDMA_CHANRT_TCFG 0x04U +#define PKTDMA_CHANRT_TCQ 0x18U + +/* Bits 16 to 19 of CHANRT TCFG register correspond to Channel Type */ +#define PKTDMA_CHAN_TYPE_MASK GENMASK(19, 16) +/* Channel Type set to 2 for Packet Oriented data transfers */ +#define PKTDMA_CHAN_TYPE_PACKET FIELD_PREP(PKTDMA_CHAN_TYPE_MASK, 2U) + +/* Step size for successive channel register sets */ +#define PKTDMA_CHANRT_STEP 0x1000U + +/* Ring realtime (ringrt) register region */ +#define RINGACC_RING_RT_DB 0x10U +#define RINGACC_RING_RT_OCC 0x18U + +/* Step size for successive ring-pair realtime register sets (forward + reverse) */ +#define RINGACC_RING_RT_STEP 0x2000U + +/* Offset of reverse ring RT base from forward ring RT base */ +#define RINGACC_REVERSE_OFS 0x1000U + +/* Offset of ring interrupt register space offset from ring RT base */ +#define RINGACC_RT_INT_CLR_OFS 0x008U +#define RINGACC_RT_INT_STATUS_SET_OFS 0x010U +#define RINGACC_RT_INT_STATUS_OFS 0x018U +#define RINGACC_RT_INT_OFS 0x140U +#define RINGACC_RT_INT_ENABLE_COMPLETE BIT(0) +#define RINGACC_RT_INT_ENABLE_TR BIT(2) +#define RINGACC_RT_INT_ENABLE_COMPLETE_TR \ + (RINGACC_RT_INT_ENABLE_COMPLETE | RINGACC_RT_INT_ENABLE_TR) + +/* Ring cfg register region */ +#define RINGACC_CFG_BA_LO 0x40U +#define RINGACC_CFG_BA_HI 0x44U +#define RINGACC_CFG_SIZE 0x48U + +/* + * BA_LO register layout: + * bits 31:0 - addr[31:0] of ring memory physical address + */ +#define RINGACC_CFG_BA_LO_ADDR_MASK GENMASK(31, 0) + +/* + * BA_HI register layout: + * bits 3:0 - addr[35:32] (upper 4 bits of ring memory physical address) + * bits 19:16 - ASEL (address-space select for RINGACC ring-memory access) + */ +#define RINGACC_CFG_BA_HI_ADDR_MASK GENMASK(3, 0) +#define RINGACC_CFG_BA_HI_ASEL_MASK GENMASK(19, 16) + +/* + * Layout of the CFG_SIZE register: + * bits 26:24 - Ring Element Size + * bits 15:0 - Number of elements + */ +#define RINGACC_CFG_SIZE_VAL(esize, cnt) \ + (FIELD_PREP(GENMASK(26, 24), (uint32_t)(esize)) | \ + ((uint32_t)(cnt) & GENMASK(15, 0))) + +/* Ring element size of 8 Bytes to be programmed into the CFG_SIZE register */ +#define RINGACC_SIZE_ELM_8BYTE 1U + +/* PKTDMA flow RT register region */ +#define PKTDMA_RX_FLOWRT_RFA 0x8U +#define PKTDMA_RFLOW_RFA_EINFO BIT(30) +#define PKTDMA_RFLOW_RFA_PSINFO BIT(29) + +/* Maximum hardware channel index supported by this driver */ +#define PKTDMA_MAX_CHANS 128U + +/* Maximum number of retries for waiting until autopair completes */ +#define PKTDMA_CHANRT_PAIR_RETRIES 5U +/* Busy wait duration before rechecking if autopair has completed */ +#define PKTDMA_AUTOPAIR_BUSY_WAIT_US 100U + +/* Maximum number of retries for waiting until channel teardown completes */ +#define PKTDMA_CHANRT_TDOWN_RETRIES 5U +/* Busy wait duration before rechecking if channel teardown has completed */ +#define PKTDMA_TDOWN_BUSY_WAIT_US 100U + +/* MMIO Helpers */ +#define DEV_CFG(dev) ((const struct pktdma_config *)(dev)->config) +#define DEV_DATA(dev) ((struct pktdma_data *)(dev)->data) + +/** + * @brief Per-channel realtime state maintained by the PKTDMA driver. + */ +struct pktdma_chan { + const struct device *dev; /* used for DMA Callback */ + const void *cb_user_data; /* user data passed to callback */ + dma_callback_t callback; /* cmpl callback registered via dma_config() */ + uintptr_t fwd_rt; /* Virtual Address of forward ring RT registers */ + uintptr_t rev_rt; /* Virtual Address of reverse ring RT registers */ + uintptr_t chanrt; /* Virtual Address of channel RT registers */ + uint64_t *fwd_mem; /* caller-owned forward ring buffer */ + uint64_t *rev_mem; /* caller-owned reverse ring buffer */ + uint32_t ring_cnt; /* number of entries in each ring */ + uint32_t fwd_widx; /* next write index into fwd_mem */ + uint32_t rev_ridx; /* next read index into rev_mem */ + uint32_t chan_id; /* channel number passed to DMA Callback */ + unsigned int irq; /* GIC INTID used for irq_enable/irq_disable */ + uint8_t asel; /* address-space 0=non-coherent, 14/15=coherent */ + bool is_rx; /* true = RX channel, false = TX channel */ + bool configured; /* true when pktdma_start() succeeds */ +}; + +/* + * Use the interrupt-map property in the device-tree to generate a map of + * channel numbers to their interrupt numbers + * + * DT_N_{path}_P_interrupt_map_MAP_ENTRY_{N}_CHILD_SPECIFIER_IDX_0 - channel id + * DT_N_{path}_P_interrupt_map_MAP_ENTRY_{N}_PARENT_SPECIFIER_IDX_0 - GIC type (0=SPI) + * DT_N_{path}_P_interrupt_map_MAP_ENTRY_{N}_PARENT_SPECIFIER_IDX_1 - GIC SPI/PPI number + * DT_N_{path}_P_interrupt_map_LEN - number of entries + * + * ARM GIC INTID = gic-irq + 32 for SPI, + 16 for PPI. + * + * Although all PKTDMA Channel interrupts in the AM62L SoC are GIC_SPI, + * for the sake of completeness, the handling for GIC_PPI is also included. + */ +#define GIC_SPI_INTID_BASE 32U +#define GIC_PPI_INTID_BASE 16U + +#define _PKTDMA_IMAP_CHAN_INNER(node_id, N) \ + node_id##_P_interrupt_map_MAP_ENTRY_##N##_CHILD_SPECIFIER_IDX_0 +#define _PKTDMA_IMAP_TYPE_INNER(node_id, N) \ + node_id##_P_interrupt_map_MAP_ENTRY_##N##_PARENT_SPECIFIER_IDX_0 +#define _PKTDMA_IMAP_IRQ_INNER(node_id, N) \ + node_id##_P_interrupt_map_MAP_ENTRY_##N##_PARENT_SPECIFIER_IDX_1 + +#define _PKTDMA_IMAP_CHAN(node_id, N) _PKTDMA_IMAP_CHAN_INNER(node_id, N) +#define _PKTDMA_IMAP_TYPE(node_id, N) _PKTDMA_IMAP_TYPE_INNER(node_id, N) +#define _PKTDMA_IMAP_IRQ(node_id, N) _PKTDMA_IMAP_IRQ_INNER(node_id, N) + +#define _PKTDMA_IRQMAP_ENTRY(i, node_id) \ + { \ + .chan_id = _PKTDMA_IMAP_CHAN(node_id, i), \ + .irq = (unsigned int)( \ + (_PKTDMA_IMAP_TYPE(node_id, i) == 0U) \ + ? _PKTDMA_IMAP_IRQ(node_id, i) + GIC_SPI_INTID_BASE \ + : _PKTDMA_IMAP_IRQ(node_id, i) + GIC_PPI_INTID_BASE) \ + } + +struct pktdma_irq_entry { + uint32_t chan_id; + unsigned int irq; +}; + +/** + * @brief PKTDMA configuration fetched from device-tree + */ +struct pktdma_config { + DEVICE_MMIO_NAMED_ROM(gcfg); + DEVICE_MMIO_NAMED_ROM(chanrt); + DEVICE_MMIO_NAMED_ROM(ringrt); + const struct pktdma_irq_entry *irq_table; + size_t irq_table_len; +}; + +/** + * @brief Driver data containing the realtime state of all PKTDMA channels + */ +struct pktdma_data { + DEVICE_MMIO_NAMED_RAM(gcfg); + DEVICE_MMIO_NAMED_RAM(chanrt); + DEVICE_MMIO_NAMED_RAM(ringrt); + struct pktdma_chan chans[PKTDMA_MAX_CHANS]; +}; + +/** + * @brief Per-channel ISR: clear ring interrupt, disable IRQ, fire callback. + * + * @param arg Pointer to the pktdma_chan for the completed channel. + */ +static void pktdma_chan_isr(const void *arg) +{ + const struct pktdma_chan *ch_ro = (const struct pktdma_chan *)arg; + struct pktdma_data *data = ch_ro->dev->data; + struct pktdma_chan *ch = &data->chans[ch_ro->chan_id]; + uint32_t occ; + + /* Clear ring completion interrupt status */ + sys_write32(0xFFU, ch->fwd_rt + RINGACC_RT_INT_OFS + RINGACC_RT_INT_STATUS_OFS); + + /* Disable the IRQ until the consumer calls dma_resume() */ + irq_disable(ch->irq); + + /* Pop all completed entries from the ring and invoke consumer's callback */ + occ = sys_read32(ch->rev_rt + RINGACC_RING_RT_OCC); + for (uint32_t i = 0U; i < occ; i++) { + if (!AM62L_PKTDMA_IS_COHERENT(ch->asel)) { + sys_cache_data_invd_range(&ch->rev_mem[ch->rev_ridx], + sizeof(uint64_t)); + } + ch->rev_ridx = (ch->rev_ridx + 1U) % ch->ring_cnt; + sys_write32((uint32_t)(-1), ch->rev_rt + RINGACC_RING_RT_DB); + + if (ch->callback != NULL) { + ch->callback(ch->dev, (void *)(uintptr_t)ch->cb_user_data, + ch->chan_id, DMA_STATUS_COMPLETE); + } + } +} + +/** + * @brief Configure a PKTDMA channel via the standard dma_config() API. + * + * @param dev PKTDMA device + * @param chan_id PKTDMA channel number + * @param cfg Standard DMA configuration (user_data must point to a + * struct ti_pktdma_chan_cfg) + * @retval 0 on success, negative errno on error + */ +static int pktdma_cfg(const struct device *dev, uint32_t chan_id, + struct dma_config *cfg) +{ + const struct pktdma_config *config = dev->config; + struct pktdma_data *data = dev->data; + const struct ti_pktdma_chan_cfg *pcfg; + struct pktdma_chan *ch; + uintptr_t fwd_rt, chanrt; + unsigned int irq = 0U; + uint32_t tcfg; + bool is_rx; + + if (chan_id >= PKTDMA_MAX_CHANS) { + LOG_ERR("chan_id %u out of range (max %u)", chan_id, + PKTDMA_MAX_CHANS - 1U); + return -EINVAL; + } + + if (cfg == NULL || cfg->user_data == NULL) { + LOG_ERR("chan %u: cfg or cfg->user_data is NULL", chan_id); + return -EINVAL; + } + + pcfg = (const struct ti_pktdma_chan_cfg *)cfg->user_data; + is_rx = (cfg->channel_direction == PERIPHERAL_TO_MEMORY); + + ch = &data->chans[chan_id]; + + fwd_rt = DEVICE_MMIO_NAMED_GET(dev, ringrt) + (uintptr_t)chan_id * RINGACC_RING_RT_STEP; + chanrt = DEVICE_MMIO_NAMED_GET(dev, chanrt) + (uintptr_t)chan_id * PKTDMA_CHANRT_STEP; + + /* Reset channel */ + sys_write32(0U, chanrt + PKTDMA_CHANRT_CTL); + + /* Configure forward ring */ + sys_write32((uint32_t)(pcfg->fwd_ring_mem & RINGACC_CFG_BA_LO_ADDR_MASK), + fwd_rt + RINGACC_CFG_BA_LO); + sys_write32(((uint32_t)((uint64_t)pcfg->fwd_ring_mem >> 32) & + RINGACC_CFG_BA_HI_ADDR_MASK) | + FIELD_PREP(RINGACC_CFG_BA_HI_ASEL_MASK, (uint32_t)pcfg->asel), + fwd_rt + RINGACC_CFG_BA_HI); + sys_write32(RINGACC_CFG_SIZE_VAL(RINGACC_SIZE_ELM_8BYTE, pcfg->ring_cnt), + fwd_rt + RINGACC_CFG_SIZE); + + /* Configure reverse ring */ + sys_write32((uint32_t)(pcfg->rev_ring_mem & RINGACC_CFG_BA_LO_ADDR_MASK), + fwd_rt + RINGACC_REVERSE_OFS + RINGACC_CFG_BA_LO); + sys_write32(((uint32_t)((uint64_t)pcfg->rev_ring_mem >> 32) & + RINGACC_CFG_BA_HI_ADDR_MASK) | + FIELD_PREP(RINGACC_CFG_BA_HI_ASEL_MASK, (uint32_t)pcfg->asel), + fwd_rt + RINGACC_REVERSE_OFS + RINGACC_CFG_BA_HI); + sys_write32(RINGACC_CFG_SIZE_VAL(RINGACC_SIZE_ELM_8BYTE, pcfg->ring_cnt), + fwd_rt + RINGACC_REVERSE_OFS + RINGACC_CFG_SIZE); + + /* Configure channel type */ + tcfg = sys_read32(chanrt + PKTDMA_CHANRT_TCFG); + tcfg = (tcfg & ~PKTDMA_CHAN_TYPE_MASK) | PKTDMA_CHAN_TYPE_PACKET; + sys_write32(tcfg, chanrt + PKTDMA_CHANRT_TCFG); + + if (!is_rx) { + /* TX: set completion queue (TCQ = tflow_id = chan_id). */ + sys_write32(chan_id, chanrt + PKTDMA_CHANRT_TCQ); + } else { + /* RX: configure flow RT (EPIB + PSD present) */ + sys_write32(PKTDMA_RFLOW_RFA_EINFO | PKTDMA_RFLOW_RFA_PSINFO, + fwd_rt + PKTDMA_RX_FLOWRT_RFA); + } + + /* Save ring pointers for push and pop operations */ + ch->fwd_rt = fwd_rt; + ch->rev_rt = fwd_rt + RINGACC_REVERSE_OFS; + ch->chanrt = chanrt; + ch->fwd_mem = (uint64_t *)pcfg->fwd_ring_mem; + ch->rev_mem = (uint64_t *)pcfg->rev_ring_mem; + ch->ring_cnt = pcfg->ring_cnt; + ch->fwd_widx = 0U; + ch->rev_ridx = 0U; + ch->is_rx = is_rx; + ch->asel = pcfg->asel; + ch->configured = false; + + /* Store fields needed by the ISR and completion callback */ + ch->dev = dev; + ch->chan_id = chan_id; + ch->callback = cfg->dma_callback; + ch->cb_user_data = pcfg->cb_user_data; + + /* Look up and register the per-channel ISR if a callback is provided */ + if (cfg->dma_callback != NULL) { + for (size_t i = 0; i < config->irq_table_len; i++) { + if (config->irq_table[i].chan_id == chan_id) { + irq = config->irq_table[i].irq; + break; + } + } + if (irq == 0U) { + LOG_ERR("PKTDMA: no interrupt-map entry for chan %u", chan_id); + return -EINVAL; + } + ch->irq = irq; + irq_connect_dynamic(irq, IRQ_DEFAULT_PRIORITY, pktdma_chan_isr, + ch, IRQ_TYPE_LEVEL); + } + + LOG_DBG("PKTDMA: chan %u configured (fwd_rt=0x%08x cnt=%u %s ASEL=%u%s)", + chan_id, (uint32_t)fwd_rt, pcfg->ring_cnt, + is_rx ? "RX" : "TX", ch->asel, + AM62L_PKTDMA_IS_COHERENT(ch->asel) ? " [ACP coherent]" : ""); + LOG_DBG(" fwd BA=0x%08x SIZE=0x%08x", + sys_read32(fwd_rt + RINGACC_CFG_BA_LO), + sys_read32(fwd_rt + RINGACC_CFG_SIZE)); + LOG_DBG(" rev BA=0x%08x SIZE=0x%08x", + sys_read32(fwd_rt + RINGACC_REVERSE_OFS + RINGACC_CFG_BA_LO), + sys_read32(fwd_rt + RINGACC_REVERSE_OFS + RINGACC_CFG_SIZE)); + + return 0; +} + +/** + * @brief Enable a PKTDMA channel + * + * @param dev PKTDMA device + * @param chan_id PKTDMA channel number + * @retval 0 on success, -ETIMEDOUT if PAIR_COMPLETE is never set + */ +static int pktdma_start(const struct device *dev, uint32_t chan_id) +{ + struct pktdma_data *data = dev->data; + struct pktdma_chan *ch; + uint32_t ctl; + uint8_t i; + + if (chan_id >= PKTDMA_MAX_CHANS) { + return -EINVAL; + } + + ch = &data->chans[chan_id]; + + sys_write32(0U, ch->chanrt + PKTDMA_CHANRT_CTL); + sys_write32(PKTDMA_CHANRT_CTL_EN | PKTDMA_CHANRT_CTL_AUTOPAIR, + ch->chanrt + PKTDMA_CHANRT_CTL); + + for (i = 0; i < PKTDMA_CHANRT_PAIR_RETRIES; i++) { + ctl = sys_read32(ch->chanrt + PKTDMA_CHANRT_CTL); + if (ctl & PKTDMA_CHANRT_CTL_PAIR_TIMEOUT) { + LOG_ERR("PKTDMA: chan %u AUTOPAIR timed out (ctl=0x%08x)", + chan_id, ctl); + return -ETIMEDOUT; + } + if (ctl & PKTDMA_CHANRT_CTL_PAIR_COMPLETE) { + break; + } + k_busy_wait(PKTDMA_AUTOPAIR_BUSY_WAIT_US); + } + + if (i > PKTDMA_CHANRT_PAIR_RETRIES) { + LOG_ERR("PKTDMA: chan %u PAIR_COMPLETE never set", chan_id); + return -ETIMEDOUT; + } + + ch->configured = true; + + LOG_DBG("PKTDMA: chan %u enabled after %d iterations (ctl=0x%08x)", + chan_id, i, sys_read32(ch->chanrt + PKTDMA_CHANRT_CTL)); + + /* + * Drain any stale entries from the reverse ring that may have been left + * by a previous usage of the ring. This must be performed before arming + * the ring interrupt to avoid spurious completion interrupts. + */ + while (sys_read32(ch->rev_rt + RINGACC_RING_RT_OCC) > 0U) { + ch->rev_ridx = (ch->rev_ridx + 1U) % ch->ring_cnt; + sys_write32((uint32_t)(-1), ch->rev_rt + RINGACC_RING_RT_DB); + } + + /* Arm the ring interrupt bits in hardware */ + sys_write32(RINGACC_RT_INT_ENABLE_COMPLETE_TR, + ch->fwd_rt + RINGACC_RT_INT_OFS); + + return 0; +} + +/** + * @brief Teardown and disable a PKTDMA channel. + * + * @param dev PKTDMA device + * @param chan_id PKTDMA channel number + * @retval 0 on success, errno on failure + */ +static int pktdma_stop(const struct device *dev, uint32_t chan_id) +{ + struct pktdma_data *data = dev->data; + struct pktdma_chan *ch; + uint32_t ctl; + int i; + + if (chan_id >= PKTDMA_MAX_CHANS) { + return -EINVAL; + } + + ch = &data->chans[chan_id]; + + if (!ch->configured) { + return 0; + } + + /* Prevent callbacks from firing during or after teardown */ + if (ch->irq != 0U) { + irq_disable(ch->irq); + } + + ctl = sys_read32(ch->chanrt + PKTDMA_CHANRT_CTL); + sys_write32(ctl | PKTDMA_CHANRT_CTL_TDOWN, ch->chanrt + PKTDMA_CHANRT_CTL); + + for (i = 0; i < PKTDMA_CHANRT_TDOWN_RETRIES; i++) { + ctl = sys_read32(ch->chanrt + PKTDMA_CHANRT_CTL); + if (!(ctl & PKTDMA_CHANRT_CTL_TDOWN)) { + break; + } + k_busy_wait(PKTDMA_TDOWN_BUSY_WAIT_US); + } + + if (i > PKTDMA_CHANRT_TDOWN_RETRIES) { + LOG_ERR("PKTDMA: chan %u teardown completion timed out", chan_id); + } + + sys_write32(0U, ch->chanrt + PKTDMA_CHANRT_CTL); + ch->configured = false; + + LOG_DBG("PKTDMA: chan %u stopped", chan_id); + + return 0; +} + +/** + * @brief Report channel busy state and direction + * + * @param dev PKTDMA device + * @param chan_id PKTDMA channel number + * @param status Channel status structure to be filled in + * @retval 0 on success, negative errno on error + */ +static int pktdma_get_status(const struct device *dev, uint32_t chan_id, + struct dma_status *status) +{ + struct pktdma_data *data = dev->data; + struct pktdma_chan *ch; + + if (chan_id >= PKTDMA_MAX_CHANS || !status) { + return -EINVAL; + } + + ch = &data->chans[chan_id]; + status->busy = ch->configured && + (sys_read32(ch->fwd_rt + RINGACC_RING_RT_OCC) > 0U); + status->dir = ch->is_rx ? PERIPHERAL_TO_MEMORY : MEMORY_TO_PERIPHERAL; + + return 0; +} + +/** + * @brief Re-arm the ring completion interrupt and re-enable the channel IRQ. + * + * @param dev PKTDMA device + * @param chan_id PKTDMA channel number + * @retval 0 on success, -EINVAL if chan_id is out of range or not configured + */ +static int pktdma_resume(const struct device *dev, uint32_t chan_id) +{ + struct pktdma_data *data = dev->data; + struct pktdma_chan *ch; + + if (chan_id >= PKTDMA_MAX_CHANS) { + return -EINVAL; + } + + ch = &data->chans[chan_id]; + if (!ch->configured || ch->irq == 0U) { + return -EINVAL; + } + + /* Re-arm ring completion interrupt bits */ + sys_write32(RINGACC_RT_INT_ENABLE_COMPLETE_TR, + ch->fwd_rt + RINGACC_RT_INT_OFS); + + /* Re-enable the GIC interrupt for this channel */ + irq_enable(ch->irq); + + return 0; +} + +/** + * @brief Submit a CPPI5 descriptor to the channel's forward ring (dma_reload). + * + * @param dev PKTDMA device + * @param chan_id PKTDMA channel number + * @param src TX descriptor physical address (ignored for RX channels) + * @param dst RX descriptor physical address (ignored for TX channels) + * @param size Unused / Ignored + * @retval 0 on success, -EINVAL if chan_id is out of range + */ +#ifdef CONFIG_DMA_64BIT +static int pktdma_reload(const struct device *dev, uint32_t chan_id, + uint64_t src, uint64_t dst, size_t size) +#else +static int pktdma_reload(const struct device *dev, uint32_t chan_id, + uint32_t src, uint32_t dst, size_t size) +#endif +{ + struct pktdma_data *data = dev->data; + struct pktdma_chan *ch; + uint64_t desc_phys; + + ARG_UNUSED(size); + + if (chan_id >= PKTDMA_MAX_CHANS) { + return -EINVAL; + } + + ch = &data->chans[chan_id]; + desc_phys = ch->is_rx ? (uint64_t)dst : (uint64_t)src; + + ch->fwd_mem[ch->fwd_widx] = desc_phys | + FIELD_PREP(AM62L_ADDRESS_ASEL_MASK, (uint64_t)ch->asel); + if (!AM62L_PKTDMA_IS_COHERENT(ch->asel)) { + sys_cache_data_flush_range(&ch->fwd_mem[ch->fwd_widx], + sizeof(uint64_t)); + } + ch->fwd_widx = (ch->fwd_widx + 1U) % ch->ring_cnt; + sys_write32(1U, ch->fwd_rt + RINGACC_RING_RT_DB); + + return 0; +} + +/** + * @brief Initialize PKTDMA regions + * + * @param dev PKTDMA device + * @retval 0 always + */ +static int pktdma_init(const struct device *dev) +{ + DEVICE_MMIO_NAMED_MAP(dev, gcfg, K_MEM_CACHE_NONE); + DEVICE_MMIO_NAMED_MAP(dev, chanrt, K_MEM_CACHE_NONE); + DEVICE_MMIO_NAMED_MAP(dev, ringrt, K_MEM_CACHE_NONE); + + LOG_DBG("PKTDMA: gcfg=0x%08x chanrt=0x%08x ringrt=0x%08x", + (uint32_t)DEVICE_MMIO_NAMED_GET(dev, gcfg), + (uint32_t)DEVICE_MMIO_NAMED_GET(dev, chanrt), + (uint32_t)DEVICE_MMIO_NAMED_GET(dev, ringrt)); + + return 0; +} + +static DEVICE_API(dma, pktdma_driver_api) = { + .config = pktdma_cfg, + .reload = pktdma_reload, + .start = pktdma_start, + .stop = pktdma_stop, + .resume = pktdma_resume, + .get_status = pktdma_get_status, +}; + +#define PKTDMA_DEVICE_INIT(n) \ + static struct pktdma_data pktdma_data_##n; \ + \ + static const struct pktdma_irq_entry pktdma_irq_table_##n[] = { \ + LISTIFY(DT_INST_PROP_LEN(n, interrupt_map), \ + _PKTDMA_IRQMAP_ENTRY, (,), DT_DRV_INST(n)) \ + }; \ + \ + static const struct pktdma_config pktdma_cfg_##n = { \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(gcfg, DT_DRV_INST(n)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(chanrt, DT_DRV_INST(n)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(ringrt, DT_DRV_INST(n)), \ + .irq_table = pktdma_irq_table_##n, \ + .irq_table_len = ARRAY_SIZE(pktdma_irq_table_##n), \ + }; \ + DEVICE_DT_INST_DEFINE(n, pktdma_init, NULL, \ + &pktdma_data_##n, &pktdma_cfg_##n, \ + POST_KERNEL, CONFIG_DMA_INIT_PRIORITY, \ + &pktdma_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PKTDMA_DEVICE_INIT) diff --git a/soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.h b/soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.h new file mode 100644 index 000000000000..c28177fb6f68 --- /dev/null +++ b/soc/ti/k3/am62lx/dma/dma_ti_am62l_pktdma.h @@ -0,0 +1,53 @@ +/* + * TI AM62L PKTDMA driver API + * + * Copyright (c) 2026 Texas Instruments Incorporated + * Author: Siddharth Vadapalli + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef DMA_TI_AM62L_PKTDMA_H_ +#define DMA_TI_AM62L_PKTDMA_H_ + +#include +#include + +/** + * @brief The 4 bits corresponding to ASEL in a 64-bit address + */ +#define AM62L_ADDRESS_ASEL_MASK GENMASK64(51, 48) + +/** + * @brief ASEL values 14 and 15 route DMA transactions through the ARM Accelerator + * Coherency Port (ACP). ACP transactions are fully coherent with the CPU cache, + * so no explicit cache flush or invalidate is required for DMA buffers and + * descriptors on coherent channels. + */ +#define AM62L_PKTDMA_IS_COHERENT(asel) ((asel) == 14U || (asel) == 15U) + +/** + * @brief PKTDMA channel configuration passed via dma_config.user_data. + */ +struct ti_pktdma_chan_cfg { + /** Virtual address of the forward ring buffer */ + uintptr_t fwd_ring_mem; + + /** Virtual address of the reverse/completion ring buffer */ + uintptr_t rev_ring_mem; + + /** Number of 8-byte entries in each ring */ + uint32_t ring_cnt; + + /** + * Address Space Select (ASEL) value (defaults to zero) + * 0 = non-coherent (cache flush/invalidate required) + * 14 or 15 = coherent (cache operations not required) + */ + uint8_t asel; + + /** Consumer's user data associated with DMA Callback */ + const void *cb_user_data; +}; + +#endif /* DMA_TI_AM62L_PKTDMA_H_ */ From 94d3c752b2e17d898af67472359e92170f0ef36a Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Fri, 16 Oct 2026 17:42:31 +0530 Subject: [PATCH 13/18] UPSTREAM-PEND: dts: bindings: mdio: introduce AM62L CPSW MDIO PR: 122461 The CPSW3G instance of CPSW in the Texas Instruments AM62L SoC [0] has an integrated MDIO module. The MDIO module allows managing the Ethernet PHYs associated with the CPSW MAC Ports. Add the bindings for CPSW MDIO. [0]: https://www.ti.com/product/AM62L Signed-off-by: Siddharth Vadapalli --- dts/bindings/ethernet/mdio/ti,am62l-cpsw-mdio.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 dts/bindings/ethernet/mdio/ti,am62l-cpsw-mdio.yaml diff --git a/dts/bindings/ethernet/mdio/ti,am62l-cpsw-mdio.yaml b/dts/bindings/ethernet/mdio/ti,am62l-cpsw-mdio.yaml new file mode 100644 index 000000000000..ed400e88c531 --- /dev/null +++ b/dts/bindings/ethernet/mdio/ti,am62l-cpsw-mdio.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2026 Texas Instruments Incorporated +# Author: Siddharth Vadapalli +# SPDX-License-Identifier: Apache-2.0 + +description: TI AM62L CPSW MDIO controller + +compatible: "ti,am62l-cpsw-mdio" + +include: mdio-controller.yaml From 6c04a8cbb595e8dbb21864e6d4a2ff65fe2a0a6f Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Thu, 14 May 2026 11:59:40 +0530 Subject: [PATCH 14/18] UPSTREAM-PEND: dts: bindings: ethernet: introduce AM62L CPSW ... PR: 122461 The Texas Instruments AM62L SoC [0] includes an integrated Ethernet Switch named CPSW3G with one Host Port (CPU facing port) and two MAC Ports. The MAC Ports support "rmii" and "rgmii" interfaces and speeds of 10, 100 and 1000 Mbps depending on the selected interface. Host Software can send packets to and receive packets from CPSW3G via dedicated PKTDMA Channels. Add the bindings for CPSW. [0]: https://www.ti.com/product/AM62L Signed-off-by: Siddharth Vadapalli --- dts/bindings/ethernet/ti,am62l-cpsw.yaml | 89 ++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 dts/bindings/ethernet/ti,am62l-cpsw.yaml diff --git a/dts/bindings/ethernet/ti,am62l-cpsw.yaml b/dts/bindings/ethernet/ti,am62l-cpsw.yaml new file mode 100644 index 000000000000..2e6612a21d6c --- /dev/null +++ b/dts/bindings/ethernet/ti,am62l-cpsw.yaml @@ -0,0 +1,89 @@ +# Copyright (c) 2026 Texas Instruments Incorporated +# Author: Siddharth Vadapalli +# SPDX-License-Identifier: Apache-2.0 + +description: TI AM62L Common Platform Switch (CPSW) + +compatible: "ti,am62l-cpsw" + +include: base.yaml + +properties: + reg: + required: true + description: | + CPSW NU Subsystem Register region. + + reg-names: + required: true + description: | + "cpsw_nuss" for the CPSW NU Subsystem register region, + "gmii_sel" for the GMII configuration CTRL MMR registers, and + "mac_efuse" for the eFuse register holding the MAC Port 1 address. + + dmas: + required: true + description: | + DMA Channels for transmitting data to and receiving data from + CPSW. The Address Select (ASEL) parameter is specified along + with the DMA Channel. The Accelerator Coherency Port (ACP) in + the ARM Cluster on the SoC enables IO Coherency in the following + manner: + A) Device initiated reads to System Memory go through the L2 + cache controller ensuring that the device gets the correct data + if the data hasn't been flushed to System Memory yet. + B) Device initiated writes to System Memory also go through the + L2 cache controller ensuring that the cache is updated to reflect + the correct contents of System Memory. + The ASEL parameter is utilized to enable this feature and the + valid values are: + ASEL 14 + => Write transactions cause L2 cache allocation for cache warming + ASEL 15 + => Write transactions do not cause L2 cache allocation + Read transactions do not result in L2 cache allocation independent + of the ASEL value. + + dma-names: + required: true + description: | + The DMA Channels should be named in the format of "tx0", "tx1" and + so on for transmit and "rx" for receive (there is a single RX DMA + Channel). Transmit and receive are defined from the perspective of + Host Software. Hence, "transmit" refers to DMA Channels moving data + from System Memory to CPSW whereas "receive" refers to DMA Channels + moving data from CPSW to System Memory. + +child-binding: + description: Ethernet Ports + + properties: + "#address-cells": + type: int + const: 1 + + "#size-cells": + type: int + const: 0 + + child-binding: + description: MAC Port + + include: + - name: ethernet-controller.yaml + property-blocklist: + - compatible + + properties: + reg: + required: true + type: array + max-len: 1 + description: | + The MAC Port number (starting from 1 for MAC Port 1). + The CPSW Host Port (CPU facing port) is numbered 0 and + doesn't have to be described. + + ti,mac-only: + type: boolean + description: Port is MAC only (no L2 switching to/from other MAC Ports). From 3fe7eb4a3d7b3d4ffd2d0642d50824b94633c1ee Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Mon, 19 Oct 2026 12:53:00 +0530 Subject: [PATCH 15/18] UPSTREAM-PEND: drivers: ethernet: mdio: introduce AM62L CPSW MDIO driver PR: 122461 The CPSW3G instance of CPSW in the Texas Instruments AM62L SoC [0] has an integrated MDIO module. The MDIO module allows managing the Ethernet PHYs associated with the CPSW MAC Ports. Add the CPSW MDIO driver to enable functionality. [0]: https://www.ti.com/product/AM62L Signed-off-by: Siddharth Vadapalli --- drivers/ethernet/mdio/CMakeLists.txt | 1 + drivers/ethernet/mdio/Kconfig | 1 + .../ethernet/mdio/Kconfig.ti_am62l_cpsw_mdio | 9 + drivers/ethernet/mdio/mdio_ti_am62l_cpsw.c | 327 ++++++++++++++++++ 4 files changed, 338 insertions(+) create mode 100644 drivers/ethernet/mdio/Kconfig.ti_am62l_cpsw_mdio create mode 100644 drivers/ethernet/mdio/mdio_ti_am62l_cpsw.c diff --git a/drivers/ethernet/mdio/CMakeLists.txt b/drivers/ethernet/mdio/CMakeLists.txt index 97149a1b1d3c..578e3ab8069a 100644 --- a/drivers/ethernet/mdio/CMakeLists.txt +++ b/drivers/ethernet/mdio/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_MDIO_RENESAS_RA mdio_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_MDIO_RENESAS_RA_RMAC mdio_renesas_ra_rmac.c) zephyr_library_sources_ifdef(CONFIG_MDIO_SENSRY_SY1XX mdio_sy1xx.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ST_STM32_HAL mdio_stm32_hal.c) +zephyr_library_sources_ifdef(CONFIG_MDIO_TI_AM62L_CPSW mdio_ti_am62l_cpsw.c) zephyr_library_sources_ifdef(CONFIG_MDIO_WCH mdio_wch.c) zephyr_library_sources_ifdef(CONFIG_MDIO_XILINX_AXI_ENET mdio_xilinx_axienet.c) zephyr_library_sources_ifdef(CONFIG_MDIO_XILINX_AXI_ETHERNET_LITE mdio_xilinx_axi_ethernet_lite.c) diff --git a/drivers/ethernet/mdio/Kconfig b/drivers/ethernet/mdio/Kconfig index f810257fb39a..0ec005d3ffbd 100644 --- a/drivers/ethernet/mdio/Kconfig +++ b/drivers/ethernet/mdio/Kconfig @@ -41,6 +41,7 @@ rsource "Kconfig.renesas_ra" rsource "Kconfig.sam" rsource "Kconfig.stm32_hal" rsource "Kconfig.sy1xx" +rsource "Kconfig.ti_am62l_cpsw_mdio" rsource "Kconfig.wch" rsource "Kconfig.xilinx_axi_ethernet_lite" rsource "Kconfig.xilinx_axienet" diff --git a/drivers/ethernet/mdio/Kconfig.ti_am62l_cpsw_mdio b/drivers/ethernet/mdio/Kconfig.ti_am62l_cpsw_mdio new file mode 100644 index 000000000000..60c7055d3e10 --- /dev/null +++ b/drivers/ethernet/mdio/Kconfig.ti_am62l_cpsw_mdio @@ -0,0 +1,9 @@ +# Copyright (c) 2026 Texas Instruments Incorporated +# SPDX-License-Identifier: Apache-2.0 + +config MDIO_TI_AM62L_CPSW + bool "TI AM62L CPSW MDIO Driver" + default y + depends on DT_HAS_TI_AM62L_CPSW_MDIO_ENABLED + help + Enable TI AM62L CPSW MDIO controller driver. diff --git a/drivers/ethernet/mdio/mdio_ti_am62l_cpsw.c b/drivers/ethernet/mdio/mdio_ti_am62l_cpsw.c new file mode 100644 index 000000000000..c9df9cd3ab3c --- /dev/null +++ b/drivers/ethernet/mdio/mdio_ti_am62l_cpsw.c @@ -0,0 +1,327 @@ +/* TI AM62L CPSW MDIO controller driver + * + * Copyright (c) 2026 Texas Instruments Incorporated + * Author: Siddharth Vadapalli + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_am62l_cpsw_mdio + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(mdio_ti_am62l_cpsw, CONFIG_MDIO_LOG_LEVEL); + +/* MDIO module base offset from CPSW base address */ +#define CPSW_MDIO_BASE_OFFSET 0xf00U + +/* MDIO register offsets relative to module base */ +#define MDIO_VERSION 0x00U +#define MDIO_CONTROL 0x04U +#define MDIO_ALIVE 0x08U +#define MDIO_LINK 0x0cU +#define MDIO_USERACCESS0 0x80U + +/* CONTROL register fields */ +#define MDIO_CTL_ENABLE BIT(30) +#define MDIO_CTL_IDLE BIT(31) +#define MDIO_CTL_DIV_MASK GENMASK(15, 0) +#define MDIO_CTL_DIV_DEF 0xffU + +/* USERACCESS register fields */ +#define MDIO_UA_GO BIT(31) +#define MDIO_UA_WRITE BIT(30) +#define MDIO_UA_ACK BIT(29) +#define MDIO_UA_REGADR_MASK GENMASK(25, 21) +#define MDIO_UA_PHYADR_MASK GENMASK(20, 16) +#define MDIO_UA_DATA_MASK GENMASK(15, 0) + +/* Clause-22 indirect access registers for extended PHY regs */ +#define MDIO_REGCR_REG 0x000dU +#define MDIO_ADDAR_REG 0x000eU +#define MDIO_REGCR_ADDR 0x001fU +#define MDIO_REGCR_DATA 0x401fU + +/* + * Wait at most 100 milliseconds for GO bit to clear. Poll every + * 100 microseconds and retry 1000 times which is effectively a + * timeout duration of 100 milliseconds. + */ +#define CPSW_MDIO_POLL_INTERVAL_US 100U +#define CPSW_MDIO_MAX_RETRIES 1000U + +struct cpsw_mdio_config { + const struct device *parent; /* Parent CPSW device */ + uint32_t bus_freq; /* Target MDC output frequency in Hz */ + const struct device *clk_dev; /* Functional clock controller device */ + clock_control_subsys_t clk_subsys; /* Clock ID for functional clock */ +}; + +struct cpsw_mdio_data { + mm_reg_t base; /* MDIO virtual base: CPSW base + CPSW_MDIO_BASE_OFFSET */ + struct k_mutex lock; /* MDIO bus access lock */ +}; + +static inline void mdio_writereg(uintptr_t base, uint32_t off, uint32_t val) +{ + sys_write32(val, base + off); +} + +static inline uint32_t mdio_readreg(uintptr_t base, uint32_t off) +{ + return sys_read32(base + off); +} + +/* Poll USERACCESS0 until GO clears. Caller must hold the bus mutex. */ +static int cpsw_mdio_wait_go(uintptr_t base) +{ + uint16_t retries = CPSW_MDIO_MAX_RETRIES; + + while (retries--) { + if (!(mdio_readreg(base, MDIO_USERACCESS0) & MDIO_UA_GO)) { + return 0; + } + k_busy_wait(CPSW_MDIO_POLL_INTERVAL_US); + } + + LOG_ERR("MDIO timeout: GO never cleared (UA=0x%08x)", + mdio_readreg(base, MDIO_USERACCESS0)); + return -ETIMEDOUT; +} + +static int cpsw_mdio_hw_read(uintptr_t base, uint8_t prtad, uint8_t regad, + uint16_t *data) +{ + uint32_t ua; + int ret; + + ret = cpsw_mdio_wait_go(base); + if (ret) { + return ret; + } + + mdio_writereg(base, MDIO_USERACCESS0, + MDIO_UA_GO | + FIELD_PREP(MDIO_UA_REGADR_MASK, (uint32_t)regad) | + FIELD_PREP(MDIO_UA_PHYADR_MASK, (uint32_t)prtad)); + + ret = cpsw_mdio_wait_go(base); + if (ret) { + return ret; + } + + ua = mdio_readreg(base, MDIO_USERACCESS0); + LOG_DBG("MDIO hw_read prtad=%u regad=0x%02x UA=0x%08x", prtad, regad, ua); + + if (ua & MDIO_UA_ACK) { + *data = (uint16_t)(ua & MDIO_UA_DATA_MASK); + return 0; + } + + LOG_ERR("MDIO read: no ACK (prtad=%u regad=0x%02x UA=0x%08x)", + prtad, regad, ua); + return -EIO; +} + +static int cpsw_mdio_hw_write(uintptr_t base, uint8_t prtad, uint8_t regad, + uint16_t data) +{ + int ret; + + ret = cpsw_mdio_wait_go(base); + if (ret) { + return ret; + } + + mdio_writereg(base, MDIO_USERACCESS0, + MDIO_UA_GO | MDIO_UA_WRITE | + FIELD_PREP(MDIO_UA_REGADR_MASK, (uint32_t)regad) | + FIELD_PREP(MDIO_UA_PHYADR_MASK, (uint32_t)prtad) | + ((uint32_t)data & MDIO_UA_DATA_MASK)); + + return cpsw_mdio_wait_go(base); +} + +/** + * @brief Clause-22 read with transparent extended-register support + * + * Addresses 0x00-0x1f use direct USERACCESS access + * Addresses > 0x1f use the 4-step REGCR/ADDAR indirect sequence + */ +static int cpsw_mdio_read(const struct device *dev, uint8_t prtad, + uint8_t regad, uint16_t *data) +{ + struct cpsw_mdio_data *d = dev->data; + mm_reg_t base = d->base; + int ret; + + if (prtad > 0x1fU) { + return -EINVAL; + } + + k_mutex_lock(&d->lock, K_FOREVER); + + if (regad <= 0x1fU) { + ret = cpsw_mdio_hw_read(base, prtad, regad, data); + } else { + LOG_DBG("MDIO ext read: prtad=%u regad=0x%02x", prtad, regad); + ret = cpsw_mdio_hw_write(base, prtad, + MDIO_REGCR_REG, MDIO_REGCR_ADDR); + if (ret) { + goto out; + } + ret = cpsw_mdio_hw_write(base, prtad, + MDIO_ADDAR_REG, (uint16_t)regad); + if (ret) { + goto out; + } + ret = cpsw_mdio_hw_write(base, prtad, + MDIO_REGCR_REG, MDIO_REGCR_DATA); + if (ret) { + goto out; + } + ret = cpsw_mdio_hw_read(base, prtad, MDIO_ADDAR_REG, data); + } + +out: + k_mutex_unlock(&d->lock); + return ret; +} + +/** + * @brief Clause-22 write with transparent extended-register support + * + * Addresses 0x00-0x1f use direct USERACCESS access + * Addresses > 0x1f use the 4-step REGCR/ADDAR indirect sequence + */ +static int cpsw_mdio_write(const struct device *dev, uint8_t prtad, + uint8_t regad, uint16_t data) +{ + struct cpsw_mdio_data *d = dev->data; + mm_reg_t base = d->base; + int ret; + + if (prtad > 0x1fU) { + return -EINVAL; + } + + k_mutex_lock(&d->lock, K_FOREVER); + + if (regad <= 0x1fU) { + ret = cpsw_mdio_hw_write(base, prtad, regad, data); + } else { + LOG_DBG("MDIO ext write: prtad=%u regad=0x%02x data=0x%04x", + prtad, regad, data); + ret = cpsw_mdio_hw_write(base, prtad, + MDIO_REGCR_REG, MDIO_REGCR_ADDR); + if (ret) { + goto out; + } + ret = cpsw_mdio_hw_write(base, prtad, + MDIO_ADDAR_REG, (uint16_t)regad); + if (ret) { + goto out; + } + ret = cpsw_mdio_hw_write(base, prtad, + MDIO_REGCR_REG, MDIO_REGCR_DATA); + if (ret) { + goto out; + } + ret = cpsw_mdio_hw_write(base, prtad, MDIO_ADDAR_REG, data); + } + +out: + k_mutex_unlock(&d->lock); + return ret; +} + +static DEVICE_API(mdio, cpsw_mdio_api) = { + .read = cpsw_mdio_read, + .write = cpsw_mdio_write, +}; + +static int cpsw_mdio_init(const struct device *dev) +{ + const struct cpsw_mdio_config *const cfg = dev->config; + struct cpsw_mdio_data *const d = dev->data; + uint32_t version, divider, ctrl, fck_freq; + uint16_t retries; + + if (!device_is_ready(cfg->parent)) { + LOG_ERR("parent CPSW device not ready"); + return -ENODEV; + } + + d->base = DEVICE_MMIO_GET(cfg->parent) + CPSW_MDIO_BASE_OFFSET; + + mm_reg_t base = d->base; + + k_mutex_init(&d->lock); + + version = mdio_readreg(base, MDIO_VERSION); + LOG_INF("MDIO base=0x%lx VERSION=0x%08x", (unsigned long)base, version); + + clock_control_get_rate(cfg->clk_dev, cfg->clk_subsys, &fck_freq); + divider = (fck_freq > 0U && cfg->bus_freq > 0U) + ? (fck_freq / cfg->bus_freq) - 1U + : MDIO_CTL_DIV_DEF; + divider &= MDIO_CTL_DIV_MASK; + + mdio_writereg(base, MDIO_CONTROL, divider | MDIO_CTL_ENABLE); + + ctrl = mdio_readreg(base, MDIO_CONTROL); + if (!(ctrl & MDIO_CTL_ENABLE)) { + LOG_ERR("MDIO CONTROL ENABLE bit did not stick (readback=0x%08x)", + ctrl); + } + + /* Poll until IDLE clears: state machine is running. */ + retries = CPSW_MDIO_MAX_RETRIES; + while (retries-- > 0) { + if (!(mdio_readreg(base, MDIO_CONTROL) & MDIO_CTL_IDLE)) { + break; + } + k_busy_wait(CPSW_MDIO_POLL_INTERVAL_US); + } + + if (mdio_readreg(base, MDIO_CONTROL) & MDIO_CTL_IDLE) { + LOG_ERR("MDIO IDLE never cleared (CONTROL=0x%08x)", + mdio_readreg(base, MDIO_CONTROL)); + return -ETIMEDOUT; + } + + /* Wait for 1 millisecond to allow the MDIO scan logic to settle */ + k_msleep(1); + + LOG_DBG("MDIO ALIVE=0x%08x LINK=0x%08x", + mdio_readreg(base, MDIO_ALIVE), + mdio_readreg(base, MDIO_LINK)); + + return 0; +} + +#define TI_AM62L_CPSW_MDIO_INIT(n) \ + static const struct cpsw_mdio_config cpsw_mdio_cfg_##n = { \ + .parent = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + .bus_freq = DT_INST_PROP(n, clock_frequency), \ + .clk_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR_BY_NAME(DT_INST_PARENT(n), \ + fck)), \ + .clk_subsys = (clock_control_subsys_t) \ + UINT_TO_POINTER( \ + DT_CLOCKS_CELL_BY_NAME(DT_INST_PARENT(n), fck, name)), \ + }; \ + \ + static struct cpsw_mdio_data cpsw_mdio_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, cpsw_mdio_init, NULL, \ + &cpsw_mdio_data_##n, &cpsw_mdio_cfg_##n, \ + POST_KERNEL, CONFIG_MDIO_INIT_PRIORITY, \ + &cpsw_mdio_api); + +DT_INST_FOREACH_STATUS_OKAY(TI_AM62L_CPSW_MDIO_INIT) From c0439ef28644761b4faa65c05fb4d8e5de8d94ff Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Sun, 17 May 2026 18:12:55 +0530 Subject: [PATCH 16/18] UPSTREAM-PEND: drivers: ethernet: introduce AM62L CPSW ... PR: 122461 The Texas Instruments AM62L SoC [0] includes an integrated Ethernet Switch named CPSW3G with one Host Port (CPU facing port) and two MAC Ports. The MAC Ports support "rmii" and "rgmii" interfaces and speeds of 10, 100 and 1000 Mbps depending on the selected interface. Host Software can send packets to and receive packets from CPSW3G via dedicated PKTDMA Channels. Add the driver to enable functionality. [0]: https://www.ti.com/product/AM62L Signed-off-by: Siddharth Vadapalli --- drivers/ethernet/CMakeLists.txt | 1 + drivers/ethernet/Kconfig | 1 + drivers/ethernet/Kconfig.ti_am62l_cpsw | 76 ++ drivers/ethernet/eth_ti_am62l_cpsw.c | 1518 ++++++++++++++++++++++++ drivers/ethernet/eth_ti_am62l_cpsw.h | 365 ++++++ 5 files changed, 1961 insertions(+) create mode 100644 drivers/ethernet/Kconfig.ti_am62l_cpsw create mode 100644 drivers/ethernet/eth_ti_am62l_cpsw.c create mode 100644 drivers/ethernet/eth_ti_am62l_cpsw.h diff --git a/drivers/ethernet/CMakeLists.txt b/drivers/ethernet/CMakeLists.txt index 4efdae0ddf8c..30a3a1d3c127 100644 --- a/drivers/ethernet/CMakeLists.txt +++ b/drivers/ethernet/CMakeLists.txt @@ -60,6 +60,7 @@ zephyr_library_sources_ifdef(CONFIG_ETH_SMSC91X eth_smsc91x.c) zephyr_library_sources_ifdef(CONFIG_ETH_STELLARIS eth_stellaris.c) zephyr_library_sources_ifdef(CONFIG_ETH_SY1XX eth_sensry_sy1xx_mac.c) zephyr_library_sources_ifdef(CONFIG_ETH_TEST eth_test.c) +zephyr_library_sources_ifdef(CONFIG_ETH_TI_AM62L_CPSW eth_ti_am62l_cpsw.c) zephyr_library_sources_ifdef(CONFIG_ETH_VIRTIO_NET eth_virtio_net.c) zephyr_library_sources_ifdef(CONFIG_ETH_W5500 eth_w5500.c) zephyr_library_sources_ifdef(CONFIG_ETH_W6100 eth_w6100.c) diff --git a/drivers/ethernet/Kconfig b/drivers/ethernet/Kconfig index 8cbae2db028c..b67c476b229d 100644 --- a/drivers/ethernet/Kconfig +++ b/drivers/ethernet/Kconfig @@ -77,6 +77,7 @@ source "drivers/ethernet/Kconfig.stellaris" source "drivers/ethernet/Kconfig.stm32_hal" source "drivers/ethernet/Kconfig.sy1xx_mac" source "drivers/ethernet/Kconfig.test" +source "drivers/ethernet/Kconfig.ti_am62l_cpsw" source "drivers/ethernet/Kconfig.virtio_net" source "drivers/ethernet/Kconfig.w5500" source "drivers/ethernet/Kconfig.w6100" diff --git a/drivers/ethernet/Kconfig.ti_am62l_cpsw b/drivers/ethernet/Kconfig.ti_am62l_cpsw new file mode 100644 index 000000000000..eea85319b63c --- /dev/null +++ b/drivers/ethernet/Kconfig.ti_am62l_cpsw @@ -0,0 +1,76 @@ +# TI AM62L CPSW Ethernet driver configuration + +# Copyright (c) 2026 Texas Instruments Incorporated +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ETH_TI_AM62L_CPSW + bool "TI AM62L CPSW Ethernet Driver" + default y + depends on DT_HAS_TI_AM62L_CPSW_ENABLED + select DYNAMIC_INTERRUPTS + select DMA + imply NVMEM if $(dt_compat_any_has_prop,$(DT_COMPAT_TI_AM62L_CPSW),nvmem-cells) + help + Enable TI AM62L CPSW (Common Platform Ethernet Switch) driver. + Uses the TI AM62L PKTDMA driver for DMA-based packet transmission + and reception. Requires the MDIO subsystem for PHY management via + the CPSW MDIO controller if Ethernet PHY(s) is(are) used with CPSW + MAC Ports. + +if ETH_TI_AM62L_CPSW + +config ETH_TI_AM62L_CPSW_TX_DESC_NUM + int "TX descriptor count" + default 128 + help + Number of TX descriptors + +config ETH_TI_AM62L_CPSW_RX_DESC_NUM + int "RX descriptor count" + default 128 + help + Number of RX descriptors + +config ETH_TI_AM62L_CPSW_TX_THREAD_STACK_SIZE + int "TX completion thread stack size" + default 2048 + help + TX completion thread stack size + +config ETH_TI_AM62L_CPSW_RX_THREAD_STACK_SIZE + int "RX thread stack size" + default 2048 + help + RX thread stack size + +config ETH_TI_AM62L_TX_THREAD_PRIO + int "TX completion thread priority" + default 2 + help + TX completion thread priority + +config ETH_TI_AM62L_RX_THREAD_PRIO + int "RX thread priority" + default 2 + help + RX thread priority + +config ETH_TI_AM62L_CPSW_TX_BUDGET + int "TX completion budget" + default 64 + help + Number of TX completions processed before yielding + +config ETH_TI_AM62L_CPSW_RX_BUDGET + int "RX budget" + default 64 + help + Number of packets received before yielding + +config ETH_TI_AM62L_CPSW_TX_DESC_ACQUIRE_TIMEOUT + int "TX descriptior acquire timeout" + default 100 + help + Timeout in milliseconds for acquiring a TX descriptor + +endif #ETH_TI_AM62L_CPSW diff --git a/drivers/ethernet/eth_ti_am62l_cpsw.c b/drivers/ethernet/eth_ti_am62l_cpsw.c new file mode 100644 index 000000000000..461498accbcd --- /dev/null +++ b/drivers/ethernet/eth_ti_am62l_cpsw.c @@ -0,0 +1,1518 @@ +/* TI AM62L CPSW3G Ethernet driver + * + * Copyright (c) 2026 Texas Instruments Incorporated + * Author: Siddharth Vadapalli + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_am62l_cpsw + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(eth_ti_am62l_cpsw, CONFIG_ETHERNET_LOG_LEVEL); + +#include "eth_ti_am62l_cpsw.h" + +BUILD_ASSERT(CONFIG_NET_BUF_DATA_SIZE >= CPSW_MIN_PACKET_SIZE, + "CONFIG_NET_BUF_DATA_SIZE must be >= CPSW_MIN_PACKET_SIZE (64) " + "for TX padding"); +BUILD_ASSERT(CPSW_RX_DESC_NUM >= CPSW_RX_MAX_SG_FRAGS, + "CPSW_RX_DESC_NUM must be >= CPSW_RX_MAX_SG_FRAGS " + " for RX scatter-gather"); + +/* Register offset in bytes between subsequent GMII registers */ +#define CPSW_GMII_SEL_REG_OFFSET 4U + +/* Register offset in bytes between MAC Low and MAC High registers */ +#define CPSW_MAC_LO_MAC_HI_OFFSET 4U + +static const uint32_t cpsw_port_bases[CPSW_NUM_MAC_PORTS] = { + CPSW_PORT1_BASE, + CPSW_PORT2_BASE, +}; + +static const uint32_t cpsw_ale_portctls[CPSW_NUM_MAC_PORTS] = { + ALE_PORTCTL1, + ALE_PORTCTL2, +}; + +/** + * @brief Per-MAC-port configuration resolved from Device Tree at build time + * + * @param phy_dev PHY device for this MAC port + * @param phy_conn_type PHY connection type resolved at compile time from DT + * @param port_num MAC Port number (1-based) + * @param mac_only MAC Only mode, port does not participate in L2 switching + * @param mac_cfg MAC address configuration (static, random, or eFuse) + */ +struct cpsw_port_dt_config { + const struct device *phy_dev; + enum cpsw_phy_conn_type phy_conn_type; + uint8_t port_num; + bool mac_only; + struct net_eth_mac_config mac_cfg; +}; + +/** + * @brief CPSW NUSS Device configuration from Device Tree + * + * @param DEVICE_MMIO_ROM physical address and size of the CPSW NU Subsystem + * register region. Must be the first member. + * @param gmii_sel DEVICE_MMIO_NAMED_ROM for "gmii_sel": physical address and + * size of the GMII configuration CTRL MMR registers. + * @param mac_efuse DEVICE_MMIO_NAMED_ROM for "mac_efuse": physical address and + * size of the eFuse register holding MAC Address for MAC Port 1. + * @param pktdma_dev Pointer to the PKTDMA device used by CPSW + * @param tx_chan_id Transmit DMA Channel ID (transmit packets to CPSW) + * @param rx_chan_id Receive DMA Channel ID (receive packets from CPSW) + * @param tx_asel ASEL value associated with the transmit DMA Channel + * @param rx_asel ASEL value associated with the receive DMA Channel + * @param port Per-MAC-port configuration, indexed by (port_num - 1) + */ +struct cpsw_dt_config { + DEVICE_MMIO_ROM; + DEVICE_MMIO_NAMED_ROM(gmii_sel); + DEVICE_MMIO_NAMED_ROM(mac_efuse); + const struct device *pktdma_dev; + uint32_t tx_chan_id; + uint32_t rx_chan_id; + uint8_t tx_asel; + uint8_t rx_asel; + struct cpsw_port_dt_config port[CPSW_NUM_MAC_PORTS]; +}; + +/** + * @brief Get 0-based port index for the given network interface + * + * @param priv Driver private data + * @param iface Network interface to look up + * @retval 0-based port index (0 for MAC Port 1, 1 for MAC Port 2) + */ +static inline int cpsw_port_idx(const struct cpsw_priv *priv, + const struct net_if *iface) +{ + if (priv->iface[0] == iface) { + return 0; + } + + /* + * Since there are only two MAC Ports, the interface must be + * that of the second MAC Port. + */ + return 1; +} + + +/** + * @brief Prepare a TX CPPI5 host descriptor + * + * @param tx_desc Pointer to the descriptor to fill + * @param buf_phys Physical address of the packet data buffer + * @param pkt_len Length of the packet in bytes + * @param port_id CPSW MAC port index to transmit the packet on + * @param asel Address Select value for IO Coherency + * @param tx_chan_id Transmit DMA Channel ID + */ +static void cppi5_fill_tx_desc(struct cppi5_host_desc *tx_desc, + uintptr_t buf_phys, uint32_t pkt_len, + uint8_t port_id, uint8_t asel, + uint32_t tx_chan_id) +{ + memset(tx_desc, 0, CPPI5_DESC_SIZE); + + /* Word 0: descriptor type, EPIB present, PSD=16 bytes, packet length */ + tx_desc->pkt_info0 = CPPI5_INFO0_HDESC_TYPE_HOST | + CPPI5_INFO0_HDESC_EPIB_PRESENT | + FIELD_PREP(CPPI5_INFO0_HDESC_PSFLGS_MASK, + CPPI5_PSD_SIZE_CPSW >> 2) | + (pkt_len & CPPI5_INFO0_HDESC_PKTLEN_MASK); + + /* Word 1: transmit flow index */ + tx_desc->pkt_info1 = CPPI5_INFO1_HDESC_FLOW_ID; + + /* Word 2: packet type, return queue */ + tx_desc->pkt_info2 = FIELD_PREP(CPPI5_INFO2_HDESC_PKTTYPE_MASK, + CPPI5_INFO2_HDESC_PKTTYPE_CPSW) | + (tx_chan_id & CPPI5_INFO2_HDESC_RETQ_MASK); + + /* Word 3: destination tag = MAC port index. */ + tx_desc->src_dst_tag = (port_id & CPPI5_TAG_DSTTAG_MASK); + + /* Words 6-7: buffer pointer with ASEL added to bits 48-51 */ + tx_desc->buf_ptr = (uint64_t)buf_phys | + FIELD_PREP(AM62L_ADDRESS_ASEL_MASK, (uint64_t)asel); + + /* Word 8: buffer length = packet length. */ + tx_desc->buf_len = pkt_len; + + /* sw_data[0-7]: original buffer pointer (set lower 32 bits, higher bits = 0) */ + tx_desc->sw_data[0] = FIELD_GET(GENMASK(7, 0), buf_phys); + tx_desc->sw_data[1] = FIELD_GET(GENMASK(15, 8), buf_phys); + tx_desc->sw_data[2] = FIELD_GET(GENMASK(23, 16), buf_phys); + tx_desc->sw_data[3] = FIELD_GET(GENMASK(31, 24), buf_phys); +} + +/** + * @brief Prepare a CPPI5 buffer descriptor for TX Scatter Gather + * + * @param desc Pointer to the descriptor to fill + * @param buf_phys Physical address of the fragment's data buffer + * @param buf_len Length of the fragment in bytes + * @param next_desc_phys Physical address of the next descriptor in the chain + * (0 for the final fragment) + * @param asel Address Select value for IO Coherency + */ +static void cppi5_fill_buf_desc(struct cppi5_host_desc *desc, + uintptr_t buf_phys, uint32_t buf_len, + uint64_t next_desc_phys, uint8_t asel) +{ + memset(desc, 0, CPPI5_DESC_SIZE); + + /* Word 0: descriptor type + buffer length */ + desc->pkt_info0 = CPPI5_INFO0_HDESC_TYPE_HOST | + (buf_len & CPPI5_INFO0_HDESC_PKTLEN_MASK); + + /* Words 4-5: link to the next descriptor in the chain (or null) */ + desc->next_desc = next_desc_phys; + + /* Words 6-7: buffer pointer with ASEL added to bits 48-51 */ + desc->buf_ptr = (uint64_t)buf_phys | + FIELD_PREP(AM62L_ADDRESS_ASEL_MASK, (uint64_t)asel); + + /* Word 8: buffer length */ + desc->buf_len = buf_len; +} + +/** + * @brief Prepare an RX CPPI5 host descriptor for the free-descriptor ring + * + * @param rx_desc Pointer to the descriptor to fill + * @param buf_phys Physical address of the receive buffer + * @param buf_size Size of the receive buffer in bytes + * @param asel Address Select value for IO Coherency + */ +static void cppi5_fill_rx_desc(struct cppi5_host_desc *rx_desc, + uintptr_t buf_phys, uint32_t buf_size, + uint8_t asel) +{ + memset(rx_desc, 0, CPPI5_DESC_SIZE); + + /* Word 0: descriptor type, buffer size (overwritten by DMA on completion) */ + rx_desc->pkt_info0 = CPPI5_INFO0_HDESC_TYPE_HOST | + (buf_size & CPPI5_INFO0_HDESC_PKTLEN_MASK); + + /* Words 6-7: receive buffer pointer with ASEL in bits 48-51 */ + rx_desc->buf_ptr = (uint64_t)buf_phys | + FIELD_PREP(AM62L_ADDRESS_ASEL_MASK, (uint64_t)asel); + + /* Word 8: buffer length */ + rx_desc->buf_len = buf_size; +} + +/** + * @brief Reset a CPSW MAC port + * + * @param priv Driver private data + * @param port_base_ofs Offset of the MAC Port base register region + * @retval 0 on success, -ETIMEDOUT on reset timeout + */ +static int cpsw_macsl_reset(struct cpsw_priv *priv, uint32_t port_base_ofs) +{ + uint32_t macsl_base = port_base_ofs + CPSW_MACSL_OFS; + + cpsw_write(priv, macsl_base + CPSW_MACSL_RESET_REG, MACSL_RESET_BIT); + + for (int i = 0; i < CPSW_MAC_RESET_MAX_RETRIES; i++) { + if (!(cpsw_read(priv, macsl_base + CPSW_MACSL_RESET_REG) & + MACSL_RESET_BIT)) { + return 0; + } + k_busy_wait(CPSW_POLL_INTERVAL_US); + } + + LOG_ERR("MAC Port reset timeout"); + return -ETIMEDOUT; +} + +/** + * @brief TX completion DMA callback + * + * @param dma_dev PKTDMA device (unused) + * @param user_data CPSW device pointer + * @param channel PKTDMA channel number (unused) + * @param status DMA completion status (unused) + */ +static void cpsw_tx_dma_cb(const struct device *dma_dev, void *user_data, + uint32_t channel, int status) +{ + const struct device *dev = user_data; + struct cpsw_priv *priv = dev->data; + + ARG_UNUSED(dma_dev); + ARG_UNUSED(channel); + ARG_UNUSED(status); + + k_sem_give(&priv->dma.tx_compl_sem); +} + +/** + * @brief RX completion DMA callback + * + * @param dma_dev PKTDMA device (unused) + * @param user_data CPSW device pointer + * @param channel PKTDMA channel number (unused) + * @param status DMA completion status (unused) + */ +static void cpsw_rx_dma_cb(const struct device *dma_dev, void *user_data, + uint32_t channel, int status) +{ + const struct device *dev = user_data; + struct cpsw_priv *priv = dev->data; + + ARG_UNUSED(dma_dev); + ARG_UNUSED(channel); + ARG_UNUSED(status); + + k_sem_give(&priv->dma.rx_avail_sem); +} + +/** + * @brief Configure CPSW's PKTDMA channels for TX and RX + * + * @param priv Driver private data + * @retval 0 on success, negative errno on failure + */ +static int cpsw_pktdma_setup(struct cpsw_priv *priv) +{ + const struct cpsw_dt_config *config = priv->dev->config; + struct cpsw_pktdma *dma = &priv->dma; + struct net_buf *frag; + uintptr_t buf_phys; + int ret; + + /* + * Initialize interrupt-driven completion semaphores: + * For TX, all TX Descriptors are initially unused and therefore free. + * For RX, all RX Descriptors have been submitted to DMA and we do not + * have any of them available (0). + */ + k_sem_init(&dma->tx_free_sem, CPSW_TX_DESC_NUM, CPSW_TX_DESC_NUM); + k_sem_init(&dma->tx_compl_sem, 0, CPSW_TX_DESC_NUM); + k_sem_init(&dma->rx_avail_sem, 0, CPSW_RX_DESC_NUM); + + struct ti_pktdma_chan_cfg tx_chan_cfg = { + .fwd_ring_mem = (uintptr_t)dma->tx_ring_mem, + /* Completions are written back to the same ring */ + .rev_ring_mem = (uintptr_t)dma->tx_ring_mem, + .ring_cnt = CPSW_TX_DESC_NUM, + .asel = config->tx_asel, + .cb_user_data = priv->dev, + }; + struct dma_config tx_dma_cfg = { + .channel_direction = MEMORY_TO_PERIPHERAL, + .user_data = &tx_chan_cfg, + .dma_callback = cpsw_tx_dma_cb, + }; + + struct ti_pktdma_chan_cfg rx_chan_cfg = { + .fwd_ring_mem = (uintptr_t)dma->rx_ring_mem, + .rev_ring_mem = (uintptr_t)dma->rx_ring_mem, + .ring_cnt = CPSW_RX_DESC_NUM, + .asel = config->rx_asel, + .cb_user_data = priv->dev, + }; + struct dma_config rx_dma_cfg = { + .channel_direction = PERIPHERAL_TO_MEMORY, + .user_data = &rx_chan_cfg, + .dma_callback = cpsw_rx_dma_cb, + }; + + ret = dma_config(config->pktdma_dev, config->tx_chan_id, &tx_dma_cfg); + if (ret < 0) { + LOG_ERR("TX dma_config failed: %d", ret); + return ret; + } + + ret = dma_start(config->pktdma_dev, config->tx_chan_id); + if (ret < 0) { + LOG_ERR("TX dma_start failed: %d", ret); + return ret; + } + + ret = dma_config(config->pktdma_dev, config->rx_chan_id, &rx_dma_cfg); + if (ret < 0) { + LOG_ERR("RX dma_config failed: %d", ret); + return ret; + } + + ret = dma_start(config->pktdma_dev, config->rx_chan_id); + if (ret < 0) { + LOG_ERR("RX dma_start failed: %d", ret); + return ret; + } + + /* + * Push all RX descriptors to the RX Free Descriptor ring to allow + * PKTDMA to send the packets received from CPSW to Software + */ + for (int i = 0; i < CPSW_RX_DESC_NUM; i++) { + frag = net_pkt_get_reserve_rx_data(CPSW_RX_BUF_SIZE, K_NO_WAIT); + + if (frag == NULL) { + LOG_ERR("RX: failed to alloc frag[%d]", i); + for (int j = 0; j < i; j++) { + net_pkt_frag_unref(dma->rx_frags[j]); + dma->rx_frags[j] = NULL; + } + return -ENOMEM; + } + + dma->rx_frags[i] = frag; + buf_phys = (uintptr_t)frag->data; + + if (!AM62L_PKTDMA_IS_COHERENT(config->rx_asel)) { + sys_cache_data_invd_range(frag->data, CPSW_RX_BUF_SIZE); + } + cppi5_fill_rx_desc(&dma->rx_descs[i], buf_phys, + CPSW_RX_BUF_SIZE, config->rx_asel); + if (!AM62L_PKTDMA_IS_COHERENT(config->rx_asel)) { + sys_cache_data_flush_range(&dma->rx_descs[i], CPPI5_DESC_SIZE); + } + + ret = dma_reload(config->pktdma_dev, config->rx_chan_id, + 0U, (uintptr_t)&dma->rx_descs[i], 0U); + if (ret < 0) { + LOG_ERR("RX dma_reload[%d] failed: %d", i, ret); + for (int j = 0; j <= i; j++) { + net_pkt_frag_unref(dma->rx_frags[j]); + dma->rx_frags[j] = NULL; + } + return ret; + } + } + + dma->initialized = true; + LOG_DBG("PKTDMA: TX chan %u and RX chan %u configured", + config->tx_chan_id, config->rx_chan_id); + + return 0; +} + +/** + * @brief PHY link state-change callback, shared by all MAC ports + * + * @param phy_dev PHY device that generated the callback (unused) + * @param state Current link state (speed, duplex, is_up) + * @param user_data Pointer to network interface for the corresponding MAC port + */ +static void cpsw_phy_link_cb(const struct device *phy_dev, + struct phy_link_state *state, + void *user_data) +{ + struct net_if *iface = user_data; + const struct device *dev = net_if_get_device(iface); + struct cpsw_priv *priv = dev->data; + int ret, idx = cpsw_port_idx(priv, iface); + uint32_t port_base, macsl_ctl; + + ARG_UNUSED(phy_dev); + + if (idx < 0) { + LOG_WRN("PHY callback for unknown iface, ignoring"); + return; + } + + port_base = cpsw_port_bases[idx]; + + if (!state->is_up) { + net_eth_carrier_off(iface); + return; + } + + ret = cpsw_macsl_reset(priv, CPSW_NU_BASE + port_base); + if (ret < 0) { + LOG_ERR("MAC port %u reset failed: %d", (uint32_t)(idx + 1), ret); + } + + macsl_ctl = MACSL_CTL_GMII_EN; + + if (PHY_LINK_IS_FULL_DUPLEX(state->speed)) { + macsl_ctl |= MACSL_CTL_FULL_DUPLEX; + } + + if (PHY_LINK_IS_SPEED_1000M(state->speed)) { + macsl_ctl |= MACSL_CTL_GIG; + } + + cpsw_write(priv, + CPSW_NU_BASE + port_base + CPSW_MACSL_OFS + + CPSW_MACSL_CTL_REG, + macsl_ctl); + + net_eth_carrier_on(iface); +} + +/** + * @brief Initialize CPSW + * + * @param priv Driver private data + * @retval 0 on success, negative errno on failure + */ +static int cpsw_hw_init(struct cpsw_priv *priv) +{ + const struct cpsw_dt_config *config = priv->dev->config; + uint32_t stat_en = CPSW_NUSS_STAT_P0_EN; + int ret, i; + + /* Initialize PKTDMA channels */ + ret = cpsw_pktdma_setup(priv); + if (ret < 0) { + LOG_ERR("PKTDMA setup failed: %d", ret); + return ret; + } + + /* Enable host port */ + cpsw_write(priv, CPSW_NU_BASE + CPSW_NUSS_CONTROL, + CPSW_NUSS_CTL_P0_ENABLE | + CPSW_NUSS_CTL_P0_TX_CRC_REMOVE | + CPSW_NUSS_CTL_P0_RX_PAD); + + /* Disable priority elevation. */ + cpsw_write(priv, CPSW_NU_BASE + CPSW_NUSS_PTYPE, 0U); + + /* Enable statistics */ + for (i = 0; i < CPSW_NUM_MAC_PORTS; i++) { + stat_en |= BIT(i+1); + } + cpsw_write(priv, CPSW_NU_BASE + CPSW_NUSS_STAT_PORT_EN, stat_en); + + /* Set maximum receive frame length for the host port */ + cpsw_write(priv, CPSW_NU_BASE + CPSW_PORT0_BASE + CPSW_PN_RX_MAXLEN, + CPSW_MAX_PACKET_SIZE); + + /* Set host port RX flow ID base */ + cpsw_write(priv, CPSW_NU_BASE + CPSW_PORT0_BASE + CPSW_P0_FLOW_ID_REG, + config->rx_chan_id); + + /* + * Set max receive frame length, source MAC address, ALE port state + * for the MAC Ports. + */ + for (i = 0; i < CPSW_NUM_MAC_PORTS; i++) { + uint32_t port_base = cpsw_port_bases[i]; + uint32_t sa_l, sa_h; + uint8_t *mac_addr = priv->mac_addr[i]; + + sa_l = ((uint32_t)mac_addr[5] << 0) | ((uint32_t)mac_addr[4] << 8) | + ((uint32_t)mac_addr[3] << 16) | ((uint32_t)mac_addr[2] << 24); + sa_h = ((uint32_t)mac_addr[1] << 0) | ((uint32_t)mac_addr[0] << 8); + + /* RMW isn't required since other fields aren't present in registers */ + cpsw_write(priv, + CPSW_NU_BASE + port_base + CPSW_PN_RX_MAXLEN, + CPSW_MAX_PACKET_SIZE); + cpsw_write(priv, CPSW_NU_BASE + port_base + CPSW_PN_SA_L, + sa_l); + cpsw_write(priv, CPSW_NU_BASE + port_base + CPSW_PN_SA_H, + sa_h); + } + + /* Clear ALE table and enable ALE in bypass mode */ + cpsw_write(priv, CPSW_NU_BASE + CPSW_ALE_BASE + ALE_CONTROL, + ALE_CONTROL_ENABLE | ALE_CONTROL_CLEAR_TBL | + ALE_CONTROL_BYPASS); + + /* Set Host Port ALE state to Forwarding */ + cpsw_write(priv, CPSW_NU_BASE + CPSW_ALE_BASE + ALE_PORTCTL0, + ALE_PORTCTL_FORWARD); + + /* Enable the default ALE thread mapping */ + cpsw_write(priv, CPSW_NU_BASE + CPSW_ALE_BASE + ALE_THREADMAPDEF, + ALE_DEFTHREAD_EN); + + return 0; +} + +/** + * @brief Process a single TX completion + * + * @param dma Pointer to the PKTDMA state + */ +static inline void cpsw_tx_process_one_compl(struct cpsw_pktdma *dma) +{ + uint32_t head_idx = dma->tx_cmpl_head_idxs[dma->tx_cmpl_rptr % + CPSW_TX_DESC_NUM]; + uint32_t slot; + uint8_t num_descs, i; + + dma->tx_cmpl_rptr++; + + if (head_idx >= CPSW_TX_DESC_NUM) { + return; + } + + num_descs = dma->tx_n_descs[head_idx]; + + /* Free all descriptors linked to the head descriptor */ + for (i = 0; i < num_descs; i++) { + slot = (head_idx + i) % CPSW_TX_DESC_NUM; + if (dma->tx_frags[slot] != NULL) { + net_pkt_frag_unref(dma->tx_frags[slot]); + dma->tx_frags[slot] = NULL; + } + k_sem_give(&dma->tx_free_sem); + } +} + +/** + * @brief Process a batch of TX completions + * + * @param priv Driver private data + */ +static inline void cpsw_tx_handle_cmpl_batch(struct cpsw_priv *priv) +{ + struct cpsw_pktdma *dma = &priv->dma; + int count = 0; + + /* Process the completion that woke the thread */ + cpsw_tx_process_one_compl(dma); + count++; + + /* Drain additional completions belonging to the same burst */ + while (count < CPSW_TX_BUDGET && + k_sem_take(&dma->tx_compl_sem, K_NO_WAIT) == 0) { + cpsw_tx_process_one_compl(dma); + count++; + if (count == CPSW_TX_BUDGET) { + k_yield(); + count = 0; + } + } +} + +/** + * @brief TX completion thread + * + * @param arg1 Driver private data + * @param arg2 Unused + * @param arg3 Unused + */ +static void cpsw_tx_cmpl_thread(void *arg1, void *arg2, void *arg3) +{ + struct cpsw_priv *priv = (struct cpsw_priv *)arg1; + const struct cpsw_dt_config *config = priv->dev->config; + struct cpsw_pktdma *dma = &priv->dma; + + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + LOG_DBG("TX completion thread started"); + + while (priv->ports_started != 0U) { + k_sem_take(&dma->tx_compl_sem, K_FOREVER); + + /* Handle completions in a batch until budget limit */ + cpsw_tx_handle_cmpl_batch(priv); + + if (priv->ports_started != 0U) { + dma_resume(config->pktdma_dev, config->tx_chan_id); + } + } + + LOG_DBG("TX completion thread stopped"); +} + +/** + * @brief Refill an RX descriptor slot with a new fragment and resubmit it + * + * @param priv Driver private data + * @param rx_desc Descriptor to refill + * @param idx Index of the descriptor slot in rx_frags[] and rx_descs[] + * @param old_frag Unconsumed fragment to reuse if allocating a new one fails, + * or NULL if the fragment was handed to the network stack + */ +static inline void cpsw_rx_refill_desc(struct cpsw_priv *priv, + struct cppi5_host_desc *rx_desc, + uint32_t idx, + struct net_buf *old_frag) +{ + const struct cpsw_dt_config *config = priv->dev->config; + struct cpsw_pktdma *dma = &priv->dma; + struct net_buf *new_frag; + + new_frag = net_pkt_get_reserve_rx_data(CPSW_RX_BUF_SIZE, K_NO_WAIT); + if (new_frag == NULL) { + new_frag = old_frag; + old_frag = NULL; + } + + if (new_frag != NULL) { + if (!AM62L_PKTDMA_IS_COHERENT(config->rx_asel)) { + sys_cache_data_invd_range(new_frag->data, CPSW_RX_BUF_SIZE); + } + dma->rx_frags[idx] = new_frag; + cppi5_fill_rx_desc(rx_desc, (uintptr_t)new_frag->data, + CPSW_RX_BUF_SIZE, config->rx_asel); + if (!AM62L_PKTDMA_IS_COHERENT(config->rx_asel)) { + sys_cache_data_flush_range(rx_desc, CPPI5_DESC_SIZE); + } + dma_reload(config->pktdma_dev, config->rx_chan_id, + 0U, (uintptr_t)rx_desc, 0U); + } else { + LOG_ERR("RX: out of buffers, descriptor slot lost"); + } + + if (old_frag != NULL) { + net_pkt_frag_unref(old_frag); + } +} + +/** + * @brief Process a single RX packet completion (scatter-gather) + * + * @param priv Driver private data + */ +static inline void cpsw_rx_process_one_pkt(struct cpsw_priv *priv) +{ + const struct cpsw_dt_config *config = priv->dev->config; + struct cpsw_pktdma *dma = &priv->dma; + struct cppi5_host_desc *rx_desc; + struct net_if *rx_iface; + struct net_pkt *pkt; + struct net_buf *frag; + uint64_t next; + uint32_t src_port, pkt_len, frag_len, idx; + uint8_t n_frags = 0; + + idx = dma->rx_drain_idx % CPSW_RX_DESC_NUM; + rx_desc = &dma->rx_descs[idx]; + + if (!AM62L_PKTDMA_IS_COHERENT(config->rx_asel)) { + sys_cache_data_invd_range(rx_desc, CPPI5_DESC_SIZE); + } + + pkt_len = rx_desc->pkt_info0 & CPPI5_INFO0_HDESC_PKTLEN_MASK; + src_port = FIELD_GET(CPPI5_TAG_SRCTAG_PORT_MASK, rx_desc->src_dst_tag); + + if (src_port >= 1U && src_port <= CPSW_NUM_MAC_PORTS && + priv->iface[src_port - 1] != NULL) { + rx_iface = priv->iface[src_port - 1]; + } else { + rx_iface = priv->iface[0]; + LOG_WRN("RX: unexpected src_port=%u", src_port); + } + + if (pkt_len == 0U || pkt_len > CPSW_MAX_PACKET_SIZE) { + LOG_WRN("RX: invalid pkt_len=%u, dropping", pkt_len); + goto drop; + } + + pkt = net_pkt_rx_alloc_on_iface(rx_iface, K_NO_WAIT); + if (pkt == NULL) { + LOG_ERR("RX: failed to alloc net_pkt"); + goto drop; + } + + do { + rx_desc = &dma->rx_descs[idx]; + if (!AM62L_PKTDMA_IS_COHERENT(config->rx_asel) && n_frags > 0) { + sys_cache_data_invd_range(rx_desc, CPPI5_DESC_SIZE); + } + + next = rx_desc->next_desc; + frag_len = rx_desc->buf_len; + frag = dma->rx_frags[idx]; + dma->rx_frags[idx] = NULL; + + if (!AM62L_PKTDMA_IS_COHERENT(config->rx_asel)) { + sys_cache_data_invd_range(frag->data, frag_len); + } + frag->len = frag_len; + net_pkt_frag_add(pkt, frag); + cpsw_rx_refill_desc(priv, rx_desc, idx, NULL); + + n_frags++; + idx = (idx + 1U) % CPSW_RX_DESC_NUM; + } while (next != 0ULL && n_frags < CPSW_RX_MAX_SG_FRAGS); + + dma->rx_drain_idx += n_frags; + + LOG_DBG("RX: %u bytes, %u frag(s) (port %u)", pkt_len, n_frags, src_port); + if (net_recv_data(rx_iface, pkt) < 0) { + net_pkt_unref(pkt); + } + return; + +drop: + do { + rx_desc = &dma->rx_descs[idx]; + if (!AM62L_PKTDMA_IS_COHERENT(config->rx_asel) && n_frags > 0) { + sys_cache_data_invd_range(rx_desc, CPPI5_DESC_SIZE); + } + + next = rx_desc->next_desc; + frag = dma->rx_frags[idx]; + dma->rx_frags[idx] = NULL; + cpsw_rx_refill_desc(priv, rx_desc, idx, frag); + + n_frags++; + idx = (idx + 1U) % CPSW_RX_DESC_NUM; + } while (next != 0ULL && n_frags < CPSW_RX_MAX_SG_FRAGS); + + dma->rx_drain_idx += n_frags; +} + +/** + * @brief Process a batch of RX completions + * + * @param priv Driver private data + */ +static inline void cpsw_rx_handle_batch(struct cpsw_priv *priv) +{ + struct cpsw_pktdma *dma = &priv->dma; + int count = 0; + + /* Process the completion that woke the thread */ + cpsw_rx_process_one_pkt(priv); + count++; + + /* Drain any additional completions belonging to the same burst */ + while (count < CPSW_RX_BUDGET && + k_sem_take(&dma->rx_avail_sem, K_NO_WAIT) == 0) { + cpsw_rx_process_one_pkt(priv); + count++; + if (count == CPSW_RX_BUDGET) { + k_yield(); + count = 0; + } + } +} + +/** + * @brief RX completion thread + * + * @param arg1 Driver private data + * @param arg2 Unused + * @param arg3 Unused + */ +static void cpsw_rx_thread(void *arg1, void *arg2, void *arg3) +{ + struct cpsw_priv *priv = (struct cpsw_priv *)arg1; + const struct cpsw_dt_config *config = priv->dev->config; + + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + LOG_DBG("RX thread started"); + + while (priv->ports_started != 0U) { + k_sem_take(&priv->dma.rx_avail_sem, K_FOREVER); + + cpsw_rx_handle_batch(priv); + + if (priv->ports_started != 0U) { + dma_resume(config->pktdma_dev, config->rx_chan_id); + } + } + + LOG_DBG("RX thread stopped"); +} + +/** + * @brief Count the non-empty fragments in a TX packet + * + * @param pkt Packet to be transmitted + * @retval Number of fragments in the packet + */ +static uint8_t cpsw_tx_count_frags(const struct net_pkt *pkt) +{ + uint8_t n = 0; + + NET_PKT_FRAG_FOR_EACH(pkt, frag) { + if (frag->len > 0) { + n++; + } + } + return n; +} + +/** + * @brief Acquire TX descriptor slots + * + * @param dma Pointer to the PKTDMA state + * @param priv Driver private data + * @param n_descs Number of descriptors to acquire + * @retval 0 on success, -ENOBUFS on timeout + */ +static int cpsw_tx_acquire_descs(struct cpsw_pktdma *dma, struct cpsw_priv *priv, + uint8_t n_descs) +{ + uint8_t i; + + for (i = 0; i < n_descs; i++) { + if (k_sem_take(&dma->tx_free_sem, + K_MSEC(CPSW_TX_DESC_ACQUIRE_TIMEOUT_MS)) != 0) { + for (uint8_t j = 0; j < i; j++) { + k_sem_give(&dma->tx_free_sem); + } + LOG_ERR("TX: no free slots (need %u)", n_descs); + return -ENOBUFS; + } + } + + if (k_mutex_lock(&priv->tx_lock, + K_MSEC(CPSW_TX_DESC_ACQUIRE_TIMEOUT_MS)) != 0) { + for (i = 0; i < n_descs; i++) { + k_sem_give(&dma->tx_free_sem); + } + LOG_ERR("TX: tx_lock timeout"); + return -ENOBUFS; + } + + return 0; +} + +/** + * @brief Build the CPPI5 descriptor chain for a TX packet + * + * @param dev CPSW device pointer + * @param head_idx Index of the Head Descriptor pointing to start of packet + * @param pkt Pointer to the packet to be transmitted + * @param pkt_len Length of the packet to be transmitted + * @param port_num 1-based MAC Port number + * @param n_descs Number of descriptors required by the packet + */ +static void cpsw_tx_fill_chain(const struct device *dev, uint32_t head_idx, + struct net_pkt *pkt, uint16_t pkt_len, + uint8_t port_num, uint8_t n_descs) +{ + const struct cpsw_dt_config *config = dev->config; + struct cpsw_priv *priv = dev->data; + struct cpsw_pktdma *dma = &priv->dma; + struct cppi5_host_desc *desc; + uint64_t next_phys; + uint32_t desc_idx, nxt; + uint8_t i = 0; + + desc_idx = head_idx; + + NET_PKT_FRAG_FOR_EACH(pkt, frag) { + if (frag->len == 0) { + continue; + } + + bool is_last = (i == n_descs - 1U); + uint16_t pad_len = (is_last && pkt_len < CPSW_MIN_PACKET_SIZE) ? + (CPSW_MIN_PACKET_SIZE - pkt_len) : 0U; + uint32_t buf_len = frag->len + pad_len; + + next_phys = 0; + if (!is_last) { + nxt = (desc_idx + 1U) % CPSW_TX_DESC_NUM; + next_phys = (uint64_t)(uintptr_t)&dma->tx_descs[nxt] | + FIELD_PREP(AM62L_ADDRESS_ASEL_MASK, + (uint64_t)config->tx_asel); + } + + if (pad_len > 0U) { + memset(frag->data + frag->len, 0, pad_len); + } + + desc = &dma->tx_descs[desc_idx]; + if (i == 0) { + cppi5_fill_tx_desc(desc, (uintptr_t)frag->data, + buf_len, port_num, + config->tx_asel, config->tx_chan_id); + desc->pkt_info0 = + (desc->pkt_info0 & ~CPPI5_INFO0_HDESC_PKTLEN_MASK) | + (MAX(pkt_len, CPSW_MIN_PACKET_SIZE) + & CPPI5_INFO0_HDESC_PKTLEN_MASK); + desc->next_desc = next_phys; + } else { + cppi5_fill_buf_desc(desc, (uintptr_t)frag->data, + buf_len, next_phys, + config->tx_asel); + } + + if (!AM62L_PKTDMA_IS_COHERENT(config->tx_asel)) { + sys_cache_data_flush_range(frag->data, buf_len); + sys_cache_data_flush_range(desc, CPPI5_DESC_SIZE); + } + + net_pkt_frag_ref(frag); + dma->tx_frags[desc_idx] = frag; + + desc_idx = (desc_idx + 1U) % CPSW_TX_DESC_NUM; + i++; + } +} + +/** + * @brief Free descriptors in a descriptor chain + * + * @param dma Pointer to the PKTDMA state + * @param head_idx Index of the Head descriptor pointing to the start of the packet + * @param n_descs Number of descriptors in the descriptor chain + */ +static void cpsw_tx_release_chain(struct cpsw_pktdma *dma, uint32_t head_idx, + uint8_t n_descs) +{ + for (uint8_t i = 0; i < n_descs; i++) { + uint32_t slot = (head_idx + i) % CPSW_TX_DESC_NUM; + + if (dma->tx_frags[slot] != NULL) { + net_pkt_frag_unref(dma->tx_frags[slot]); + dma->tx_frags[slot] = NULL; + } + k_sem_give(&dma->tx_free_sem); + } +} + +/** + * @brief Transmit a packet via CPSW + * + * @param dev CPSW device pointer + * @param pkt Pointer to the packet to transmit + * @retval 0 on success, negative errno on failure + */ +static int cpsw_tx(const struct device *dev, struct net_pkt *pkt) +{ + const struct cpsw_dt_config *config = dev->config; + struct cpsw_priv *priv = dev->data; + struct cpsw_pktdma *dma = &priv->dma; + uint32_t head_idx; + uint16_t pkt_len; + uint8_t port_num, n_frags, n_descs; + int i, ret; + + i = cpsw_port_idx(priv, net_pkt_iface(pkt)); + if (i < 0 || !(priv->ports_started & BIT(i)) || !dma->initialized) { + return -ENETDOWN; + } + + pkt_len = net_pkt_get_len(pkt); + port_num = (uint8_t)(i + 1); + + n_frags = cpsw_tx_count_frags(pkt); + if (n_frags == 0) { + LOG_ERR("TX: packet has no data"); + return -EINVAL; + } + + n_descs = n_frags; + + ret = cpsw_tx_acquire_descs(dma, priv, n_descs); + if (ret < 0) { + return ret; + } + + head_idx = dma->tx_head % CPSW_TX_DESC_NUM; + cpsw_tx_fill_chain(dev, head_idx, pkt, pkt_len, port_num, n_descs); + dma->tx_n_descs[head_idx] = n_descs; + + ret = dma_reload(config->pktdma_dev, config->tx_chan_id, + (uintptr_t)&dma->tx_descs[head_idx], 0U, 0U); + if (ret < 0) { + LOG_ERR("TX: dma_reload failed: %d", ret); + cpsw_tx_release_chain(dma, head_idx, n_descs); + } else { + dma->tx_cmpl_head_idxs[dma->tx_cmpl_wptr % CPSW_TX_DESC_NUM] = head_idx; + dma->tx_cmpl_wptr++; + LOG_DBG("TX: %u bytes queued", + MAX(pkt_len, CPSW_MIN_PACKET_SIZE)); + dma->tx_head += n_descs; + } + + k_mutex_unlock(&priv->tx_lock); + return ret; +} + +/** + * @brief Program the GMII_SEL MMR register for a MAC Port based on requested + * PHY Connection Type + * + * @param port_cfg Per-port configuration containing phy_conn_type + * @param gmii_sel_virt Virtual address of this port's GMII_SEL register + */ +static void cpsw_gmii_sel_set(const struct cpsw_port_dt_config *port_cfg, + mm_reg_t gmii_sel_virt) +{ + uint32_t reg, mode_val, rgmii_id = 0U; + + switch (port_cfg->phy_conn_type) { + case CPSW_PHY_CONN_RMII: + mode_val = GMII_SEL_MODE_RMII; + break; + case CPSW_PHY_CONN_RGMII_ID: + case CPSW_PHY_CONN_RGMII_TXID: + /* + * MAC Port has to add a delay for RGMII_ID and RGMII_TX_ID + * modes. A delay is added when 'RGMII_ID' field of the + * register is 'cleared', we have to set it to '0'. + */ + mode_val = GMII_SEL_MODE_RGMII; + break; + case CPSW_PHY_CONN_RGMII: + case CPSW_PHY_CONN_RGMII_RXID: + mode_val = GMII_SEL_MODE_RGMII; + /* Do not add a delay */ + rgmii_id = GMII_SEL_RGMII_ID_BIT; + break; + default: + LOG_WRN("Unsupported phy_conn_type: %d", port_cfg->phy_conn_type); + return; + } + + reg = sys_read32(gmii_sel_virt); + reg &= ~(GMII_SEL_MODE_MASK | GMII_SEL_RGMII_ID_BIT); + reg |= (mode_val & GMII_SEL_MODE_MASK) | rgmii_id; + sys_write32(reg, gmii_sel_virt); + + LOG_DBG("MAC port %u: GMII_SEL @0x%08lx = 0x%08x", + port_cfg->port_num, (unsigned long)gmii_sel_virt, reg); +} + +/** + * @brief Start the CPSW network interface for the MAC Port + * + * @param dev CPSW device pointer + * @param iface Network interface pointer + * @retval 0 on success, negative errno on failure + */ +static int cpsw_start(const struct device *dev, struct net_if *iface) +{ + const struct cpsw_dt_config *config = dev->config; + struct cpsw_priv *priv = dev->data; + int ret, i = cpsw_port_idx(priv, iface); + uint8_t port_num; + + if (i < 0) { + return -EINVAL; + } + + port_num = (uint8_t)(i + 1); + + k_mutex_lock(&priv->start_lock, K_FOREVER); + + /* + * First port to start initialises the shared hardware i.e. + * setup DMA Channels, configure ALE and Host Port, and create + * completion threads. Subsequent ports will skip this setup. + */ + if (priv->ports_started == 0U) { + LOG_DBG("Starting CPSW shared hardware"); + + ret = cpsw_hw_init(priv); + if (ret < 0) { + k_mutex_unlock(&priv->start_lock); + LOG_ERR("HW init failed: %d", ret); + return ret; + } + + priv->ports_started |= BIT(i); + + priv->tx_tid = k_thread_create(&priv->tx_thread, + priv->tx_stack, + CPSW_TX_THREAD_STACK_SIZE, + cpsw_tx_cmpl_thread, + priv, NULL, NULL, + CPSW_TX_THREAD_PRIORITY, + 0, K_NO_WAIT); + k_thread_name_set(priv->tx_tid, "cpsw_tx"); + + priv->rx_tid = k_thread_create(&priv->rx_thread, + priv->rx_stack, + CPSW_RX_THREAD_STACK_SIZE, + cpsw_rx_thread, + priv, NULL, NULL, + CPSW_RX_THREAD_PRIORITY, + 0, K_NO_WAIT); + k_thread_name_set(priv->rx_tid, "cpsw_rx"); + + dma_resume(config->pktdma_dev, config->tx_chan_id); + dma_resume(config->pktdma_dev, config->rx_chan_id); + } else { + priv->ports_started |= BIT(i); + } + + k_mutex_unlock(&priv->start_lock); + + /* Program the GMII_SEL register with the phy connection type from DT */ + cpsw_gmii_sel_set(&config->port[i], + priv->gmii_sel_base + ((uint8_t)i * CPSW_GMII_SEL_REG_OFFSET)); + + /* Set MAC Port's ALE state to forwarding and set MAC Only mode based on DT */ + cpsw_write(priv, CPSW_NU_BASE + CPSW_ALE_BASE + cpsw_ale_portctls[i], + ALE_PORTCTL_FORWARD | + (config->port[i].mac_only ? ALE_PORTCTL_MAC_ONLY : 0U)); + + LOG_DBG("Started MAC port %u", port_num); + + return 0; +} + +/** + * @brief Stop the CPSW network interface + * + * @param dev CPSW device pointer + * @param iface Network interface pointer + * @retval 0 always + */ +static int cpsw_stop(const struct device *dev, struct net_if *iface) +{ + const struct cpsw_dt_config *config = dev->config; + struct cpsw_priv *priv = dev->data; + int i = cpsw_port_idx(priv, iface); + uint8_t port_num; + + /* Exit if port does not exist */ + if (i < 0) { + return 0; + } + + port_num = (uint8_t)(i + 1); + priv->ports_started &= ~BIT(i); + + LOG_DBG("Stopped MAC port %u", port_num); + + /* If other ports are active, shared hardware should remain functional */ + if (priv->ports_started != 0U) { + return 0; + } + + /* + * Stop DMA channels to disable the channel IRQs and prevent + * new callbacks from firing. + */ + dma_stop(config->pktdma_dev, config->tx_chan_id); + dma_stop(config->pktdma_dev, config->rx_chan_id); + + /* Wake the TX and RX completion threads so they can exit their loops */ + k_sem_give(&priv->dma.tx_compl_sem); + k_sem_give(&priv->dma.rx_avail_sem); + + /* Stop receiving wire-side traffic by disabling ALE */ + cpsw_write(priv, CPSW_NU_BASE + CPSW_ALE_BASE + ALE_CONTROL, 0U); + cpsw_write(priv, CPSW_NUSS_CONTROL, 0U); + + /* Allow the RX thread to finish draining existing packets and exit */ + k_sleep(K_MSEC(CPSW_RX_DRAIN_PERIOD_MS)); + + /* Release all RX fragments remaining that aren't drained by the RX thread */ + for (int j = 0; j < CPSW_RX_DESC_NUM; j++) { + if (priv->dma.rx_frags[j] != NULL) { + net_pkt_frag_unref(priv->dma.rx_frags[j]); + priv->dma.rx_frags[j] = NULL; + } + } + + /* Release any TX fragment references not freed via the completion ring */ + for (int j = 0; j < CPSW_TX_DESC_NUM; j++) { + if (priv->dma.tx_frags[j] != NULL) { + net_pkt_frag_unref(priv->dma.tx_frags[j]); + priv->dma.tx_frags[j] = NULL; + } + } + + priv->dma.initialized = false; + + return 0; +} + +/** + * @brief Return the link speeds supported by this CPSW MAC port + * + * @param dev CPSW device pointer + * @param iface Network interface pointer + * @return Bitmask of supported ETHERNET_LINK capabilities + */ +static enum ethernet_hw_caps cpsw_get_capabilities(const struct device *dev, + struct net_if *iface) +{ + const struct cpsw_dt_config *config = dev->config; + struct cpsw_priv *priv = dev->data; + int i = cpsw_port_idx(priv, iface); + + if (i >= 0 && config->port[i].phy_conn_type == CPSW_PHY_CONN_RMII) { + return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE; + } + + /* Default for RGMII */ + return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | + ETHERNET_LINK_1000BASE; +} + +/** + * @brief Handle CPSW network interface configuration commands + * + * @param dev CPSW device pointer + * @param iface Network interface pointer + * @param type Configuration type + * @param config Configuration value + * @retval 0 on success, -ENOTSUP for unsupported types + */ +static int cpsw_set_config(const struct device *dev, + struct net_if *iface, + enum ethernet_config_type type, + const struct ethernet_config *config) +{ + struct cpsw_priv *priv = dev->data; + int i = cpsw_port_idx(priv, iface); + uint32_t sa_l, sa_h; + uint8_t *mac; + + if (i < 0) { + return -EINVAL; + } + + mac = priv->mac_addr[i]; + + if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) { + memcpy(mac, config->mac_address.addr, NET_ETH_ADDR_LEN); + + sa_l = ((uint32_t)mac[5] << 0) | ((uint32_t)mac[4] << 8) | + ((uint32_t)mac[3] << 16) | ((uint32_t)mac[2] << 24); + sa_h = ((uint32_t)mac[1] << 0) | ((uint32_t)mac[0] << 8); + + cpsw_write(priv, + CPSW_NU_BASE + cpsw_port_bases[i] + CPSW_PN_SA_L, + sa_l); + cpsw_write(priv, + CPSW_NU_BASE + cpsw_port_bases[i] + CPSW_PN_SA_H, + sa_h); + + LOG_DBG("MAC port %u address updated", i + 1); + return 0; + } + + return -ENOTSUP; +} + +/** + * @brief Initialize the network interface for CPSW + * + * @param iface The network interface to initialize + */ +static void cpsw_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + const struct cpsw_dt_config *config = dev->config; + const struct cpsw_port_dt_config *port_cfg; + struct cpsw_priv *priv = dev->data; + int i; + + /* Determine which port slot this interface belongs to */ + for (i = 0; i < CPSW_NUM_MAC_PORTS; i++) { + if (priv->iface[i] == NULL) { + break; + } + } + + if (i >= CPSW_NUM_MAC_PORTS) { + LOG_ERR("CPSW: interface does not have an associated MAC port"); + return; + } + + port_cfg = &config->port[i]; + priv->iface[i] = iface; + net_if_set_link_addr(iface, priv->mac_addr[i], + sizeof(priv->mac_addr[i]), NET_LINK_ETHERNET); + ethernet_init(iface); + + /* Register PHY callback for the MAC Port */ + if (port_cfg->phy_dev != NULL) { + /* Carrier should be enabled by PHY */ + net_if_carrier_off(iface); + + if (device_is_ready(port_cfg->phy_dev)) { + phy_link_callback_set(port_cfg->phy_dev, + cpsw_phy_link_cb, + iface); + } else { + LOG_ERR("PHY Device for MAC port %d is not ready", i + 1); + } + } +} + +/** + * @brief Get the Ethernet PHY device for CPSW's MAC Port + * + * @param dev CPSW device pointer + * @param iface Network interface pointer + * returns PHY Device pointer (NULL if PHY doesn't exist) + */ +static const struct device *cpsw_get_phy(const struct device *dev, struct net_if *iface) +{ + const struct cpsw_dt_config *config = dev->config; + struct cpsw_priv *priv = dev->data; + int i = cpsw_port_idx(priv, iface); + + if (i < 0) { + return NULL; + } + + return config->port[i].phy_dev; +} + +static const struct ethernet_api cpsw_api = { + .iface_api.init = cpsw_iface_init, + .get_phy = cpsw_get_phy, + .start = cpsw_start, + .stop = cpsw_stop, + .get_capabilities = cpsw_get_capabilities, + .set_config = cpsw_set_config, + .send = cpsw_tx, +}; + +/** + * @brief CPSW driver initialization callback + * + * @param dev CPSW device pointer + * @retval 0 on success, negative errno on failure + */ +static int cpsw_init(const struct device *dev) +{ + const struct cpsw_dt_config *config = dev->config; + struct cpsw_priv *priv = dev->data; + int ret; + + /* Map the CPSW SS register region */ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + priv->base = (uint32_t *)DEVICE_MMIO_GET(dev); + + /* + * Map the GMII_SEL CTRL MMR region. Use device_map since + * we don't have a device for the GMII SEL block which falls + * in a different register space compared to the CPSW SS register + * region. + */ + device_map(&priv->gmii_sel_base, + config->gmii_sel.phys_addr, + config->gmii_sel.size, + K_MEM_CACHE_NONE); + + /* + * Map the MAC eFuse region to fetch MAC Port 1's MAC Address. + * Use device_map since we don't have a device for the eFuse + * registers storing the MAC Address and the registers belong + * to a different register space compared to the CPSW SS register + * region. + */ + device_map(&priv->mac_efuse_base, + config->mac_efuse.phys_addr, + config->mac_efuse.size, + K_MEM_CACHE_NONE); + + /* + * Attempt to use the Device-tree configured source for MAC Address and + * fallback to the MAC eFuse registers only for the first MAC Port. + */ + for (int i = 0; i < CPSW_NUM_MAC_PORTS; i++) { + ret = net_eth_mac_load(&config->port[i].mac_cfg, priv->mac_addr[i]); + if (ret == 0) { + continue; + } + + if (ret == -ENODATA && i == 0) { + /* Fall back to hardware eFuse for MAC Port 1's MAC Address*/ + uint32_t mac_lo = sys_read32(priv->mac_efuse_base); + uint32_t mac_hi = sys_read32(priv->mac_efuse_base + + CPSW_MAC_LO_MAC_HI_OFFSET); + uint8_t *mac = priv->mac_addr[i]; + + mac[0] = FIELD_GET(GENMASK(15, 8), mac_hi); + mac[1] = FIELD_GET(GENMASK(7, 0), mac_hi); + mac[2] = FIELD_GET(GENMASK(31, 24), mac_lo); + mac[3] = FIELD_GET(GENMASK(23, 16), mac_lo); + mac[4] = FIELD_GET(GENMASK(15, 8), mac_lo); + mac[5] = FIELD_GET(GENMASK(7, 0), mac_lo); + } else { + LOG_WRN("MAC address not found for MAC port %d: %d", + i + 1, ret); + } + } + + priv->dev = dev; + k_mutex_init(&priv->tx_lock); + k_mutex_init(&priv->start_lock); + + if (!device_is_ready(config->pktdma_dev)) { + LOG_ERR("PKTDMA device not ready"); + return -ENODEV; + } + + LOG_INF("CPSW version: 0x%08x", cpsw_read(priv, CPSW_NUSS_VER)); + + return 0; +} + +/* MAC port nodes fetched from device-tree */ +#define CPSW_ETH_PORTS_NODE(n) DT_INST_CHILD(n, ethernet_ports) +#define CPSW_PORT_NODE(n, idx) DT_CHILD(CPSW_ETH_PORTS_NODE(n), port_##idx) + +/* MAC Port device-tree configuration */ +#define CPSW_PORT_DT_CONFIG_INIT(n, port_idx) \ +{ \ + .phy_dev = COND_CODE_1(DT_NODE_HAS_PROP(CPSW_PORT_NODE(n, port_idx), phy_handle),\ + (DEVICE_DT_GET(DT_PHANDLE(CPSW_PORT_NODE(n, port_idx), \ + phy_handle))), \ + (NULL)), \ + .phy_conn_type = CPSW_PHY_CONN_TYPE(CPSW_PORT_NODE(n, port_idx)), \ + .mac_only = DT_PROP(CPSW_PORT_NODE(n, port_idx), ti_mac_only), \ + .port_num = (port_idx), \ + .mac_cfg = NET_ETH_MAC_DT_CONFIG_INIT(CPSW_PORT_NODE(n, port_idx)), \ +} + +#define CPSW_DEVICE_INIT(n) \ + static struct cpsw_priv cpsw_priv_##n; \ + \ + static const struct cpsw_dt_config cpsw_cfg_##n = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(gmii_sel, \ + DT_DRV_INST(n)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(mac_efuse, \ + DT_DRV_INST(n)), \ + .pktdma_dev = DEVICE_DT_GET( \ + DT_INST_DMAS_CTLR_BY_NAME(n, tx0)), \ + .tx_chan_id = DT_INST_DMAS_CELL_BY_NAME(n, tx0, \ + channel_id), \ + .rx_chan_id = DT_INST_DMAS_CELL_BY_NAME(n, rx, \ + channel_id), \ + .tx_asel = DT_INST_DMAS_CELL_BY_NAME(n, tx0, asel), \ + .rx_asel = DT_INST_DMAS_CELL_BY_NAME(n, rx, asel), \ + .port = { \ + [0] = CPSW_PORT_DT_CONFIG_INIT(n, 1), \ + [1] = CPSW_PORT_DT_CONFIG_INIT(n, 2), \ + }, \ + }; \ + \ + BUILD_ASSERT(CPSW_PHY_CONN_TYPE(CPSW_PORT_NODE(n, 1)) != \ + CPSW_PHY_CONN_INVALID, \ + "Invalid phy-connection-type for MAC port 1"); \ + BUILD_ASSERT(CPSW_PHY_CONN_TYPE(CPSW_PORT_NODE(n, 2)) != \ + CPSW_PHY_CONN_INVALID, \ + "Invalid phy-connection-type for MAC port 2"); \ + \ + ETH_NET_DEVICE_DT_INST_DEFINE(n, cpsw_init, NULL, \ + &cpsw_priv_##n, &cpsw_cfg_##n, \ + CONFIG_ETH_INIT_PRIORITY, \ + &cpsw_api, NET_ETH_MTU); \ + \ + NET_DEVICE_DT_INST_ADD_IFACE(n, ETHERNET_L2, \ + NET_L2_GET_CTX_TYPE(ETHERNET_L2), \ + NET_ETH_MTU, 1); + +DT_INST_FOREACH_STATUS_OKAY(CPSW_DEVICE_INIT) diff --git a/drivers/ethernet/eth_ti_am62l_cpsw.h b/drivers/ethernet/eth_ti_am62l_cpsw.h new file mode 100644 index 000000000000..c41b3483bae5 --- /dev/null +++ b/drivers/ethernet/eth_ti_am62l_cpsw.h @@ -0,0 +1,365 @@ +/* TI AM62L CPSW3G Ethernet driver + * + * Copyright (c) 2026 Texas Instruments Incorporated + * Author: Siddharth Vadapalli + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ETH_TI_AM62L_CPSW_H_ +#define ETH_TI_AM62L_CPSW_H_ + +#include +#include +#include +#include +#include +#include +#include + +/* CPSW Subsystem (CPSW_NUSS) register offsets from SS_BASE */ +#define CPSW_NUSS_VER 0x0000 +#define CPSW_NUSS_CONTROL 0x0004 +#define CPSW_NUSS_STAT_PORT_EN 0x0014 +#define CPSW_NUSS_PTYPE 0x0018 + +/* CPSW_NU inner module base offset from SS_BASE */ +#define CPSW_NU_BASE 0x20000 + +/* Sub-module offsets relative to CPSW_NU_BASE */ +#define CPSW_PORT0_BASE 0x01000 +#define CPSW_PORT1_BASE 0x02000 +#define CPSW_PORT2_BASE 0x03000 +#define CPSW_ALE_BASE 0x1E000 + +/* CPSW NUSS Control Register fields */ +#define CPSW_NUSS_CTL_P0_ENABLE BIT(2) +#define CPSW_NUSS_CTL_P0_TX_CRC_REMOVE BIT(13) +#define CPSW_NUSS_CTL_P0_RX_PAD BIT(14) + +/* CPSW NUSS Port Statistics Enable */ +#define CPSW_NUSS_STAT_P0_EN BIT(0) + +/* Per-port register offsets (relative to port base) */ +#define CPSW_P0_FLOW_ID_REG 0x0008 /* Host Port only */ +#define CPSW_PN_RX_MAXLEN 0x0024 +#define CPSW_PN_SA_L 0x0308 +#define CPSW_PN_SA_H 0x030c + +/* MACSL module offset relative to port_base */ +#define CPSW_MACSL_OFS 0x0330 + +/* Register offsets relative to CPSW_MACSL_OFS */ +#define CPSW_MACSL_CTL_REG 0x0000 +#define CPSW_MACSL_STATUS_REG 0x0004 +#define CPSW_MACSL_RESET_REG 0x0008 + +/* GMII_SEL register bit fields */ +#define GMII_SEL_MODE_MASK GENMASK(2, 0) +#define GMII_SEL_MODE_RMII 1U +#define GMII_SEL_MODE_RGMII 2U +#define GMII_SEL_RGMII_ID_BIT BIT(4) + +/* MACSL CTL register fields */ +#define MACSL_CTL_FULL_DUPLEX BIT(0) +#define MACSL_CTL_GMII_EN BIT(5) +#define MACSL_CTL_GIG BIT(7) +#define MACSL_RESET_BIT BIT(0) + +/* ALE register offsets (relative to CPSW_ALE_BASE) */ +#define ALE_CONTROL 0x08 +#define ALE_PORTCTL0 0x40 +#define ALE_PORTCTL1 0x44 +#define ALE_PORTCTL2 0x48 +#define ALE_THREADMAPDEF 0x134 + +/* ALE Control Register fields */ +#define ALE_CONTROL_ENABLE BIT(31) +#define ALE_CONTROL_CLEAR_TBL BIT(30) +#define ALE_CONTROL_BYPASS BIT(4) + +/* ALE Port Control register fields */ +#define ALE_PORTCTL_FORWARD 0x3U +#define ALE_PORTCTL_MAC_ONLY BIT(11) + +/* ALE Default Thread Map register fields */ +#define ALE_DEFTHREAD_EN BIT(15) + +#define CPSW_NUM_MAC_PORTS 2U + +/** + * @brief PHY connection type for a CPSW MAC port + * + * Resolved at compile time from the phy-connection-type DT property via + * CPSW_PHY_CONN_TYPE(). Stored as an integer in cpsw_dt_config so that + * cpsw_gmii_sel_set() can use a switch rather than strcmp(). + */ +enum cpsw_phy_conn_type { + CPSW_PHY_CONN_RMII, + CPSW_PHY_CONN_RGMII, + CPSW_PHY_CONN_RGMII_ID, + CPSW_PHY_CONN_RGMII_RXID, + CPSW_PHY_CONN_RGMII_TXID, + CPSW_PHY_CONN_INVALID, +}; + +/** + * @brief Translate a DT phy-connection-type string to cpsw_phy_conn_type + * + * Evaluated entirely at compile time using DT_ENUM_HAS_VALUE(). + * + * @param node_id DT node identifier for the MAC port + */ +#define CPSW_PHY_CONN_TYPE(node_id) \ + (DT_ENUM_HAS_VALUE(node_id, phy_connection_type, rmii) ? \ + CPSW_PHY_CONN_RMII : \ + DT_ENUM_HAS_VALUE(node_id, phy_connection_type, rgmii) ? \ + CPSW_PHY_CONN_RGMII : \ + DT_ENUM_HAS_VALUE(node_id, phy_connection_type, rgmii_id) ? \ + CPSW_PHY_CONN_RGMII_ID : \ + DT_ENUM_HAS_VALUE(node_id, phy_connection_type, rgmii_rxid) ? \ + CPSW_PHY_CONN_RGMII_RXID : \ + DT_ENUM_HAS_VALUE(node_id, phy_connection_type, rgmii_txid) ? \ + CPSW_PHY_CONN_RGMII_TXID : \ + CPSW_PHY_CONN_INVALID) + +/* Maximum / minimum Ethernet frame sizes */ +#define CPSW_MAX_PACKET_SIZE 2024U +#define CPSW_MIN_PACKET_SIZE 64U + +/* CPPI5 host descriptor definitions */ + +/* pkt_info0 fields */ +#define CPPI5_INFO0_HDESC_TYPE_HOST (0x1U << 30) +#define CPPI5_INFO0_HDESC_EPIB_PRESENT BIT(29) +#define CPPI5_INFO0_HDESC_PKTLEN_MASK GENMASK(21, 0) +#define CPPI5_INFO0_HDESC_PSFLGS_MASK GENMASK(27, 24) + +/* pkt_info1 fields */ +#define CPPI5_INFO1_HDESC_FLOW_ID 0x3FFF + +/* pkt_info2 fields */ +#define CPPI5_INFO2_HDESC_PKTTYPE_MASK GENMASK(29, 27) +#define CPPI5_INFO2_HDESC_RETQ_MASK GENMASK(15, 0) +#define CPPI5_INFO2_HDESC_PKTTYPE_CPSW 0x7U + +/* src_dst_tag fields */ +#define CPPI5_TAG_SRCTAG_PORT_MASK GENMASK(18, 16) +#define CPPI5_TAG_DSTTAG_MASK GENMASK(15, 0) + +/* Protocol-specific data size for CPSW TX descriptors */ +#define CPPI5_PSD_SIZE_CPSW 16U + +/* Total CPPI5 host descriptor size in bytes */ +#define CPPI5_DESC_SIZE 128U + +/* Ring element size: each ring entry holds one 8-byte descriptor pointer. */ +#define RING_ELEM_SIZE 8U + +/** + * @brief CPPI5 host descriptor layout. + * + * 128-byte structure aligned to a 64-byte cache line. The sw_data[] + * region carries the original buffer pointer (bytes 0-7), EPIB (8-23), + * protocol-specific data (24-39), and padding (40-95). + */ +struct cppi5_host_desc { + uint32_t pkt_info0; + uint32_t pkt_info1; + uint32_t pkt_info2; + uint32_t src_dst_tag; + uint64_t next_desc; /* Linking words (words 4-5) */ + uint64_t buf_ptr; /* Buffer pointer (words 6-7) */ + uint32_t buf_len; /* Buffer length (word 8) */ + uint32_t org_buf_len; /* Original buffer length (word 9) */ + uint64_t org_buf_ptr; /* Original buffer pointer (words 10-11) */ + uint8_t sw_data[96]; /* [0-7]=org_buf [8-23]=EPIB [24-39]=PSD [40-95]=pad */ +} __packed __aligned(64); + +/* Descriptor pool parameters */ +#define CPSW_TX_DESC_NUM CONFIG_ETH_TI_AM62L_CPSW_TX_DESC_NUM +#define CPSW_RX_DESC_NUM CONFIG_ETH_TI_AM62L_CPSW_RX_DESC_NUM +#define CPSW_RX_BUF_SIZE CONFIG_NET_BUF_DATA_SIZE +#define CPSW_RX_MAX_SG_FRAGS DIV_ROUND_UP(CPSW_MAX_PACKET_SIZE, CONFIG_NET_BUF_DATA_SIZE) +#define CPSW_TX_RING_MEM_SIZE (CPSW_TX_DESC_NUM * RING_ELEM_SIZE) +#define CPSW_RX_RING_MEM_SIZE (CPSW_RX_DESC_NUM * RING_ELEM_SIZE) + +/* PKTDMA state maintained by the CPSW driver */ +struct cpsw_pktdma { + /* Descriptor pools (64-byte aligned for cache operations) */ + struct cppi5_host_desc tx_descs[CPSW_TX_DESC_NUM] __aligned(64); + struct cppi5_host_desc rx_descs[CPSW_RX_DESC_NUM] __aligned(64); + + /* + * RX fragment pointers for zero-copy receive. Each entry holds a + * net_buf whose data area is the live DMA receive buffer for the + * corresponding rx_descs[] slot. NULL when the slot is unused. + */ + struct net_buf *rx_frags[CPSW_RX_DESC_NUM]; + + /* Ring element backing memory: 8 bytes per entry */ + uint64_t tx_ring_mem[CPSW_TX_DESC_NUM] __aligned(64); + uint64_t rx_ring_mem[CPSW_RX_DESC_NUM] __aligned(64); + + /* TX descriptor allocation index (wraps at CPSW_TX_DESC_NUM) */ + uint32_t tx_head; + + /* + * Zero-copy TX per-descriptor tracking + * + * tx_frags[i] – net_buf reference held for the fragment whose data + * buffer backs descriptor slot i. NULL for the pad + * descriptor (pointing to tx_pad_buf). + * tx_n_descs[i] – number of CPPI5 descriptors chained for the packet + * whose head descriptor is at slot i. + */ + struct net_buf *tx_frags[CPSW_TX_DESC_NUM]; + uint8_t tx_n_descs[CPSW_TX_DESC_NUM]; + + /* + * TX completion drain counter + * + * Each dma_reload() TX submission records the head descriptor slot + * index in tx_cmpl_head_idxs[] at position (tx_cmpl_wptr % N). + * The PKTDMA ISR pops completions from the ring in FIFO order and + * invokes the callback once per completion. Each callback invocation + * gives tx_compl_sem by one, which the TX completion thread consumes, + * and advances tx_cmpl_rptr to find the head_idx for that completion. + */ + uint32_t tx_cmpl_head_idxs[CPSW_TX_DESC_NUM]; + uint32_t tx_cmpl_wptr; /* write pointer, advanced per dma_reload TX */ + uint32_t tx_cmpl_rptr; /* read pointer, advanced per TX completion */ + + /* + * RX completion drain counter + * + * RX descriptors are submitted to PKTDMA in slot order (0, 1, 2, ...) + * and completions are returned in FIFO order. rx_drain_idx identifies + * the rx_descs[] slot that just completed, and it is advanced by one for + * each callback invocation received from the PKTDMA ISR. + */ + uint32_t rx_drain_idx; + + /* PKTDMA initialization state */ + bool initialized; + + /* + * Interrupt-driven completion signalling. + * tx_free_sem: counting semaphore, value = free TX descriptor slots. + * Initialised to CPSW_TX_DESC_NUM (all slots free). + * cpsw_tx() takes one slot before pushing to the ring; + * the TX thread gives one slot back for each completion. + * tx_compl_sem: given by TX ISR when the completion ring becomes + * non-empty; taken by the TX completion thread. + * rx_avail_sem: given by RX ISR when the completion ring becomes + * non-empty; taken by the RX thread. + */ + struct k_sem tx_free_sem; + struct k_sem tx_compl_sem; + struct k_sem rx_avail_sem; +}; + +#define CPSW_TX_THREAD_STACK_SIZE CONFIG_ETH_TI_AM62L_CPSW_TX_THREAD_STACK_SIZE +#define CPSW_TX_THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_ETH_TI_AM62L_TX_THREAD_PRIO) + +#define CPSW_RX_THREAD_STACK_SIZE CONFIG_ETH_TI_AM62L_CPSW_RX_THREAD_STACK_SIZE +#define CPSW_RX_THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_ETH_TI_AM62L_RX_THREAD_PRIO) + +/* Maximum packets processed per poll cycle before yielding */ +#define CPSW_TX_BUDGET CONFIG_ETH_TI_AM62L_CPSW_TX_BUDGET +#define CPSW_RX_BUDGET CONFIG_ETH_TI_AM62L_CPSW_RX_BUDGET + +/* Timeout for acquiring a free transmit descriptor */ +#define CPSW_TX_DESC_ACQUIRE_TIMEOUT_MS CONFIG_ETH_TI_AM62L_CPSW_TX_DESC_ACQUIRE_TIMEOUT + +/* + * CPSW MAC Port reset timeout of 1 millisecond is implemented as: + * Poll every 100 microseconds and retry 10 times. + */ +#define CPSW_POLL_INTERVAL_US 100U +#define CPSW_MAC_RESET_MAX_RETRIES 10U + +/* + * Wait period for RX Completion thread to drain packets after + * all interfaces are stopped. + */ +#define CPSW_RX_DRAIN_PERIOD_MS 10U + +/** + * @brief CPSW Ethernet driver private data + * + * One instance is shared by both MAC port devices. Per-port fields are + * indexed by (port_num - 1). + */ +struct cpsw_priv { + /* DEVICE_MMIO_RAM must be the first member */ + DEVICE_MMIO_RAM; + + /* CPSW SS virtual base address */ + uint32_t *base; + + /* Virtual base of mapped GMII SEL region */ + mm_reg_t gmii_sel_base; + + /* Virtual base of mapped MAC eFuse region */ + mm_reg_t mac_efuse_base; + + /* Primary (MAC port 1) device reference */ + const struct device *dev; + + /* Per-MAC-port network interfaces, indexed by (port_num - 1) */ + struct net_if *iface[CPSW_NUM_MAC_PORTS]; + + /* Lock protecting TX DMA Channel shared by network interfaces */ + struct k_mutex tx_lock; + + /* Lock protecting shared hardware initialization in cpsw_start() */ + struct k_mutex start_lock; + + /* Per-MAC-port MAC addresses, indexed by (port_num - 1) */ + uint8_t mac_addr[CPSW_NUM_MAC_PORTS][6]; + + /* Bitmask of enabled MAC ports: BIT(0) = port 1, BIT(1) = port 2 */ + uint32_t ports_started; + + /* PKTDMA ring memory and descriptor state */ + struct cpsw_pktdma dma; + + /* TX completion thread */ + struct k_thread tx_thread; + + /* TX completion thread ID */ + k_tid_t tx_tid; + + /* TX completion thread stack */ + K_KERNEL_STACK_MEMBER(tx_stack, CPSW_TX_THREAD_STACK_SIZE); + + /* RX completion thread */ + struct k_thread rx_thread; + + /* RX completion thread ID */ + k_tid_t rx_tid; + + /* RX completion thread stack */ + K_KERNEL_STACK_MEMBER(rx_stack, CPSW_RX_THREAD_STACK_SIZE); +}; + + +/* MMIO Helpers */ + +/* Read a 32-bit CPSW register at byte offset @p offset from SS_BASE. */ +static inline uint32_t cpsw_read(struct cpsw_priv *priv, uint32_t offset) +{ + __sync_synchronize(); + return priv->base[offset / 4]; +} + +/* Write a 32-bit value to a CPSW register at byte offset @p offset. */ +static inline void cpsw_write(struct cpsw_priv *priv, uint32_t offset, + uint32_t value) +{ + priv->base[offset / 4] = value; + __sync_synchronize(); +} + +#endif /* ETH_TI_AM62L_CPSW_H_ */ From a4656d4b3a7dfc2b02f1e6402f56e65c0478d9e5 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Mon, 19 Oct 2026 12:56:31 +0530 Subject: [PATCH 17/18] UPSTREAM-PEND: boards: ti: am62l_evm: enable CPSW3G and PKTDMA PR: 122461 The CPSW3G instance of CPSW (Common Platform Switch) on the AM62L SoC enables Ethernet functionality. CPSW3G has two MAC Ports that are brought out on the AM62L EVM [0] and interface with the DP83867 Ethernet PHY and support RGMII-ID mode of operation at link speeds of up to 1 Gbps each. The integrated MDIO module within CPSW3G allows communicating with the Ethernet PHYs connected to CPSW3G's MAC Ports. Software exchanges network traffic with CPSW3G via dedicated PKTDMA (Packet DMA) Channels that move data between CPSW3G and system memory (DDR). Hence, add the necessary device-tree and configs to enable Ethernet functionality on the AM62L EVM. [0]: https://www.ti.com/tool/TMDS62LEVM Signed-off-by: Siddharth Vadapalli --- boards/ti/am62l_evm/Kconfig.defconfig | 3 + boards/ti/am62l_evm/am62l_evm_am62l3_a53.dts | 36 +++++++ boards/ti/am62l_evm/am62l_evm_am62l3_a53.yaml | 2 +- boards/ti/am62l_evm/doc/index.rst | 8 ++ dts/vendor/ti/am62l-main.dtsi | 93 +++++++++++++++++++ dts/vendor/ti/am62l_power_domains.dtsi | 12 +++ 6 files changed, 153 insertions(+), 1 deletion(-) diff --git a/boards/ti/am62l_evm/Kconfig.defconfig b/boards/ti/am62l_evm/Kconfig.defconfig index 56a003236e39..47cc90ec402d 100644 --- a/boards/ti/am62l_evm/Kconfig.defconfig +++ b/boards/ti/am62l_evm/Kconfig.defconfig @@ -3,6 +3,9 @@ if BOARD_AM62L_EVM +configdefault ETH_DRIVER + default y + if FLASH config BOARD_TI_MSPI_FLASH_BOOT_MODE_RESET diff --git a/boards/ti/am62l_evm/am62l_evm_am62l3_a53.dts b/boards/ti/am62l_evm/am62l_evm_am62l3_a53.dts index 2e25dd70105f..0bdad59456b8 100644 --- a/boards/ti/am62l_evm/am62l_evm_am62l3_a53.dts +++ b/boards/ti/am62l_evm/am62l_evm_am62l3_a53.dts @@ -297,3 +297,39 @@ zephyr_udc0: &main_usb0 { ti,syscon-phy-pll-refclk = <&usb0_phy_ctrl>; ti,vbus-divider; }; + +&pktdma { + status = "okay"; +}; + +&cpsw3g { + status = "okay"; +}; + +&cpsw_port1 { + phy-handle = <&cpsw_phy1>; +}; + +&cpsw_port2 { + phy-handle = <&cpsw_phy2>; +}; + +&cpsw_mdio { + status = "okay"; + + cpsw_phy1: ethernet-phy@0 { + compatible = "ti,dp83867"; + reg = <0>; + ti,interface-type = "rgmii-id"; + ti,rx-internal-delay = <7>; /* 2 ns delay */ + ti,tx-internal-delay = <0>; /* Delay added by MAC */ + }; + + cpsw_phy2: ethernet-phy@1 { + compatible = "ti,dp83867"; + reg = <1>; + ti,interface-type = "rgmii-id"; + ti,rx-internal-delay = <7>; /* 2 ns delay */ + ti,tx-internal-delay = <0>; /* Delay added by MAC */ + }; +}; diff --git a/boards/ti/am62l_evm/am62l_evm_am62l3_a53.yaml b/boards/ti/am62l_evm/am62l_evm_am62l3_a53.yaml index 9a688e7001b0..f72c8f28b051 100644 --- a/boards/ti/am62l_evm/am62l_evm_am62l3_a53.yaml +++ b/boards/ti/am62l_evm/am62l_evm_am62l3_a53.yaml @@ -11,8 +11,8 @@ supported: - uart - shdc - pwm + - netif:eth testing: ignore_tags: - - net - bluetooth vendor: ti diff --git a/boards/ti/am62l_evm/doc/index.rst b/boards/ti/am62l_evm/doc/index.rst index 351a09bb13de..9ec96d1b22f8 100644 --- a/boards/ti/am62l_evm/doc/index.rst +++ b/boards/ti/am62l_evm/doc/index.rst @@ -13,6 +13,7 @@ the TI AM62L platform. The board configuration provides support for: - On-chip SRAM (oc_sram) - UART interfaces (uart0 to uart6) - I/O expander (via ti-io-exp snippet) + - CPSW3G Ethernet Switch with two 1Gbps capable MAC Ports The board configuration also enables support for the semihosting debugging console. @@ -85,6 +86,13 @@ Serial Port This board configuration uses a single serial communication channel with the MAIN domain UART (main_uart0). +CPSW3G (Common Platform Switch) Ethernet Switch +----------------------------------------------- + +The CPSW3G Ethernet Switch integrated in the SoC has two 1 Gbps capable MAC Ports +which are brought out on the board and interface with the DP83867 Ethernet PHY. +CPSW3G enables Ethernet functionality on the board. + Building and Booting ********************* diff --git a/dts/vendor/ti/am62l-main.dtsi b/dts/vendor/ti/am62l-main.dtsi index 090159324f0f..499c09c17295 100644 --- a/dts/vendor/ti/am62l-main.dtsi +++ b/dts/vendor/ti/am62l-main.dtsi @@ -365,6 +365,99 @@ status = "disabled"; }; + pktdma: dma@485c0000 { + compatible = "ti,am62l-pktdma"; + reg = <0x485c0000 0x4000>, + <0x48900000 0x80000>, + <0x47200000 0x100000>; + reg-names = "gcfg", "chanrt", "ringrt"; + #address-cells = <0>; + #dma-cells = <2>; + power-domains = <&pktdma_pd>; + #interrupt-cells = <1>; + interrupt-map = <0 &gic 0 GIC_SPI 354 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <1 &gic 0 GIC_SPI 355 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <2 &gic 0 GIC_SPI 358 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <3 &gic 0 GIC_SPI 359 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <4 &gic 0 GIC_SPI 362 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <5 &gic 0 GIC_SPI 363 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <6 &gic 0 GIC_SPI 366 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <7 &gic 0 GIC_SPI 367 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <8 &gic 0 GIC_SPI 370 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <9 &gic 0 GIC_SPI 371 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <10 &gic 0 GIC_SPI 374 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <11 &gic 0 GIC_SPI 375 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <12 &gic 0 GIC_SPI 378 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <13 &gic 0 GIC_SPI 379 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <64 &gic 0 GIC_SPI 500 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <65 &gic 0 GIC_SPI 501 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <66 &gic 0 GIC_SPI 502 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <67 &gic 0 GIC_SPI 503 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <68 &gic 0 GIC_SPI 504 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <69 &gic 0 GIC_SPI 505 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <70 &gic 0 GIC_SPI 506 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <71 &gic 0 GIC_SPI 507 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <72 &gic 0 GIC_SPI 508 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <73 &gic 0 GIC_SPI 509 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <74 &gic 0 GIC_SPI 510 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <75 &gic 0 GIC_SPI 511 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <76 &gic 0 GIC_SPI 512 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <77 &gic 0 GIC_SPI 513 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <78 &gic 0 GIC_SPI 514 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <79 &gic 0 GIC_SPI 515 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>, + <96 &gic 0 GIC_SPI 484 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; + status = "disabled"; + }; + + cpsw3g: ethernet@8000000 { + compatible = "ti,am62l-cpsw"; + reg = <0x08000000 0x200000>, + <0x091be000 0x8>, + <0x43002000 0x8>; + reg-names = "cpsw_nuss", "gmii_sel", "mac_efuse"; + clocks = <&scmi_clk 9>; + clock-names = "fck"; + power-domains = <&cpsw3g_pd>; + dmas = <&pktdma 64 15>, + <&pktdma 66 15>, + <&pktdma 68 15>, + <&pktdma 70 15>, + <&pktdma 72 15>, + <&pktdma 74 15>, + <&pktdma 76 15>, + <&pktdma 78 15>, + <&pktdma 96 15>; + dma-names = "tx0", "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", + "tx7", "rx"; + status = "disabled"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + cpsw_port1: port@1 { + reg = <1>; + phy-connection-type = "rgmii-id"; + ti,mac-only; + }; + + cpsw_port2: port@2 { + reg = <2>; + zephyr,random-mac-address; + phy-connection-type = "rgmii-id"; + ti,mac-only; + }; + }; + + cpsw_mdio: mdio { + compatible = "ti,am62l-cpsw-mdio"; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; + main_sdhci0: mmc@fa10000 { compatible = "ti,am654-sdhci"; reg = <0xfa10000 DT_SIZE_K(4)>, <0xfa18000 DT_SIZE_K(1)>; diff --git a/dts/vendor/ti/am62l_power_domains.dtsi b/dts/vendor/ti/am62l_power_domains.dtsi index 4d8113850014..fb3d8517eb67 100644 --- a/dts/vendor/ti/am62l_power_domains.dtsi +++ b/dts/vendor/ti/am62l_power_domains.dtsi @@ -223,5 +223,17 @@ reg = <95>; #power-domain-cells = <0>; }; + + cpsw3g_pd: power-domain@3 { + compatible = "arm,scmi-power-domain"; + reg = <3>; + #power-domain-cells = <0>; + }; + + pktdma_pd: power-domain@b { + compatible = "arm,scmi-power-domain"; + reg = <11>; + #power-domain-cells = <0>; + }; }; }; From 39ff1c7b48fc88f40d085b1773fd83b4deb5739e Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Wed, 20 May 2026 15:47:10 +0530 Subject: [PATCH 18/18] UPSTREAM-PEND: samples: net: zperf: add AM62L EVM config fragment PR: 122461 Add config fragment for the AM62L EVM to run Zperf with CPSW3G (Common Platform Switch) Ethernet Switch. Signed-off-by: Siddharth Vadapalli --- samples/net/zperf/boards/am62l_evm.conf | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 samples/net/zperf/boards/am62l_evm.conf diff --git a/samples/net/zperf/boards/am62l_evm.conf b/samples/net/zperf/boards/am62l_evm.conf new file mode 100644 index 000000000000..f70b76e50648 --- /dev/null +++ b/samples/net/zperf/boards/am62l_evm.conf @@ -0,0 +1,20 @@ +# Network support +CONFIG_NET_L2_ETHERNET_MGMT=y +CONFIG_NET_ZPERF_MAX_PACKET_SIZE=1500 +CONFIG_NET_RX_STACK_SIZE=2560 +CONFIG_NET_MGMT_EVENT_STACK_SIZE=2048 +CONFIG_NET_SOCKETS_SERVICE_STACK_SIZE=4096 + +# IPv4 and IPv6 slots for two MAC Ports of CPSW3G +CONFIG_NET_IF_MAX_IPV4_COUNT=2 +CONFIG_NET_IF_MAX_IPV6_COUNT=2 + +# Default KERNEL_VM_SIZE of 2 MB is insufficient +CONFIG_KERNEL_VM_SIZE=0x1000000 + +# Since 14 XLAT_TABLES are used by this sample, the default +# MAX_XLAT_TABLES value of 16 throws a warning. +# Increase it to 20 to future-proof the sample, since other +# peripherals may be added to the board later on and could +# require more tables. +CONFIG_MAX_XLAT_TABLES=20