summaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/dap8211r.c
diff options
context:
space:
mode:
authorKees Cook <kees+treewide@kernel.org>2026-09-02 15:31:14 -0700
committerKees Cook <kees@kernel.org>2026-09-04 21:37:00 -0700
commit3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d (patch)
treec65086f9bdcd48c6360fb7cb4598bca084da1f32 /drivers/net/phy/dap8211r.c
downloadlinux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.tar.gz
linux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.zip
treewide: refresh kmalloc_obj() conversionsgrafted
This is another run of the Coccinelle script for converting kmalloc() family of allocations to kmalloc_obj() via the existing rules in scripts/coccinelle/api/kmalloc_objs.cocci This catches both the set of kmalloc() uses added since the first kmalloc_obj() conversions in v7.0 and adds a large group missed in the first pass due to Coccinelle not interacting well with the cleanup.h scoped_...() family of macros[1]. I worked around this with spatch's "--macro-file" argument to a file with all the scoped_...() macros mapped to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control flow indicator I could find. Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc, riscv, and s390 with no new warnings. Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1] Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2] Signed-off-by: Kees Cook <kees+treewide@kernel.org>
Diffstat (limited to 'drivers/net/phy/dap8211r.c')
-rw-r--r--drivers/net/phy/dap8211r.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/drivers/net/phy/dap8211r.c b/drivers/net/phy/dap8211r.c
new file mode 100644
index 000000000..0bf770f8e
--- /dev/null
+++ b/drivers/net/phy/dap8211r.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY.
+ *
+ * Specifications:
+ * - IEEE 802.3 10BASE-Te, 100BASE-TX, 1000BASE-T
+ * - IEEE 802.3az-2010 Energy Efficient Ethernet
+ * - IEEE 1588 SyncE support
+ * - RGMII
+ *
+ * Author: Artem Shimko <a.shimko.dev@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/errno.h>
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/iopoll.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#define DAP8211R_PHY_ID 0x0008011B
+#define DAP8211R_PHY_ID_MASK 0xFFFFFFFF
+
+#define DAP8211R_EXT_ADD 0x1E
+#define DAP8211R_EXT_DATA 0x1F
+
+#define DAP8211R_PHY_CON 0xA001
+#define DAP8211R_PHY_SW_RST BIT(15)
+
+#define DAP8211R_RGMII_CON 0xA003
+#define DAP8211R_RGMII_TX_DEL_MASK GENMASK(3, 0)
+#define DAP8211R_RGMII_RX_DEL_MASK GENMASK(13, 10)
+
+#define DAP8211R_RGMII_CONFIG_MASK (DAP8211R_RGMII_RX_DEL_MASK | DAP8211R_RGMII_TX_DEL_MASK)
+
+/*
+ * Hardware reset RX RGMII default delay from the datasheet: 0 * 150ps == 0.00ns
+ * Used when rx-internal-delay-ps is not specified in DT for RGMII mode and
+ * in RGMII_TXID to set rx delay.
+ */
+#define DAP8211R_INITIAL_RX_DEL_VAL 0
+
+/*
+ * Hardware reset TX RGMII default delay from the datasheet: 1 * 150ps == 0.15ns
+ * Used when tx-internal-delay-ps is not specified in DT for RGMII mode and
+ * in RGMII_RXID to set tx delay.
+ */
+#define DAP8211R_INITIAL_TX_DEL_VAL 1
+
+/*
+ * Default RGMII delay: 13 * 150 == 1.95ns
+ * Used when rx-internal-delay-ps or tx-internal-delay-ps are not specified in DT
+ * for RGMII ID modes to set tx or rx delay.
+ */
+#define DAP8211R_DEFAULT_DEL_SEL 0xD
+
+static const int dap8211r_internal_delay[] = {0, 150, 300, 450, 600, 750, 900,
+ 1050, 1200, 1350, 1500, 1650, 1800,
+ 1950, 2100, 2250};
+
+#define DAP8211R_DELAY_SIZE ARRAY_SIZE(dap8211r_internal_delay)
+
+/**
+ * dap8211r_read_ext() - Read extended register
+ * @phydev: PHY device structure
+ * @reg: Extended register address
+ *
+ * Reads a PHY extended register using the indirect access method.
+ * The caller must hold the MDIO bus lock.
+ *
+ * Return: Register value on success, or negative error code
+ */
+static int dap8211r_read_ext(struct phy_device *phydev, u16 reg)
+{
+ int ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = __phy_write(phydev, DAP8211R_EXT_ADD, reg);
+ if (ret < 0)
+ goto out;
+
+ ret = __phy_read(phydev, DAP8211R_EXT_DATA);
+out:
+ phy_unlock_mdio_bus(phydev);
+ return ret;
+}
+
+/**
+ * dap8211r_modify_ext() - Modify extended register bits
+ * @phydev: PHY device structure
+ * @reg: Extended register address
+ * @mask: Bit mask of bits to clear
+ * @set: Bit mask of bits to set
+ *
+ * Modifies a PHY extended register using the indirect access method.
+ * New value = (old value & ~mask) | set.
+ * The caller must hold the MDIO bus lock.
+ *
+ * Return: 0 on success, or negative error code
+ */
+static int dap8211r_modify_ext(struct phy_device *phydev, u16 reg, u16 mask, u16 set)
+{
+ int ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = __phy_write(phydev, DAP8211R_EXT_ADD, reg);
+ if (ret < 0)
+ goto out;
+
+ ret = __phy_modify(phydev, DAP8211R_EXT_DATA, mask, set);
+out:
+ phy_unlock_mdio_bus(phydev);
+ return ret;
+}
+
+/**
+ * dap8211r_config_init() - Initialize PHY
+ * @phydev: PHY device structure
+ *
+ * Configures the PHY during initialization:
+ * - RGMII delays based on interface mode
+ * - Software reset to apply settings (low active, self clear)
+ *
+ * Return: 0 on success, or negative error code
+ */
+static int dap8211r_config_init(struct phy_device *phydev)
+{
+ u16 set = 0;
+ int ret, val;
+ s32 rx_internal_delay = DAP8211R_INITIAL_RX_DEL_VAL;
+ s32 tx_internal_delay = DAP8211R_INITIAL_TX_DEL_VAL;
+
+ if (!phy_interface_is_rgmii(phydev))
+ return 0;
+
+ if (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)
+ rx_internal_delay = phy_get_internal_delay(phydev, dap8211r_internal_delay,
+ DAP8211R_DELAY_SIZE, true);
+
+ if (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)
+ tx_internal_delay = phy_get_internal_delay(phydev, dap8211r_internal_delay,
+ DAP8211R_DELAY_SIZE, false);
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ if (rx_internal_delay < 0)
+ rx_internal_delay = DAP8211R_INITIAL_RX_DEL_VAL;
+
+ if (tx_internal_delay < 0)
+ tx_internal_delay = DAP8211R_INITIAL_TX_DEL_VAL;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ if (rx_internal_delay < 0)
+ rx_internal_delay = DAP8211R_DEFAULT_DEL_SEL;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ if (rx_internal_delay < 0)
+ rx_internal_delay = DAP8211R_DEFAULT_DEL_SEL;
+ fallthrough;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (tx_internal_delay < 0)
+ tx_internal_delay = DAP8211R_DEFAULT_DEL_SEL;
+ break;
+ default:
+ phydev_err(phydev, "Unsupported interface: %d\n",
+ phydev->interface);
+ return -EINVAL;
+ }
+
+ set |= FIELD_PREP(DAP8211R_RGMII_RX_DEL_MASK, rx_internal_delay);
+ set |= FIELD_PREP(DAP8211R_RGMII_TX_DEL_MASK, tx_internal_delay);
+
+ ret = dap8211r_modify_ext(phydev, DAP8211R_PHY_CON, DAP8211R_PHY_SW_RST, 0);
+ if (ret)
+ return ret;
+
+ /* Wait for reset self-clear (from low active to high) */
+ ret = read_poll_timeout(dap8211r_read_ext, val,
+ (val & DAP8211R_PHY_SW_RST),
+ 20, 200, false, phydev, DAP8211R_PHY_CON);
+ if (ret)
+ return ret;
+ if (val < 0)
+ return val;
+
+ ret = dap8211r_modify_ext(phydev, DAP8211R_RGMII_CON, DAP8211R_RGMII_CONFIG_MASK, set);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct phy_driver dap8211r_driver[] = {
+ {
+ PHY_ID_MATCH_EXACT(DAP8211R_PHY_ID),
+ .name = "DAP8211R Gigabit Ethernet",
+ .soft_reset = genphy_soft_reset,
+ .config_init = dap8211r_config_init,
+ .read_status = genphy_read_status,
+ .set_loopback = genphy_loopback,
+ .config_aneg = genphy_config_aneg,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ },
+};
+module_phy_driver(dap8211r_driver);
+
+MODULE_DESCRIPTION("DAP8211R Gigabit Ethernet PHY driver");
+MODULE_AUTHOR("Artem Shimko <a.shimko.dev@gmail.com>");
+MODULE_LICENSE("GPL");
+
+static const struct mdio_device_id __maybe_unused dap8211r_tb[] = {
+ { DAP8211R_PHY_ID, DAP8211R_PHY_ID_MASK },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(mdio, dap8211r_tb);
+