* Re: [PATCH 4/4] arm64: drop binutils version checks
From: Will Deacon @ 2025-04-08 8:46 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-kbuild, Arnd Bergmann, H. Peter Anvin, Ard Biesheuvel,
Borislav Petkov, Brian Gerst, Catalin Marinas, Dave Hansen,
Herbert Xu, Ingo Molnar, Jonathan Corbet, Marc Zyngier,
Mark Rutland, Masahiro Yamada, Nathan Chancellor, Nicolas Schier,
Takashi Iwai, Thomas Gleixner, Uros Bizjak, linux-arm-kernel,
linux-crypto, linux-doc, linux-kernel, linux-raid, x86
In-Reply-To: <20250407094116.1339199-5-arnd@kernel.org>
Hi Arnd,
On Mon, Apr 07, 2025 at 11:41:16AM +0200, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> Now that gcc-8 and binutils-2.30 are the minimum versions, a lot of
> the individual feature checks can go away for simplification.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> arch/arm64/Kconfig | 37 ++-------------------------------
> arch/arm64/Makefile | 21 ++-----------------
> arch/arm64/include/asm/rwonce.h | 4 ----
> arch/arm64/kvm/Kconfig | 1 -
> arch/arm64/lib/xor-neon.c | 2 +-
> 5 files changed, 5 insertions(+), 60 deletions(-)
Since some of these checks are dynamic (i.e. they try passing various
options to the tools to see if they barf), have you checked that the
minimum supported version of clang implements them all?
Will
^ permalink raw reply
* Re: [PATCH v12 27/28] riscv: Documentation for shadow stack on riscv
From: Alexandre Ghiti @ 2025-04-08 8:48 UTC (permalink / raw)
To: Deepak Gupta, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Andrew Morton, Liam R. Howlett,
Vlastimil Babka, Lorenzo Stoakes, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Conor Dooley, Rob Herring, Krzysztof Kozlowski,
Arnd Bergmann, Christian Brauner, Peter Zijlstra, Oleg Nesterov,
Eric Biederman, Kees Cook, Jonathan Corbet, Shuah Khan, Jann Horn,
Conor Dooley
Cc: linux-kernel, linux-fsdevel, linux-mm, linux-riscv, devicetree,
linux-arch, linux-doc, linux-kselftest, alistair.francis,
richard.henderson, jim.shu, andybnac, kito.cheng, charlie, atishp,
evan, cleger, alexghiti, samitolvanen, broonie, rick.p.edgecombe,
Zong Li
In-Reply-To: <20250314-v5_user_cfi_series-v12-27-e51202b53138@rivosinc.com>
On 14/03/2025 22:39, Deepak Gupta wrote:
> Adding documentation on shadow stack for user mode on riscv and kernel
> interfaces exposed so that user tasks can enable it.
>
> Reviewed-by: Zong Li <zong.li@sifive.com>
> Signed-off-by: Deepak Gupta <debug@rivosinc.com>
> ---
> Documentation/arch/riscv/index.rst | 1 +
> Documentation/arch/riscv/zicfiss.rst | 176 +++++++++++++++++++++++++++++++++++
> 2 files changed, 177 insertions(+)
>
> diff --git a/Documentation/arch/riscv/index.rst b/Documentation/arch/riscv/index.rst
> index be7237b69682..e240eb0ceb70 100644
> --- a/Documentation/arch/riscv/index.rst
> +++ b/Documentation/arch/riscv/index.rst
> @@ -15,6 +15,7 @@ RISC-V architecture
> vector
> cmodx
> zicfilp
> + zicfiss
>
> features
>
> diff --git a/Documentation/arch/riscv/zicfiss.rst b/Documentation/arch/riscv/zicfiss.rst
> new file mode 100644
> index 000000000000..5ba389f15b3f
> --- /dev/null
> +++ b/Documentation/arch/riscv/zicfiss.rst
> @@ -0,0 +1,176 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +:Author: Deepak Gupta <debug@rivosinc.com>
> +:Date: 12 January 2024
> +
> +=========================================================
> +Shadow stack to protect function returns on RISC-V Linux
> +=========================================================
> +
> +This document briefly describes the interface provided to userspace by Linux
> +to enable shadow stack for user mode applications on RISV-V
s/RISV-V/RISC-V and the final dot
> +
> +1. Feature Overview
> +--------------------
> +
> +Memory corruption issues usually result in to crashes, however when in hands of
s/in to/into
> +an adversary and if used creatively can result into variety security issues.
"into a variety of"
> +
> +One of those security issues can be code re-use attacks on program where
> +adversary can use corrupt return addresses present on stack and chain them
> +together to perform return oriented programming (ROP) and thus compromising
> +control flow integrity (CFI) of the program.
> +
> +Return addresses live on stack and thus in read-write memory and thus are
> +susceptible to corruption and allows an adversary to reach any program counter
s/and allows/which allows
> +(PC) in address space. On RISC-V ``zicfiss`` extension provides an alternate
> +stack termed as shadow stack on which return addresses can be safely placed in
> +prolog of the function and retrieved in epilog. ``zicfiss`` extension makes
> +following changes:
> +
> +- PTE encodings for shadow stack virtual memory
> + An earlier reserved encoding in first stage translation i.e.
> + PTE.R=0, PTE.W=1, PTE.X=0 becomes PTE encoding for shadow stack pages.
> +
> +- ``sspush x1/x5`` instruction pushes (stores) ``x1/x5`` to shadow stack.
> +
> +- ``sspopchk x1/x5`` instruction pops (loads) from shadow stack and compares
> + with ``x1/x5`` and if un-equal, CPU raises ``software check exception`` with
> + ``*tval = 3``
> +
> +Compiler toolchain makes sure that function prologue have ``sspush x1/x5`` to
> +save return address on shadow stack in addition to regular stack. Similarly
> +function epilogs have ``ld x5, offset(x2)`` followed by ``sspopchk x5`` to
> +ensure that popped value from regular stack matches with popped value from
> +shadow stack.
> +
> +2. Shadow stack protections and linux memory manager
> +-----------------------------------------------------
> +
> +As mentioned earlier, shadow stack get new page table encodings and thus have
s/shadow stack/shadow stacks
> +some special properties assigned to them and instructions that operate on them
> +as below:
> +
> +- Regular stores to shadow stack memory raises access store faults. This way
> + shadow stack memory is protected from stray inadvertant writes.
s/inadvertant/inadvertent
> +
> +- Regular loads to shadow stack memory are allowed. This allows stack trace
> + utilities or backtrace functions to read true callstack (not tampered).
> +
> +- Only shadow stack instructions can generate shadow stack load or shadow stack
> + store.
> +
> +- Shadow stack load / shadow stack store on read-only memory raises AMO/store
> + page fault. Thus both ``sspush x1/x5`` and ``sspopchk x1/x5`` will raise AMO/
> + store page fault. This simplies COW handling in kernel During fork, kernel
s/During/during
> + can convert shadow stack pages into read-only memory (as it does for regular
> + read-write memory) and as soon as subsequent ``sspush`` or ``sspopchk`` in
> + userspace is encountered, then kernel can perform COW.
> +
> +- Shadow stack load / shadow stack store on read-write, read-write-execute
> + memory raises an access fault. This is a fatal condition because shadow stack
> + should never be operating on read-write, read-write-execute memory.
> +
> +3. ELF and psABI
> +-----------------
> +
> +Toolchain sets up :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_BCFI` for property
> +:c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_AND` in notes section of the object file.
> +
> +4. Linux enabling
> +------------------
> +
> +User space programs can have multiple shared objects loaded in its address space
> +and it's a difficult task to make sure all the dependencies have been compiled
> +with support of shadow stack. Thus it's left to dynamic loader to enable
> +shadow stack for the program.
> +
> +5. prctl() enabling
> +--------------------
> +
> +:c:macro:`PR_SET_SHADOW_STACK_STATUS` / :c:macro:`PR_GET_SHADOW_STACK_STATUS` /
> +:c:macro:`PR_LOCK_SHADOW_STACK_STATUS` are three prctls added to manage shadow
> +stack enabling for tasks. prctls are arch agnostic and returns -EINVAL on other
> +arches.
> +
> +* prctl(PR_SET_SHADOW_STACK_STATUS, unsigned long arg)
> +
> +If arg1 :c:macro:`PR_SHADOW_STACK_ENABLE` and if CPU supports ``zicfiss`` then
> +kernel will enable shadow stack for the task. Dynamic loader can issue this
> +:c:macro:`prctl` once it has determined that all the objects loaded in address
> +space have support for shadow stack. Additionally if there is a
> +:c:macro:`dlopen` to an object which wasn't compiled with ``zicfiss``, dynamic
> +loader can issue this prctl with arg1 set to 0 (i.e.
> +:c:macro:`PR_SHADOW_STACK_ENABLE` being clear)
> +
> +* prctl(PR_GET_SHADOW_STACK_STATUS, unsigned long *arg)
> +
> +Returns current status of indirect branch tracking. If enabled it'll return
> +:c:macro:`PR_SHADOW_STACK_ENABLE`.
> +
> +* prctl(PR_LOCK_SHADOW_STACK_STATUS, unsigned long arg)
> +
> +Locks current status of shadow stack enabling on the task. User space may want
> +to run with strict security posture and wouldn't want loading of objects
> +without ``zicfiss`` support in it and thus would want to disallow disabling of
> +shadow stack on current task. In that case user space can use this prctl to
> +lock current settings.
> +
> +5. violations related to returns with shadow stack enabled
> +-----------------------------------------------------------
> +
> +Pertaining to shadow stack, CPU raises software check exception in following
> +condition:
> +
> +- On execution of ``sspopchk x1/x5``, ``x1/x5`` didn't match top of shadow
> + stack. If mismatch happens then cpu does ``*tval = 3`` and raise software
> + check exception.
> +
> +Linux kernel will treat this as :c:macro:`SIGSEV`` with code =
> +:c:macro:`SEGV_CPERR` and follow normal course of signal delivery.
> +
> +6. Shadow stack tokens
> +-----------------------
> +Regular stores on shadow stacks are not allowed and thus can't be tampered
> +with via arbitrary stray writes due to bugs. Method of pivoting / switching to
> +shadow stack is simply writing to csr ``CSR_SSP`` changes active shadow stack.
I don't understand the end of this sentence.
> +This can be problematic because usually value to be written to ``CSR_SSP`` will
> +be loaded somewhere in writeable memory and thus allows an adversary to
> +corruption bug in software to pivot to an any address in shadow stack range.
Remove "an"
> +Shadow stack tokens can help mitigate this problem by making sure that:
> +
> +- When software is switching away from a shadow stack, shadow stack pointer
> + should be saved on shadow stack itself and call it ``shadow stack token``
> +
> +- When software is switching to a shadow stack, it should read the
> + ``shadow stack token`` from shadow stack pointer and verify that
> + ``shadow stack token`` itself is pointer to shadow stack itself.
> +
> +- Once the token verification is done, software can perform the write to
> + ``CSR_SSP`` to switch shadow stack.
> +
> +Here software can be user mode task runtime itself which is managing various
> +contexts as part of single thread. Software can be kernel as well when kernel
> +has to deliver a signal to user task and must save shadow stack pointer. Kernel
> +can perform similar procedure by saving a token on user shadow stack itself.
> +This way whenever :c:macro:`sigreturn` happens, kernel can read the token and
> +verify the token and then switch to shadow stack. Using this mechanism, kernel
> +helps user task so that any corruption issue in user task is not exploited by
> +adversary by arbitrarily using :c:macro:`sigreturn`. Adversary will have to
> +make sure that there is a ``shadow stack token`` in addition to invoking
> +:c:macro:`sigreturn`
> +
> +7. Signal shadow stack
> +-----------------------
> +Following structure has been added to sigcontext for RISC-V::
> +
> + struct __sc_riscv_cfi_state {
> + unsigned long ss_ptr;
> + };
> +
> +As part of signal delivery, shadow stack token is saved on current shadow stack
> +itself and updated pointer is saved away in :c:macro:`ss_ptr` field in
> +:c:macro:`__sc_riscv_cfi_state` under :c:macro:`sigcontext`. Existing shadow
> +stack allocation is used for signal delivery. During :c:macro:`sigreturn`,
> +kernel will obtain :c:macro:`ss_ptr` from :c:macro:`sigcontext` and verify the
> +saved token on shadow stack itself and switch shadow stack.
>
^ permalink raw reply
* Re: [PATCH v4 0/3] Use proper printk format in appletbdrm
From: Aditya Garg @ 2025-04-08 8:52 UTC (permalink / raw)
To: Andy Shevchenko
Cc: alyssa@rosenzweig.io, Petr Mladek, Sven Peter, Thomas Zimmermann,
Aun-Ali Zaidi, Maxime Ripard, airlied@redhat.com, Simona Vetter,
Steven Rostedt, Rasmus Villemoes, Sergey Senozhatsky,
Jonathan Corbet, Andrew Morton, apw@canonical.com,
joe@perches.com, dwaipayanray1@gmail.com, lukas.bulwahn@gmail.com,
Kees Cook, tamird@gmail.com, Linux Kernel Mailing List,
dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org,
Hector Martin, asahi@lists.linux.dev
In-Reply-To: <Z_ThPOOKXa3VwvmO@smile.fi.intel.com>
> On 8 Apr 2025, at 2:11 PM, Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
>
> On Tue, Apr 08, 2025 at 12:17:13PM +0530, Aditya Garg wrote:
>> The vsprint patch was originally being sent as a seperate patch [1], and
>> I was waiting it to be taken up. But as suggested by Petr, I'm sending
>> them via DRM.
>
> You need to do something about your tools, really.
Uhh, I'll just revert to the tried and tested macOS mail.
Although I don't think a resend is necessary here now.
> Now it's patch 3 threaded to patch 1, while the rest, including cover letter,
> seems okay.
>
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
^ permalink raw reply
* [PATCH net-next v4 07/14] net:phy:motorcomm: Add PHY_INTERFACE_MODE_INTERNAL to support YT6801
From: Frank Sae @ 2025-04-08 9:28 UTC (permalink / raw)
To: Jakub Kicinski, Paolo Abeni, Andrew Lunn, Heiner Kallweit,
Russell King, David S . Miller, Eric Dumazet, Frank, netdev
Cc: Masahiro Yamada, Parthiban.Veerasooran, linux-kernel,
andrew+netdev @ lunn . ch, lee, horms, linux-doc, corbet,
geert+renesas, xiaogang.fan, fei.zhang, hua.sun
In-Reply-To: <20250408092835.3952-1-Frank.Sae@motor-comm.com>
YT6801 NIC Integrated a PHY that is YT8531S, but it used GMII interface.
Add a case of PHY_INTERFACE_MODE_INTERNAL to support YT6801.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
drivers/net/phy/motorcomm.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
index 0e91f5d1a..ac3a46939 100644
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -896,6 +896,12 @@ static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg) |
FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg);
break;
+ case PHY_INTERFACE_MODE_INTERNAL:
+ if (phydev->drv->phy_id != PHY_ID_YT8531S)
+ return -EOPNOTSUPP;
+
+ dev_info_once(&phydev->mdio.dev, "Integrated YT8531S phy of YT6801.\n");
+ return 0;
default: /* do not support other modes */
return -EOPNOTSUPP;
}
--
2.34.1
^ permalink raw reply related
* [PATCH net-next v4 01/14] yt6801: Add support for a pci table in this module
From: Frank Sae @ 2025-04-08 9:28 UTC (permalink / raw)
To: Jakub Kicinski, Paolo Abeni, Andrew Lunn, Heiner Kallweit,
Russell King, David S . Miller, Eric Dumazet, Frank, netdev
Cc: Masahiro Yamada, Parthiban.Veerasooran, linux-kernel,
andrew+netdev @ lunn . ch, lee, horms, linux-doc, corbet,
geert+renesas, xiaogang.fan, fei.zhang, hua.sun
In-Reply-To: <20250408092835.3952-1-Frank.Sae@motor-comm.com>
Add support for a pci table in this module, and implement pci_driver
function to initialize this driver, remove this driver or shutdown this
driver.
Implement the fxgmac_drv_probe function to init interrupts, register mdio
and netdev.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
.../ethernet/motorcomm/yt6801/yt6801_main.c | 194 ++++++++++++++++++
.../ethernet/motorcomm/yt6801/yt6801_type.h | 114 ++++++++++
2 files changed, 308 insertions(+)
create mode 100644 drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
create mode 100644 drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
new file mode 100644
index 000000000..10d63a8ed
--- /dev/null
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2022 - 2024 Motorcomm Electronic Technology Co.,Ltd.
+ *
+ * Below is a simplified block diagram of YT6801 chip and its relevant
+ * interfaces.
+ * ||
+ * ********************++**********************
+ * * | PCIE Endpoint | *
+ * * +---------------+ *
+ * * | GMAC | *
+ * * +--++--+ *
+ * * |**| *
+ * * GMII --> |**| <-- MDIO *
+ * * +-++--+ *
+ * * | Integrated PHY | YT8531S *
+ * * +-++-+ *
+ * ********************||******************* **
+ */
+
+#include <linux/module.h>
+#include "yt6801_type.h"
+
+static void fxgmac_phy_release(struct fxgmac_pdata *priv)
+{
+ fxgmac_io_wr_bits(priv, EPHY_CTRL, EPHY_CTRL_RESET, 1);
+ fsleep(100);
+
+static void fxgmac_phy_reset(struct fxgmac_pdata *priv)
+{
+ fxgmac_io_wr_bits(priv, EPHY_CTRL, EPHY_CTRL_RESET, 0);
+ fsleep(1500);
+}
+
+static void fxgmac_init_interrupt_scheme(struct fxgmac_pdata *priv)
+{
+ struct pci_dev *pdev = to_pci_dev(priv->dev);
+ int req_vectors = FXGMAC_MAX_DMA_CHANNELS;
+
+ /* Since we have FXGMAC_MAX_DMA_CHANNELS channels, we must ensure the
+ * number of cpu core is ok. otherwise, just roll back to legacy.
+ */
+ if (num_online_cpus() < FXGMAC_MAX_DMA_CHANNELS - 1)
+ goto enable_msi_interrupt;
+
+ priv->msix_entries =
+ kcalloc(req_vectors, sizeof(struct msix_entry), GFP_KERNEL);
+ if (!priv->msix_entries)
+ goto enable_msi_interrupt;
+
+ for (u32 i = 0; i < req_vectors; i++)
+ priv->msix_entries[i].entry = i;
+
+ if (pci_enable_msix_exact(pdev, priv->msix_entries, req_vectors) < 0) {
+ /* Roll back to msi */
+ kfree(priv->msix_entries);
+ priv->msix_entries = NULL;
+ dev_err(priv->dev, "Enable MSIx failed, clear msix entries.\n");
+ goto enable_msi_interrupt;
+ }
+
+ priv->int_flag &= ~INT_FLAG_INTERRUPT;
+ priv->int_flag |= INT_FLAG_MSIX;
+ priv->per_channel_irq = 1;
+ return;
+
+enable_msi_interrupt:
+ priv->int_flag &= ~INT_FLAG_INTERRUPT;
+ if (pci_enable_msi(pdev) < 0) {
+ priv->int_flag |= INT_FLAG_LEGACY;
+ dev_err(priv->dev, "rollback to LEGACY.\n");
+ } else {
+ priv->int_flag |= INT_FLAG_MSI;
+ dev_err(priv->dev, "rollback to MSI.\n");
+ priv->dev_irq = pdev->irq;
+ }
+}
+
+static int fxgmac_drv_probe(struct device *dev, struct fxgmac_resources *res)
+{
+ struct fxgmac_pdata *priv;
+ struct net_device *ndev;
+ int ret;
+
+ ndev = alloc_etherdev_mq(sizeof(struct fxgmac_pdata),
+ FXGMAC_MAX_DMA_RX_CHANNELS);
+ if (!ndev)
+ return -ENOMEM;
+
+ SET_NETDEV_DEV(ndev, dev);
+ priv = netdev_priv(ndev);
+
+ priv->dev = dev;
+ priv->ndev = ndev;
+ priv->dev_irq = res->irq;
+ priv->hw_addr = res->addr;
+ priv->msg_enable = NETIF_MSG_DRV;
+ priv->dev_state = FXGMAC_DEV_PROBE;
+
+ /* Default to legacy interrupt */
+ priv->int_flag &= ~INT_FLAG_INTERRUPT;
+ priv->int_flag |= INT_FLAG_LEGACY;
+
+ pci_set_drvdata(to_pci_dev(priv->dev), priv);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ fxgmac_init_interrupt_scheme(priv);
+
+ ret = fxgmac_init(priv, true);
+ if (ret < 0) {
+ dev_err(dev, "fxgmac init failed:%d\n", ret);
+ goto err_free_netdev;
+ }
+
+ fxgmac_phy_reset(priv);
+ fxgmac_phy_release(priv);
+ ret = fxgmac_mdio_register(priv);
+ if (ret < 0) {
+ dev_err(dev, "Register fxgmac mdio failed:%d\n", ret);
+ goto err_free_netdev;
+ }
+
+ netif_carrier_off(ndev);
+ ret = register_netdev(ndev);
+ if (ret) {
+ dev_err(dev, "Register ndev failed:%d\n", ret);
+ goto err_free_netdev;
+ }
+
+ return 0;
+
+err_free_netdev:
+ free_netdev(ndev);
+ return ret;
+}
+
+static int fxgmac_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
+{
+ struct fxgmac_resources res;
+ int err;
+
+ err = pcim_enable_device(pcidev);
+ if (err)
+ return err;
+
+ memset(&res, 0, sizeof(res));
+ res.irq = pcidev->irq;
+ res.addr = pcim_iomap_region(pcidev, 0, pci_name(pcidev));
+ err = PTR_ERR_OR_ZERO(res.addr);
+ if (err)
+ return err;
+
+ pci_set_master(pcidev);
+ return fxgmac_drv_probe(&pcidev->dev, &res);
+}
+
+static void fxgmac_remove(struct pci_dev *pcidev)
+{
+ struct fxgmac_pdata *priv = dev_get_drvdata(&pcidev->dev);
+ struct net_device *ndev = priv->ndev;
+
+ unregister_netdev(ndev);
+ fxgmac_phy_reset(priv);
+ free_netdev(ndev);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI) &&
+ FIELD_GET(INT_FLAG_MSIX, priv->int_flag)) {
+ pci_disable_msix(pcidev);
+ kfree(priv->msix_entries);
+ priv->msix_entries = NULL;
+ }
+}
+
+#define MOTORCOMM_PCI_ID 0x1f0a
+#define YT6801_PCI_DEVICE_ID 0x6801
+
+static const struct pci_device_id fxgmac_pci_tbl[] = {
+ { PCI_DEVICE(MOTORCOMM_PCI_ID, YT6801_PCI_DEVICE_ID) },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, fxgmac_pci_tbl);
+
+static struct pci_driver fxgmac_pci_driver = {
+ .name = FXGMAC_DRV_NAME,
+ .id_table = fxgmac_pci_tbl,
+ .probe = fxgmac_probe,
+ .remove = fxgmac_remove,
+};
+
+module_pci_driver(fxgmac_pci_driver);
+
+MODULE_AUTHOR("Motorcomm Electronic Tech. Co., Ltd.");
+MODULE_DESCRIPTION(FXGMAC_DRV_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
new file mode 100644
index 000000000..bb6c2640a
--- /dev/null
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2022 - 2024 Motorcomm Electronic Technology Co.,Ltd. */
+
+#ifndef YT6801_TYPE_H
+#define YT6801_TYPE_H
+
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#define FXGMAC_DRV_NAME "yt6801"
+#define FXGMAC_DRV_DESC "Motorcomm Gigabit Ethernet Driver"
+
+#define FXGMAC_RX_BUF_ALIGN 64
+#define FXGMAC_TX_MAX_BUF_SIZE (0x3fff & ~(FXGMAC_RX_BUF_ALIGN - 1))
+#define FXGMAC_RX_MIN_BUF_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
+
+/* Descriptors required for maximum contiguous TSO/GSO packet */
+#define FXGMAC_TX_MAX_SPLIT ((GSO_MAX_SIZE / FXGMAC_TX_MAX_BUF_SIZE) + 1)
+
+/* Maximum possible descriptors needed for a SKB */
+#define FXGMAC_TX_MAX_DESC_NR (MAX_SKB_FRAGS + FXGMAC_TX_MAX_SPLIT + 2)
+
+#define FXGMAC_DMA_STOP_TIMEOUT 5
+#define FXGMAC_JUMBO_PACKET_MTU 9014
+#define FXGMAC_MAX_DMA_RX_CHANNELS 4
+#define FXGMAC_MAX_DMA_TX_CHANNELS 1
+#define FXGMAC_MAX_DMA_CHANNELS \
+ (FXGMAC_MAX_DMA_RX_CHANNELS + FXGMAC_MAX_DMA_TX_CHANNELS)
+
+#define EPHY_CTRL 0x1004
+#define EPHY_CTRL_RESET BIT(0)
+#define EPHY_CTRL_STA_LINKUP BIT(1)
+#define EPHY_CTRL_STA_DUPLEX BIT(2)
+#define EPHY_CTRL_STA_SPEED GENMASK(4, 3)
+
+struct fxgmac_resources {
+ void __iomem *addr;
+ int irq;
+};
+
+enum fxgmac_dev_state {
+ FXGMAC_DEV_OPEN = 0x0,
+ FXGMAC_DEV_CLOSE = 0x1,
+ FXGMAC_DEV_STOP = 0x2,
+ FXGMAC_DEV_START = 0x3,
+ FXGMAC_DEV_SUSPEND = 0x4,
+ FXGMAC_DEV_RESUME = 0x5,
+ FXGMAC_DEV_PROBE = 0xFF,
+};
+
+struct fxgmac_pdata {
+ struct net_device *ndev;
+ struct device *dev;
+ struct phy_device *phydev;
+
+ void __iomem *hw_addr; /* Registers base */
+
+ /* Device interrupt */
+ int dev_irq;
+ unsigned int per_channel_irq;
+ u32 channel_irq[FXGMAC_MAX_DMA_CHANNELS];
+ struct msix_entry *msix_entries;
+#define INT_FLAG_INTERRUPT GENMASK(4, 0)
+#define INT_FLAG_MSI BIT(1)
+#define INT_FLAG_MSIX BIT(3)
+#define INT_FLAG_LEGACY BIT(4)
+#define INT_FLAG_RX0_NAPI BIT(18)
+#define INT_FLAG_RX1_NAPI BIT(19)
+#define INT_FLAG_RX2_NAPI BIT(20)
+#define INT_FLAG_RX3_NAPI BIT(21)
+#define INT_FLAG_RX0_IRQ BIT(22)
+#define INT_FLAG_RX1_IRQ BIT(23)
+#define INT_FLAG_RX2_IRQ BIT(24)
+#define INT_FLAG_RX3_IRQ BIT(25)
+#define INT_FLAG_TX_NAPI BIT(26)
+#define INT_FLAG_TX_IRQ BIT(27)
+#define INT_FLAG_LEGACY_NAPI BIT(30)
+#define INT_FLAG_LEGACY_IRQ BIT(31)
+ u32 int_flag; /* interrupt flag */
+
+ u32 msg_enable;
+ enum fxgmac_dev_state dev_state;
+};
+
+static inline u32 fxgmac_io_rd(struct fxgmac_pdata *priv, u32 reg)
+{
+ return ioread32(priv->hw_addr + reg);
+}
+
+static inline u32
+fxgmac_io_rd_bits(struct fxgmac_pdata *priv, u32 reg, u32 mask)
+{
+ u32 cfg = fxgmac_io_rd(priv, reg);
+
+ return FIELD_GET(mask, cfg);
+}
+
+static inline void fxgmac_io_wr(struct fxgmac_pdata *priv, u32 reg, u32 set)
+{
+ iowrite32(set, priv->hw_addr + reg);
+}
+
+static inline void
+fxgmac_io_wr_bits(struct fxgmac_pdata *priv, u32 reg, u32 mask, u32 set)
+{
+ u32 cfg = fxgmac_io_rd(priv, reg);
+
+ cfg &= ~mask;
+ cfg |= FIELD_PREP(mask, set);
+ fxgmac_io_wr(priv, reg, cfg);
+}
+
+#endif /* YT6801_TYPE_H */
--
2.34.1
^ permalink raw reply related
* [PATCH net-next v4 12/14] yt6801: Implement pci_driver suspend and resume
From: Frank Sae @ 2025-04-08 9:28 UTC (permalink / raw)
To: Jakub Kicinski, Paolo Abeni, Andrew Lunn, Heiner Kallweit,
Russell King, David S . Miller, Eric Dumazet, Frank, netdev
Cc: Masahiro Yamada, Parthiban.Veerasooran, linux-kernel,
andrew+netdev @ lunn . ch, lee, horms, linux-doc, corbet,
geert+renesas, xiaogang.fan, fei.zhang, hua.sun
In-Reply-To: <20250408092835.3952-1-Frank.Sae@motor-comm.com>
Implement the pci_driver suspend function to enable the device to sleep,
and implement the resume function to enable the device to resume
operation.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
.../ethernet/motorcomm/yt6801/yt6801_main.c | 73 +++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
index 6523fe4de..67ff71f80 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
@@ -17,7 +17,11 @@
* ********************||******************* **
*/
+#include <linux/if_vlan.h>
#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/tcp.h>
+
#include "yt6801_type.h"
#include "yt6801_desc.h"
@@ -1380,6 +1384,21 @@ static void fxgmac_restart_work(struct work_struct *work)
fxgmac_restart(container_of(work, struct fxgmac_pdata, restart_work));
rtnl_unlock();
}
+
+static int fxgmac_net_powerup(struct fxgmac_pdata *priv)
+{
+ int ret;
+
+ priv->power_state = 0;/* clear all bits as normal now */
+ ret = fxgmac_start(priv);
+ if (ret < 0) {
+ dev_err(priv->dev, "fxgmac start failed:%d.\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static void fxgmac_config_powerdown(struct fxgmac_pdata *priv)
{
fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_RE, 1); /* Enable MAC Rx */
@@ -2908,6 +2927,55 @@ static void fxgmac_shutdown(struct pci_dev *pcidev)
}
rtnl_unlock();
}
+
+static int fxgmac_suspend(struct device *device)
+{
+ struct fxgmac_pdata *priv = dev_get_drvdata(device);
+ struct net_device *ndev = priv->ndev;
+
+ rtnl_lock();
+ if (priv->dev_state != FXGMAC_DEV_START)
+ goto unlock;
+
+ if (netif_running(ndev))
+ __fxgmac_shutdown(to_pci_dev(device));
+
+ priv->dev_state = FXGMAC_DEV_SUSPEND;
+unlock:
+ rtnl_unlock();
+
+ return 0;
+}
+
+static int fxgmac_resume(struct device *device)
+{
+ struct fxgmac_pdata *priv = dev_get_drvdata(device);
+ struct net_device *ndev = priv->ndev;
+ int ret = 0;
+
+ rtnl_lock();
+ if (priv->dev_state != FXGMAC_DEV_SUSPEND)
+ goto unlock;
+
+ priv->dev_state = FXGMAC_DEV_RESUME;
+ __clear_bit(FXGMAC_POWER_STATE_DOWN, &priv->power_state);
+ rtnl_lock();
+ if (netif_running(ndev)) {
+ ret = fxgmac_net_powerup(priv);
+ if (ret < 0) {
+ netdev_err(priv->ndev, "%s, fxgmac net powerup failed:%d\n",
+ __func__, ret);
+ goto unlock;
+ }
+ }
+
+ netif_device_attach(ndev);
+unlock:
+ rtnl_unlock();
+
+ return ret;
+}
+
#define MOTORCOMM_PCI_ID 0x1f0a
#define YT6801_PCI_DEVICE_ID 0x6801
@@ -2918,11 +2986,16 @@ static const struct pci_device_id fxgmac_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, fxgmac_pci_tbl);
+static const struct dev_pm_ops fxgmac_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(fxgmac_suspend, fxgmac_resume)
+};
+
static struct pci_driver fxgmac_pci_driver = {
.name = FXGMAC_DRV_NAME,
.id_table = fxgmac_pci_tbl,
.probe = fxgmac_probe,
.remove = fxgmac_remove,
+ .driver.pm = pm_ptr(&fxgmac_pm_ops),
.shutdown = fxgmac_shutdown,
};
--
2.34.1
^ permalink raw reply related
* [PATCH net-next v4 08/14] yt6801: Implement the fxgmac_hw_init function
From: Frank Sae @ 2025-04-08 9:28 UTC (permalink / raw)
To: Jakub Kicinski, Paolo Abeni, Andrew Lunn, Heiner Kallweit,
Russell King, David S . Miller, Eric Dumazet, Frank, netdev
Cc: Masahiro Yamada, Parthiban.Veerasooran, linux-kernel,
andrew+netdev @ lunn . ch, lee, horms, linux-doc, corbet,
geert+renesas, xiaogang.fan, fei.zhang, hua.sun
In-Reply-To: <20250408092835.3952-1-Frank.Sae@motor-comm.com>
Implement some hardware init functions to set default hardware
settings, including PHY control, Vlan related config, RX coalescing,
and other basic function control.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
.../ethernet/motorcomm/yt6801/yt6801_main.c | 546 ++++++++++++++++++
.../ethernet/motorcomm/yt6801/yt6801_type.h | 193 +++++++
2 files changed, 739 insertions(+)
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
index 34ccefdf9..5922a2449 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
@@ -484,6 +484,325 @@ static void fxgmac_enable_msix_irqs(struct fxgmac_pdata *priv)
fxgmac_enable_msix_one_irq(priv, intid);
}
+static void __fxgmac_set_mac_address(struct fxgmac_pdata *priv, u8 *addr)
+{
+ u32 mac_hi, mac_lo;
+
+ mac_lo = (u32)addr[0] | ((u32)addr[1] << 8) | ((u32)addr[2] << 16) |
+ ((u32)addr[3] << 24);
+
+ mac_hi = (u32)addr[4] | ((u32)addr[5] << 8);
+
+ fxgmac_io_wr(priv, MAC_MACA0LR, mac_lo);
+ fxgmac_io_wr(priv, MAC_MACA0HR, mac_hi);
+}
+
+static void fxgmac_config_mac_address(struct fxgmac_pdata *priv)
+{
+ __fxgmac_set_mac_address(priv, priv->mac_addr);
+ fxgmac_io_wr_bits(priv, MAC_PFR, MAC_PFR_HPF, 1);
+ fxgmac_io_wr_bits(priv, MAC_PFR, MAC_PFR_HUC, 1);
+ fxgmac_io_wr_bits(priv, MAC_PFR, MAC_PFR_HMC, 1);
+}
+
+static void fxgmac_config_crc_check_en(struct fxgmac_pdata *priv)
+{
+ fxgmac_io_wr_bits(priv, MAC_ECR, MAC_ECR_DCRCC, 1);
+}
+
+static void fxgmac_config_checksum_offload(struct fxgmac_pdata *priv)
+{
+ if (priv->ndev->features & NETIF_F_RXCSUM)
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_IPC, 1);
+ else
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_IPC, 0);
+}
+
+static void fxgmac_set_promiscuous_mode(struct fxgmac_pdata *priv,
+ unsigned int enable)
+{
+ fxgmac_io_wr_bits(priv, MAC_PFR, MAC_PFR_PR, enable);
+}
+
+static void fxgmac_enable_rx_broadcast(struct fxgmac_pdata *priv,
+ unsigned int enable)
+{
+ fxgmac_io_wr_bits(priv, MAC_PFR, MAC_PFR_DBF, enable);
+}
+
+static void fxgmac_set_all_multicast_mode(struct fxgmac_pdata *priv,
+ unsigned int enable)
+{
+ fxgmac_io_wr_bits(priv, MAC_PFR, MAC_PFR_PM, enable);
+}
+
+static void fxgmac_config_rx_mode(struct fxgmac_pdata *priv)
+{
+ u32 pr_mode, am_mode, bd_mode;
+
+ pr_mode = ((priv->ndev->flags & IFF_PROMISC) != 0);
+ am_mode = ((priv->ndev->flags & IFF_ALLMULTI) != 0);
+ bd_mode = ((priv->ndev->flags & IFF_BROADCAST) != 0);
+
+ fxgmac_enable_rx_broadcast(priv, bd_mode);
+ fxgmac_set_promiscuous_mode(priv, pr_mode);
+ fxgmac_set_all_multicast_mode(priv, am_mode);
+}
+
+static void fxgmac_config_tx_flow_control(struct fxgmac_pdata *priv)
+{
+ /* Set MTL flow control */
+ for (u32 i = 0; i < priv->rx_q_count; i++)
+ fxgmac_mtl_wr_bits(priv, i, MTL_Q_RQOMR, MTL_Q_RQOMR_EHFC,
+ priv->tx_pause);
+
+ /* Set MAC flow control */
+ fxgmac_io_wr_bits(priv, MAC_Q0TFCR, MAC_Q0TFCR_TFE, priv->tx_pause);
+
+ if (priv->tx_pause == 1) /* Set pause time */
+ fxgmac_io_wr_bits(priv, MAC_Q0TFCR, MAC_Q0TFCR_PT, 0xffff);
+}
+
+static void fxgmac_config_rx_flow_control(struct fxgmac_pdata *priv)
+{
+ fxgmac_io_wr_bits(priv, MAC_RFCR, MAC_RFCR_RFE, priv->rx_pause);
+}
+
+static void fxgmac_config_rx_coalesce(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++) {
+ if (!channel->rx_ring)
+ break;
+ fxgmac_dma_wr_bits(channel, DMA_CH_RIWT, DMA_CH_RIWT_RWT,
+ priv->rx_riwt);
+ }
+}
+
+static void fxgmac_config_rx_fep_disable(struct fxgmac_pdata *priv)
+{
+ /* Enable the rx queue forward packet with error status
+ * (crc error,gmii_er, watch dog timeout.or overflow)
+ */
+ for (u32 i = 0; i < priv->rx_q_count; i++)
+ fxgmac_mtl_wr_bits(priv, i, MTL_Q_RQOMR, MTL_Q_RQOMR_FEP, 1);
+}
+
+static void fxgmac_config_rx_fup_enable(struct fxgmac_pdata *priv)
+{
+ for (u32 i = 0; i < priv->rx_q_count; i++)
+ fxgmac_mtl_wr_bits(priv, i, MTL_Q_RQOMR, MTL_Q_RQOMR_FUP, 1);
+}
+
+static void fxgmac_config_rx_buffer_size(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++)
+ fxgmac_dma_wr_bits(channel, DMA_CH_RCR, DMA_CH_RCR_RBSZ,
+ priv->rx_buf_size);
+}
+
+static void fxgmac_config_tso_mode(struct fxgmac_pdata *priv)
+{
+ fxgmac_dma_wr_bits(priv->channel_head, DMA_CH_TCR, DMA_CH_TCR_TSE,
+ priv->hw_feat.tso);
+}
+
+static void fxgmac_config_sph_mode(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++)
+ fxgmac_dma_wr_bits(channel, DMA_CH_CR, DMA_CH_CR_SPH, 0);
+
+ fxgmac_io_wr_bits(priv, MAC_ECR, MAC_ECR_HDSMS, MAC_ECR_HDSMS_512B);
+}
+
+static void fxgmac_config_rx_threshold(struct fxgmac_pdata *priv,
+ unsigned int set_val)
+{
+ for (u32 i = 0; i < priv->rx_q_count; i++)
+ fxgmac_mtl_wr_bits(priv, i, MTL_Q_RQOMR, MTL_Q_RQOMR_RTC,
+ set_val);
+}
+
+static void fxgmac_config_mtl_mode(struct fxgmac_pdata *priv)
+{
+ /* Set Tx to weighted round robin scheduling algorithm */
+ fxgmac_io_wr_bits(priv, MTL_OMR, MTL_OMR_ETSALG, MTL_ETSALG_WRR);
+
+ /* Set Tx traffic classes to use WRR algorithm with equal weights */
+ fxgmac_mtl_wr_bits(priv, 0, MTL_TC_QWR, MTL_TC_QWR_QW, 1);
+
+ /* Set Rx to strict priority algorithm */
+ fxgmac_io_wr_bits(priv, MTL_OMR, MTL_OMR_RAA, MTL_RAA_SP);
+}
+
+static void fxgmac_config_queue_mapping(struct fxgmac_pdata *priv)
+{
+ unsigned int ppq, ppq_extra, prio_queues;
+ unsigned int __maybe_unused prio;
+ unsigned int reg, val, mask;
+
+ /* Map the 8 VLAN priority values to available MTL Rx queues */
+ prio_queues =
+ min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, priv->rx_q_count);
+ ppq = IEEE_8021QAZ_MAX_TCS / prio_queues;
+ ppq_extra = IEEE_8021QAZ_MAX_TCS % prio_queues;
+
+ reg = MAC_RQC2R;
+ for (u32 i = 0, prio = 0; i < prio_queues;) {
+ val = 0;
+ mask = 0;
+ for (u32 j = 0; j < ppq; j++) {
+ mask |= (1 << prio);
+ prio++;
+ }
+
+ if (i < ppq_extra) {
+ mask |= (1 << prio);
+ prio++;
+ }
+
+ val |= (mask << ((i++ % MAC_RQC2_Q_PER_REG) << 3));
+
+ if ((i % MAC_RQC2_Q_PER_REG) && i != prio_queues)
+ continue;
+
+ fxgmac_io_wr(priv, reg, val);
+ reg += MAC_RQC2_INC;
+ }
+
+ /* Configure one to one, MTL Rx queue to DMA Rx channel mapping
+ * ie Q0 <--> CH0, Q1 <--> CH1 ... Q7 <--> CH7
+ */
+ val = fxgmac_io_rd(priv, MTL_RQDCM0R);
+ val |= (MTL_RQDCM0R_Q0MDMACH | MTL_RQDCM0R_Q1MDMACH |
+ MTL_RQDCM0R_Q2MDMACH | MTL_RQDCM0R_Q3MDMACH);
+ fxgmac_io_wr(priv, MTL_RQDCM0R, val);
+
+ val = fxgmac_io_rd(priv, MTL_RQDCM0R + MTL_RQDCM_INC);
+ val |= (MTL_RQDCM1R_Q4MDMACH | MTL_RQDCM1R_Q5MDMACH |
+ MTL_RQDCM1R_Q6MDMACH | MTL_RQDCM1R_Q7MDMACH);
+ fxgmac_io_wr(priv, MTL_RQDCM0R + MTL_RQDCM_INC, val);
+}
+
+static unsigned int fxgmac_calculate_per_queue_fifo(unsigned int fifo_size,
+ unsigned int queue_count)
+{
+ u32 q_fifo_size, p_fifo;
+
+ /* Calculate the configured fifo size */
+ q_fifo_size = 1 << (fifo_size + 7);
+
+#define FXGMAC_MAX_FIFO 81920
+ /* The configured value may not be the actual amount of fifo RAM */
+ q_fifo_size = min_t(unsigned int, FXGMAC_MAX_FIFO, q_fifo_size);
+ q_fifo_size = q_fifo_size / queue_count;
+
+ /* Each increment in the queue fifo size represents 256 bytes of
+ * fifo, with 0 representing 256 bytes. Distribute the fifo equally
+ * between the queues.
+ */
+ p_fifo = q_fifo_size / 256;
+ if (p_fifo)
+ p_fifo--;
+
+ return p_fifo;
+}
+
+static void fxgmac_config_tx_fifo_size(struct fxgmac_pdata *priv)
+{
+ u32 fifo_size;
+
+ fifo_size = fxgmac_calculate_per_queue_fifo(priv->hw_feat.tx_fifo_size,
+ FXGMAC_TX_1_Q);
+ fxgmac_mtl_wr_bits(priv, 0, MTL_Q_TQOMR, MTL_Q_TQOMR_TQS, fifo_size);
+}
+
+static void fxgmac_config_rx_fifo_size(struct fxgmac_pdata *priv)
+{
+ u32 fifo_size;
+
+ fifo_size = fxgmac_calculate_per_queue_fifo(priv->hw_feat.rx_fifo_size,
+ priv->rx_q_count);
+
+ for (u32 i = 0; i < priv->rx_q_count; i++)
+ fxgmac_mtl_wr_bits(priv, i, MTL_Q_RQOMR, MTL_Q_RQOMR_RQS,
+ fifo_size);
+}
+
+static void fxgmac_config_flow_control_threshold(struct fxgmac_pdata *priv)
+{
+ for (u32 i = 0; i < priv->rx_q_count; i++) {
+ /* Activate flow control when less than 4k left in fifo */
+ fxgmac_mtl_wr_bits(priv, i, MTL_Q_RQOMR, MTL_Q_RQOMR_RFA, 6);
+ /* De-activate flow control when more than 6k left in fifo */
+ fxgmac_mtl_wr_bits(priv, i, MTL_Q_RQOMR, MTL_Q_RQOMR_RFD, 10);
+ }
+}
+
+static void fxgmac_config_tx_threshold(struct fxgmac_pdata *priv,
+ unsigned int set_val)
+{
+ fxgmac_mtl_wr_bits(priv, 0, MTL_Q_TQOMR, MTL_Q_TQOMR_TTC, set_val);
+}
+
+static void fxgmac_config_rsf_mode(struct fxgmac_pdata *priv,
+ unsigned int set_val)
+{
+ for (u32 i = 0; i < priv->rx_q_count; i++)
+ fxgmac_mtl_wr_bits(priv, i, MTL_Q_RQOMR, MTL_Q_RQOMR_RSF,
+ set_val);
+}
+
+static void fxgmac_config_tsf_mode(struct fxgmac_pdata *priv,
+ unsigned int set_val)
+{
+ fxgmac_mtl_wr_bits(priv, 0, MTL_Q_TQOMR, MTL_Q_TQOMR_TSF, set_val);
+}
+
+static void fxgmac_config_osp_mode(struct fxgmac_pdata *priv)
+{
+ fxgmac_dma_wr_bits(priv->channel_head, DMA_CH_TCR, DMA_CH_TCR_OSP,
+ priv->tx_osp_mode);
+}
+
+static void fxgmac_config_pblx8(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++)
+ fxgmac_dma_wr_bits(channel, DMA_CH_CR, DMA_CH_CR_PBLX8,
+ priv->pblx8);
+}
+
+static void fxgmac_config_tx_pbl_val(struct fxgmac_pdata *priv)
+{
+ fxgmac_dma_wr_bits(priv->channel_head, DMA_CH_TCR, DMA_CH_TCR_PBL,
+ priv->tx_pbl);
+}
+
+static void fxgmac_config_rx_pbl_val(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++)
+ fxgmac_dma_wr_bits(channel, DMA_CH_RCR, DMA_CH_RCR_PBL,
+ priv->rx_pbl);
+}
+
+static void fxgmac_config_mmc(struct fxgmac_pdata *priv)
+{
+ /* Set counters to reset on read, Reset the counters */
+ fxgmac_io_wr_bits(priv, MMC_CR, MMC_CR_ROR, 1);
+ fxgmac_io_wr_bits(priv, MMC_CR, MMC_CR_CR, 1);
+
+ fxgmac_io_wr(priv, MMC_IPC_RXINT_MASK, 0xffffffff);
+}
+
static void fxgmac_enable_dma_interrupts(struct fxgmac_pdata *priv)
{
struct fxgmac_channel *channel = priv->channel_head;
@@ -514,6 +833,233 @@ static void fxgmac_enable_dma_interrupts(struct fxgmac_pdata *priv)
}
}
+static void fxgmac_enable_mtl_interrupts(struct fxgmac_pdata *priv)
+{
+ unsigned int mtl_q_isr;
+
+ for (u32 i = 0; i < priv->hw_feat.rx_q_cnt; i++) {
+ /* Clear all the interrupts which are set */
+ mtl_q_isr = fxgmac_mtl_io_rd(priv, i, MTL_Q_IR);
+ fxgmac_mtl_io_wr(priv, i, MTL_Q_IR, mtl_q_isr);
+
+ /* No MTL interrupts to be enabled */
+ fxgmac_mtl_io_wr(priv, i, MTL_Q_IR, 0);
+ }
+}
+
+static void fxgmac_enable_mac_interrupts(struct fxgmac_pdata *priv)
+{
+ /* Disable Timestamp interrupt */
+ fxgmac_io_wr_bits(priv, MAC_IER, MAC_IER_TSIE, 0);
+
+ fxgmac_io_wr_bits(priv, MMC_RIER, MMC_RIER_ALL_INTERRUPTS, 0);
+ fxgmac_io_wr_bits(priv, MMC_TIER, MMC_TIER_ALL_INTERRUPTS, 0);
+}
+
+static int fxgmac_flush_tx_queues(struct fxgmac_pdata *priv)
+{
+ u32 val, count = 2000;
+
+ fxgmac_mtl_wr_bits(priv, 0, MTL_Q_TQOMR, MTL_Q_TQOMR_FTQ, 1);
+ do {
+ fsleep(20);
+ val = fxgmac_mtl_io_rd(priv, 0, MTL_Q_TQOMR);
+ val = FIELD_GET(MTL_Q_TQOMR_FTQ, val);
+
+ } while (--count && val);
+
+ if (val)
+ return -EBUSY;
+
+ return 0;
+}
+
+static void fxgmac_config_dma_bus(struct fxgmac_pdata *priv)
+{
+ u32 val = fxgmac_io_rd(priv, DMA_SBMR);
+
+ val &= ~(DMA_SBMR_EAME | DMA_SBMR_RD_OSR_LMT |
+ DMA_SBMR_WR_OSR_LMT | DMA_SBMR_FB);
+
+ /* Set enhanced addressing mode */
+ val |= DMA_SBMR_EAME;
+
+ /* Out standing read/write requests */
+ val |= FIELD_PREP(DMA_SBMR_RD_OSR_LMT, 0x7);
+ val |= FIELD_PREP(DMA_SBMR_WR_OSR_LMT, 0x7);
+
+ /* Set the System Bus mode */
+ val |= (DMA_SBMR_BLEN_4 | DMA_SBMR_BLEN_8 |
+ DMA_SBMR_BLEN_16 | DMA_SBMR_BLEN_32);
+
+ fxgmac_io_wr(priv, DMA_SBMR, val);
+}
+
+static void fxgmac_desc_rx_channel_init(struct fxgmac_channel *channel)
+{
+ struct fxgmac_ring *ring = channel->rx_ring;
+ unsigned int start_index = ring->cur;
+ struct fxgmac_desc_data *desc_data;
+
+ /* Initialize all descriptors */
+ for (u32 i = 0; i < ring->dma_desc_count; i++) {
+ desc_data = FXGMAC_GET_DESC_DATA(ring, i);
+ fxgmac_desc_rx_reset(desc_data); /* Initialize Rx descriptor */
+ }
+
+ /* Update the total number of Rx descriptors */
+ fxgmac_dma_io_wr(channel, DMA_CH_RDRLR, ring->dma_desc_count - 1);
+
+ /* Update the starting address of descriptor ring */
+ desc_data = FXGMAC_GET_DESC_DATA(ring, start_index);
+
+ fxgmac_dma_io_wr(channel, DMA_CH_RDLR_HI,
+ upper_32_bits(desc_data->dma_desc_addr));
+ fxgmac_dma_io_wr(channel, DMA_CH_RDLR_LO,
+ lower_32_bits(desc_data->dma_desc_addr));
+
+ /* Update the Rx Descriptor Tail Pointer */
+ desc_data = FXGMAC_GET_DESC_DATA(ring, start_index +
+ ring->dma_desc_count - 1);
+ fxgmac_dma_io_wr(channel, DMA_CH_RDTR_LO,
+ lower_32_bits(desc_data->dma_desc_addr));
+}
+
+static void fxgmac_desc_rx_init(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+ struct fxgmac_desc_data *desc_data;
+ struct fxgmac_dma_desc *dma_desc;
+ dma_addr_t dma_desc_addr;
+ struct fxgmac_ring *ring;
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++) {
+ ring = channel->rx_ring;
+ dma_desc = ring->dma_desc_head;
+ dma_desc_addr = ring->dma_desc_head_addr;
+
+ for (u32 j = 0; j < ring->dma_desc_count; j++) {
+ desc_data = FXGMAC_GET_DESC_DATA(ring, j);
+ desc_data->dma_desc = dma_desc;
+ desc_data->dma_desc_addr = dma_desc_addr;
+ if (fxgmac_rx_buffe_map(priv, ring, desc_data))
+ break;
+
+ dma_desc++;
+ dma_desc_addr += sizeof(struct fxgmac_dma_desc);
+ }
+
+ ring->cur = 0;
+ ring->dirty = 0;
+
+ fxgmac_desc_rx_channel_init(channel);
+ }
+}
+
+static void fxgmac_desc_tx_channel_init(struct fxgmac_channel *channel)
+{
+ struct fxgmac_ring *ring = channel->tx_ring;
+ struct fxgmac_desc_data *desc_data;
+ int start_index = ring->cur;
+
+ /* Initialize all descriptors */
+ for (u32 i = 0; i < ring->dma_desc_count; i++) {
+ desc_data = FXGMAC_GET_DESC_DATA(ring, i);
+ fxgmac_desc_tx_reset(desc_data); /* Initialize Tx descriptor */
+ }
+
+ /* Update the total number of Tx descriptors */
+ fxgmac_dma_io_wr(channel, DMA_CH_TDRLR,
+ channel->priv->tx_desc_count - 1);
+
+ /* Update the starting address of descriptor ring */
+ desc_data = FXGMAC_GET_DESC_DATA(ring, start_index);
+
+ fxgmac_dma_io_wr(channel, DMA_CH_TDLR_HI,
+ upper_32_bits(desc_data->dma_desc_addr));
+ fxgmac_dma_io_wr(channel, DMA_CH_TDLR_LO,
+ lower_32_bits(desc_data->dma_desc_addr));
+}
+
+static void fxgmac_desc_tx_init(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+ struct fxgmac_ring *ring = channel->tx_ring;
+ struct fxgmac_desc_data *desc_data;
+ struct fxgmac_dma_desc *dma_desc;
+ dma_addr_t dma_desc_addr;
+
+ dma_desc = ring->dma_desc_head;
+ dma_desc_addr = ring->dma_desc_head_addr;
+
+ for (u32 j = 0; j < ring->dma_desc_count; j++) {
+ desc_data = FXGMAC_GET_DESC_DATA(ring, j);
+ desc_data->dma_desc = dma_desc;
+ desc_data->dma_desc_addr = dma_desc_addr;
+
+ dma_desc++;
+ dma_desc_addr += sizeof(struct fxgmac_dma_desc);
+ }
+
+ ring->cur = 0;
+ ring->dirty = 0;
+ memset(&ring->tx, 0, sizeof(ring->tx));
+ fxgmac_desc_tx_channel_init(priv->channel_head);
+}
+
+static int fxgmac_hw_init(struct fxgmac_pdata *priv)
+{
+ int ret;
+
+ ret = fxgmac_flush_tx_queues(priv); /* Flush Tx queues */
+ if (ret < 0) {
+ dev_err(priv->dev, "%s, flush tx queue failed:%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Initialize DMA related features */
+ fxgmac_config_dma_bus(priv);
+ fxgmac_config_osp_mode(priv);
+ fxgmac_config_pblx8(priv);
+ fxgmac_config_tx_pbl_val(priv);
+ fxgmac_config_rx_pbl_val(priv);
+ fxgmac_config_rx_coalesce(priv);
+ fxgmac_config_rx_buffer_size(priv);
+ fxgmac_config_tso_mode(priv);
+ fxgmac_config_sph_mode(priv);
+ fxgmac_desc_tx_init(priv);
+ fxgmac_desc_rx_init(priv);
+ fxgmac_enable_dma_interrupts(priv);
+
+ /* Initialize MTL related features */
+ fxgmac_config_mtl_mode(priv);
+ fxgmac_config_queue_mapping(priv);
+ fxgmac_config_tsf_mode(priv, priv->tx_sf_mode);
+ fxgmac_config_rsf_mode(priv, priv->rx_sf_mode);
+ fxgmac_config_tx_threshold(priv, priv->tx_threshold);
+ fxgmac_config_rx_threshold(priv, priv->rx_threshold);
+ fxgmac_config_tx_fifo_size(priv);
+ fxgmac_config_rx_fifo_size(priv);
+ fxgmac_config_flow_control_threshold(priv);
+ fxgmac_config_rx_fep_disable(priv);
+ fxgmac_config_rx_fup_enable(priv);
+ fxgmac_enable_mtl_interrupts(priv);
+
+ /* Initialize MAC related features */
+ fxgmac_config_mac_address(priv);
+ fxgmac_config_crc_check_en(priv);
+ fxgmac_config_rx_mode(priv);
+ fxgmac_config_tx_flow_control(priv);
+ fxgmac_config_rx_flow_control(priv);
+ fxgmac_config_mac_speed(priv);
+ fxgmac_config_checksum_offload(priv);
+ fxgmac_config_mmc(priv);
+ fxgmac_enable_mac_interrupts(priv);
+
+ return 0;
+}
+
static void fxgmac_dismiss_all_int(struct fxgmac_pdata *priv)
{
struct fxgmac_channel *channel = priv->channel_head;
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
index 4afc6d4cd..4702ed1dc 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
@@ -134,6 +134,33 @@
#define MAC_CR_IPC BIT(27)
#define MAC_CR_ARPEN BIT(31)
+#define MAC_ECR 0x2004
+#define MAC_ECR_DCRCC BIT(16)
+#define MAC_ECR_HDSMS GENMASK(22, 20)
+#define MAC_ECR_HDSMS_64B 0
+#define MAC_ECR_HDSMS_128B 1
+#define MAC_ECR_HDSMS_256B 2
+#define MAC_ECR_HDSMS_512B 3
+#define MAC_ECR_HDSMS_1023B 4
+
+#define MAC_PFR 0x3008
+#define MAC_PFR_PR BIT(0) /* Promiscuous Mode. */
+#define MAC_PFR_HUC BIT(1) /* Hash Unicast Mode. */
+#define MAC_PFR_HMC BIT(2)
+#define MAC_PFR_PM BIT(4) /* Pass all Multicast. */
+#define MAC_PFR_DBF BIT(5) /* Disable Broadcast Packets. */
+#define MAC_PFR_HPF BIT(10)
+#define MAC_PFR_VTFE BIT(16)
+
+#define MAC_Q0TFCR 0x2070
+#define MAC_Q0TFCR_TFE BIT(1)
+#define MAC_Q0TFCR_PT GENMASK(31, 16)
+
+#define MAC_RFCR 0x2090
+#define MAC_RFCR_RFE BIT(0)
+#define MAC_RFCR_UP BIT(1)
+#define MAC_RFCR_PFCE BIT(8)
+
#define MAC_RQC0R 0x20a0
#define MAC_RQC1R 0x20a4
#define MAC_RQC2R 0x20a8
@@ -230,6 +257,60 @@
#define MAC_MDIO_DATA_GD GENMASK(15, 0)
#define MAC_MDIO_DATA_RA GENMASK(31, 16)
+#define MAC_GPIO_CR 0x2208
+#define MAC_GPIO_SR 0x220c
+#define MAC_ARP_PROTO_ADDR 0x2210
+#define MAC_CSR_SW_CTRL 0x2230
+#define MAC_MACA0HR 0x2300
+#define MAC_MACA0LR 0x2304
+#define MAC_MACA1HR 0x2308
+#define MAC_MACA1LR 0x230c
+
+/* MMC registers */
+#define MMC_CR 0x2700
+#define MMC_CR_CR BIT(0)
+#define MMC_CR_CSR BIT(1)
+#define MMC_CR_ROR BIT(2)
+#define MMC_CR_MCF BIT(3)
+
+#define MMC_RISR 0x2704
+#define MMC_TISR 0x2708
+
+#define MMC_RIER 0x270c
+#define MMC_RIER_ALL_INTERRUPTS GENMASK(27, 0)
+
+#define MMC_TIER 0x2710
+#define MMC_TIER_ALL_INTERRUPTS GENMASK(27, 0)
+
+#define MMC_IPC_RXINT_MASK 0x2800
+#define MMC_IPC_RXINT 0x2808
+
+/* MTL registers */
+#define MTL_OMR 0x2c00
+#define MTL_OMR_RAA BIT(2)
+#define MTL_OMR_ETSALG GENMASK(6, 5)
+
+#define MTL_FDCR 0x2c08
+#define MTL_FDSR 0x2c0c
+#define MTL_FDDR 0x2c10
+#define MTL_INT_SR 0x2c20
+
+#define MTL_RQDCM_INC 4
+#define MTL_RQDCM_Q_PER_REG 4
+
+#define MTL_RQDCM0R 0x2c30
+#define MTL_RQDCM0R_Q0MDMACH 0x0
+#define MTL_RQDCM0R_Q1MDMACH 0x00000100
+#define MTL_RQDCM0R_Q2MDMACH 0x00020000
+#define MTL_RQDCM0R_Q3MDMACH 0x03000000
+
+#define MTL_ECC_INT_SR 0x2ccc
+
+#define MTL_RQDCM1R_Q4MDMACH 0x00000004
+#define MTL_RQDCM1R_Q5MDMACH 0x00000500
+#define MTL_RQDCM1R_Q6MDMACH 0x00060000
+#define MTL_RQDCM1R_Q7MDMACH 0x07000000
+
/* MTL queue registers */
#define MTL_Q_BASE 0x2d00
#define MTL_Q_INC 0x40
@@ -242,11 +323,69 @@
#define MTL_Q_EN_IF_AV 0x01
#define MTL_Q_ENABLED 0x02
+#define MTL_Q_TQOMR_TTC GENMASK(6, 4)
+#define MTL_Q_TQOMR_TTC_THRESHOLD_32 0x00
+#define MTL_Q_TQOMR_TTC_THRESHOLD_64 0x01
+#define MTL_Q_TQOMR_TTC_THRESHOLD_96 0x02
+#define MTL_Q_TQOMR_TTC_THRESHOLD_128 0x03
+#define MTL_Q_TQOMR_TTC_THRESHOLD_192 0x04
+#define MTL_Q_TQOMR_TTC_THRESHOLD_256 0x05
+#define MTL_Q_TQOMR_TTC_THRESHOLD_384 0x06
+#define MTL_Q_TQOMR_TTC_THRESHOLD_512 0x07
+
+#define MTL_Q_TQOMR_TQS GENMASK(22, 16)
+
+#define MTL_Q_TQUR 0x04
+#define MTL_Q_TXDEG 0x08 /* Transmit debug */
#define MTL_Q_IR 0x2c /* Interrupt control status */
+
+#define MTL_Q_RQOMR 0x30
+#define MTL_Q_RQOMR_RTC GENMASK(1, 0)
+#define MTL_Q_RQOMR_RTC_THRESHOLD_64 0x00
+#define MTL_Q_RQOMR_RTC_THRESHOLD_32 0x01
+#define MTL_Q_RQOMR_RTC_THRESHOLD_96 0x02
+#define MTL_Q_RQOMR_RTC_THRESHOLD_128 0x03
+
+#define MTL_Q_RQOMR_FUP BIT(3)
+#define MTL_Q_RQOMR_FEP BIT(4)
+#define MTL_Q_RQOMR_RSF BIT(5)
+#define MTL_Q_RQOMR_EHFC BIT(7)
+#define MTL_Q_RQOMR_RFA GENMASK(13, 8)
+#define MTL_Q_RQOMR_RFD GENMASK(19, 14)
+#define MTL_Q_RQOMR_RQS GENMASK(28, 20)
+
+#define MTL_Q_RQMPOCR 0x34
+
#define MTL_Q_RQDR 0x38
#define MTL_Q_RQDR_RXQSTS GENMASK(5, 4)
#define MTL_Q_RQDR_PRXQ GENMASK(29, 16)
+#define MTL_Q_RQCR 0x3c
+
+/* MTL queue registers */
+#define MTL_ETSALG_WRR 0x00
+#define MTL_ETSALG_WFQ 0x01
+#define MTL_ETSALG_DWRR 0x02
+#define MTL_ETSALG_SP 0x03
+
+#define MTL_RAA_SP 0x00
+#define MTL_RAA_WSP 0x01
+
+/* MTL traffic class registers */
+#define MTL_TC_BASE MTL_Q_BASE
+#define MTL_TC_INC MTL_Q_INC
+
+#define MTL_TC_TQDR 0x08
+#define MTL_TC_TQDR_TRCSTS GENMASK(2, 1)
+#define MTL_TC_TQDR_TXQSTS BIT(4)
+
+#define MTL_TC_ETSCR 0x10
+#define MTL_TC_ETSCR_TSA GENMASK(1, 0)
+
+#define MTL_TC_ETSSR 0x14
+#define MTL_TC_QWR 0x18
+#define MTL_TC_QWR_QW GENMASK(20, 0)
+
/* DMA registers */
#define DMA_MR 0x3000
#define DMA_MR_SWR BIT(0)
@@ -256,16 +395,50 @@
#define DMA_MR_TNDF GENMASK(21, 20)
#define DMA_MR_RNDF GENMASK(23, 22)
+#define DMA_SBMR 0x3004
+#define DMA_SBMR_FB BIT(0)
+#define DMA_SBMR_BLEN_4 BIT(1)
+#define DMA_SBMR_BLEN_8 BIT(2)
+#define DMA_SBMR_BLEN_16 BIT(3)
+#define DMA_SBMR_BLEN_32 BIT(4)
+#define DMA_SBMR_BLEN_64 BIT(5)
+#define DMA_SBMR_BLEN_128 BIT(6)
+#define DMA_SBMR_BLEN_256 BIT(7)
+#define DMA_SBMR_AALE BIT(10)
+#define DMA_SBMR_EAME BIT(11)
+#define DMA_SBMR_AAL BIT(12)
+#define DMA_SBMR_RD_OSR_LMT GENMASK(23, 16)
+#define DMA_SBMR_WR_OSR_LMT GENMASK(29, 24)
+#define DMA_SBMR_LPI_XIT_PKT BIT(30)
+#define DMA_SBMR_EN_LPI BIT(31)
+
+#define DMA_ISR 0x3008
+#define DMA_ISR_MTLIS BIT(16)
+#define DMA_ISR_MACIS BIT(17)
+
#define DMA_DSRX_INC 4
#define DMA_DSR0 0x300c
#define DMA_DSR0_TPS GENMASK(15, 12)
#define DMA_TPS_STOPPED 0x00
#define DMA_TPS_SUSPENDED 0x06
+#define DMA_DSR1 0x3010
+#define DMA_DSR2 0x3014
+#define DMA_AXIARCR 0x3020
+#define DMA_AXIAWCR 0x3024
+#define DMA_AXIAWRCR 0x3028
+#define DMA_SAFE_ISR 0x3080
+#define DMA_ECC_IE 0x3084
+#define DMA_ECC_INT_SR 0x3088
+
/* DMA channel registers */
#define DMA_CH_BASE 0x3100
#define DMA_CH_INC 0x80
+#define DMA_CH_CR 0x00
+#define DMA_CH_CR_PBLX8 BIT(16)
+#define DMA_CH_CR_SPH BIT(24)
+
#define DMA_CH_TCR 0x04
#define DMA_CH_TCR_ST BIT(0)
#define DMA_CH_TCR_OSP BIT(4)
@@ -286,6 +459,15 @@
#define DMA_CH_RCR_RBSZ GENMASK(14, 1)
#define DMA_CH_RCR_PBL GENMASK(21, 16)
+#define DMA_CH_TDLR_HI 0x10
+#define DMA_CH_TDLR_LO 0x14
+#define DMA_CH_RDLR_HI 0x18
+#define DMA_CH_RDLR_LO 0x1c
+#define DMA_CH_TDTR_LO 0x20
+#define DMA_CH_RDTR_LO 0x28
+#define DMA_CH_TDRLR 0x2c
+#define DMA_CH_RDRLR 0x30
+
#define DMA_CH_IER 0x34
#define DMA_CH_IER_TIE BIT(0)
#define DMA_CH_IER_TXSE BIT(1)
@@ -297,6 +479,16 @@
#define DMA_CH_IER_AIE BIT(14)
#define DMA_CH_IER_NIE BIT(15)
+#define DMA_CH_RIWT 0x38
+#define DMA_CH_RIWT_RWT GENMASK(7, 0)
+
+#define DMA_CH_CATDR_LO 0x44
+#define DMA_CH_CARDR_LO 0x4c
+#define DMA_CH_CATBR_HI 0x50
+#define DMA_CH_CATBR_LO 0x54
+#define DMA_CH_CARBR_HI 0x58
+#define DMA_CH_CARBR_LO 0x5c
+
#define DMA_CH_SR 0x60
#define DMA_CH_SR_TI BIT(0)
#define DMA_CH_SR_TPS BIT(1)
@@ -558,6 +750,7 @@ struct fxgmac_pdata {
/* ndev related settings */
unsigned char mac_addr[ETH_ALEN];
+ struct napi_struct napi;
int mac_speed;
int mac_duplex;
--
2.34.1
^ permalink raw reply related
* [PATCH net-next v4 14/14] yt6801: update ethernet documentation and maintainer
From: Frank Sae @ 2025-04-08 9:28 UTC (permalink / raw)
To: Jakub Kicinski, Paolo Abeni, Andrew Lunn, Heiner Kallweit,
Russell King, David S . Miller, Eric Dumazet, Frank, netdev
Cc: Masahiro Yamada, Parthiban.Veerasooran, linux-kernel,
andrew+netdev @ lunn . ch, lee, horms, linux-doc, corbet,
geert+renesas, xiaogang.fan, fei.zhang, hua.sun
In-Reply-To: <20250408092835.3952-1-Frank.Sae@motor-comm.com>
Add the yt6801.rst in ethernet/motorcomm folder
Add the yt6801 entry in the index.rst.
Add myself as the maintainer for the motorcomm ethernet driver.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
.../device_drivers/ethernet/index.rst | 1 +
.../ethernet/motorcomm/yt6801.rst | 20 +++++++++++++++++++
MAINTAINERS | 8 ++++++++
3 files changed, 29 insertions(+)
create mode 100644 Documentation/networking/device_drivers/ethernet/motorcomm/yt6801.rst
diff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst
index 05d822b90..7a158af55 100644
--- a/Documentation/networking/device_drivers/ethernet/index.rst
+++ b/Documentation/networking/device_drivers/ethernet/index.rst
@@ -46,6 +46,7 @@ Contents:
mellanox/mlx5/index
meta/fbnic
microsoft/netvsc
+ motorcomm/yt6801
neterion/s2io
netronome/nfp
pensando/ionic
diff --git a/Documentation/networking/device_drivers/ethernet/motorcomm/yt6801.rst b/Documentation/networking/device_drivers/ethernet/motorcomm/yt6801.rst
new file mode 100644
index 000000000..dd1e59c33
--- /dev/null
+++ b/Documentation/networking/device_drivers/ethernet/motorcomm/yt6801.rst
@@ -0,0 +1,20 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================================================================
+Linux Base Driver for Motorcomm(R) Gigabit PCI Express Adapters
+================================================================
+
+Motorcomm Gigabit Linux driver.
+Copyright (c) 2021 - 2024 Motor-comm Co., Ltd.
+
+
+Contents
+========
+
+- Support
+
+
+Support
+=======
+If you got any problem, contact Motorcomm support team via support@motor-comm.com
+and Cc: netdev.
diff --git a/MAINTAINERS b/MAINTAINERS
index 4c5c2e2c1..1d7700e6b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16351,6 +16351,14 @@ F: drivers/most/
F: drivers/staging/most/
F: include/linux/most.h
+MOTORCOMM ETHERNET DRIVER
+M: Frank <Frank.Sae@motor-comm.com>
+L: netdev@vger.kernel.org
+S: Maintained
+W: https://www.motor-comm.com/
+F: Documentation/networking/device_drivers/ethernet/motorcomm/*
+F: drivers/net/ethernet/motorcomm/*
+
MOTORCOMM PHY DRIVER
M: Frank <Frank.Sae@motor-comm.com>
L: netdev@vger.kernel.org
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v4 0/3] Use proper printk format in appletbdrm
From: Andy Shevchenko @ 2025-04-08 9:38 UTC (permalink / raw)
To: Aditya Garg
Cc: alyssa@rosenzweig.io, Petr Mladek, Sven Peter, Thomas Zimmermann,
Aun-Ali Zaidi, Maxime Ripard, airlied@redhat.com, Simona Vetter,
Steven Rostedt, Rasmus Villemoes, Sergey Senozhatsky,
Jonathan Corbet, Andrew Morton, apw@canonical.com,
joe@perches.com, dwaipayanray1@gmail.com, lukas.bulwahn@gmail.com,
Kees Cook, tamird@gmail.com, Linux Kernel Mailing List,
dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org,
Hector Martin, asahi@lists.linux.dev
In-Reply-To: <PN3PR01MB959761E1B759183D83C1AC33B8B52@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM>
On Tue, Apr 08, 2025 at 08:52:10AM +0000, Aditya Garg wrote:
> > On 8 Apr 2025, at 2:11 PM, Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> > On Tue, Apr 08, 2025 at 12:17:13PM +0530, Aditya Garg wrote:
> >> The vsprint patch was originally being sent as a seperate patch [1], and
> >> I was waiting it to be taken up. But as suggested by Petr, I'm sending
> >> them via DRM.
> >
> > You need to do something about your tools, really.
>
> Uhh, I'll just revert to the tried and tested macOS mail.
>
> Although I don't think a resend is necessary here now.
I dunno. If people are using `b4`, it might mess up the patch ordering,
I haven't checked this myself (it depends if it takes [PATCH x/y] or message
threading into account first).
It seems not a big deal with _this_ series, but for the future it may be really
a problem (esp. from [runtime] bisectability point of view).
> > Now it's patch 3 threaded to patch 1, while the rest, including cover letter,
> > seems okay.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH net-next v4 02/14] yt6801: Implement mdio register
From: Frank Sae @ 2025-04-08 9:28 UTC (permalink / raw)
To: Jakub Kicinski, Paolo Abeni, Andrew Lunn, Heiner Kallweit,
Russell King, David S . Miller, Eric Dumazet, Frank, netdev
Cc: Masahiro Yamada, Parthiban.Veerasooran, linux-kernel,
andrew+netdev @ lunn . ch, lee, horms, linux-doc, corbet,
geert+renesas, xiaogang.fan, fei.zhang, hua.sun
In-Reply-To: <20250408092835.3952-1-Frank.Sae@motor-comm.com>
Implement the mdio bus read, write and register function.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
.../ethernet/motorcomm/yt6801/yt6801_main.c | 86 +++++++++++++++++++
.../ethernet/motorcomm/yt6801/yt6801_type.h | 8 ++
2 files changed, 94 insertions(+)
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
index 10d63a8ed..39f03b4a4 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
@@ -20,6 +20,92 @@
#include <linux/module.h>
#include "yt6801_type.h"
+#define PHY_WR_CONFIG(reg_offset) (0x8000205 + ((reg_offset) * 0x10000))
+static int fxgmac_phy_write_reg(struct fxgmac_pdata *priv, u32 reg_id, u32 data)
+{
+ u32 val;
+ int ret;
+
+ fxgmac_io_wr(priv, MAC_MDIO_DATA, data);
+ fxgmac_io_wr(priv, MAC_MDIO_ADDR, PHY_WR_CONFIG(reg_id));
+ ret = read_poll_timeout_atomic(fxgmac_io_rd, val,
+ !FIELD_GET(MAC_MDIO_ADDR_BUSY, val),
+ 10, 250, false, priv, MAC_MDIO_ADDR);
+ if (ret == -ETIMEDOUT)
+ dev_err(priv->dev, "%s, id:%x ctrl:0x%08x, data:0x%08x\n",
+ __func__, reg_id, PHY_WR_CONFIG(reg_id), data);
+
+ return ret;
+}
+
+#define PHY_RD_CONFIG(reg_offset) (0x800020d + ((reg_offset) * 0x10000))
+static int fxgmac_phy_read_reg(struct fxgmac_pdata *priv, u32 reg_id)
+{
+ u32 val;
+ int ret;
+
+ fxgmac_io_wr(priv, MAC_MDIO_ADDR, PHY_RD_CONFIG(reg_id));
+ ret = read_poll_timeout_atomic(fxgmac_io_rd, val,
+ !FIELD_GET(MAC_MDIO_ADDR_BUSY, val),
+ 10, 250, false, priv, MAC_MDIO_ADDR);
+ if (ret == -ETIMEDOUT) {
+ dev_err(priv->dev, "%s, id:%x, ctrl:0x%08x, val:0x%08x.\n",
+ __func__, reg_id, PHY_RD_CONFIG(reg_id), val);
+ return ret;
+ }
+
+ return fxgmac_io_rd(priv, MAC_MDIO_DATA); /* Read data */
+}
+
+static int fxgmac_mdio_write_reg(struct mii_bus *mii_bus, int phyaddr,
+ int phyreg, u16 val)
+{
+ if (phyaddr > 0)
+ return -ENODEV;
+
+ return fxgmac_phy_write_reg(mii_bus->priv, phyreg, val);
+}
+
+static int fxgmac_mdio_read_reg(struct mii_bus *mii_bus, int phyaddr,
+ int phyreg)
+{
+ if (phyaddr > 0)
+ return -ENODEV;
+
+ return fxgmac_phy_read_reg(mii_bus->priv, phyreg);
+}
+
+static int fxgmac_mdio_register(struct fxgmac_pdata *priv)
+{
+ struct pci_dev *pdev = to_pci_dev(priv->dev);
+ struct phy_device *phydev;
+ struct mii_bus *new_bus;
+ int ret;
+
+ new_bus = devm_mdiobus_alloc(&pdev->dev);
+ if (!new_bus)
+ return -ENOMEM;
+
+ new_bus->name = "yt6801";
+ new_bus->priv = priv;
+ new_bus->parent = &pdev->dev;
+ new_bus->read = fxgmac_mdio_read_reg;
+ new_bus->write = fxgmac_mdio_write_reg;
+ snprintf(new_bus->id, MII_BUS_ID_SIZE, "yt6801-%x-%x",
+ pci_domain_nr(pdev->bus), pci_dev_id(pdev));
+
+ ret = devm_mdiobus_register(&pdev->dev, new_bus);
+ if (ret < 0)
+ return ret;
+
+ phydev = mdiobus_get_phy(new_bus, 0);
+ if (!phydev)
+ return -ENODEV;
+
+ priv->phydev = phydev;
+ return 0;
+}
+
static void fxgmac_phy_release(struct fxgmac_pdata *priv)
{
fxgmac_io_wr_bits(priv, EPHY_CTRL, EPHY_CTRL_RESET, 1);
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
index bb6c2640a..b43952981 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
@@ -34,6 +34,14 @@
#define EPHY_CTRL_STA_DUPLEX BIT(2)
#define EPHY_CTRL_STA_SPEED GENMASK(4, 3)
+#define MAC_MDIO_ADDR 0x2200
+#define MAC_MDIO_ADDR_BUSY BIT(0)
+#define MAC_MDIO_ADDR_GOC GENMASK(3, 2)
+
+#define MAC_MDIO_DATA 0x2204
+#define MAC_MDIO_DATA_GD GENMASK(15, 0)
+#define MAC_MDIO_DATA_RA GENMASK(31, 16)
+
struct fxgmac_resources {
void __iomem *addr;
int irq;
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v3] docs: update THP admin guide about non-tmpfs filesystem support
From: Pankaj Raghav (Samsung) @ 2025-04-08 9:44 UTC (permalink / raw)
To: David Hildenbrand
Cc: Andrew Morton, Jonathan Corbet, linux-kernel, willy, linux-mm,
Bagas Sanjaya, da.gomez, mcgrof, gost.dev, linux-doc,
Pankaj Raghav
In-Reply-To: <f4924ad4-c70b-4999-b595-01c488607189@redhat.com>
On Fri, Apr 04, 2025 at 09:16:10PM +0200, David Hildenbrand wrote:
> On 04.04.25 16:06, Pankaj Raghav (Samsung) wrote:
> > From: Pankaj Raghav <p.raghav@samsung.com>
> >
> > THP support for non-tmpfs filesystem has been around for some time now.
> > Update the admin guide to reflect it.
> >
> > While we are at it, move FilePmdMapped to previous paragraph for clarity,
> > and clarify ShmemPmdMapped & ShmemHugePage.
> >
> > Signed-off-by: Pankaj Raghav <p.raghav@samsung.com>
> > Acked-by: David Hildenbrand <david@redhat.com>
> > ---
>
> BTW, we should go over the whole document and bring it up to date.
> Interestingly, it starts with
>
> "Performance critical computing applications dealing with large memory
> working sets are already running on top of libhugetlbfs and in turn
> hugetlbfs. Transparent HugePage Support (THP) is an alternative mean of
> using huge pages for the backing of virtual memory with huge pages
> that supports the automatic promotion and demotion of page sizes and
> without the shortcomings of hugetlbfs.
>
> Currently THP only works for anonymous memory mappings and tmpfs/shmem.
> But in the future it can expand to other filesystems."
As a part of this patch, I do change 2nd paragraph:
-Currently THP only works for anonymous memory mappings and tmpfs/shmem.
-But in the future it can expand to other filesystems.
+Currently, THP only works for anonymous memory mappings, tmpfs/shmem and
+filesystems that support large folios.
Do we need to add more changes to the first paragraph as well?
--
Pankaj
^ permalink raw reply
* [PATCH net-next v4 00/14] yt6801: Add Motorcomm yt6801 PCIe driver
From: Frank Sae @ 2025-04-08 9:28 UTC (permalink / raw)
To: Jakub Kicinski, Paolo Abeni, Andrew Lunn, Heiner Kallweit,
Russell King, David S . Miller, Eric Dumazet, Frank, netdev
Cc: Masahiro Yamada, Parthiban.Veerasooran, linux-kernel,
andrew+netdev @ lunn . ch, lee, horms, linux-doc, corbet,
geert+renesas, xiaogang.fan, fei.zhang, hua.sun
This series includes adding Motorcomm YT6801 Gigabit ethernet driver
and adding yt6801 ethernet driver entry in MAINTAINERS file.
YT6801 integrates a YT8531S phy.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
v4:
- Redefine rges and bits
- Reorganize the read and write function of regs
- Replae ‘pcim_iomap_regions’ as 'pcim_iomap_region'
- Replae ‘mutex_lock(&priv->mutex)’ as 'rtnl_lock()'
- Replae ‘phydev_info(...YT6801.\n");’ as 'dev_info_once(...YT6801.\n");'
in phy driver
- Remove pcim_iomap_table
- Use "yt6801: " and "net: phy: motorcomm: " as prefixes for these patches
v3: https://patchwork.kernel.org/project/netdevbpf/cover/20250228100020.3944-1-Frank.Sae@motor-comm.com/
- Remove about 5000 lines of code
- Remove statistics, ethtool, WoL, PHY handling ...
- Reorganize this driver code and remove redundant code
- Remove unnecessary yt_dbg information
- Remove netif_carrier_on/netif_carrier_off
- Remove hw_ops
- Add PHY_INTERFACE_MODE_INTERNAL mode in phy driver to support yt6801
- Replae '#ifdef CONFIG_PCI_MSI' as 'if (IS_ENABLED(CONFIG_PCI_MSI) {}'
- Replae ‘fxgmac_pdata val’ as 'priv'
v2: https://patchwork.kernel.org/project/netdevbpf/cover/20241120105625.22508-1-Frank.Sae@motor-comm.com/
- Split this driver into multiple patches.
- Reorganize this driver code and remove redundant code
- Remove PHY handling code and use phylib.
- Remove writing ASPM config
- Use generic power management instead of pci_driver.suspend()/resume()
- Add Space before closing "*/"
v1: https://patchwork.kernel.org/project/netdevbpf/patch/20240913124113.9174-1-Frank.Sae@motor-comm.com/
This patch is to add the ethernet device driver for the PCIe interface of
Motorcomm YT6801 Gigabit Ethernet.
We tested this driver on an Ubuntu x86 PC with YT6801 network card.
Frank Sae (14):
yt6801: Add support for a pci table in this module
yt6801: Implement mdio register
yt6801: Implement pci_driver shutdown
yt6801: Implement the fxgmac_init function
yt6801: Implement the .ndo_open function
yt6801: Implement the fxgmac_start function
net:phy:motorcomm: Add PHY_INTERFACE_MODE_INTERNAL to support YT6801
yt6801: Implement the fxgmac_hw_init function
yt6801: Implement the poll functions
yt6801: Implement .ndo_start_xmit function
yt6801: Implement some net_device_ops function
yt6801: Implement pci_driver suspend and resume
yt6801: Add makefile and Kconfig
yt6801: update ethernet documentation and maintainer
.../device_drivers/ethernet/index.rst | 1 +
.../ethernet/motorcomm/yt6801.rst | 20 +
MAINTAINERS | 8 +
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/motorcomm/Kconfig | 27 +
drivers/net/ethernet/motorcomm/Makefile | 6 +
.../net/ethernet/motorcomm/yt6801/Makefile | 8 +
.../ethernet/motorcomm/yt6801/yt6801_desc.c | 565 ++++
.../ethernet/motorcomm/yt6801/yt6801_desc.h | 35 +
.../ethernet/motorcomm/yt6801/yt6801_main.c | 3006 +++++++++++++++++
.../ethernet/motorcomm/yt6801/yt6801_type.h | 956 ++++++
drivers/net/phy/motorcomm.c | 6 +
13 files changed, 4640 insertions(+)
create mode 100644 Documentation/networking/device_drivers/ethernet/motorcomm/yt6801.rst
create mode 100644 drivers/net/ethernet/motorcomm/Kconfig
create mode 100644 drivers/net/ethernet/motorcomm/Makefile
create mode 100644 drivers/net/ethernet/motorcomm/yt6801/Makefile
create mode 100644 drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.c
create mode 100644 drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.h
create mode 100644 drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
create mode 100644 drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
--
2.34.1
^ permalink raw reply
* [PATCH net-next v4 03/14] yt6801: Implement pci_driver shutdown
From: Frank Sae @ 2025-04-08 9:28 UTC (permalink / raw)
To: Jakub Kicinski, Paolo Abeni, Andrew Lunn, Heiner Kallweit,
Russell King, David S . Miller, Eric Dumazet, Frank, netdev
Cc: Masahiro Yamada, Parthiban.Veerasooran, linux-kernel,
andrew+netdev @ lunn . ch, lee, horms, linux-doc, corbet,
geert+renesas, xiaogang.fan, fei.zhang, hua.sun
In-Reply-To: <20250408092835.3952-1-Frank.Sae@motor-comm.com>
Implement the pci_driver shutdown function to shutdown this driver.
Implement the fxgmac_net_powerdown function to stop tx, disable tx,
disable rx, config powerdown, free rx date and free tx date.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
.../ethernet/motorcomm/yt6801/yt6801_desc.c | 50 +++
.../ethernet/motorcomm/yt6801/yt6801_desc.h | 19 ++
.../ethernet/motorcomm/yt6801/yt6801_main.c | 310 ++++++++++++++++++
.../ethernet/motorcomm/yt6801/yt6801_type.h | 281 ++++++++++++++++
4 files changed, 660 insertions(+)
create mode 100644 drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.c
create mode 100644 drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.h
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.c
new file mode 100644
index 000000000..a83ebb478
--- /dev/null
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2022 - 2024 Motorcomm Electronic Technology Co.,Ltd. */
+
+#include "yt6801_type.h"
+#include "yt6801_desc.h"
+
+void fxgmac_desc_data_unmap(struct fxgmac_pdata *priv,
+ struct fxgmac_desc_data *desc_data)
+{
+ if (desc_data->skb_dma) {
+ if (desc_data->mapped_as_page) {
+ dma_unmap_page(priv->dev, desc_data->skb_dma,
+ desc_data->skb_dma_len, DMA_TO_DEVICE);
+ } else {
+ dma_unmap_single(priv->dev, desc_data->skb_dma,
+ desc_data->skb_dma_len, DMA_TO_DEVICE);
+ }
+ desc_data->skb_dma = 0;
+ desc_data->skb_dma_len = 0;
+ }
+
+ if (desc_data->skb) {
+ dev_kfree_skb_any(desc_data->skb);
+ desc_data->skb = NULL;
+ }
+
+ if (desc_data->rx.hdr.pa.pages)
+ put_page(desc_data->rx.hdr.pa.pages);
+
+ if (desc_data->rx.hdr.pa_unmap.pages) {
+ dma_unmap_page(priv->dev, desc_data->rx.hdr.pa_unmap.pages_dma,
+ desc_data->rx.hdr.pa_unmap.pages_len,
+ DMA_FROM_DEVICE);
+ put_page(desc_data->rx.hdr.pa_unmap.pages);
+ }
+
+ if (desc_data->rx.buf.pa.pages)
+ put_page(desc_data->rx.buf.pa.pages);
+
+ if (desc_data->rx.buf.pa_unmap.pages) {
+ dma_unmap_page(priv->dev, desc_data->rx.buf.pa_unmap.pages_dma,
+ desc_data->rx.buf.pa_unmap.pages_len,
+ DMA_FROM_DEVICE);
+ put_page(desc_data->rx.buf.pa_unmap.pages);
+ }
+ memset(&desc_data->tx, 0, sizeof(desc_data->tx));
+ memset(&desc_data->rx, 0, sizeof(desc_data->rx));
+
+ desc_data->mapped_as_page = 0;
+}
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.h b/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.h
new file mode 100644
index 000000000..a4c7a8af2
--- /dev/null
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2022 - 2024 Motorcomm Electronic Technology Co.,Ltd. */
+
+#ifndef YT6801_DESC_H
+#define YT6801_DESC_H
+
+#define FXGMAC_TX_DESC_CNT 256
+#define FXGMAC_TX_DESC_MIN_FREE (FXGMAC_TX_DESC_CNT >> 3)
+#define FXGMAC_TX_DESC_MAX_PROC (FXGMAC_TX_DESC_CNT >> 1)
+#define FXGMAC_RX_DESC_CNT 1024
+#define FXGMAC_RX_DESC_MAX_DIRTY (FXGMAC_RX_DESC_CNT >> 3)
+
+#define FXGMAC_GET_DESC_DATA(ring, idx) ((ring)->desc_data_head + (idx))
+#define FXGMAC_GET_ENTRY(x, size) (((x) + 1) & ((size) - 1))
+
+void fxgmac_desc_data_unmap(struct fxgmac_pdata *priv,
+ struct fxgmac_desc_data *desc_data);
+
+#endif /* YT6801_DESC_H */
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
index 39f03b4a4..8baabeb53 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include "yt6801_type.h"
+#include "yt6801_desc.h"
#define PHY_WR_CONFIG(reg_offset) (0x8000205 + ((reg_offset) * 0x10000))
static int fxgmac_phy_write_reg(struct fxgmac_pdata *priv, u32 reg_id, u32 data)
@@ -106,6 +107,219 @@ static int fxgmac_mdio_register(struct fxgmac_pdata *priv)
return 0;
}
+static void fxgmac_disable_mgm_irq(struct fxgmac_pdata *priv)
+{
+ fxgmac_io_wr_bits(priv, MGMT_INT_CTRL0, MGMT_INT_CTRL0_INT_MASK,
+ MGMT_INT_CTRL0_INT_MASK_MASK);
+}
+
+static void napi_disable_del(struct fxgmac_pdata *priv, struct napi_struct *n,
+ u32 flag)
+{
+ napi_disable(n);
+ netif_napi_del(n);
+ priv->int_flag &= ~flag;
+}
+
+static void fxgmac_napi_disable(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+ u32 rx_napi[] = {INT_FLAG_RX0_NAPI, INT_FLAG_RX1_NAPI,
+ INT_FLAG_RX2_NAPI, INT_FLAG_RX3_NAPI};
+
+ if (!priv->per_channel_irq) {
+ if (!FIELD_GET(INT_FLAG_LEGACY_NAPI, priv->int_flag))
+ return;
+
+ napi_disable_del(priv, &priv->napi,
+ INT_FLAG_LEGACY_NAPI);
+ return;
+ }
+
+ if (FIELD_GET(INT_FLAG_TX_NAPI, priv->int_flag))
+ napi_disable_del(priv, &channel->napi_tx, INT_FLAG_TX_NAPI);
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++)
+ if (priv->int_flag & rx_napi[i])
+ napi_disable_del(priv, &channel->napi_rx, rx_napi[i]);
+}
+
+static void fxgmac_free_irqs(struct fxgmac_pdata *priv)
+{
+ u32 rx_irq[] = {INT_FLAG_RX0_IRQ, INT_FLAG_RX1_IRQ,
+ INT_FLAG_RX2_IRQ, INT_FLAG_RX3_IRQ};
+ struct fxgmac_channel *channel = priv->channel_head;
+
+ if (!FIELD_GET(INT_FLAG_MSIX, priv->int_flag) &&
+ FIELD_GET(INT_FLAG_LEGACY_IRQ, priv->int_flag)) {
+ devm_free_irq(priv->dev, priv->dev_irq, priv);
+ priv->int_flag &= ~INT_FLAG_LEGACY_IRQ;
+ }
+
+ if (!priv->per_channel_irq)
+ return;
+
+ if (FIELD_GET(INT_FLAG_TX_IRQ, priv->int_flag)) {
+ priv->int_flag &= ~INT_FLAG_TX_IRQ;
+ devm_free_irq(priv->dev, channel->dma_irq_tx, channel);
+ }
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++)
+ if (priv->int_flag & rx_irq[i]) {
+ priv->int_flag &= ~rx_irq[i];
+ devm_free_irq(priv->dev, channel->dma_irq_rx, channel);
+ }
+}
+
+static void fxgmac_free_tx_data(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+ struct fxgmac_ring *ring;
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++) {
+ ring = channel->tx_ring;
+ if (!ring)
+ break;
+
+ for (u32 j = 0; j < ring->dma_desc_count; j++)
+ fxgmac_desc_data_unmap(priv,
+ FXGMAC_GET_DESC_DATA(ring, j));
+ }
+}
+
+static void fxgmac_free_rx_data(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+ struct fxgmac_ring *ring;
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++) {
+ ring = channel->rx_ring;
+ if (!ring)
+ break;
+
+ for (u32 j = 0; j < ring->dma_desc_count; j++)
+ fxgmac_desc_data_unmap(priv,
+ FXGMAC_GET_DESC_DATA(ring, j));
+ }
+}
+
+static void fxgmac_prepare_tx_stop(struct fxgmac_pdata *priv,
+ struct fxgmac_channel *channel)
+{
+ unsigned long tx_timeout;
+ unsigned int tx_status;
+
+ /* The Tx engine cannot be stopped if it is actively processing
+ * descriptors. Wait for the Tx engine to enter the stopped or
+ * suspended state.
+ */
+ tx_timeout = jiffies + (FXGMAC_DMA_STOP_TIMEOUT * HZ);
+
+ while (time_before(jiffies, tx_timeout)) {
+ tx_status = fxgmac_io_rd(priv, DMA_DSR0);
+ tx_status = FIELD_GET(DMA_DSR0_TPS, tx_status);
+ if (tx_status == DMA_TPS_STOPPED ||
+ tx_status == DMA_TPS_SUSPENDED)
+ break;
+
+ fsleep(500);
+ }
+
+ if (!time_before(jiffies, tx_timeout))
+ dev_err(priv->dev, "timed out waiting for Tx DMA channel stop\n");
+}
+
+static void fxgmac_disable_tx(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+
+ /* Prepare for Tx DMA channel stop */
+ fxgmac_prepare_tx_stop(priv, channel);
+
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_TE, 0); /* Disable MAC Tx */
+
+ /* Disable Tx queue */
+ fxgmac_mtl_wr_bits(priv, 0, MTL_Q_TQOMR, MTL_Q_TQOMR_TXQEN,
+ MTL_Q_DISABLED);
+
+ /* Disable Tx DMA channel */
+ fxgmac_dma_wr_bits(channel, DMA_CH_TCR, DMA_CH_TCR_ST, 0);
+}
+
+static void fxgmac_prepare_rx_stop(struct fxgmac_pdata *priv,
+ unsigned int queue)
+{
+ unsigned int rx_status, rx_q, rx_q_sts;
+ unsigned long rx_timeout;
+
+ /* The Rx engine cannot be stopped if it is actively processing
+ * packets. Wait for the Rx queue to empty the Rx fifo.
+ */
+ rx_timeout = jiffies + (FXGMAC_DMA_STOP_TIMEOUT * HZ);
+
+ while (time_before(jiffies, rx_timeout)) {
+ rx_status = fxgmac_mtl_io_rd(priv, queue, MTL_Q_RQDR);
+ rx_q = FIELD_GET(MTL_Q_RQDR_PRXQ, rx_status);
+ rx_q_sts = FIELD_GET(MTL_Q_RQDR_RXQSTS, rx_status);
+ if (rx_q == 0 && rx_q_sts == 0)
+ break;
+
+ fsleep(500);
+ }
+
+ if (!time_before(jiffies, rx_timeout))
+ dev_err(priv->dev, "timed out waiting for Rx queue %u to empty\n",
+ queue);
+}
+
+static void fxgmac_disable_rx(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+ u32 i;
+
+ /* Disable MAC Rx */
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_CST, 0);
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_ACS, 0);
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_RE, 0);
+
+ /* Prepare for Rx DMA channel stop */
+ for (i = 0; i < priv->rx_q_count; i++)
+ fxgmac_prepare_rx_stop(priv, i);
+
+ fxgmac_io_wr(priv, MAC_RQC0R, 0); /* Disable each Rx queue */
+
+ /* Disable each Rx DMA channel */
+ for (i = 0; i < priv->channel_count; i++, channel++)
+ fxgmac_dma_wr_bits(channel, DMA_CH_RCR, DMA_CH_RCR_SR, 0);
+}
+
+/**
+ * fxgmac_set_oob_wol - disable or enable oob wol crtl function
+ * @priv: driver private struct
+ * @en: 1 or 0
+ *
+ * Description: After enable OOB_WOL from efuse, mac will loopcheck phy status,
+ * and lead to panic sometimes. So we should disable it from powerup,
+ * enable it from power down.
+ */
+static void fxgmac_set_oob_wol(struct fxgmac_pdata *priv, unsigned int en)
+{
+ /* en = 1 is disable */
+ fxgmac_io_wr_bits(priv, OOB_WOL_CTRL, OOB_WOL_CTRL_DIS, !en);
+}
+
+static void fxgmac_config_powerup(struct fxgmac_pdata *priv)
+{
+ fxgmac_set_oob_wol(priv, 0);
+ /* GAMC power up */
+ fxgmac_io_wr_bits(priv, MAC_PMT_STA, MAC_PMT_STA_PWRDWN, 0);
+}
+
+static void fxgmac_pre_powerdown(struct fxgmac_pdata *priv)
+{
+ fxgmac_set_oob_wol(priv, 1);
+ fsleep(2000);
+}
static void fxgmac_phy_release(struct fxgmac_pdata *priv)
{
fxgmac_io_wr_bits(priv, EPHY_CTRL, EPHY_CTRL_RESET, 1);
@@ -117,6 +331,82 @@ static void fxgmac_phy_reset(struct fxgmac_pdata *priv)
fsleep(1500);
}
+static void fxgmac_disable_msix_irqs(struct fxgmac_pdata *priv)
+{
+ for (u32 intid = 0; intid < MSIX_TBL_MAX_NUM; intid++)
+ fxgmac_disable_msix_one_irq(priv, intid);
+}
+
+static void fxgmac_stop(struct fxgmac_pdata *priv)
+{
+ struct net_device *ndev = priv->ndev;
+ struct netdev_queue *txq;
+
+ if (priv->dev_state != FXGMAC_DEV_START)
+ return;
+
+ priv->dev_state = FXGMAC_DEV_STOP;
+
+ if (priv->per_channel_irq)
+ fxgmac_disable_msix_irqs(priv);
+ else
+ fxgmac_disable_mgm_irq(priv);
+
+ netif_carrier_off(ndev);
+ netif_tx_stop_all_queues(ndev);
+ fxgmac_disable_tx(priv);
+ fxgmac_disable_rx(priv);
+ fxgmac_free_irqs(priv);
+ fxgmac_napi_disable(priv);
+ phy_stop(priv->phydev);
+
+ txq = netdev_get_tx_queue(ndev, priv->channel_head->queue_index);
+ netdev_tx_reset_queue(txq);
+}
+
+static void fxgmac_config_powerdown(struct fxgmac_pdata *priv)
+{
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_RE, 1); /* Enable MAC Rx */
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_TE, 1); /* Enable MAC TX */
+
+ /* Set GAMC power down */
+ fxgmac_io_wr_bits(priv, MAC_PMT_STA, MAC_PMT_STA_PWRDWN, 1);
+}
+
+static int fxgmac_net_powerdown(struct fxgmac_pdata *priv)
+{
+ struct net_device *ndev = priv->ndev;
+
+ /* Signal that we are down to the interrupt handler */
+ if (__test_and_set_bit(FXGMAC_POWER_STATE_DOWN, &priv->power_state))
+ return 0; /* do nothing if already down */
+
+ __clear_bit(FXGMAC_POWER_STATE_UP, &priv->power_state);
+ netif_tx_stop_all_queues(ndev); /* Shut off incoming Tx traffic */
+
+ /* Call carrier off first to avoid false dev_watchdog timeouts */
+ netif_carrier_off(ndev);
+ netif_tx_disable(ndev);
+ fxgmac_disable_rx(priv);
+
+ /* Synchronize_rcu() needed for pending XDP buffers to drain */
+ synchronize_rcu();
+
+ fxgmac_stop(priv);
+ fxgmac_pre_powerdown(priv);
+
+ if (!test_bit(FXGMAC_POWER_STATE_DOWN, &priv->power_state))
+ dev_err(priv->dev, "fxgmac powerstate is %lu when config powe down.\n",
+ priv->power_state);
+
+ /* Set mac to lowpower mode */
+ fxgmac_config_powerdown(priv);
+ fxgmac_free_tx_data(priv);
+ fxgmac_free_rx_data(priv);
+
+ return 0;
+}
+
static void fxgmac_init_interrupt_scheme(struct fxgmac_pdata *priv)
{
struct pci_dev *pdev = to_pci_dev(priv->dev);
@@ -256,6 +546,25 @@ static void fxgmac_remove(struct pci_dev *pcidev)
}
}
+static void __fxgmac_shutdown(struct pci_dev *pcidev)
+{
+ struct fxgmac_pdata *priv = dev_get_drvdata(&pcidev->dev);
+ struct net_device *ndev = priv->ndev;
+
+ fxgmac_net_powerdown(priv);
+ netif_device_detach(ndev);
+}
+
+static void fxgmac_shutdown(struct pci_dev *pcidev)
+{
+ rtnl_lock();
+ __fxgmac_shutdown(pcidev);
+ if (system_state == SYSTEM_POWER_OFF) {
+ pci_wake_from_d3(pcidev, false);
+ pci_set_power_state(pcidev, PCI_D3hot);
+ }
+ rtnl_unlock();
+}
#define MOTORCOMM_PCI_ID 0x1f0a
#define YT6801_PCI_DEVICE_ID 0x6801
@@ -271,6 +580,7 @@ static struct pci_driver fxgmac_pci_driver = {
.id_table = fxgmac_pci_tbl,
.probe = fxgmac_probe,
.remove = fxgmac_remove,
+ .shutdown = fxgmac_shutdown,
};
module_pci_driver(fxgmac_pci_driver);
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
index b43952981..124860602 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
@@ -34,6 +34,61 @@
#define EPHY_CTRL_STA_DUPLEX BIT(2)
#define EPHY_CTRL_STA_SPEED GENMASK(4, 3)
+#define OOB_WOL_CTRL 0x1010
+#define OOB_WOL_CTRL_DIS BIT(0)
+
+/* MAC management registers */
+#define MGMT_INT_CTRL0 0x1100
+#define MGMT_INT_CTRL0_INT_STATUS GENMASK(15, 0)
+#define MGMT_INT_CTRL0_INT_STATUS_RX 0x000f
+#define MGMT_INT_CTRL0_INT_STATUS_TX 0x0010
+#define MGMT_INT_CTRL0_INT_STATUS_MISC 0x0020
+#define MGMT_INT_CTRL0_INT_STATUS_RXTX 0x0030
+#define MGMT_INT_CTRL0_INT_MASK GENMASK(31, 16)
+#define MGMT_INT_CTRL0_INT_MASK_RXCH 0x000f
+#define MGMT_INT_CTRL0_INT_MASK_TXCH 0x0010
+#define MGMT_INT_CTRL0_INT_MASK_MISC 0x0020
+#define MGMT_INT_CTRL0_INT_MASK_EX_PMT 0xf7ff
+#define MGMT_INT_CTRL0_INT_MASK_DISABLE 0xf000
+#define MGMT_INT_CTRL0_INT_MASK_MASK 0xffff
+
+/* msi table */
+#define MSI_ID_RXQ0 0
+#define MSI_ID_RXQ1 1
+#define MSI_ID_RXQ2 2
+#define MSI_ID_RXQ3 3
+#define MSI_ID_TXQ0 4
+#define MSIX_TBL_MAX_NUM 5
+
+/**************** GMAC register. *********************/
+#define MAC_CR 0x2000
+#define MAC_CR_RE BIT(0)
+#define MAC_CR_TE BIT(1)
+#define MAC_CR_LM BIT(12)
+#define MAC_CR_DM BIT(13)
+#define MAC_CR_FES BIT(14)
+#define MAC_CR_PS BIT(15)
+#define MAC_CR_JE BIT(16)
+#define MAC_CR_ACS BIT(20)
+#define MAC_CR_CST BIT(21)
+#define MAC_CR_IPC BIT(27)
+#define MAC_CR_ARPEN BIT(31)
+
+#define MAC_RQC0R 0x20a0
+#define MAC_RQC1R 0x20a4
+#define MAC_RQC2R 0x20a8
+#define MAC_RQC2_INC 4
+#define MAC_RQC2_Q_PER_REG 4
+
+#define MAC_PMT_STA 0x20c0
+#define MAC_PMT_STA_PWRDWN BIT(0)
+#define MAC_PMT_STA_MGKPKTEN BIT(1)
+#define MAC_PMT_STA_RWKPKTEN BIT(2)
+#define MAC_PMT_STA_MGKPRCVD BIT(5)
+#define MAC_PMT_STA_RWKPRCVD BIT(6)
+#define MAC_PMT_STA_GLBLUCAST BIT(9)
+#define MAC_PMT_STA_RWKPTR GENMASK(27, 24)
+#define MAC_PMT_STA_RWKFILTERST BIT(31)
#define MAC_MDIO_ADDR 0x2200
#define MAC_MDIO_ADDR_BUSY BIT(0)
#define MAC_MDIO_ADDR_GOC GENMASK(3, 2)
@@ -42,6 +97,153 @@
#define MAC_MDIO_DATA_GD GENMASK(15, 0)
#define MAC_MDIO_DATA_RA GENMASK(31, 16)
+/* MTL queue registers */
+#define MTL_Q_BASE 0x2d00
+#define MTL_Q_INC 0x40
+
+#define MTL_Q_TQOMR 0x00
+#define MTL_Q_TQOMR_FTQ BIT(0)
+#define MTL_Q_TQOMR_TSF BIT(1)
+#define MTL_Q_TQOMR_TXQEN GENMASK(3, 2)
+#define MTL_Q_DISABLED 0x00
+#define MTL_Q_EN_IF_AV 0x01
+#define MTL_Q_ENABLED 0x02
+
+#define MTL_Q_RQDR 0x38
+#define MTL_Q_RQDR_RXQSTS GENMASK(5, 4)
+#define MTL_Q_RQDR_PRXQ GENMASK(29, 16)
+#define DMA_DSRX_INC 4
+#define DMA_DSR0 0x300c
+#define DMA_DSR0_TPS GENMASK(15, 12)
+#define DMA_TPS_STOPPED 0x00
+#define DMA_TPS_SUSPENDED 0x06
+
+/* DMA channel registers */
+#define DMA_CH_BASE 0x3100
+#define DMA_CH_INC 0x80
+
+#define DMA_CH_TCR 0x04
+#define DMA_CH_TCR_ST BIT(0)
+#define DMA_CH_TCR_OSP BIT(4)
+#define DMA_CH_TCR_TSE BIT(12)
+#define DMA_CH_TCR_PBL GENMASK(21, 16)
+#define DMA_CH_PBL_1 1
+#define DMA_CH_PBL_2 2
+#define DMA_CH_PBL_4 4
+#define DMA_CH_PBL_8 8
+#define DMA_CH_PBL_16 16
+#define DMA_CH_PBL_32 32
+#define DMA_CH_PBL_64 64
+#define DMA_CH_PBL_128 128
+#define DMA_CH_PBL_256 256
+
+#define DMA_CH_RCR 0x08
+#define DMA_CH_RCR_SR BIT(0)
+#define DMA_CH_RCR_RBSZ GENMASK(14, 1)
+#define DMA_CH_RCR_PBL GENMASK(21, 16)
+
+/* Page allocation related values */
+struct fxgmac_page_alloc {
+ struct page *pages;
+ unsigned int pages_len;
+ unsigned int pages_offset;
+ dma_addr_t pages_dma;
+};
+
+/* Ring entry buffer data */
+struct fxgmac_buffer_data {
+ struct fxgmac_page_alloc pa;
+ struct fxgmac_page_alloc pa_unmap;
+
+ dma_addr_t dma_base;
+ unsigned long dma_off;
+ unsigned int dma_len;
+};
+
+struct fxgmac_tx_desc_data {
+ unsigned int packets; /* BQL packet count */
+ unsigned int bytes; /* BQL byte count */
+};
+
+struct fxgmac_rx_desc_data {
+ struct fxgmac_buffer_data hdr; /* Header locations */
+ struct fxgmac_buffer_data buf; /* Payload locations */
+ unsigned short hdr_len; /* Length of received header */
+ unsigned short len; /* Length of received packet */
+};
+
+struct fxgmac_desc_data {
+ struct fxgmac_dma_desc *dma_desc; /* Virtual address of descriptor */
+ dma_addr_t dma_desc_addr; /* DMA address of descriptor */
+ struct sk_buff *skb; /* Virtual address of SKB */
+ dma_addr_t skb_dma; /* DMA address of SKB data */
+ unsigned int skb_dma_len; /* Length of SKB DMA area */
+
+ /* Tx/Rx -related data */
+ struct fxgmac_tx_desc_data tx;
+ struct fxgmac_rx_desc_data rx;
+
+ unsigned int mapped_as_page;
+};
+
+struct fxgmac_ring {
+ struct fxgmac_pkt_info pkt_info; /* packet related information */
+
+ /* Virtual/DMA addresses of DMA descriptor list */
+ struct fxgmac_dma_desc *dma_desc_head;
+ dma_addr_t dma_desc_head_addr;
+ unsigned int dma_desc_count;
+
+ /* Array of descriptor data corresponding the DMA descriptor
+ * (always use the FXGMAC_GET_DESC_DATA macro to access this data)
+ */
+ struct fxgmac_desc_data *desc_data_head;
+
+ /* Page allocation for RX buffers */
+ struct fxgmac_page_alloc rx_hdr_pa;
+ struct fxgmac_page_alloc rx_buf_pa;
+
+ /* Ring index values
+ * cur - Tx: index of descriptor to be used for current transfer
+ * Rx: index of descriptor to check for packet availability
+ * dirty - Tx: index of descriptor to check for transfer complete
+ * Rx: index of descriptor to check for buffer reallocation
+ */
+ unsigned int cur;
+ unsigned int dirty;
+
+ struct {
+ unsigned int xmit_more;
+ unsigned int queue_stopped;
+ unsigned short cur_mss;
+ unsigned short cur_vlan_ctag;
+ } tx;
+} ____cacheline_aligned;
+
+struct fxgmac_channel {
+ char name[16];
+
+ /* Address of private data area for device */
+ struct fxgmac_pdata *priv;
+
+ /* Queue index and base address of queue's DMA registers */
+ unsigned int queue_index;
+
+ /* Per channel interrupt irq number */
+ u32 dma_irq_rx;
+ char dma_irq_rx_name[IFNAMSIZ + 32];
+ u32 dma_irq_tx;
+ char dma_irq_tx_name[IFNAMSIZ + 32];
+
+ /* ndev related settings */
+ struct napi_struct napi_tx;
+ struct napi_struct napi_rx;
+
+ void __iomem *dma_regs;
+ struct fxgmac_ring *tx_ring;
+ struct fxgmac_ring *rx_ring;
+} ____cacheline_aligned;
+
struct fxgmac_resources {
void __iomem *addr;
int irq;
@@ -64,6 +266,16 @@ struct fxgmac_pdata {
void __iomem *hw_addr; /* Registers base */
+ /* Rings for Tx/Rx on a DMA channel */
+ struct fxgmac_channel *channel_head;
+ unsigned int channel_count;
+ unsigned int rx_ring_count;
+ unsigned int rx_desc_count;
+ unsigned int rx_q_count;
+#define FXGMAC_TX_1_RING 1
+#define FXGMAC_TX_1_Q 1
+ unsigned int tx_desc_count;
+
/* Device interrupt */
int dev_irq;
unsigned int per_channel_irq;
@@ -89,6 +301,9 @@ struct fxgmac_pdata {
u32 msg_enable;
enum fxgmac_dev_state dev_state;
+#define FXGMAC_POWER_STATE_DOWN 0
+#define FXGMAC_POWER_STATE_UP 1
+ unsigned long power_state;
};
static inline u32 fxgmac_io_rd(struct fxgmac_pdata *priv, u32 reg)
@@ -119,4 +334,70 @@ fxgmac_io_wr_bits(struct fxgmac_pdata *priv, u32 reg, u32 mask, u32 set)
fxgmac_io_wr(priv, reg, cfg);
}
+static inline u32 fxgmac_mtl_io_rd(struct fxgmac_pdata *priv, u8 n, u32 reg)
+{
+ return fxgmac_io_rd(priv, reg + n * MTL_Q_INC);
+}
+
+static inline u32
+fxgmac_mtl_rd_bits(struct fxgmac_pdata *priv, u8 n, u32 reg, u32 mask)
+{
+ return fxgmac_io_rd_bits(priv, reg + n * MTL_Q_INC, mask);
+}
+
+static inline void
+fxgmac_mtl_io_wr(struct fxgmac_pdata *priv, u8 n, u32 reg, u32 set)
+{
+ return fxgmac_io_wr(priv, reg + n * MTL_Q_INC, set);
+}
+
+static inline void
+fxgmac_mtl_wr_bits(struct fxgmac_pdata *priv, u8 n, u32 reg, u32 mask, u32 set)
+{
+ return fxgmac_io_wr_bits(priv, reg + n * MTL_Q_INC, mask, set);
+}
+
+static inline u32 fxgmac_dma_io_rd(struct fxgmac_channel *channel, u32 reg)
+{
+ return ioread32(channel->dma_regs + reg);
+}
+
+static inline u32
+fxgmac_dma_rd_bits(struct fxgmac_channel *channel, u32 reg, u32 mask)
+{
+ u32 cfg = fxgmac_dma_io_rd(channel, reg);
+
+ return FIELD_GET(mask, cfg);
+}
+
+static inline void
+fxgmac_dma_io_wr(struct fxgmac_channel *channel, u32 reg, u32 set)
+{
+ iowrite32(set, channel->dma_regs + reg);
+}
+
+static inline void
+fxgmac_dma_wr_bits(struct fxgmac_channel *channel, u32 reg, u32 mask, u32 set)
+{
+ u32 cfg = fxgmac_dma_io_rd(channel, reg);
+
+ cfg &= ~mask;
+ cfg |= FIELD_PREP(mask, set);
+ fxgmac_dma_io_wr(channel, reg, cfg);
+}
+
+static inline u32 fxgmac_desc_rd_bits(__le32 desc, u32 mask)
+{
+ return FIELD_GET(mask, le32_to_cpu(desc));
+}
+
+static inline void fxgmac_desc_wr_bits(__le32 *desc, u32 mask, u32 set)
+{
+ u32 cfg = le32_to_cpu(*desc);
+
+ cfg &= ~mask;
+ cfg |= FIELD_PREP(mask, set);
+ *desc = cpu_to_le32(cfg);
+}
+
#endif /* YT6801_TYPE_H */
--
2.34.1
^ permalink raw reply related
* [PATCH v3 02/33] scripts/kernel-doc: add a symlink to the Perl version of kernel-doc
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
Preserve kernel-doc name, associating with the curent version
in Perl.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc | 1 +
1 file changed, 1 insertion(+)
create mode 120000 scripts/kernel-doc
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
new file mode 120000
index 000000000000..f175155c1e66
--- /dev/null
+++ b/scripts/kernel-doc
@@ -0,0 +1 @@
+kernel-doc.pl
\ No newline at end of file
--
2.49.0
^ permalink raw reply related
* [PATCH v3 18/33] docs: add a .pylintrc file with sys path for docs scripts
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
The docs scripts that are used by Documentation/sphinx are
using scripts/lib/* directories to place classes that will
be used by both extensions and scripts.
When pylint is used, it needs to identify the path where
such scripts are, otherwise it will bail out. Add a simple
RC file placing the location of such files.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
.pylintrc | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 .pylintrc
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 000000000000..30b8ae1659f8
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,2 @@
+[MASTER]
+init-hook='import sys; sys.path += ["scripts/lib/kdoc", "scripts/lib/abi"]'
--
2.49.0
^ permalink raw reply related
* [PATCH v3 12/33] scripts/kernel-doc.py: move file lists to the parser function
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
Instead of setting file lists at __init__ time, move it to
the actual parsing function. This allows adding more files
to be parsed in real time, by calling parse function multiple
times.
With the new way, the export_files logic was rewritten to
avoid parsing twice EXPORT_SYMBOL for partial matches.
Please notice that, with this logic, it can still read the
same file twice when export_file is used.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 7 +++----
scripts/lib/kdoc/kdoc_files.py | 37 ++++++++++++++++------------------
2 files changed, 20 insertions(+), 24 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 63efec4b3f4b..e258a9df7f78 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -274,14 +274,13 @@ def main():
else:
out_style = RestFormat()
- kfiles = KernelFiles(files=args.files, verbose=args.verbose,
+ kfiles = KernelFiles(verbose=args.verbose,
out_style=out_style, werror=args.werror,
wreturn=args.wreturn, wshort_desc=args.wshort_desc,
wcontents_before_sections=args.wcontents_before_sections,
- modulename=args.modulename,
- export_file=args.export_file)
+ modulename=args.modulename)
- kfiles.parse()
+ kfiles.parse(args.files, export_file=args.export_file)
for t in kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
internal=args.internal, symbol=args.symbol,
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 817ed98b2727..47dab46c89fe 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -124,7 +124,7 @@ class KernelFiles():
self.config.log.error("Cannot find file %s", fname)
self.config.errors += 1
- def __init__(self, files=None, verbose=False, out_style=None,
+ def __init__(self, verbose=False, out_style=None,
werror=False, wreturn=False, wshort_desc=False,
wcontents_before_sections=False,
logger=None, modulename=None, export_file=None):
@@ -181,51 +181,48 @@ class KernelFiles():
self.config.src_tree = os.environ.get("SRCTREE", None)
self.out_style = out_style
- self.export_file = export_file
# Initialize internal variables
self.config.errors = 0
self.results = []
- self.file_list = files
self.files = set()
+ self.export_files = set()
- def parse(self):
+ def parse(self, file_list, export_file=None):
"""
Parse all files
"""
glob = GlobSourceFiles(srctree=self.config.src_tree)
- # Let's use a set here to avoid duplicating files
+ # Prevent parsing the same file twice to speedup parsing and
+ # avoid reporting errors multiple times
- for fname in glob.parse_files(self.file_list, self.file_not_found_cb):
+ for fname in glob.parse_files(file_list, self.file_not_found_cb):
if fname in self.files:
continue
- self.files.add(fname)
-
res = self.parse_file(fname)
+
self.results.append((res.fname, res.entries))
-
- if not self.files:
- sys.exit(1)
+ self.files.add(fname)
# If a list of export files was provided, parse EXPORT_SYMBOL*
- # from the ones not already parsed
+ # from files that weren't fully parsed
- if self.export_file:
- files = self.files
+ if not export_file:
+ return
- glob = GlobSourceFiles(srctree=self.config.src_tree)
+ self.export_files |= self.files
- for fname in glob.parse_files(self.export_file,
- self.file_not_found_cb):
- if fname not in files:
- files.add(fname)
+ glob = GlobSourceFiles(srctree=self.config.src_tree)
- self.process_export_file(fname)
+ for fname in glob.parse_files(export_file, self.file_not_found_cb):
+ if fname not in self.export_files:
+ self.process_export_file(fname)
+ self.export_files.add(fname)
def out_msg(self, fname, name, arg):
"""
--
2.49.0
^ permalink raw reply related
* [PATCH v3 01/33] scripts/kernel-doc: rename it to scripts/kernel-doc.pl
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
In preparation for deprecating scripts/kernel-doc in favor of a
new version written in Perl, rename it to scripts/kernel-doc.pl.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/{kernel-doc => kernel-doc.pl} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename scripts/{kernel-doc => kernel-doc.pl} (100%)
diff --git a/scripts/kernel-doc b/scripts/kernel-doc.pl
similarity index 100%
rename from scripts/kernel-doc
rename to scripts/kernel-doc.pl
--
2.49.0
^ permalink raw reply
* [PATCH v3 04/33] scripts/kernel-doc.py: output warnings the same way as kerneldoc
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
Add a formatter to logging to produce outputs in a similar way
to kernel-doc. This should help making it more compatible with
existing scripts.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 114f3699bf7c..8625209d6293 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -2715,6 +2715,11 @@ neither here nor at the original Perl script.
"""
+class MsgFormatter(logging.Formatter):
+ def format(self, record):
+ record.levelname = record.levelname.capitalize()
+ return logging.Formatter.format(self, record)
+
def main():
"""Main program"""
@@ -2799,10 +2804,19 @@ def main():
args.wshort_desc = True
args.wcontents_before_sections = True
+ logger = logging.getLogger()
+
if not args.debug:
- level = logging.INFO
+ logger.setLevel(logging.INFO)
else:
- level = logging.DEBUG
+ logger.setLevel(logging.DEBUG)
+
+ formatter = MsgFormatter('%(levelname)s: %(message)s')
+
+ handler = logging.StreamHandler()
+ handler.setFormatter(formatter)
+
+ logger.addHandler(handler)
if args.man:
out_style = ManFormat()
@@ -2811,8 +2825,6 @@ def main():
else:
out_style = RestFormat()
- logging.basicConfig(level=level, format="%(levelname)s: %(message)s")
-
kfiles = KernelFiles(files=args.files, verbose=args.verbose,
out_style=out_style, werror=args.werror,
wreturn=args.wreturn, wshort_desc=args.wshort_desc,
--
2.49.0
^ permalink raw reply related
* [PATCH v3 13/33] scripts/kernel-doc.py: implement support for -no-doc-sections
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
The venerable kernel-doc Perl script has a number of options that
aren't properly documented. Among them, there is -no-doc-sections,
which is used by the Sphinx extension.
Implement support for it.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 8 ++++++--
scripts/lib/kdoc/kdoc_files.py | 5 +++--
scripts/lib/kdoc/kdoc_output.py | 7 ++++++-
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index e258a9df7f78..90aacd17499a 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -239,10 +239,13 @@ def main():
sel_mut.add_argument("-s", "-function", "--symbol", action='append',
help=FUNCTION_DESC)
- # This one is valid for all 3 types of filter
+ # Those are valid for all 3 types of filter
parser.add_argument("-n", "-nosymbol", "--nosymbol", action='append',
help=NOSYMBOL_DESC)
+ parser.add_argument("-D", "-no-doc-sections", "--no-doc-sections",
+ action='store_true', help="Don't outputt DOC sections")
+
parser.add_argument("files", metavar="FILE",
nargs="+", help=FILES_DESC)
@@ -284,7 +287,8 @@ def main():
for t in kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
internal=args.internal, symbol=args.symbol,
- nosymbol=args.nosymbol):
+ nosymbol=args.nosymbol,
+ no_doc_sections=args.no_doc_sections):
msg = t[1]
if msg:
print(msg)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 47dab46c89fe..4c04546a74fe 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -238,7 +238,7 @@ class KernelFiles():
return self.out_style.msg(fname, name, arg)
def msg(self, enable_lineno=False, export=False, internal=False,
- symbol=None, nosymbol=None):
+ symbol=None, nosymbol=None, no_doc_sections=False):
"""
Interacts over the kernel-doc results and output messages,
returning kernel-doc markups on each interaction
@@ -257,7 +257,8 @@ class KernelFiles():
self.out_style.set_config(self.config)
self.out_style.set_filter(export, internal, symbol, nosymbol,
- function_table, enable_lineno)
+ function_table, enable_lineno,
+ no_doc_sections)
for fname, arg_tuple in self.results:
msg = ""
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index fda07049ecf7..a246d213523c 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -70,6 +70,7 @@ class OutputFormat:
self.symbol = None
self.function_table = set()
self.config = None
+ self.no_doc_sections = False
self.data = ""
@@ -77,7 +78,7 @@ class OutputFormat:
self.config = config
def set_filter(self, export, internal, symbol, nosymbol, function_table,
- enable_lineno):
+ enable_lineno, no_doc_sections):
"""
Initialize filter variables according with the requested mode.
@@ -87,6 +88,7 @@ class OutputFormat:
"""
self.enable_lineno = enable_lineno
+ self.no_doc_sections = no_doc_sections
if symbol:
self.out_mode = self.OUTPUT_INCLUDE
@@ -117,6 +119,9 @@ class OutputFormat:
def check_doc(self, name):
"""Check if DOC should be output"""
+ if self.no_doc_sections:
+ return False
+
if self.out_mode == self.OUTPUT_ALL:
return True
--
2.49.0
^ permalink raw reply related
* [PATCH v3 22/33] scripts/kernel-doc.py: Set an output format for --none
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
Now that warnings output is deferred to the output plugin, we
need to have an output style for none as well.
So, use the OutputFormat base class on such cases.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_files.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 4c04546a74fe..dd3dbe87520b 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -20,6 +20,7 @@ from datetime import datetime
from dateutil import tz
from kdoc_parser import KernelDoc
+from kdoc_output import OutputFormat
class GlobSourceFiles:
@@ -138,6 +139,9 @@ class KernelFiles():
if not modulename:
modulename = "Kernel API"
+ if out_style is None:
+ out_style = OutputFormat()
+
dt = datetime.now()
if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
# use UTC TZ
--
2.49.0
^ permalink raw reply related
* [PATCH v3 16/33] scripts/kernel-doc.py: properly handle out_section for ReST
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
There is a difference at the way DOC sections are output with
the include mode. Handle such difference properly.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_output.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index 7a945dd80c9b..d0c8cedb0ea5 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -315,12 +315,12 @@ class RestFormat(OutputFormat):
if section in self.nosymbol:
continue
- if not self.out_mode == self.OUTPUT_INCLUDE:
- if out_docblock:
+ if out_docblock:
+ if not self.out_mode == self.OUTPUT_INCLUDE:
self.data += f".. _{section}:\n\n"
-
- if not self.symbol:
self.data += f'{self.lineprefix}**{section}**\n\n'
+ else:
+ self.data += f'{self.lineprefix}**{section}**\n\n'
self.print_lineno(section_start_lines.get(section, 0))
self.output_highlight(sections[section])
--
2.49.0
^ permalink raw reply related
* [PATCH v3 30/33] scripts/lib/kdoc/kdoc_files.py: allow filtering output per fname
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
For kerneldoc Sphinx extension, it is useful to display
parsed results only from a single file. Change the logic at
KernelFiles.msg() to allow such usage.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_files.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 182d9ed58a72..527ab9117268 100644
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -95,7 +95,7 @@ class KernelFiles():
doc = KernelDoc(self.config, fname)
doc.run()
- return doc
+ return doc.entries
def process_export_file(self, fname):
"""
@@ -173,7 +173,7 @@ class KernelFiles():
# Initialize internal variables
self.config.errors = 0
- self.results = []
+ self.results = {}
self.files = set()
self.export_files = set()
@@ -189,13 +189,9 @@ class KernelFiles():
# avoid reporting errors multiple times
for fname in glob.parse_files(file_list, self.file_not_found_cb):
- if fname in self.files:
- continue
-
- res = self.parse_file(fname)
-
- self.results.append((res.fname, res.entries))
- self.files.add(fname)
+ if fname not in self.files:
+ self.results[fname] = self.parse_file(fname)
+ self.files.add(fname)
# If a list of export files was provided, parse EXPORT_SYMBOL*
# from files that weren't fully parsed
@@ -226,7 +222,8 @@ class KernelFiles():
return self.out_style.msg(fname, name, arg)
def msg(self, enable_lineno=False, export=False, internal=False,
- symbol=None, nosymbol=None, no_doc_sections=False):
+ symbol=None, nosymbol=None, no_doc_sections=False,
+ filenames=None):
"""
Interacts over the kernel-doc results and output messages,
returning kernel-doc markups on each interaction
@@ -248,9 +245,12 @@ class KernelFiles():
function_table, enable_lineno,
no_doc_sections)
- for fname, arg_tuple in self.results:
+ if not filenames:
+ filenames = sorted(self.results.keys())
+
+ for fname in filenames:
msg = ""
- for name, arg in arg_tuple:
+ for name, arg in self.results[fname]:
msg += self.out_msg(fname, name, arg)
if msg is None:
--
2.49.0
^ permalink raw reply related
* [PATCH v3 29/33] scripts/kernel-doc: switch to use kernel-doc.py
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
Now that all features are in place, change the kernel-doc alias
to point to kernel-doc.py.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index f175155c1e66..3b6ef807791a 120000
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1 +1 @@
-kernel-doc.pl
\ No newline at end of file
+kernel-doc.py
\ No newline at end of file
--
2.49.0
^ permalink raw reply related
* [PATCH v3 07/33] scripts/kernel-doc.py: move regex methods to a separate file
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
In preparation for letting kerneldoc Sphinx extension to import
Python libraries, move regex ancillary classes to a separate
file.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 223 +----------------------------
scripts/lib/kdoc/kdoc_re.py | 272 ++++++++++++++++++++++++++++++++++++
2 files changed, 277 insertions(+), 218 deletions(-)
create mode 100755 scripts/lib/kdoc/kdoc_re.py
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index fb96d42d287c..7f00c8c86a78 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -110,228 +110,15 @@ from pprint import pformat
from dateutil import tz
-# Local cache for regular expressions
-re_cache = {}
+# Import Python modules
+LIB_DIR = "lib/kdoc"
+SRC_DIR = os.path.dirname(os.path.realpath(__file__))
-class Re:
- """
- Helper class to simplify regex declaration and usage,
+sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
- It calls re.compile for a given pattern. It also allows adding
- regular expressions and define sub at class init time.
+from kdoc_re import Re, NestedMatch
- Regular expressions can be cached via an argument, helping to speedup
- searches.
- """
-
- def _add_regex(self, string, flags):
- if string in re_cache:
- self.regex = re_cache[string]
- else:
- self.regex = re.compile(string, flags=flags)
-
- if self.cache:
- re_cache[string] = self.regex
-
- def __init__(self, string, cache=True, flags=0):
- self.cache = cache
- self.last_match = None
-
- self._add_regex(string, flags)
-
- def __str__(self):
- return self.regex.pattern
-
- def __add__(self, other):
- return Re(str(self) + str(other), cache=self.cache or other.cache,
- flags=self.regex.flags | other.regex.flags)
-
- def match(self, string):
- self.last_match = self.regex.match(string)
- return self.last_match
-
- def search(self, string):
- self.last_match = self.regex.search(string)
- return self.last_match
-
- def findall(self, string):
- return self.regex.findall(string)
-
- def split(self, string):
- return self.regex.split(string)
-
- def sub(self, sub, string, count=0):
- return self.regex.sub(sub, string, count=count)
-
- def group(self, num):
- return self.last_match.group(num)
-
-class NestedMatch:
- """
- Finding nested delimiters is hard with regular expressions. It is
- even harder on Python with its normal re module, as there are several
- advanced regular expressions that are missing.
-
- This is the case of this pattern:
-
- '\\bSTRUCT_GROUP(\\(((?:(?>[^)(]+)|(?1))*)\\))[^;]*;'
-
- which is used to properly match open/close parenthesis of the
- string search STRUCT_GROUP(),
-
- Add a class that counts pairs of delimiters, using it to match and
- replace nested expressions.
-
- The original approach was suggested by:
- https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
-
- Although I re-implemented it to make it more generic and match 3 types
- of delimiters. The logic checks if delimiters are paired. If not, it
- will ignore the search string.
- """
-
- # TODO:
- # Right now, regular expressions to match it are defined only up to
- # the start delimiter, e.g.:
- #
- # \bSTRUCT_GROUP\(
- #
- # is similar to: STRUCT_GROUP\((.*)\)
- # except that the content inside the match group is delimiter's aligned.
- #
- # The content inside parenthesis are converted into a single replace
- # group (e.g. r`\1').
- #
- # It would be nice to change such definition to support multiple
- # match groups, allowing a regex equivalent to.
- #
- # FOO\((.*), (.*), (.*)\)
- #
- # it is probably easier to define it not as a regular expression, but
- # with some lexical definition like:
- #
- # FOO(arg1, arg2, arg3)
-
-
- DELIMITER_PAIRS = {
- '{': '}',
- '(': ')',
- '[': ']',
- }
-
- RE_DELIM = re.compile(r'[\{\}\[\]\(\)]')
-
- def _search(self, regex, line):
- """
- Finds paired blocks for a regex that ends with a delimiter.
-
- The suggestion of using finditer to match pairs came from:
- https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
- but I ended using a different implementation to align all three types
- of delimiters and seek for an initial regular expression.
-
- The algorithm seeks for open/close paired delimiters and place them
- into a stack, yielding a start/stop position of each match when the
- stack is zeroed.
-
- The algorithm shoud work fine for properly paired lines, but will
- silently ignore end delimiters that preceeds an start delimiter.
- This should be OK for kernel-doc parser, as unaligned delimiters
- would cause compilation errors. So, we don't need to rise exceptions
- to cover such issues.
- """
-
- stack = []
-
- for match_re in regex.finditer(line):
- start = match_re.start()
- offset = match_re.end()
-
- d = line[offset -1]
- if d not in self.DELIMITER_PAIRS:
- continue
-
- end = self.DELIMITER_PAIRS[d]
- stack.append(end)
-
- for match in self.RE_DELIM.finditer(line[offset:]):
- pos = match.start() + offset
-
- d = line[pos]
-
- if d in self.DELIMITER_PAIRS:
- end = self.DELIMITER_PAIRS[d]
-
- stack.append(end)
- continue
-
- # Does the end delimiter match what it is expected?
- if stack and d == stack[-1]:
- stack.pop()
-
- if not stack:
- yield start, offset, pos + 1
- break
-
- def search(self, regex, line):
- """
- This is similar to re.search:
-
- It matches a regex that it is followed by a delimiter,
- returning occurrences only if all delimiters are paired.
- """
-
- for t in self._search(regex, line):
-
- yield line[t[0]:t[2]]
-
- def sub(self, regex, sub, line, count=0):
- """
- This is similar to re.sub:
-
- It matches a regex that it is followed by a delimiter,
- replacing occurrences only if all delimiters are paired.
-
- if r'\1' is used, it works just like re: it places there the
- matched paired data with the delimiter stripped.
-
- If count is different than zero, it will replace at most count
- items.
- """
- out = ""
-
- cur_pos = 0
- n = 0
-
- found = False
- for start, end, pos in self._search(regex, line):
- out += line[cur_pos:start]
-
- # Value, ignoring start/end delimiters
- value = line[end:pos - 1]
-
- # replaces \1 at the sub string, if \1 is used there
- new_sub = sub
- new_sub = new_sub.replace(r'\1', value)
-
- out += new_sub
-
- # Drop end ';' if any
- if line[pos] == ';':
- pos += 1
-
- cur_pos = pos
- n += 1
-
- if count and count >= n:
- break
-
- # Append the remaining string
- l = len(line)
- out += line[cur_pos:l]
-
- return out
#
# Regular expressions used to parse kernel-doc markups at KernelDoc class.
diff --git a/scripts/lib/kdoc/kdoc_re.py b/scripts/lib/kdoc/kdoc_re.py
new file mode 100755
index 000000000000..512b6521e79d
--- /dev/null
+++ b/scripts/lib/kdoc/kdoc_re.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
+
+"""
+Regular expression ancillary classes.
+
+Those help caching regular expressions and do matching for kernel-doc.
+"""
+
+import re
+
+# Local cache for regular expressions
+re_cache = {}
+
+
+class Re:
+ """
+ Helper class to simplify regex declaration and usage,
+
+ It calls re.compile for a given pattern. It also allows adding
+ regular expressions and define sub at class init time.
+
+ Regular expressions can be cached via an argument, helping to speedup
+ searches.
+ """
+
+ def _add_regex(self, string, flags):
+ """
+ Adds a new regex or re-use it from the cache.
+ """
+
+ if string in re_cache:
+ self.regex = re_cache[string]
+ else:
+ self.regex = re.compile(string, flags=flags)
+
+ if self.cache:
+ re_cache[string] = self.regex
+
+ def __init__(self, string, cache=True, flags=0):
+ """
+ Compile a regular expression and initialize internal vars.
+ """
+
+ self.cache = cache
+ self.last_match = None
+
+ self._add_regex(string, flags)
+
+ def __str__(self):
+ """
+ Return the regular expression pattern.
+ """
+ return self.regex.pattern
+
+ def __add__(self, other):
+ """
+ Allows adding two regular expressions into one.
+ """
+
+ return Re(str(self) + str(other), cache=self.cache or other.cache,
+ flags=self.regex.flags | other.regex.flags)
+
+ def match(self, string):
+ """
+ Handles a re.match storing its results
+ """
+
+ self.last_match = self.regex.match(string)
+ return self.last_match
+
+ def search(self, string):
+ """
+ Handles a re.search storing its results
+ """
+
+ self.last_match = self.regex.search(string)
+ return self.last_match
+
+ def findall(self, string):
+ """
+ Alias to re.findall
+ """
+
+ return self.regex.findall(string)
+
+ def split(self, string):
+ """
+ Alias to re.split
+ """
+
+ return self.regex.split(string)
+
+ def sub(self, sub, string, count=0):
+ """
+ Alias to re.sub
+ """
+
+ return self.regex.sub(sub, string, count=count)
+
+ def group(self, num):
+ """
+ Returns the group results of the last match
+ """
+
+ return self.last_match.group(num)
+
+
+class NestedMatch:
+ """
+ Finding nested delimiters is hard with regular expressions. It is
+ even harder on Python with its normal re module, as there are several
+ advanced regular expressions that are missing.
+
+ This is the case of this pattern:
+
+ '\\bSTRUCT_GROUP(\\(((?:(?>[^)(]+)|(?1))*)\\))[^;]*;'
+
+ which is used to properly match open/close parenthesis of the
+ string search STRUCT_GROUP(),
+
+ Add a class that counts pairs of delimiters, using it to match and
+ replace nested expressions.
+
+ The original approach was suggested by:
+ https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
+
+ Although I re-implemented it to make it more generic and match 3 types
+ of delimiters. The logic checks if delimiters are paired. If not, it
+ will ignore the search string.
+ """
+
+ # TODO:
+ # Right now, regular expressions to match it are defined only up to
+ # the start delimiter, e.g.:
+ #
+ # \bSTRUCT_GROUP\(
+ #
+ # is similar to: STRUCT_GROUP\((.*)\)
+ # except that the content inside the match group is delimiter's aligned.
+ #
+ # The content inside parenthesis are converted into a single replace
+ # group (e.g. r`\1').
+ #
+ # It would be nice to change such definition to support multiple
+ # match groups, allowing a regex equivalent to.
+ #
+ # FOO\((.*), (.*), (.*)\)
+ #
+ # it is probably easier to define it not as a regular expression, but
+ # with some lexical definition like:
+ #
+ # FOO(arg1, arg2, arg3)
+
+ DELIMITER_PAIRS = {
+ '{': '}',
+ '(': ')',
+ '[': ']',
+ }
+
+ RE_DELIM = re.compile(r'[\{\}\[\]\(\)]')
+
+ def _search(self, regex, line):
+ """
+ Finds paired blocks for a regex that ends with a delimiter.
+
+ The suggestion of using finditer to match pairs came from:
+ https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
+ but I ended using a different implementation to align all three types
+ of delimiters and seek for an initial regular expression.
+
+ The algorithm seeks for open/close paired delimiters and place them
+ into a stack, yielding a start/stop position of each match when the
+ stack is zeroed.
+
+ The algorithm shoud work fine for properly paired lines, but will
+ silently ignore end delimiters that preceeds an start delimiter.
+ This should be OK for kernel-doc parser, as unaligned delimiters
+ would cause compilation errors. So, we don't need to rise exceptions
+ to cover such issues.
+ """
+
+ stack = []
+
+ for match_re in regex.finditer(line):
+ start = match_re.start()
+ offset = match_re.end()
+
+ d = line[offset - 1]
+ if d not in self.DELIMITER_PAIRS:
+ continue
+
+ end = self.DELIMITER_PAIRS[d]
+ stack.append(end)
+
+ for match in self.RE_DELIM.finditer(line[offset:]):
+ pos = match.start() + offset
+
+ d = line[pos]
+
+ if d in self.DELIMITER_PAIRS:
+ end = self.DELIMITER_PAIRS[d]
+
+ stack.append(end)
+ continue
+
+ # Does the end delimiter match what it is expected?
+ if stack and d == stack[-1]:
+ stack.pop()
+
+ if not stack:
+ yield start, offset, pos + 1
+ break
+
+ def search(self, regex, line):
+ """
+ This is similar to re.search:
+
+ It matches a regex that it is followed by a delimiter,
+ returning occurrences only if all delimiters are paired.
+ """
+
+ for t in self._search(regex, line):
+
+ yield line[t[0]:t[2]]
+
+ def sub(self, regex, sub, line, count=0):
+ """
+ This is similar to re.sub:
+
+ It matches a regex that it is followed by a delimiter,
+ replacing occurrences only if all delimiters are paired.
+
+ if r'\1' is used, it works just like re: it places there the
+ matched paired data with the delimiter stripped.
+
+ If count is different than zero, it will replace at most count
+ items.
+ """
+ out = ""
+
+ cur_pos = 0
+ n = 0
+
+ for start, end, pos in self._search(regex, line):
+ out += line[cur_pos:start]
+
+ # Value, ignoring start/end delimiters
+ value = line[end:pos - 1]
+
+ # replaces \1 at the sub string, if \1 is used there
+ new_sub = sub
+ new_sub = new_sub.replace(r'\1', value)
+
+ out += new_sub
+
+ # Drop end ';' if any
+ if line[pos] == ';':
+ pos += 1
+
+ cur_pos = pos
+ n += 1
+
+ if count and count >= n:
+ break
+
+ # Append the remaining string
+ l = len(line)
+ out += line[cur_pos:l]
+
+ return out
--
2.49.0
^ permalink raw reply related
* [PATCH v3 20/33] docs: sphinx: kerneldoc: ignore "\" characters from options
From: Mauro Carvalho Chehab @ 2025-04-08 10:09 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Kees Cook, linux-kernel
In-Reply-To: <cover.1744106241.git.mchehab+huawei@kernel.org>
Documentation/driver-api/infiniband.rst has a kernel-doc tag
with "\" characters at the end:
.. kernel-doc:: drivers/infiniband/ulp/iser/iscsi_iser.c
:functions: iscsi_iser_pdu_alloc iser_initialize_task_headers \
iscsi_iser_task_init iscsi_iser_mtask_xmit iscsi_iser_task_xmit \
iscsi_iser_cleanup_task iscsi_iser_check_protection \
iscsi_iser_conn_create iscsi_iser_conn_bind \
iscsi_iser_conn_start iscsi_iser_conn_stop \
iscsi_iser_session_destroy iscsi_iser_session_create \
iscsi_iser_set_param iscsi_iser_ep_connect iscsi_iser_ep_poll \
iscsi_iser_ep_disconnect
This is not handled well, as the "\" strings will be just stored inside
Sphinx options.
While the actual problem deserves being fixed, better to relax the
keneldoc.py extension to silently strip "\" from the end of strings,
as otherwise this may cause troubles when preparing arguments to
be executed by kernel-doc.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
Documentation/sphinx/kerneldoc.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py
index d206eb2be10a..344789ed9ea2 100644
--- a/Documentation/sphinx/kerneldoc.py
+++ b/Documentation/sphinx/kerneldoc.py
@@ -118,6 +118,10 @@ class KernelDocDirective(Directive):
identifiers = self.options.get('identifiers').split()
if identifiers:
for i in identifiers:
+ i = i.rstrip("\\").strip()
+ if not i:
+ continue
+
cmd += ['-function', i]
else:
cmd += ['-no-doc-sections']
@@ -126,9 +130,17 @@ class KernelDocDirective(Directive):
no_identifiers = self.options.get('no-identifiers').split()
if no_identifiers:
for i in no_identifiers:
+ i = i.rstrip("\\").strip()
+ if not i:
+ continue
+
cmd += ['-nosymbol', i]
for pattern in export_file_patterns:
+ pattern = pattern.rstrip("\\").strip()
+ if not pattern:
+ continue
+
for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern):
env.note_dependency(os.path.abspath(f))
cmd += ['-export-file', f]
--
2.49.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox