From nobody Thu Oct 2 18:30:34 2025 Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 826CD26E653; Tue, 18 Feb 2025 16:19:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739895568; cv=none; b=tplYOb11BW/T2FKQrXerfDTBkfuUAuWVeFom7yccvJd7kkGtmaXOZfXsZ+hMqj5aLak9LICUz44M7NCYKtCR2xro4eNpU+YEcKzLA8NFLHR+TaQpQpHDXMx1BVFc5SM8LK6wgTE0BJtGdVjiSaYF86VaOUR0H1ogjtx5gAP38C8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739895568; c=relaxed/simple; bh=DVdEIb3xvQxVkQCvfC7Ocp5UFddDH4E0ketTTDMnXBw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=NjLi92CGvDbI8tp1+Zb06j2E8aIuwh/aU7T+VgGvewrwJHxNSekUqhQkDx+Rn1yoZ7FTZgh8xTLtuMe5GJfPHYYlk0jXVerrWE66g0Eg+lMmQH0JwD75k3pCK+S8Ke6AdKwdIiLgqMV26CreoKh+ehIFS7W452bl5ofGgPCD1i0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=OZjeM5Gn; arc=none smtp.client-ip=217.70.183.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="OZjeM5Gn" Received: by mail.gandi.net (Postfix) with ESMTPSA id B28EF44314; Tue, 18 Feb 2025 16:19:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1739895557; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=K5ajaisYHOWX2NVmE3eoQ6jq4A3noA5wmqvLw9+zi3E=; b=OZjeM5GnZi/fPpJg7n2JIy9UdiFwnEAYB0YVBMxhuznWU5FvmocqREsBLUk5nyyOnBPEVE UIztgSyJmOFxLsfN46alUAc7jeB8ZhMLuBZvkC64Q+bdn4ye929feH8ULyoR8hYBCiONtz hUWf8jsm3S3o9rDLmDV7kJG+UgJ31ZEfy1Qe7jFuo3trg6T3yDHHl7Pb/NSK1GJ+I3XvpQ rl3dRDQr034vzJjKid+5ap5aSO3Z1tBBhzgsx6SsVCM8hWreiY8YRwO4gV07qwCaXGDa2a gQRAjEOeEnl5F0+69yK0besTsb1jnwcZP33u2trS1TWVmz3q+4GnSnEpTGoyhA== From: Kory Maincent Date: Tue, 18 Feb 2025 17:19:06 +0100 Subject: [PATCH net-next v5 02/12] net: pse-pd: Add support for reporting events Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250218-feature_poe_port_prio-v5-2-3da486e5fd64@bootlin.com> References: <20250218-feature_poe_port_prio-v5-0-3da486e5fd64@bootlin.com> In-Reply-To: <20250218-feature_poe_port_prio-v5-0-3da486e5fd64@bootlin.com> To: Andrew Lunn , Oleksij Rempel , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Jonathan Corbet , Donald Hunter , Rob Herring , Andrew Lunn , Simon Horman , Heiner Kallweit , Russell King , Krzysztof Kozlowski , Conor Dooley Cc: Thomas Petazzoni , netdev@vger.kernel.org, linux-doc@vger.kernel.org, Kyle Swenson , Dent Project , kernel@pengutronix.de, Maxime Chevallier , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, "Kory Maincent (Dent Project)" X-Mailer: b4 0.15-dev-8cb71 X-GND-State: clean X-GND-Score: -100 X-GND-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdeiudejjecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfitefpfffkpdcuggftfghnshhusghstghrihgsvgenuceurghilhhouhhtmecufedtudenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujfgurhephfffufggtgfgkfhfjgfvvefosehtjeertdertdejnecuhfhrohhmpefmohhrhicuofgrihhntggvnhhtuceokhhorhihrdhmrghinhgtvghnthessghoohhtlhhinhdrtghomheqnecuggftrfgrthhtvghrnhepvefgvdfgkeetgfefgfegkedugffghfdtffeftdeuteehjedtvdelvddvleehtdevnecukfhppedvrgdtudemtggstddumeeftdehfeemrgdvieeimeelvgeivgemleeisgdumegvsgguleemfhdtrgegnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehinhgvthepvdgrtddumegtsgdtudemfedtheefmegrvdeiieemlegviegvmeeliegsudemvggsugelmehftdgrgedphhgvlhhopegluddvjedrtddruddrudgnpdhmrghilhhfrhhomhepkhhorhihrdhmrghinhgtvghnthessghoohhtlhhinhdrtghomhdpnhgspghrtghpthhtohepvdehpdhrtghpthhtoheprghnughrvgifodhnvghtuggvvheslhhunhhnrdgthhdprhgtphhtthhopeguvghnthhprhhojhgvtghtsehlihhnuhigfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpthhtoheplhhinhhugiesrghrmhhlihhnuhigrdhorhhgrdhuk hdprhgtphhtthhopehprggsvghnihesrhgvughhrghtrdgtohhmpdhrtghpthhtohepuggvvhhitggvthhrvggvsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepkhhriihkodgutheskhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprhhosghhsehkvghrnhgvlhdrohhrghdprhgtphhtthhopehkvghrnhgvlhesphgvnhhguhhtrhhonhhigidruggv X-GND-Sasl: kory.maincent@bootlin.com From: Kory Maincent (Dent Project) Add support for devm_pse_irq_helper() to register PSE interrupts. This aims to report events such as over-current or over-temperature conditions similarly to how the regulator API handles them but using a specific PSE ethtool netlink socket. Signed-off-by: Kory Maincent (Dent Project) --- Change in v4: - Fix netlink notification message issues. - Use netlink bitset in ethtool_pse_send_ntf. - Add kdoc. Change in v3: - Remove C33 prefix when it is not in the standards. - Fix pse_to_regulator_notifs which could not report regulator events together. - Fix deadlock issue. - Save interrupt in pcdev structure for later use. Change in v2: - Add support for PSE ethtool notification. - Saved the attached phy_device in the pse_control structure to know which interface should have the notification. - Rethink devm_pse_irq_helper() without devm_regulator_irq_helper() call. --- Documentation/netlink/specs/ethtool.yaml | 26 ++++ Documentation/networking/ethtool-netlink.rst | 19 +++ drivers/net/mdio/fwnode_mdio.c | 26 ++-- drivers/net/pse-pd/pse_core.c | 157 +++++++++++++++++++++= +++- include/linux/ethtool_netlink.h | 9 ++ include/linux/pse-pd/pse.h | 24 +++- include/uapi/linux/ethtool.h | 17 +++ include/uapi/linux/ethtool_netlink_generated.h | 10 ++ net/ethtool/common.c | 6 + net/ethtool/common.h | 2 + net/ethtool/pse-pd.c | 53 +++++++++ net/ethtool/strset.c | 5 + 12 files changed, 337 insertions(+), 17 deletions(-) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netli= nk/specs/ethtool.yaml index 655d8d10fe24..da78c5daf537 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -1526,6 +1526,22 @@ attribute-sets: name: hwtstamp-flags type: nest nested-attributes: bitset + - + name: pse-ntf + attr-cnt-name: __ethtool-a-pse-ntf-cnt + attributes: + - + name: unspec + type: unused + value: 0 + - + name: header + type: nest + nested-attributes: header + - + name: events + type: nest + nested-attributes: bitset =20 operations: enum-model: directional @@ -2382,3 +2398,13 @@ operations: attributes: *tsconfig reply: attributes: *tsconfig + - + name: pse-ntf + doc: Notification for pse events. + + attribute-set: pse-ntf + + event: + attributes: + - header + - events diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/n= etworking/ethtool-netlink.rst index 3770a2294509..9fc5e29b3928 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -290,6 +290,7 @@ Kernel to userspace: ``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change ``ETHTOOL_MSG_TSCONFIG_GET_REPLY`` hw timestamping configuration ``ETHTOOL_MSG_TSCONFIG_SET_REPLY`` new hw timestamping configurati= on + ``ETHTOOL_MSG_PSE_NTF`` PSE events notification =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 ``GET`` requests are sent by userspace applications to retrieve device @@ -1896,6 +1897,24 @@ various existing products that document power consum= ption in watts rather than classes. If power limit configuration based on classes is needed, the conversion can be done in user space, for example by ethtool. =20 +PSE_NTF +=3D=3D=3D=3D=3D=3D=3D + +Notify PSE events. + +Notification contents: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + ``ETHTOOL_A_PSE_HEADER`` nested request header + ``ETHTOOL_A_PSE_EVENTS`` bitset PSE events + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +When set, the optional ``ETHTOOL_A_PSE_EVENTS`` attribute identifies the +PSE events. + +.. kernel-doc:: include/uapi/linux/ethtool.h + :identifiers: ethtool_pse_events + RSS_GET =3D=3D=3D=3D=3D=3D=3D =20 diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c index aea0f0357568..9b41d4697a40 100644 --- a/drivers/net/mdio/fwnode_mdio.c +++ b/drivers/net/mdio/fwnode_mdio.c @@ -18,7 +18,8 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("FWNODE MDIO bus (Ethernet PHY) accessors"); =20 static struct pse_control * -fwnode_find_pse_control(struct fwnode_handle *fwnode) +fwnode_find_pse_control(struct fwnode_handle *fwnode, + struct phy_device *phydev) { struct pse_control *psec; struct device_node *np; @@ -30,7 +31,7 @@ fwnode_find_pse_control(struct fwnode_handle *fwnode) if (!np) return NULL; =20 - psec =3D of_pse_control_get(np); + psec =3D of_pse_control_get(np, phydev); if (PTR_ERR(psec) =3D=3D -ENOENT) return NULL; =20 @@ -128,15 +129,9 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus, u32 phy_id; int rc; =20 - psec =3D fwnode_find_pse_control(child); - if (IS_ERR(psec)) - return PTR_ERR(psec); - mii_ts =3D fwnode_find_mii_timestamper(child); - if (IS_ERR(mii_ts)) { - rc =3D PTR_ERR(mii_ts); - goto clean_pse; - } + if (IS_ERR(mii_ts)) + return PTR_ERR(mii_ts); =20 is_c45 =3D fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45= "); if (is_c45 || fwnode_get_phy_id(child, &phy_id)) @@ -169,6 +164,12 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus, goto clean_phy; } =20 + psec =3D fwnode_find_pse_control(child, phy); + if (IS_ERR(psec)) { + rc =3D PTR_ERR(psec); + goto unregister_phy; + } + phy->psec =3D psec; =20 /* phy->mii_ts may already be defined by the PHY driver. A @@ -180,12 +181,13 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus, =20 return 0; =20 +unregister_phy: + if (is_acpi_node(child) || is_of_node(child)) + phy_device_remove(phy); clean_phy: phy_device_free(phy); clean_mii_ts: unregister_mii_timestamper(mii_ts); -clean_pse: - pse_control_put(psec); =20 return rc; } diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c index 4602e26eb8c8..10a5ab30afdd 100644 --- a/drivers/net/pse-pd/pse_core.c +++ b/drivers/net/pse-pd/pse_core.c @@ -7,6 +7,7 @@ =20 #include #include +#include #include #include #include @@ -23,6 +24,7 @@ static LIST_HEAD(pse_controller_list); * @list: list entry for the pcdev's PSE controller list * @id: ID of the PSE line in the PSE controller device * @refcnt: Number of gets of this pse_control + * @attached_phydev: PHY device pointer attached by the PSE control */ struct pse_control { struct pse_controller_dev *pcdev; @@ -30,6 +32,7 @@ struct pse_control { struct list_head list; unsigned int id; struct kref refcnt; + struct phy_device *attached_phydev; }; =20 static int of_load_single_pse_pi_pairset(struct device_node *node, @@ -557,6 +560,151 @@ int devm_pse_controller_register(struct device *dev, } EXPORT_SYMBOL_GPL(devm_pse_controller_register); =20 +struct pse_irq { + struct pse_controller_dev *pcdev; + struct pse_irq_desc desc; + unsigned long *notifs; +}; + +/** + * pse_to_regulator_notifs - Convert PSE notifications to Regulator + * notifications + * @notifs: PSE notifications + * + * Return: Regulator notifications + */ +static unsigned long pse_to_regulator_notifs(unsigned long notifs) +{ + unsigned long rnotifs =3D 0; + + if (notifs & ETHTOOL_PSE_EVENT_OVER_CURRENT) + rnotifs |=3D REGULATOR_EVENT_OVER_CURRENT; + if (notifs & ETHTOOL_PSE_EVENT_OVER_TEMP) + rnotifs |=3D REGULATOR_EVENT_OVER_TEMP; + + return rnotifs; +} + +/** + * pse_control_find_phy_by_id - Find PHY attached to the a pse control id + * @pcdev: a pointer to the PSE + * @id: index of the PSE control + * + * Return: PHY device pointer or NULL + */ +static struct phy_device * +pse_control_find_phy_by_id(struct pse_controller_dev *pcdev, int id) +{ + struct pse_control *psec; + + mutex_lock(&pse_list_mutex); + list_for_each_entry(psec, &pcdev->pse_control_head, list) { + if (psec->id =3D=3D id) { + mutex_unlock(&pse_list_mutex); + return psec->attached_phydev; + } + } + mutex_unlock(&pse_list_mutex); + + return NULL; +} + +/** + * pse_isr - IRQ handler for PSE + * @irq: irq number + * @data: pointer to user interrupt structure + * + * Return: irqreturn_t - status of IRQ + */ +static irqreturn_t pse_isr(int irq, void *data) +{ + struct netlink_ext_ack extack =3D {}; + struct pse_controller_dev *pcdev; + unsigned long notifs_mask =3D 0; + struct pse_irq_desc *desc; + struct pse_irq *h =3D data; + int ret, i; + + desc =3D &h->desc; + pcdev =3D h->pcdev; + + /* Clear notifs mask */ + memset(h->notifs, 0, pcdev->nr_lines * sizeof(*h->notifs)); + mutex_lock(&pcdev->lock); + ret =3D desc->map_event(irq, pcdev, h->notifs, ¬ifs_mask); + mutex_unlock(&pcdev->lock); + if (ret || !notifs_mask) + return IRQ_NONE; + + for_each_set_bit(i, ¬ifs_mask, pcdev->nr_lines) { + struct phy_device *phydev; + unsigned long notifs, rnotifs; + + /* Do nothing PI not described */ + if (!pcdev->pi[i].rdev) + continue; + + notifs =3D h->notifs[i]; + dev_dbg(h->pcdev->dev, + "Sending PSE notification EVT 0x%lx\n", notifs); + + phydev =3D pse_control_find_phy_by_id(pcdev, i); + if (phydev) + ethnl_pse_send_ntf(phydev, notifs, &extack); + rnotifs =3D pse_to_regulator_notifs(notifs); + regulator_notifier_call_chain(pcdev->pi[i].rdev, rnotifs, + NULL); + } + + return IRQ_HANDLED; +} + +/** + * devm_pse_irq_helper - Register IRQ based PSE event notifier + * + * @pcdev: a pointer to the PSE + * @irq: the irq value to be passed to request_irq + * @irq_flags: the flags to be passed to request_irq + * @d: PSE interrupt description + * + * Return: 0 on success and failure value on error + */ +int devm_pse_irq_helper(struct pse_controller_dev *pcdev, int irq, + int irq_flags, const struct pse_irq_desc *d) +{ + struct device *dev =3D pcdev->dev; + struct pse_irq *h; + int ret; + + if (!d || !d->map_event || !d->name) + return -EINVAL; + + h =3D devm_kzalloc(dev, sizeof(*h), GFP_KERNEL); + if (!h) + return -ENOMEM; + + h->pcdev =3D pcdev; + h->desc =3D *d; + h->desc.name =3D devm_kstrdup(dev, d->name, GFP_KERNEL); + if (!h->desc.name) + return -ENOMEM; + + h->notifs =3D devm_kcalloc(pcdev->dev, pcdev->nr_lines, + sizeof(*h->notifs), GFP_KERNEL); + if (!h->notifs) + return -ENOMEM; + + ret =3D devm_request_threaded_irq(dev, irq, NULL, pse_isr, + IRQF_ONESHOT | irq_flags, + h->desc.name, h); + if (ret) + dev_err(pcdev->dev, "Failed to request IRQ %d\n", irq); + + pcdev->irq =3D irq; + return ret; +} +EXPORT_SYMBOL_GPL(devm_pse_irq_helper); + /* PSE control section */ =20 static void __pse_control_release(struct kref *kref) @@ -599,7 +747,8 @@ void pse_control_put(struct pse_control *psec) EXPORT_SYMBOL_GPL(pse_control_put); =20 static struct pse_control * -pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int in= dex) +pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int in= dex, + struct phy_device *phydev) { struct pse_control *psec; int ret; @@ -638,6 +787,7 @@ pse_control_get_internal(struct pse_controller_dev *pcd= ev, unsigned int index) psec->pcdev =3D pcdev; list_add(&psec->list, &pcdev->pse_control_head); psec->id =3D index; + psec->attached_phydev =3D phydev; kref_init(&psec->refcnt); =20 return psec; @@ -693,7 +843,8 @@ static int psec_id_xlate(struct pse_controller_dev *pcd= ev, return pse_spec->args[0]; } =20 -struct pse_control *of_pse_control_get(struct device_node *node) +struct pse_control *of_pse_control_get(struct device_node *node, + struct phy_device *phydev) { struct pse_controller_dev *r, *pcdev; struct of_phandle_args args; @@ -743,7 +894,7 @@ struct pse_control *of_pse_control_get(struct device_no= de *node) } =20 /* pse_list_mutex also protects the pcdev's pse_control list */ - psec =3D pse_control_get_internal(pcdev, psec_id); + psec =3D pse_control_get_internal(pcdev, psec_id, phydev); =20 out: mutex_unlock(&pse_list_mutex); diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlin= k.h index aba91335273a..0fa1d8f59cf2 100644 --- a/include/linux/ethtool_netlink.h +++ b/include/linux/ethtool_netlink.h @@ -43,6 +43,9 @@ void ethtool_aggregate_rmon_stats(struct net_device *dev, struct ethtool_rmon_stats *rmon_stats); bool ethtool_dev_mm_supported(struct net_device *dev); =20 +void ethnl_pse_send_ntf(struct phy_device *phydev, unsigned long notif, + struct netlink_ext_ack *extack); + #else static inline int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd) { @@ -120,6 +123,12 @@ static inline bool ethtool_dev_mm_supported(struct net= _device *dev) return false; } =20 +static inline void ethnl_pse_send_ntf(struct phy_device *phydev, + unsigned long notif, + struct netlink_ext_ack *extack) +{ +} + #endif /* IS_ENABLED(CONFIG_ETHTOOL_NETLINK) */ =20 static inline int ethnl_cable_test_result(struct phy_device *phydev, u8 pa= ir, diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h index c773eeb92d04..5d41a1c984bd 100644 --- a/include/linux/pse-pd/pse.h +++ b/include/linux/pse-pd/pse.h @@ -7,6 +7,7 @@ =20 #include #include +#include =20 /* Maximum current in uA according to IEEE 802.3-2022 Table 145-1 */ #define MAX_PI_CURRENT 1920000 @@ -37,6 +38,19 @@ struct ethtool_c33_pse_pw_limit_range { u32 max; }; =20 +/** + * struct pse_irq_desc - notification sender description for IRQ based eve= nts. + * + * @name: the visible name for the IRQ + * @map_event: driver callback to map IRQ status into PSE devices with eve= nts. + */ +struct pse_irq_desc { + const char *name; + int (*map_event)(int irq, struct pse_controller_dev *pcdev, + unsigned long *notifs, + unsigned long *notifs_mask); +}; + /** * struct pse_control_config - PSE control/channel configuration. * @@ -228,6 +242,7 @@ struct pse_pi { * @types: types of the PSE controller * @pi: table of PSE PIs described in this controller device * @no_of_pse_pi: flag set if the pse_pis devicetree node is not used + * @irq: PSE interrupt */ struct pse_controller_dev { const struct pse_controller_ops *ops; @@ -241,6 +256,7 @@ struct pse_controller_dev { enum ethtool_pse_types types; struct pse_pi *pi; bool no_of_pse_pi; + int irq; }; =20 #if IS_ENABLED(CONFIG_PSE_CONTROLLER) @@ -249,8 +265,11 @@ void pse_controller_unregister(struct pse_controller_d= ev *pcdev); struct device; int devm_pse_controller_register(struct device *dev, struct pse_controller_dev *pcdev); +int devm_pse_irq_helper(struct pse_controller_dev *pcdev, int irq, + int irq_flags, const struct pse_irq_desc *d); =20 -struct pse_control *of_pse_control_get(struct device_node *node); +struct pse_control *of_pse_control_get(struct device_node *node, + struct phy_device *phydev); void pse_control_put(struct pse_control *psec); =20 int pse_ethtool_get_status(struct pse_control *psec, @@ -268,7 +287,8 @@ bool pse_has_c33(struct pse_control *psec); =20 #else =20 -static inline struct pse_control *of_pse_control_get(struct device_node *n= ode) +static inline struct pse_control *of_pse_control_get(struct device_node *n= ode, + struct phy_device *phydev) { return ERR_PTR(-ENOENT); } diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index 2feba0929a8a..8793946ff851 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -683,6 +683,7 @@ enum ethtool_link_ext_substate_module { * @ETH_SS_STATS_RMON: names of RMON statistics * @ETH_SS_STATS_PHY: names of PHY(dev) statistics * @ETH_SS_TS_FLAGS: hardware timestamping flags + * @ETH_SS_PSE_EVENTS: names of PSE events * * @ETH_SS_COUNT: number of defined string sets */ @@ -710,6 +711,7 @@ enum ethtool_stringset { ETH_SS_STATS_RMON, ETH_SS_STATS_PHY, ETH_SS_TS_FLAGS, + ETH_SS_PSE_EVENTS, =20 /* add new constants above here */ ETH_SS_COUNT @@ -1002,6 +1004,21 @@ enum ethtool_c33_pse_pw_d_status { ETHTOOL_C33_PSE_PW_D_STATUS_OTHERFAULT, }; =20 +/** + * enum ethtool_pse_events - event list of the PSE controller. + * @ETHTOOL_PSE_EVENT_OVER_CURRENT: PSE output current is too high. + * @ETHTOOL_PSE_EVENT_OVER_TEMP: PSE in over temperature state. + * + * @ETHTOOL_PSE_EVENT_LAST: Last PSE event of the enum. + */ + +enum ethtool_pse_events { + ETHTOOL_PSE_EVENT_OVER_CURRENT =3D 1 << 0, + ETHTOOL_PSE_EVENT_OVER_TEMP =3D 1 << 1, + + ETHTOOL_PSE_EVENT_LAST =3D ETHTOOL_PSE_EVENT_OVER_TEMP, +}; + /** * enum ethtool_podl_pse_admin_state - operational state of the PoDL PSE * functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/= linux/ethtool_netlink_generated.h index fe24c3459ac0..f03b51766311 100644 --- a/include/uapi/linux/ethtool_netlink_generated.h +++ b/include/uapi/linux/ethtool_netlink_generated.h @@ -709,6 +709,15 @@ enum { ETHTOOL_A_TSCONFIG_MAX =3D (__ETHTOOL_A_TSCONFIG_CNT - 1) }; =20 +enum { + ETHTOOL_A_PSE_NTF_UNSPEC, + ETHTOOL_A_PSE_NTF_HEADER, + ETHTOOL_A_PSE_NTF_EVENTS, + + __ETHTOOL_A_PSE_NTF_CNT, + ETHTOOL_A_PSE_NTF_MAX =3D (__ETHTOOL_A_PSE_NTF_CNT - 1) +}; + enum { ETHTOOL_MSG_USER_NONE =3D 0, ETHTOOL_MSG_STRSET_GET =3D 1, @@ -813,6 +822,7 @@ enum { ETHTOOL_MSG_PHY_NTF, ETHTOOL_MSG_TSCONFIG_GET_REPLY, ETHTOOL_MSG_TSCONFIG_SET_REPLY, + ETHTOOL_MSG_PSE_NTF, =20 __ETHTOOL_MSG_KERNEL_CNT, ETHTOOL_MSG_KERNEL_MAX =3D (__ETHTOOL_MSG_KERNEL_CNT - 1) diff --git a/net/ethtool/common.c b/net/ethtool/common.c index 7149d07e90c6..8d207ec6456e 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -517,6 +517,12 @@ const char udp_tunnel_type_names[][ETH_GSTRING_LEN] = =3D { static_assert(ARRAY_SIZE(udp_tunnel_type_names) =3D=3D __ETHTOOL_UDP_TUNNEL_TYPE_CNT); =20 +const char pse_event_names[][ETH_GSTRING_LEN] =3D { + [const_ilog2(ETHTOOL_PSE_EVENT_OVER_CURRENT)] =3D "over-current", + [const_ilog2(ETHTOOL_PSE_EVENT_OVER_TEMP)] =3D "over-temperature", +}; +static_assert(ARRAY_SIZE(pse_event_names) =3D=3D __PSE_EVENT_CNT); + /* return false if legacy contained non-0 deprecated fields * maxtxpkt/maxrxpkt. rest of ksettings always updated */ diff --git a/net/ethtool/common.h b/net/ethtool/common.h index 58e9e7db06f9..edef4c230cf1 100644 --- a/net/ethtool/common.h +++ b/net/ethtool/common.h @@ -14,6 +14,7 @@ =20 #define __SOF_TIMESTAMPING_CNT (const_ilog2(SOF_TIMESTAMPING_LAST) + 1) #define __HWTSTAMP_FLAG_CNT (const_ilog2(HWTSTAMP_FLAG_LAST) + 1) +#define __PSE_EVENT_CNT (const_ilog2(ETHTOOL_PSE_EVENT_LAST) + 1) =20 struct link_mode_info { int speed; @@ -41,6 +42,7 @@ extern const char ts_tx_type_names[][ETH_GSTRING_LEN]; extern const char ts_rx_filter_names[][ETH_GSTRING_LEN]; extern const char ts_flags_names[][ETH_GSTRING_LEN]; extern const char udp_tunnel_type_names[][ETH_GSTRING_LEN]; +extern const char pse_event_names[][ETH_GSTRING_LEN]; =20 int __ethtool_get_link(struct net_device *dev); =20 diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c index 2819e2ba6be2..e471e577d4b6 100644 --- a/net/ethtool/pse-pd.c +++ b/net/ethtool/pse-pd.c @@ -12,6 +12,7 @@ #include #include #include +#include "bitset.h" =20 struct pse_req_info { struct ethnl_req_info base; @@ -315,3 +316,55 @@ const struct ethnl_request_ops ethnl_pse_request_ops = =3D { .set =3D ethnl_set_pse, /* PSE has no notification */ }; + +void ethnl_pse_send_ntf(struct phy_device *phydev, unsigned long notifs, + struct netlink_ext_ack *extack) +{ + struct net_device *netdev =3D phydev->attached_dev; + struct genl_info info; + void *reply_payload; + struct sk_buff *skb; + int reply_len; + int ret; + + if (!netdev || !notifs) + return; + + ethnl_info_init_ntf(&info, ETHTOOL_MSG_PSE_NTF); + info.extack =3D extack; + + reply_len =3D ethnl_reply_header_size(); + /* _C33_PSE_NTF_EVENTS */ + ret =3D ethnl_bitset_size(¬ifs, NULL, __PSE_EVENT_CNT, + pse_event_names, 0); + if (ret < 0) + return; + + reply_len +=3D ret; + skb =3D genlmsg_new(reply_len, GFP_KERNEL); + reply_payload =3D ethnl_bcastmsg_put(skb, ETHTOOL_MSG_PSE_NTF); + if (!reply_payload) + goto err_skb; + + ret =3D ethnl_fill_reply_header(skb, netdev, + ETHTOOL_A_PSE_NTF_HEADER); + if (ret < 0) + goto err_skb; + + ret =3D ethnl_put_bitset(skb, ETHTOOL_A_PSE_NTF_EVENTS, ¬ifs, + NULL, __PSE_EVENT_CNT, pse_event_names, 0); + if (ret) { + WARN_ONCE(ret =3D=3D -EMSGSIZE, + "calculated message payload length (%d) not sufficient\n", + reply_len); + goto err_skb; + } + + genlmsg_end(skb, reply_payload); + ethnl_multicast(skb, netdev); + return; + +err_skb: + nlmsg_free(skb); +} +EXPORT_SYMBOL_GPL(ethnl_pse_send_ntf); diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c index 6b76c05caba4..b71392fa9129 100644 --- a/net/ethtool/strset.c +++ b/net/ethtool/strset.c @@ -115,6 +115,11 @@ static const struct strset_info info_template[] =3D { .count =3D __ETHTOOL_A_STATS_PHY_CNT, .strings =3D stats_phy_names, }, + [ETH_SS_PSE_EVENTS] =3D { + .per_dev =3D false, + .count =3D __PSE_EVENT_CNT, + .strings =3D pse_event_names, + }, }; =20 struct strset_req_info { --=20 2.34.1