diff options
| author | Kees Cook <kees+treewide@kernel.org> | 2026-09-02 15:31:14 -0700 |
|---|---|---|
| committer | Kees Cook <kees@kernel.org> | 2026-09-04 21:37:00 -0700 |
| commit | 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d (patch) | |
| tree | c65086f9bdcd48c6360fb7cb4598bca084da1f32 /drivers/net/phy/dap8211r.c | |
| download | linux-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.c | 220 |
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); + |
