summaryrefslogtreecommitdiff
path: root/drivers/net/phy/bcm84881.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-14 18:36:10 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-14 18:36:10 -0700
commit91a4855d6c03e770e42f17c798a36a3c46e63de2 (patch)
tree5103bfe3aea2aab7e8b358c5c9329539508f648d /drivers/net/phy/bcm84881.c
parentf5ad4101009e7f5f5984ffea6923d4fcd470932a (diff)
parent35c2c39832e569449b9192fa1afbbc4c66227af7 (diff)
downloadlwn-91a4855d6c03e770e42f17c798a36a3c46e63de2.tar.gz
lwn-91a4855d6c03e770e42f17c798a36a3c46e63de2.zip
Merge tag 'net-next-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from Jakub Kicinski: "Core & protocols: - Support HW queue leasing, allowing containers to be granted access to HW queues for zero-copy operations and AF_XDP - Number of code moves to help the compiler with inlining. Avoid output arguments for returning drop reason where possible - Rework drop handling within qdiscs to include more metadata about the reason and dropping qdisc in the tracepoints - Remove the rtnl_lock use from IP Multicast Routing - Pack size information into the Rx Flow Steering table pointer itself. This allows making the table itself a flat array of u32s, thus making the table allocation size a power of two - Report TCP delayed ack timer information via socket diag - Add ip_local_port_step_width sysctl to allow distributing the randomly selected ports more evenly throughout the allowed space - Add support for per-route tunsrc in IPv6 segment routing - Start work of switching sockopt handling to iov_iter - Improve dynamic recvbuf sizing in MPTCP, limit burstiness and avoid buffer size drifting up - Support MSG_EOR in MPTCP - Add stp_mode attribute to the bridge driver for STP mode selection. This addresses concerns about call_usermodehelper() usage - Remove UDP-Lite support (as announced in 2023) - Remove support for building IPv6 as a module. Remove the now unnecessary function calling indirection Cross-tree stuff: - Move Michael MIC code from generic crypto into wireless, it's considered insecure but some WiFi networks still need it Netfilter: - Switch nft_fib_ipv6 module to no longer need temporary dst_entry object allocations by using fib6_lookup() + RCU. Florian W reports this gets us ~13% higher packet rate - Convert IPVS's global __ip_vs_mutex to per-net service_mutex and switch the service tables to be per-net. Convert some code that walks the service lists to use RCU instead of the service_mutex - Add more opinionated input validation to lower security exposure - Make IPVS hash tables to be per-netns and resizable Wireless: - Finished assoc frame encryption/EPPKE/802.1X-over-auth - Radar detection improvements - Add 6 GHz incumbent signal detection APIs - Multi-link support for FILS, probe response templates and client probing - New APIs and mac80211 support for NAN (Neighbor Aware Networking, aka Wi-Fi Aware) so less work must be in firmware Driver API: - Add numerical ID for devlink instances (to avoid having to create fake bus/device pairs just to have an ID). Support shared devlink instances which span multiple PFs - Add standard counters for reporting pause storm events (implement in mlx5 and fbnic) - Add configuration API for completion writeback buffering (implement in mana) - Support driver-initiated change of RSS context sizes - Support DPLL monitoring input frequency (implement in zl3073x) - Support per-port resources in devlink (implement in mlx5) Misc: - Expand the YAML spec for Netfilter Drivers - Software: - macvlan: support multicast rx for bridge ports with shared source MAC address - team: decouple receive and transmit enablement for IEEE 802.3ad LACP "independent control" - Ethernet high-speed NICs: - nVidia/Mellanox: - support high order pages in zero-copy mode (for payload coalescing) - support multiple packets in a page (for systems with 64kB pages) - Broadcom 25-400GE (bnxt): - implement XDP RSS hash metadata extraction - add software fallback for UDP GSO, lowering the IOMMU cost - Broadcom 800GE (bnge): - add link status and configuration handling - add various HW and SW statistics - Marvell/Cavium: - NPC HW block support for cn20k - Huawei (hinic3): - add mailbox / control queue - add rx VLAN offload - add driver info and link management - Ethernet NICs: - Marvell/Aquantia: - support reading SFP module info on some AQC100 cards - Realtek PCI (r8169): - add support for RTL8125cp - Realtek USB (r8152): - support for the RTL8157 5Gbit chip - add 2500baseT EEE status/configuration support - Ethernet NICs embedded and off-the-shelf IP: - Synopsys (stmmac): - cleanup and reorganize SerDes handling and PCS support - cleanup descriptor handling and per-platform data - cleanup and consolidate MDIO defines and handling - shrink driver memory use for internal structures - improve Tx IRQ coalescing - improve TCP segmentation handling - add support for Spacemit K3 - Cadence (macb): - support PHYs that have inband autoneg disabled with GEM - support IEEE 802.3az EEE - rework usrio capabilities and handling - AMD (xgbe): - improve power management for S0i3 - improve TX resilience for link-down handling - Virtual: - Google cloud vNIC: - support larger ring sizes in DQO-QPL mode - improve HW-GRO handling - support UDP GSO for DQO format - PCIe NTB: - support queue count configuration - Ethernet PHYs: - automatically disable PHY autonomous EEE if MAC is in charge - Broadcom: - add BCM84891/BCM84892 support - Micrel: - support for LAN9645X internal PHY - Realtek: - add RTL8224 pair order support - support PHY LEDs on RTL8211F-VD - support spread spectrum clocking (SSC) - Maxlinear: - add PHY-level statistics via ethtool - Ethernet switches: - Maxlinear (mxl862xx): - support for bridge offloading - support for VLANs - support driver statistics - Bluetooth: - large number of fixes and new device IDs - Mediatek: - support MT6639 (MT7927) - support MT7902 SDIO - WiFi: - Intel (iwlwifi): - UNII-9 and continuing UHR work - MediaTek (mt76): - mt7996/mt7925 MLO fixes/improvements - mt7996 NPU support (HW eth/wifi traffic offload) - Qualcomm (ath12k): - monitor mode support on IPQ5332 - basic hwmon temperature reporting - support IPQ5424 - Realtek: - add USB RX aggregation to improve performance - add USB TX flow control by tracking in-flight URBs - Cellular: - IPA v5.2 support" * tag 'net-next-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1561 commits) net: pse-pd: fix kernel-doc function name for pse_control_find_by_id() wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit wireguard: allowedips: remove redundant space tools: ynl: add sample for wireguard wireguard: allowedips: Use kfree_rcu() instead of call_rcu() MAINTAINERS: Add netkit selftest files selftests/net: Add additional test coverage in nk_qlease selftests/net: Split netdevsim tests from HW tests in nk_qlease tools/ynl: Make YnlFamily closeable as a context manager net: airoha: Add missing PPE configurations in airoha_ppe_hw_init() net: airoha: Fix VIP configuration for AN7583 SoC net: caif: clear client service pointer on teardown net: strparser: fix skb_head leak in strp_abort_strp() net: usb: cdc-phonet: fix skb frags[] overflow in rx_complete() selftests/bpf: add test for xdp_master_redirect with bond not up net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master net: airoha: Remove PCE_MC_EN_MASK bit in REG_FE_PCE_CFG configuration sctp: disable BH before calling udp_tunnel_xmit_skb() sctp: fix missing encap_port propagation for GSO fragments net: airoha: Rely on net_device pointer in ETS callbacks ...
Diffstat (limited to 'drivers/net/phy/bcm84881.c')
-rw-r--r--drivers/net/phy/bcm84881.c204
1 files changed, 203 insertions, 1 deletions
diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c
index d7f7cc44c532..2ae70dcf82ec 100644
--- a/drivers/net/phy/bcm84881.c
+++ b/drivers/net/phy/bcm84881.c
@@ -20,6 +20,33 @@ enum {
MDIO_AN_C22 = 0xffe0,
};
+/* BCM8489x LED controller (BCM84891L datasheet 2.4.1.58). Each pin has
+ * CTL bits in 0xA83B (stride 3: 2-bit CTL + 1-bit OE_N) plus MASK_LOW/
+ * MASK_EXT source selects. LED4 is firmware-controlled; always RMW.
+ */
+#define BCM8489X_LED_CTL 0xa83b
+#define BCM8489X_LED_CTL_ON(i) (0x2 << ((i) * 3))
+#define BCM8489X_LED_CTL_MASK(i) (0x3 << ((i) * 3))
+
+#define BCM8489X_LED_SRC_RX BIT(1)
+#define BCM8489X_LED_SRC_TX BIT(2)
+#define BCM8489X_LED_SRC_1000 BIT(3) /* high only at 1000 */
+#define BCM8489X_LED_SRC_100_1000 BIT(4) /* high at 100 and 1000 */
+#define BCM8489X_LED_SRC_FORCE BIT(5) /* always-1 source */
+#define BCM8489X_LED_SRC_10G BIT(7)
+#define BCM8489X_LED_SRCX_2500 BIT(2)
+#define BCM8489X_LED_SRCX_5000 BIT(3)
+
+#define BCM8489X_MAX_LEDS 2
+
+static const struct {
+ u16 mask_low;
+ u16 mask_ext;
+} bcm8489x_led_regs[BCM8489X_MAX_LEDS] = {
+ { 0xa82c, 0xa8ef }, /* LED1 */
+ { 0xa82f, 0xa8f0 }, /* LED2 */
+};
+
static int bcm84881_wait_init(struct phy_device *phydev)
{
int val;
@@ -54,6 +81,142 @@ static int bcm84881_config_init(struct phy_device *phydev)
return 0;
}
+static int bcm8489x_config_init(struct phy_device *phydev)
+{
+ __set_bit(PHY_INTERFACE_MODE_USXGMII, phydev->possible_interfaces);
+
+ if (phydev->interface != PHY_INTERFACE_MODE_USXGMII)
+ return -ENODEV;
+
+ /* MDIO_CTRL1_LPOWER is set at boot on the tested platform. Does not
+ * recur on ifdown/ifup, cable events, or link-partner advertisement
+ * changes; clear it once.
+ */
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
+ MDIO_CTRL1_LPOWER);
+}
+
+static int bcm8489x_led_write(struct phy_device *phydev, u8 index,
+ u16 low, u16 ext)
+{
+ int ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD,
+ bcm8489x_led_regs[index].mask_low, low);
+ if (ret)
+ return ret;
+ ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD,
+ bcm8489x_led_regs[index].mask_ext, ext);
+ if (ret)
+ return ret;
+ return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, BCM8489X_LED_CTL,
+ BCM8489X_LED_CTL_MASK(index),
+ (low | ext) ? BCM8489X_LED_CTL_ON(index) : 0);
+}
+
+static int bcm8489x_led_brightness_set(struct phy_device *phydev,
+ u8 index, enum led_brightness value)
+{
+ if (index >= BCM8489X_MAX_LEDS)
+ return -EINVAL;
+
+ return bcm8489x_led_write(phydev, index,
+ value ? BCM8489X_LED_SRC_FORCE : 0, 0);
+}
+
+static const unsigned long bcm8489x_supported_triggers =
+ BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000) |
+ BIT(TRIGGER_NETDEV_LINK_2500) |
+ BIT(TRIGGER_NETDEV_LINK_5000) |
+ BIT(TRIGGER_NETDEV_LINK_10000) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX);
+
+static int bcm8489x_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ if (index >= BCM8489X_MAX_LEDS)
+ return -EINVAL;
+
+ if (rules & ~bcm8489x_supported_triggers)
+ return -EOPNOTSUPP;
+
+ /* Source bit 4 lights at both 100 and 1000; "100 only" isn't
+ * representable in hardware. Accept LINK_100 only alongside
+ * LINK_1000 or LINK so the offload is precise.
+ */
+ if ((rules & BIT(TRIGGER_NETDEV_LINK_100)) &&
+ !(rules & (BIT(TRIGGER_NETDEV_LINK_1000) |
+ BIT(TRIGGER_NETDEV_LINK))))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int bcm8489x_led_hw_control_set(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ u16 low = 0, ext = 0;
+
+ if (index >= BCM8489X_MAX_LEDS)
+ return -EINVAL;
+
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+ low |= BCM8489X_LED_SRC_100_1000;
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+ low |= BCM8489X_LED_SRC_1000;
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
+ ext |= BCM8489X_LED_SRCX_2500;
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK)))
+ ext |= BCM8489X_LED_SRCX_5000;
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK)))
+ low |= BCM8489X_LED_SRC_10G;
+ if (rules & BIT(TRIGGER_NETDEV_RX))
+ low |= BCM8489X_LED_SRC_RX;
+ if (rules & BIT(TRIGGER_NETDEV_TX))
+ low |= BCM8489X_LED_SRC_TX;
+
+ return bcm8489x_led_write(phydev, index, low, ext);
+}
+
+static int bcm8489x_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules)
+{
+ int low, ext;
+
+ if (index >= BCM8489X_MAX_LEDS)
+ return -EINVAL;
+
+ low = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
+ bcm8489x_led_regs[index].mask_low);
+ if (low < 0)
+ return low;
+ ext = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
+ bcm8489x_led_regs[index].mask_ext);
+ if (ext < 0)
+ return ext;
+
+ *rules = 0;
+ if (low & BCM8489X_LED_SRC_100_1000)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
+ if (low & BCM8489X_LED_SRC_1000)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+ if (ext & BCM8489X_LED_SRCX_2500)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
+ if (ext & BCM8489X_LED_SRCX_5000)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_5000);
+ if (low & BCM8489X_LED_SRC_10G)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_10000);
+ if (low & BCM8489X_LED_SRC_RX)
+ *rules |= BIT(TRIGGER_NETDEV_RX);
+ if (low & BCM8489X_LED_SRC_TX)
+ *rules |= BIT(TRIGGER_NETDEV_TX);
+
+ return 0;
+}
+
static int bcm84881_probe(struct phy_device *phydev)
{
/* This driver requires PMAPMD and AN blocks */
@@ -201,6 +364,15 @@ static int bcm84881_read_status(struct phy_device *phydev)
return 0;
}
+ /* BCM84891/92 on USXGMII: the host interface mode doesn't change
+ * with copper speed (USXGMII symbol replication; the MAC receives
+ * the negotiated copper speed, not 10G, so no rate adaptation).
+ * Skip 0x4011; phy_resolve_aneg_linkmode() above already set the
+ * speed. Only bcm8489x_config_init() allows USXGMII.
+ */
+ if (phydev->interface == PHY_INTERFACE_MODE_USXGMII)
+ return genphy_c45_read_mdix(phydev);
+
/* Set the host link mode - we set the phy interface mode and
* the speed according to this register so that downshift works.
* We leave the duplex setting as per the resolution from the
@@ -256,6 +428,34 @@ static struct phy_driver bcm84881_drivers[] = {
.config_aneg = bcm84881_config_aneg,
.aneg_done = bcm84881_aneg_done,
.read_status = bcm84881_read_status,
+ }, {
+ PHY_ID_MATCH_MODEL(0x35905080),
+ .name = "Broadcom BCM84891",
+ .inband_caps = bcm84881_inband_caps,
+ .config_init = bcm8489x_config_init,
+ .probe = bcm84881_probe,
+ .get_features = bcm84881_get_features,
+ .config_aneg = bcm84881_config_aneg,
+ .aneg_done = bcm84881_aneg_done,
+ .read_status = bcm84881_read_status,
+ .led_brightness_set = bcm8489x_led_brightness_set,
+ .led_hw_is_supported = bcm8489x_led_hw_is_supported,
+ .led_hw_control_set = bcm8489x_led_hw_control_set,
+ .led_hw_control_get = bcm8489x_led_hw_control_get,
+ }, {
+ PHY_ID_MATCH_MODEL(0x359050a0),
+ .name = "Broadcom BCM84892",
+ .inband_caps = bcm84881_inband_caps,
+ .config_init = bcm8489x_config_init,
+ .probe = bcm84881_probe,
+ .get_features = bcm84881_get_features,
+ .config_aneg = bcm84881_config_aneg,
+ .aneg_done = bcm84881_aneg_done,
+ .read_status = bcm84881_read_status,
+ .led_brightness_set = bcm8489x_led_brightness_set,
+ .led_hw_is_supported = bcm8489x_led_hw_is_supported,
+ .led_hw_control_set = bcm8489x_led_hw_control_set,
+ .led_hw_control_get = bcm8489x_led_hw_control_get,
},
};
@@ -264,9 +464,11 @@ module_phy_driver(bcm84881_drivers);
/* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */
static const struct mdio_device_id __maybe_unused bcm84881_tbl[] = {
{ 0xae025150, 0xfffffff0 },
+ { PHY_ID_MATCH_MODEL(0x35905080) },
+ { PHY_ID_MATCH_MODEL(0x359050a0) },
{ },
};
MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Broadcom BCM84881 PHY driver");
+MODULE_DESCRIPTION("Broadcom BCM84881/BCM84891/BCM84892 PHY driver");
MODULE_DEVICE_TABLE(mdio, bcm84881_tbl);
MODULE_LICENSE("GPL");