From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.221.43 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794529960; b=pT1kMrNbS3iosyBtDUtbW8liUoLCBeN5f/q3aPnQt75vP53vSpPBET0z5ziMf4b8lqJd rAaINyUPw7mUFVV731+Okut1sEIdE5ttWCLAqHzVp7WUQGGCG8/VXUvzV18sTX1UqdExj H4ETyPoXDaCg77qGPnQ5pImaJSaGgmcaVljSAytZPE+klfak2wdZQxYgpQZJh0okn5+dL 7g2uaGDStF/4ZEZ5Vd33PT24e4Z7d/j5GXb06J1uRsYIyuI1nhHBpZqf1xNhQNkvHF2ML f66R/mY5WSuhQlREe7ZHONi05t7xP/PrjEV8XOfTBdiF0OqMHtfIpmchg4dnF8xUNvQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794529960; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received: From:To:Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; bh=cqKN8t63b3IlTdSqj1uTv4S+18+380s33ycIKsdReAA=; b=Xzk2VuotKX4BrZcwZn/IFC0a5ZkpBI+P9hTN2CvsurRRg2ceJNWCLEW3Pn+QLytpG2zs 4dMy+PvpFpg/yu8HTixGQwBZlZnuCCbIGthC6z31OZN6vHVlQ+I65b2XpWxzSq4NcRPB1 b7+hBhXO6Ws+kxmhYGbTCyHfG8J9oOBcLREmrXRXnWSFlgyUIErhJMz31cbkuG45HTYIA 7dQEFpmet0DXzP/g8Sov2q7Io7xwo/7O8JwtA5JxolYeZY08nVIND7030SJKu0Ch81w7o kgRDgngAvZToymd3mB8lfCTZK3DrPr9u+DBqGwFM1kXb4WTgCAT9GGFiFNlngdBB+Xg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=0A1yJW+4; arc=none smtp.remote-ip=209.85.221.43 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D06760A2625 for ; Fri, 13 Nov 2026 00:32:39 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 7D06760A2625 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=0A1yJW+4 Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-49a92144733so120721f8f.0 for ; Thu, 12 Nov 2026 16:32:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1794529958; x=1795134758; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=cqKN8t63b3IlTdSqj1uTv4S+18+380s33ycIKsdReAA=; b=0A1yJW+4QPiO6h79ZG3b797Op7IGatLis44iBxDS9t6/+8VWA7fXMWuHvcFUj34P70 oOvlNRPCwpSN8PakLKyrvC2eCkcntdixffjq462gr+oGz5GRY1W5PjxV7A3K9vTYVQyV 7T7JGre796xhtVry+KOEjgenOKFKfGXqVQgPzsF86wJPfv1GzKX/kr871YhmA+rbOFi1 FkX4Yl8UnGS8k/Obb1W6tqdIHtKR2duLf0RAUOnO/CriLnCEbTCRynML5t6rUgXGCbfn nXdhGKs+ViOmJnn69RLvgmNaFDrBb8YEVUPsgzTKafSOtwugfVQqpTACR3shaiY8UwtE Hu/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1794529958; x=1795134758; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=cqKN8t63b3IlTdSqj1uTv4S+18+380s33ycIKsdReAA=; b=eDMUZr/x/DdWQev42/ym1B//nf935If7GTT+ONcxFccNSoluROGb3nkqKWpR9DOwc+ cA7SAsMU6Ge03JpLI1z6zeZJgD+KtiCvsgJvrbkl+ZqZS/WtA8DrRV4aYKvK5OhgRXpM 7eyXoXkEwqLGFJn9kzSZ42HfyvXU/MwJUOAMrytoBw+z9VEDWXCGLVAnt0iiqjvbbk0g chxfxpzczJv0RoVe4UVFWatgkBtEAz49/m8pcj55WLAA7FoyageyTQKzAV1rCxAph6L3 mVCSyFAGBS8qLhtTf49bvE5mH2u7e3WKycvflgeOpXIrQUeb3f2VXxVDY3sZxbzA+lA2 NhHw== X-Forwarded-Encrypted: i=1; AL+hErEwqIkXphggrllsdETj/zHQui0M9FwfhrgRInULdefSkVjuKpH74l2Sq4aXYlaa+RVG97PwV3f2L2E=@vger.kernel.org X-Gm-Message-State: APuU4Z9HRMjA8uxiLyxv19p1zXgIAiWbOk1Veedv6bw+mFo3Vl+36R6O TRfjK8no9iDHG1ry1PCUSzPyLy9+HYvOEX9NZkk5LOdK5WmHNs+OKGpC X-Gm-Gg: AYBFou2hVMCZB7D4a3+dGXEhhhfsi7Dd4Duk8BcEsccG7caTvN/mEKz69eB6w2z5TT0 Qr0nzf8apFes4tWnfvhYsDmw27RzJCNpXOULDU58nYHmtCkyEHqggmoHfrcJEAjNNsGI9AW2h0B W5J7JiPtb2jMHvga9YatxCRKewiw4UnkrO0NAzE5oKxqS3x1vZDWd/rv7bBKBpdJxVjYp/sEpNE DjnWC8C2goC8PkD2RWQKCuRgKXVtd9UYFUzu2Wa9cNxlhclmTF++bHweUS3Tnu2TYBUFzW8jL1J ECToAcfhxWCgcT3lLonCVDJm/GArLazgCnhY/Nu9SKT4tnMZ4Z8Oz7NkK+/fTHIrU3hHrMZ8ict HqD1h1wSMmW0wWcB0ae3U/Jq7sZCl3CrI6L8DnuVrf5UHdk79NsnhdwpcTpoUE4kugB4UOQbyFu rWiBM7Cg9J795di9PqIbNlIseZUVWXJVnsT4lglUD845rXdDhr4m8yhbzJHzK/EPuiYbTG2dkqF mEbGo1VxAGy7QolY4zYxQvCXa0cQWtRFfe9TENiKKfXC+exrYs7YGWZPyEoDw4pSpV8ZkWEG1Oi rMd9GmUjtdrlXIeLy649kUC8MIKJtUby8TIBuHndu8i0mosVoyRBjmIgfBuuxWf8dXoSm1yiVMk jr72cueMr1eqDsx5pcXjxkYYP26qZ4DCzPrtZZNfNbLMFUmhSjkKSYw== X-Received: by 2002:a05:6000:25f1:b0:48a:fba3:d5b1 with SMTP id ffacd0b85a97d-49c7381a73amr2025788f8f.55.1794529957747; Thu, 12 Nov 2026 16:32:37 -0800 (PST) Received: from Ansuel-XPS24.localdomain (host-212-171-11-167.retail.telecomitalia.it. [212.171.11.167]) by smtp.googlemail.com with ESMTPSA id ffacd0b85a97d-49c5f7828a4sm2029768f8f.23.2026.11.12.16.32.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 12 Nov 2026 16:32:36 -0800 (PST) From: Christian Marangi To: Maxime Chevallier , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Simon Horman , Jonathan Corbet , Shuah Khan , Randy Dunlap , Christian Marangi , Lorenzo Bianconi , Heiner Kallweit , Russell King , Philipp Zabel , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, llvm@lists.linux.dev Cc: Daniel Golle Subject: [PATCH net-next v19 04/15] net: pcs: implement Firmware node support for PCS driver Date: Fri, 13 Nov 2026 01:31:54 +0100 Message-ID: <20261113003217.197757-5-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20261113003217.197757-1-ansuelsmth@gmail.com> References: <20261113003217.197757-1-ansuelsmth@gmail.com> X-Mailing-List: linux-doc@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Implement the foundation of Firmware node support for PCS driver. To support this, implement a simple Provider API where a PCS driver can expose multiple PCS with an xlate .fwnode_xlate function. PCS driver will have to call fwnode_pcs_add_provider() and pass the firmware node pointer and a xlate function to return the correct PCS for the passed #pcs-cells. This will register the PCS in a global list of providers so that consumer can access it. The consumer will then use fwnode_pcs_get() to get the actual PCS by passing the firmware node pointer and the index for #pcs-cells. For a simple implementation where #pcs-cells is 0 and the PCS driver expose a single PCS, the xlate function fwnode_pcs_simple_xlate() is provided. For an advanced implementation a custom xlate function is required. On removal the PCS driver must delete itself from the provider list using fwnode_pcs_del_provider(). A devm variant devm_fwnode_pcs_add() is provided to automate the release procedure. Generic functions fwnode_phylink_pcs_count() and fwnode_phylink_pcs_parse() are provided for MAC driver that will declare PCS in DT (or ACPI). Function fwnode_phylink_pcs_count() will parse "pcs-handle" property and will return the number of PCS entries described in the passed firmware node. Function fwnode_phylink_pcs_parse() will parse "pcs-handle" property and fill the passed available_pcs array with the available PCS found up to passed num_pcs value. It's worth to mention that this function will ignore PCS that still needs to be probed (returning -ENODEV) and such PCS won't be added to the available_pcs array. Co-developed-by: Daniel Golle Signed-off-by: Daniel Golle Signed-off-by: Christian Marangi --- drivers/net/pcs/Kconfig | 6 + drivers/net/pcs/Makefile | 1 + drivers/net/pcs/pcs.c | 245 +++++++++++++++++++++++++++++++ include/linux/pcs/pcs-provider.h | 70 +++++++++ include/linux/pcs/pcs.h | 74 ++++++++++ 5 files changed, 396 insertions(+) create mode 100644 drivers/net/pcs/pcs.c create mode 100644 include/linux/pcs/pcs-provider.h create mode 100644 include/linux/pcs/pcs.h diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig index 108d47257bee..3d4d81c8e098 100644 --- a/drivers/net/pcs/Kconfig +++ b/drivers/net/pcs/Kconfig @@ -5,6 +5,12 @@ menu "PCS device drivers" +config FWNODE_PCS + bool "PCS Firmware Node" + depends on ACPI || OF || COMPILE_TEST + help + Firmware node PCS accessors + config PCS_XPCS tristate "Synopsys DesignWare Ethernet XPCS" select PHYLINK diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile index f9f6cf2578d7..53ba1d560f69 100644 --- a/drivers/net/pcs/Makefile +++ b/drivers/net/pcs/Makefile @@ -3,6 +3,7 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o pcs-xpcs-wx.o +obj-$(CONFIG_FWNODE_PCS) += pcs.o obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o obj-$(CONFIG_PCS_XPCS_PLATFORM) += pcs-xpcs-plat.o obj-$(CONFIG_PCS_XPCS_ROCKCHIP) += pcs-xpcs-rk.o diff --git a/drivers/net/pcs/pcs.c b/drivers/net/pcs/pcs.c new file mode 100644 index 000000000000..39550d9a12a2 --- /dev/null +++ b/drivers/net/pcs/pcs.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("PCS library"); +MODULE_AUTHOR("Christian Marangi "); +MODULE_LICENSE("GPL"); + +struct fwnode_pcs_provider { + struct list_head link; + + struct fwnode_handle *fwnode; + struct phylink_pcs *(*fwnode_xlate)(struct fwnode_reference_args *pcsspec, + void *data); + + void *data; +}; + +static LIST_HEAD(fwnode_pcs_providers); +static DEFINE_MUTEX(fwnode_pcs_mutex); + +struct phylink_pcs *fwnode_pcs_simple_xlate(struct fwnode_reference_args *pcsspec, + void *data) +{ + return data; +} +EXPORT_SYMBOL_GPL(fwnode_pcs_simple_xlate); + +struct fwnode_pcs_provider * +fwnode_pcs_add_provider(struct fwnode_handle *fwnode, + struct phylink_pcs *(*fwnode_xlate)(struct fwnode_reference_args *pcsspec, + void *data), + void *data) +{ + struct fwnode_pcs_provider *pp; + + if (!fwnode) + return ERR_PTR(-EINVAL); + + pp = kzalloc_obj(*pp); + if (!pp) + return ERR_PTR(-ENOMEM); + + pp->fwnode = fwnode_handle_get(fwnode); + pp->data = data; + pp->fwnode_xlate = fwnode_xlate; + + mutex_lock(&fwnode_pcs_mutex); + + list_add(&pp->link, &fwnode_pcs_providers); + fwnode_dev_initialized(fwnode, true); + + mutex_unlock(&fwnode_pcs_mutex); + + pr_debug("Added pcs provider from %pfwf\n", fwnode); + + return pp; +} +EXPORT_SYMBOL_GPL(fwnode_pcs_add_provider); + +void fwnode_pcs_del_provider(struct fwnode_pcs_provider *pp) +{ + if (IS_ERR_OR_NULL(pp)) + return; + + mutex_lock(&fwnode_pcs_mutex); + + list_del(&pp->link); + fwnode_dev_initialized(pp->fwnode, false); + + mutex_unlock(&fwnode_pcs_mutex); + + fwnode_handle_put(pp->fwnode); + kfree(pp); +} +EXPORT_SYMBOL_GPL(fwnode_pcs_del_provider); + +static void devm_fwnode_pcs_del(struct device *dev, void *res) +{ + struct fwnode_pcs_provider *pp = *(struct fwnode_pcs_provider **)res; + + fwnode_pcs_del_provider(pp); +} + +struct fwnode_pcs_provider * +devm_fwnode_pcs_add_provider(struct device *dev, struct fwnode_handle *fwnode, + struct phylink_pcs *(*fwnode_xlate)(struct fwnode_reference_args *pcsspec, + void *data), + void *data) +{ + struct fwnode_pcs_provider **ptr, *pp; + + ptr = devres_alloc(devm_fwnode_pcs_del, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + pp = fwnode_pcs_add_provider(fwnode, fwnode_xlate, data); + + if (!IS_ERR(pp)) { + *ptr = pp; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return pp; +} +EXPORT_SYMBOL_GPL(devm_fwnode_pcs_add_provider); + +static int fwnode_parse_pcsspec(const struct fwnode_handle *fwnode, + int index, const char *name, + struct fwnode_reference_args *out_args) +{ + if (!fwnode) + return -EINVAL; + + if (name) { + index = fwnode_property_match_string(fwnode, "pcs-names", + name); + if (index < 0) + return index; + } + + return fwnode_property_get_reference_args(fwnode, "pcs-handle", + "#pcs-cells", 0, index, + out_args); +} + +static struct phylink_pcs * +__fwnode_pcs_get_from_pcsspec_provider(struct fwnode_reference_args *pcsspec, + struct fwnode_pcs_provider *provider) +{ + if (provider->fwnode != pcsspec->fwnode) + return ERR_PTR(-EINVAL); + + return provider->fwnode_xlate(pcsspec, provider->data); +} + +static struct phylink_pcs * +fwnode_pcs_get_from_pcsspec(struct fwnode_reference_args *pcsspec) +{ + struct fwnode_pcs_provider *provider; + struct phylink_pcs *pcs = NULL; + + if (!pcsspec) + return ERR_PTR(-EINVAL); + + mutex_lock(&fwnode_pcs_mutex); + list_for_each_entry(provider, &fwnode_pcs_providers, link) { + pcs = __fwnode_pcs_get_from_pcsspec_provider(pcsspec, provider); + if (!IS_ERR(pcs)) + break; + } + mutex_unlock(&fwnode_pcs_mutex); + + return !IS_ERR_OR_NULL(pcs) ? pcs : ERR_PTR(-ENODEV); +} + +static struct phylink_pcs *__fwnode_pcs_get(const struct fwnode_handle *fwnode, + unsigned int index, const char *con_id) +{ + struct fwnode_reference_args pcsspec; + struct phylink_pcs *pcs; + int ret; + + ret = fwnode_parse_pcsspec(fwnode, index, con_id, &pcsspec); + if (ret) + return ERR_PTR(ret); + + pcs = fwnode_pcs_get_from_pcsspec(&pcsspec); + fwnode_handle_put(pcsspec.fwnode); + + return pcs; +} + +struct phylink_pcs *fwnode_pcs_get(const struct fwnode_handle *fwnode, unsigned int index) +{ + return __fwnode_pcs_get(fwnode, index, NULL); +} +EXPORT_SYMBOL_GPL(fwnode_pcs_get); + +unsigned int fwnode_phylink_pcs_count(struct fwnode_handle *fwnode) +{ + struct fwnode_reference_args out_args; + int index = 0; + int ret; + + while (true) { + ret = fwnode_property_get_reference_args(fwnode, "pcs-handle", + "#pcs-cells", 0, index, + &out_args); + /* We expect to reach an -ENOENT error while counting */ + if (ret) + break; + + fwnode_handle_put(out_args.fwnode); + index++; + } + + return index; +} +EXPORT_SYMBOL_GPL(fwnode_phylink_pcs_count); + +int fwnode_phylink_pcs_parse(struct fwnode_handle *fwnode, + struct phylink_pcs **available_pcs, + unsigned int num_pcs) +{ + unsigned int i, found = 0; + + if (!available_pcs) + return -EINVAL; + + if (!fwnode_property_present(fwnode, "pcs-handle")) + return -ENODEV; + + for (i = 0; i < num_pcs; i++) { + struct phylink_pcs *pcs; + + pcs = fwnode_pcs_get(fwnode, i); + if (IS_ERR(pcs)) { + /* Exit early if no PCS remain.*/ + if (PTR_ERR(pcs) == -ENOENT) + break; + + /* + * Ignore -ENODEV error for PCS that still + * needs to probe. + */ + if (PTR_ERR(pcs) == -ENODEV) + continue; + + return PTR_ERR(pcs); + } + + available_pcs[found] = pcs; + found++; + } + + return found; +} +EXPORT_SYMBOL_GPL(fwnode_phylink_pcs_parse); diff --git a/include/linux/pcs/pcs-provider.h b/include/linux/pcs/pcs-provider.h new file mode 100644 index 000000000000..15c198ffdd58 --- /dev/null +++ b/include/linux/pcs/pcs-provider.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __LINUX_PCS_PROVIDER_H +#define __LINUX_PCS_PROVIDER_H + +struct fwnode_pcs_provider; + +/** + * fwnode_pcs_simple_xlate - Simple xlate function to retrieve PCS + * @pcsspec: reference arguments + * @data: Context data (assumed assigned to the single PCS) + * + * Returns: the PCS pointed by data. + */ +struct phylink_pcs *fwnode_pcs_simple_xlate(struct fwnode_reference_args *pcsspec, + void *data); + +/** + * fwnode_pcs_add_provider - Registers a new PCS provider + * @fwnode: Firmware node + * @fwnode_xlate: xlate function to retrieve the PCS + * @data: Context data + * + * Register and add a new PCS provider to the global providers list + * for the firmware node. The relevant PCS from the PCS provider + * is retrieved from the passed fwnode_xlate function. + * + * The xlate function MUST return a pointer to an existing, already-allocated + * struct phylink_pcs and MUST NOT dynamically allocate a new PCS. + * The same PCS object must be returned for a given firmware reference and args, + * as PCS pointer identity is used to associate PCS objects with their provider. + * + * Returns: A pointer to the registered PCS provider on success, or + * an ERR_PTR() encoded error code on failure. + */ +struct fwnode_pcs_provider * +fwnode_pcs_add_provider(struct fwnode_handle *fwnode, + struct phylink_pcs *(*fwnode_xlate)(struct fwnode_reference_args *pcsspec, + void *data), + void *data); + +/** + * fwnode_pcs_del_provider - Removes a PCS provider + * @pp: PCS provider returned by fwnode_pcs_add_provider() + */ +void fwnode_pcs_del_provider(struct fwnode_pcs_provider *pp); + +/** + * devm_fwnode_pcs_add_provider - Registers a new PCS provider + * @dev: Device of the PCS provider + * @fwnode: Firmware node + * @fwnode_xlate: xlate function to retrieve the PCS + * @data: Context data + * + * Register and add a new PCS provider to the global providers list + * for the firmware node. The relevant PCS from the PCS provider + * is retrieved from the passed fwnode_xlate function. While at that, it + * also associates the device with the PCS provider using devres. + * On driver detach, release function is invoked on the devres data, + * then, devres data is freed. + * + * Returns: A pointer to the registered PCS provider on success, or + * an ERR_PTR() encoded error code on failure. + */ +struct fwnode_pcs_provider * +devm_fwnode_pcs_add_provider(struct device *dev, struct fwnode_handle *fwnode, + struct phylink_pcs *(*fwnode_xlate)(struct fwnode_reference_args *pcsspec, + void *data), + void *data); + +#endif /* __LINUX_PCS_PROVIDER_H */ diff --git a/include/linux/pcs/pcs.h b/include/linux/pcs/pcs.h new file mode 100644 index 000000000000..ef2134c578c7 --- /dev/null +++ b/include/linux/pcs/pcs.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __LINUX_PCS_H +#define __LINUX_PCS_H + +#include + +#if IS_ENABLED(CONFIG_FWNODE_PCS) +/** + * fwnode_pcs_get - Retrieves a PCS from a firmware node + * @fwnode: firmware node + * @index: index fwnode PCS handle in firmware node + * + * Get a PCS from the firmware node at index. + * + * Returns: a pointer to the phylink_pcs or a negative error pointer. Can + * return -ENODEV if the PCS is not present in global providers list (either + * due to driver still needs to be probed or it failed to probe/removed). + */ +struct phylink_pcs *fwnode_pcs_get(const struct fwnode_handle *fwnode, + unsigned int index); + +/** + * fwnode_phylink_pcs_count - Count PCS entries described in firmware node + * @fwnode: firmware node + * + * Helper function to count the number of PCS entries referenced by the + * "pcs-handle" property in a firmware node. + * + * Note that this function counts all PCS references in the firmware node, + * regardless of whether the corresponding PCS devices are already probed. + * + * Returns: number of PCS entries described in the firmware node. + */ +unsigned int fwnode_phylink_pcs_count(struct fwnode_handle *fwnode); + +/** + * fwnode_phylink_pcs_parse - Parse available PCS from firmware node + * @fwnode: firmware node + * @available_pcs: pointer to preallocated array of PCS + * @num_pcs: maximum number of PCS entries to scan + * + * Helper function that parses PCS references from the "pcs-handle" + * property of a firmware node and fills @available_pcs with PCS that are + * currently available up to @num_pcs. + * + * Only PCS that are currently available are stored in @available_pcs. + * PCS that returns -ENODEV are skipped. + * + * Returns: number of PCS stored in @available_pcs, or negative error code. + */ +int fwnode_phylink_pcs_parse(struct fwnode_handle *fwnode, + struct phylink_pcs **available_pcs, + unsigned int num_pcs); +#else +static inline struct phylink_pcs *fwnode_pcs_get(const struct fwnode_handle *fwnode, + unsigned int index) +{ + return ERR_PTR(-ENOENT); +} + +static inline unsigned int fwnode_phylink_pcs_count(struct fwnode_handle *fwnode) +{ + return 0; +} + +static inline int fwnode_phylink_pcs_parse(struct fwnode_handle *fwnode, + struct phylink_pcs **available_pcs, + unsigned int num_pcs) +{ + return -EOPNOTSUPP; +} +#endif + +#endif /* __LINUX_PCS_H */ -- 2.55.0