From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (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 7844F433BAC for ; Mon, 6 Jul 2026 12:54:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783342484; cv=none; b=kO0VZk6HbyDksSsAXwdMUscsmAn0grbjarAxezAt+Ts+rBNAr1bO2CY5M+V8gTYtu/YlHBuiWOVDda5gpyS9L43s5q0lnOUfkB5zt+2aPoQJPqSzqJEgpoaQQuWtcYEGYciMN5nJdBzqerm0W1Z+EPWGvMQz1aJopc62NmaVpVY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783342484; c=relaxed/simple; bh=phmFEdyOZod78by6YVJXqWGwH37Tp/3wv2Cd0/Fsk5w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=POG6iIoIpyBcvlC0sPodfuM3kSw8e0IY5LSBXTrk05VNor5TFYx1JCRm3Eq54kwbubpjdbSniYtNT+/SME4PoMy9ipr2AI/UMhF2rtCWwIw94PCdXECTwUMKRhv7EWVfyPjHyzlq1n2T0iSQHrtBUtjsKmF+jw3ch5cBi0r1PZc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=K6WCNhKB; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=fz8C0vgu; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="K6WCNhKB"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="fz8C0vgu" Received: from pps.filterd (m0279869.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 666AxOEA395441 for ; Mon, 6 Jul 2026 12:54:41 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= 4sjGkdbiFEyhIcJbivNdLH/SqIiY+zqTcBIMsxvO/78=; b=K6WCNhKBtuN/tE17 NhITYXTpCDOp3UexZ2O+dsOmWG0LE/WBYKjV+ouDmaZT0UbcsZvAHLkMuwAaybv0 RXZbdnqmUZ/gyaalI+dlTZihE44YX10O2P2cGhy3SXFlkFFsFylaF04CKQvB+3GM tWj5UCIQBPvd7TE0K2+UD5WV9CLabQWrWJ5Wr9H7HemwO6zWYioS1GhKKh0yHcJy ct2lDb82l8SklgHmzMB83D0RxZwSTpUHyfQsU71YcsmN3Vx/4Fda1h22F07CjCTu SnRRk9osxOAD4QIlu83obB49UCrAPlWX2Y/lkBfyMZ/HCLAERrLANmqkB7Pr7Qul EFGCDw== Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4f89qpgrt6-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Mon, 06 Jul 2026 12:54:41 +0000 (GMT) Received: by mail-qk1-f199.google.com with SMTP id af79cd13be357-91ed0e140c5so540427085a.0 for ; Mon, 06 Jul 2026 05:54:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1783342481; x=1783947281; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=4sjGkdbiFEyhIcJbivNdLH/SqIiY+zqTcBIMsxvO/78=; b=fz8C0vguknqA+5wTlVznnAxcv5wVea7LWU5vMFLp5yOfomhyxcblyonCoB4s/n6GM2 ndfex8kK6n/hbSEuY7z95fH5Qo6lXMu3OZBj0ownqHseoS5pmuzE9hUynKSfhUtYSXo1 qRDigo6DaRoWZ+34zSi3FlblY3h4EiJL6ZQ2yrltKo2Zsrw49WP6DiARHKG2+JTH0bvi vnUca6/6XFHTPFKL8d3PEBAnKowD7d0CmfGB8kMXlh82DWQLu32IeQMx9yeTurG3dymg NaViOHCqBG2vsEMI01YwRz42n1WDV1b6kp5g4kBGoJWADloHQ63OL1C5S13uDvcVyBF8 8aBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783342481; x=1783947281; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=4sjGkdbiFEyhIcJbivNdLH/SqIiY+zqTcBIMsxvO/78=; b=oIS2pfjWSM6vzVaXNbc3+INs7CG4bOZlcif7VSpqFlsPud1RSOy3Xt7X7/sqGt0hxD /3jlzvL98UrYV6HCH/0qz5UAhSzffGyK1K2ypo0QAg5nyEju8SAYX4atu8IozS3GRlMA 1d3waaK7J9EgQkL9MqFv6Iw9OULwshVNtQCH47aKRQDWyhggV8v+D4XfbpXLt4dU28Ph +rB05osdtRtok8JuzyU9vglkFDo7rkRGTgb6Mth2XW+I2EMm6k5iuKRGvoSaaqGKn7Ue wWknQVtdsWiItusBUPNRNHqNEHI0X2TIcorr09Q8YcEDcfSpTDAGtMrmch6EQ2uBUk5M rMNg== X-Forwarded-Encrypted: i=1; AHgh+RqxW3kLKA+ife+q9RP+4pv/KbzIfHguoE6TZtjDB1ihBnG3HshhMUWAAW129NWr0NaQYGMxH9a7hm5w@vger.kernel.org X-Gm-Message-State: AOJu0Yz1W7wQDyHrZoZAuCGgNRnE2qBV+1l/BW0CMvEM5t4tclxFQf8s rhbyBJCofDcFB3+qoVn0Ha6v+jCOR+7/ohhKZVp61P/XBR5BrEYocMI4dVFQbTxNF6QTWDzwK/q 0DyeaSSKj/hIQFLlsy9Itmcdr74wH1SrtkiUwfLrG8Ribboq4v2KGs3jWLkxb+UP4 X-Gm-Gg: AfdE7cnDjnfdncvQFXNfwJrb3pwC6zsrqOr6Ww6ABkqSB/cQNEhbKwcVd4mR4Gb4PPF bqjplEAMm/VE4069Z0Y3HjlO+70SQvLcnl3ks0oVvEvN9hnYItqbAQ2MefCvM48Rh1bXJFotFVM 7SDpfqyCk+no4QMTRUuqASLMjMfQqkpLd3WwLLNOIldrsTboVaZKs7eZsj2cN68dNxmYApIqCZk JYpLUOLkUWJZWmmWw5r/GyQEmmSz74sTkOBxXLvple5aLAS8evwgyPgnL351QL9WZPxFVyMCxP8 rZHQ2k3oEl/HTFmQstQn1ARaXmP0ZbfrLEqxvgGnOkw4kZrHFbSTfniqN5z6JxZx93jelo2TutO SzkWA3a4AZOxsLY/KdGVDaN8z8TcUqkuHqWLqvieM X-Received: by 2002:a05:620a:2794:b0:92e:7c72:7f71 with SMTP id af79cd13be357-92ebb4e47cemr59345885a.23.1783342480924; Mon, 06 Jul 2026 05:54:40 -0700 (PDT) X-Received: by 2002:a05:620a:2794:b0:92e:7c72:7f71 with SMTP id af79cd13be357-92ebb4e47cemr59339785a.23.1783342480231; Mon, 06 Jul 2026 05:54:40 -0700 (PDT) Received: from brgl-qcom.local ([2a01:cb1d:dc:7e00:86f0:c42b:ef4c:d3bb]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47a9de1e736sm26856931f8f.7.2026.07.06.05.54.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jul 2026 05:54:39 -0700 (PDT) From: Bartosz Golaszewski Date: Mon, 06 Jul 2026 14:54:10 +0200 Subject: [PATCH v2 3/5] software node: add kunit tests for fw_devlink support Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260706-swnode-fw-devlink-v2-3-f39b09d50112@oss.qualcomm.com> References: <20260706-swnode-fw-devlink-v2-0-f39b09d50112@oss.qualcomm.com> In-Reply-To: <20260706-swnode-fw-devlink-v2-0-f39b09d50112@oss.qualcomm.com> To: Brendan Higgins , David Gow , Rae Moar , Andy Shevchenko , Daniel Scally , Heikki Krogerus , Sakari Ailus , Bartosz Golaszewski , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Linus Walleij , Dmitry Torokhov Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, linux-acpi@vger.kernel.org, driver-core@lists.linux.dev, linux-gpio@vger.kernel.org, Bartosz Golaszewski X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=13648; i=bartosz.golaszewski@oss.qualcomm.com; h=from:subject:message-id; bh=phmFEdyOZod78by6YVJXqWGwH37Tp/3wv2Cd0/Fsk5w=; b=owEBbQKS/ZANAwAKAQWdLsv/NoTDAcsmYgBqS6WEQdywWVPhkGz5a1Calci/ONhlAOfX1ARlM yvmytTznQyJAjMEAAEKAB0WIQSR5RMt5bVGHXuiZfwFnS7L/zaEwwUCakulhAAKCRAFnS7L/zaE w8/FEACu+Lh+tdC89M3eHhi2o42b1GFrjAwub1RFY0Ue2qcudx76ODabzA/8EP71jCYv1nxGgQs rAl1SNzyQX0OCCibxS65KTzTM7y15h+b5PIdJSme585y7WX1xYDFnoTNEJKGW8jZL/iLsfmR5Wj fr1bbxCSVKl79G1wyTvIW2JXmu/xXx035RXMT0izLubeqw18RSxqozygAMW7HDs3oVEHKfN40z6 7sHdDxMLCw+lSP8W6XgTFPIbNnLveyoAeVex0ULm//Xn8e+QwrA5NU1rWaxqKhcPiEQq3ybBmge dX4DDkYE1vFpu6codz6pzIfcfgFJ2soV52Z10U74gt1WyU4eeuu6wDDc9NIzHSXuq77+uBZNCNh zO+r2lLJkIdMDpt9U3He9CO8Pkz8RgM9RwJuYKzYvMKlAa31NrS3IlxtJRIr6//MU8gjhhzH2EH 56dkwWJbzwfhWhWfjgpf5erlik4JHOx2wMAZCV9eFqOzmjWbqvwDXxfbwrVh7PbK4wVFcdwxPLi caG71lwphAVjhjhXpCdZfSl7IUnYJYTip3APNUMvo4armE33cnhgkaAYYGarVtoVjIwMSqqI+Jo J2fnTs33XvRQeExPXFaqNH3jiVZCmedgcRGasRV6atSnzHIH+1BZ15s+uW2KGUX2UwG+nQETlzD DnyrTqPBZ/WECyw== X-Developer-Key: i=bartosz.golaszewski@oss.qualcomm.com; a=openpgp; fpr=169DEB6C0BC3C46013D2C79F11A72EA01471D772 X-Authority-Analysis: v=2.4 cv=c6qbhx9l c=1 sm=1 tr=0 ts=6a4ba591 cx=c_pps a=HLyN3IcIa5EE8TELMZ618Q==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=RAioF0-LDSMA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_glEPmIy2e8OvE2BGh3C:22 a=EUspDBNiAAAA:8 a=VwQbUJbxAAAA:8 a=9zVEpjMGfH8rPmTIezIA:9 a=QEXdDO2ut3YA:10 a=bTQJ7kPSJx9SKPbeHEYW:22 X-Proofpoint-ORIG-GUID: LhWmoOxVjqPLVGDZEn1qiVQwphroKl4w X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzA2MDEzMSBTYWx0ZWRfX0fRSPF3Vxi6x IBJLJc6ted/Acl22OeB0Q6O51GD4UkIm11Lz512MO4jKY1uDXBuaAeinw3EXkqwio8oE4/zf/gf 9LqLfWkQCpMr/y9Gpw0pX1KtrL0iF3jZpQ9RLPfr2QlIpiPEhpNs/257bltN1gu1I6dqlgWHOkg bD/1uSy9frQAtaeSgkIDEfE5keDGJFzrA9F03HnQSgzqeb56AnFM+R186k9TvQ7Cykrfr0M84ZB Rrf6AxFpqQmrEErribybh7+Z2+7fE+fvszOn32wDSxR7RSZxOQ9ePWOpYSrL194Nm+1ceDU2bwP NCNKINe1hr30lIlPySBF1jSIxGPIEwktEq22wb3c7QX9wUJ1RyjUMW5Fyn6+XL+z/ewtQaKm+u7 IERWyx67Vu9HVZE/9M8aTEY1AhwZe5qAha3p/7RIzp41QrCZTch2+G+ub9t25kDSGvoclT5frmW 4uiDHD4E7WaNSyQcbTg== X-Proofpoint-Spam-Info: AW1haW4tMjYwNzA2MDEzMSBTYWx0ZWRfX+rX5BxDMgxcg nWvi60n8uJIxlDG8s/BjubWNOjtSGUc+8kVBymuQYdRkdvOCJdE9Az1WgYEdOL92luUlWHrM12r YgQL3sMbmdKfe/PqwxM/gmub5sp4xsM= X-Proofpoint-GUID: LhWmoOxVjqPLVGDZEn1qiVQwphroKl4w X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-06_01,2026-07-06_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 bulkscore=0 impostorscore=0 phishscore=0 adultscore=0 lowpriorityscore=0 priorityscore=1501 clxscore=1015 spamscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607060131 Add a kunit test suite for fw_devlink support for software nodes. Most cases call add_links() directly and inspect the resulting fwnode supplier/consumer lists: a single reference, multiple references, a reference to an unregistered node, a "remote-endpoint" reference and a reference array. The last case is end-to-end - it registers real consumer and supplier platform devices together with their drivers, adds the consumer first and checks that fw_devlink defers its probe until the supplier has been bound. Signed-off-by: Bartosz Golaszewski --- MAINTAINERS | 1 + drivers/base/test/Kconfig | 5 + drivers/base/test/Makefile | 2 + drivers/base/test/swnode-devlink-test.c | 339 ++++++++++++++++++++++++++++++++ 4 files changed, 347 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4a8b0fd665ce2447c3e89784b142d998f7384b95..d7741614c941ceed9e46e9caea72bad77cfb7618 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25105,6 +25105,7 @@ L: linux-acpi@vger.kernel.org S: Maintained F: drivers/base/property.c F: drivers/base/swnode.c +F: drivers/base/test/swnode-devlink-test.c F: include/linux/fwnode.h F: include/linux/property.h diff --git a/drivers/base/test/Kconfig b/drivers/base/test/Kconfig index 2756870615ccab67ec26d8671c1e4dba69342134..1ecf0791241a1b2eee7e1e787772217724abacb9 100644 --- a/drivers/base/test/Kconfig +++ b/drivers/base/test/Kconfig @@ -18,3 +18,8 @@ config DRIVER_PE_KUNIT_TEST tristate "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS + +config DRIVER_SWNODE_KUNIT_TEST + tristate "KUnit Tests for software node fw_devlink links" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS diff --git a/drivers/base/test/Makefile b/drivers/base/test/Makefile index e321dfc7e92266d2073d442f652cadb6e911dba5..9ced7bbd569fc49ba2719aa0cab57c7d8245dde1 100644 --- a/drivers/base/test/Makefile +++ b/drivers/base/test/Makefile @@ -6,3 +6,5 @@ obj-$(CONFIG_DM_KUNIT_TEST) += platform-device-test.o obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN) + +obj-$(CONFIG_DRIVER_SWNODE_KUNIT_TEST) += swnode-devlink-test.o diff --git a/drivers/base/test/swnode-devlink-test.c b/drivers/base/test/swnode-devlink-test.c new file mode 100644 index 0000000000000000000000000000000000000000..6f59f13214fcf39cebe02244bd0029470d3d104a --- /dev/null +++ b/drivers/base/test/swnode-devlink-test.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int swnode_count_suppliers(struct fwnode_handle *fwnode) +{ + struct fwnode_link *link; + unsigned int count = 0; + + /* + * The suppliers and consumers lists should typically only be accessed + * with the fwnode_link_lock taken but it's private to the driver core. + * + * These are tests and at this point nobody should be modifying them so + * let's just access the list. + */ + list_for_each_entry(link, &fwnode->suppliers, c_hook) + count++; + + return count; +} + +/* True if a supplier link con->sup exists, checked from both list ends. */ +static bool swnode_has_link(struct fwnode_handle *consumer, + struct fwnode_handle *supplier) +{ + bool from_con = false, from_sup = false; + struct fwnode_link *link; + + list_for_each_entry(link, &consumer->suppliers, c_hook) { + if (link->supplier == supplier && link->consumer == consumer) + from_con = true; + } + + list_for_each_entry(link, &supplier->consumers, s_hook) { + if (link->supplier == supplier && link->consumer == consumer) + from_sup = true; + } + + return from_con && from_sup; +} + +/* A single reference creates exactly one supplier link, on both list ends. */ +static void swnode_devlink_test_single_ref(struct kunit *test) +{ + static const struct software_node supp_swnode = { + .name = "swnode-devlink-test-supplier", + }; + + struct fwnode_handle *cons_fwnode, *supp_fwnode; + int ret; + + const struct property_entry props[] = { + PROPERTY_ENTRY_REF("supplier", &supp_swnode), + { } + }; + + supp_fwnode = kunit_software_node_register(test, &supp_swnode); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, supp_fwnode); + + cons_fwnode = kunit_fwnode_create_software_node(test, props, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cons_fwnode); + + ret = fwnode_call_int_op(cons_fwnode, add_links); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_EQ(test, swnode_count_suppliers(cons_fwnode), 1); + KUNIT_EXPECT_TRUE(test, swnode_has_link(cons_fwnode, supp_fwnode)); +} + +/* Multiple distinct references create multiple supplier links. */ +static void swnode_devlink_test_multiple_refs(struct kunit *test) +{ + static const struct software_node supp1_swnode = { + .name = "swnode-devlink-test-supplier-1", + }; + static const struct software_node supp2_swnode = { + .name = "swnode-devlink-test-supplier-2", + }; + static const struct software_node *supp_nodes[] = { + &supp1_swnode, &supp2_swnode, NULL + }; + + const struct property_entry props[] = { + PROPERTY_ENTRY_REF("foo", &supp1_swnode), + PROPERTY_ENTRY_REF("bar", &supp2_swnode), + { } + }; + + struct fwnode_handle *fwnode; + int ret; + + ret = kunit_software_node_register_node_group(test, supp_nodes); + KUNIT_ASSERT_EQ(test, ret, 0); + + fwnode = kunit_fwnode_create_software_node(test, props, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); + + ret = fwnode_call_int_op(fwnode, add_links); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_EQ(test, swnode_count_suppliers(fwnode), 2); + KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode, software_node_fwnode(&supp1_swnode))); + KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode, software_node_fwnode(&supp2_swnode))); +} + +/* A reference to an unregistered node creates no link (graceful skip). */ +static void swnode_devlink_test_unregistered_ref(struct kunit *test) +{ + static const struct software_node supp_swnode = { + .name = "swnode-devlink-test-supplier", + }; + + const struct property_entry props[] = { + PROPERTY_ENTRY_REF("supplier", &supp_swnode), + { } + }; + + struct fwnode_handle *fwnode; + int ret; + + fwnode = kunit_fwnode_create_software_node(test, props, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); + + ret = fwnode_call_int_op(fwnode, add_links); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, swnode_count_suppliers(fwnode), 0); +} + +/* Graph "remote-endpoint" references are excluded. */ +static void swnode_devlink_test_remote_endpoint_excluded(struct kunit *test) +{ + static const struct software_node ep_swnode = { + .name = "swnode-devlink-test-end-point" + }; + + const struct property_entry props[] = { + PROPERTY_ENTRY_REF("remote-endpoint", &ep_swnode), + { } + }; + + struct fwnode_handle *cons_fwnode, *supp_fwnode; + int ret; + + supp_fwnode = kunit_software_node_register(test, &ep_swnode); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, supp_fwnode); + + cons_fwnode = kunit_fwnode_create_software_node(test, props, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cons_fwnode); + + ret = fwnode_call_int_op(cons_fwnode, add_links); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, swnode_count_suppliers(cons_fwnode), 0); +} + +/* A reference array creates one link per registered element. */ +static void swnode_devlink_test_ref_array(struct kunit *test) +{ + static const struct software_node supp1_swnode = { + .name = "swnode-devlink-test-supplier-1", + }; + static const struct software_node supp2_swnode = { + .name = "swnode-devlink-test-supplier-2", + }; + static const struct software_node *supp_nodes[] = { + &supp1_swnode, &supp2_swnode, NULL + }; + static const struct software_node_ref_args refs[] = { + SOFTWARE_NODE_REFERENCE(&supp1_swnode), + SOFTWARE_NODE_REFERENCE(&supp2_swnode, 4, 2), + }; + + const struct property_entry props[] = { + PROPERTY_ENTRY_REF_ARRAY("suppliers", refs), + { } + }; + + struct fwnode_handle *fwnode; + int ret; + + ret = kunit_software_node_register_node_group(test, supp_nodes); + KUNIT_ASSERT_EQ(test, ret, 0); + + fwnode = kunit_fwnode_create_software_node(test, props, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); + + ret = fwnode_call_int_op(fwnode, add_links); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_EQ(test, swnode_count_suppliers(fwnode), 2); + KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode, software_node_fwnode(&supp1_swnode))); + KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode, software_node_fwnode(&supp2_swnode))); +} + +/* + * End-to-end test: fw_devlink must defer a consumer's probe until its + * supplier has probed. + * + * The reference created by software_node_add_links() is only useful if the + * driver core promotes it to a real device_link and uses it to order probing. + * This test drives actual probing through the platform bus and asserts the + * supplier binds before the consumer. + */ + +#define SWNODE_DEVLINK_TEST_SUPPLIER "swnode-link-supplier" +#define SWNODE_DEVLINK_TEST_CONSUMER "swnode-link-consumer" +#define SWNODE_DEVLINK_TEST_TIMEOUT_MS (2 * MSEC_PER_SEC) + +struct swnode_test_probe_order { + /* Names in the order their drivers' .probe ran. */ + const char *probed[2]; + unsigned int count; + wait_queue_head_t wq; +}; + +static int swnode_test_record_probe(struct platform_device *pdev) +{ + struct swnode_test_probe_order *order = platform_get_drvdata(pdev); + + if (order && order->count < ARRAY_SIZE(order->probed)) { + order->probed[order->count++] = dev_name(&pdev->dev); + wake_up_interruptible(&order->wq); + } + + return 0; +} + +static struct platform_driver swnode_test_supplier_driver = { + .probe = swnode_test_record_probe, + .driver = { + .name = SWNODE_DEVLINK_TEST_SUPPLIER, + }, +}; + +static struct platform_driver swnode_test_consumer_driver = { + .probe = swnode_test_record_probe, + .driver = { + .name = SWNODE_DEVLINK_TEST_CONSUMER, + }, +}; + +static void swnode_devlink_test_probe_order(struct kunit *test) +{ + static const struct software_node supplier_swnode = { + .name = "swnode-devlink-test-supplier", + }; + + const struct property_entry consumer_props[] = { + PROPERTY_ENTRY_REF("supplier-ref", &supplier_swnode), + { } + }; + + struct platform_device *supplier, *consumer; + struct swnode_test_probe_order *order; + struct fwnode_handle *fwnode; + int ret; + + order = kunit_kzalloc(test, sizeof(*order), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, order); + init_waitqueue_head(&order->wq); + + fwnode = kunit_software_node_register(test, &supplier_swnode); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); + + ret = kunit_platform_driver_register(test, &swnode_test_supplier_driver); + KUNIT_ASSERT_EQ(test, ret, 0); + ret = kunit_platform_driver_register(test, &swnode_test_consumer_driver); + KUNIT_ASSERT_EQ(test, ret, 0); + + supplier = kunit_platform_device_alloc(test, SWNODE_DEVLINK_TEST_SUPPLIER, + PLATFORM_DEVID_NONE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, supplier); + consumer = kunit_platform_device_alloc(test, SWNODE_DEVLINK_TEST_CONSUMER, + PLATFORM_DEVID_NONE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, consumer); + + platform_set_drvdata(supplier, order); + platform_set_drvdata(consumer, order); + + ret = device_add_software_node(&supplier->dev, &supplier_swnode); + KUNIT_ASSERT_EQ(test, ret, 0); + ret = device_create_managed_software_node(&consumer->dev, + consumer_props, NULL); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = kunit_platform_device_add(test, consumer); + KUNIT_ASSERT_EQ(test, ret, 0); + ret = kunit_platform_device_add(test, supplier); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = wait_event_interruptible_timeout(order->wq, + order->count == 2, + msecs_to_jiffies(SWNODE_DEVLINK_TEST_TIMEOUT_MS)); + KUNIT_ASSERT_GT(test, ret, 0); + + KUNIT_EXPECT_STREQ(test, order->probed[0], SWNODE_DEVLINK_TEST_SUPPLIER); + KUNIT_EXPECT_STREQ(test, order->probed[1], SWNODE_DEVLINK_TEST_CONSUMER); + + /* Tear down the consumer (and its device link) before the supplier. */ + kunit_platform_device_unregister(test, consumer); + + device_remove_software_node(&supplier->dev); +} + +static struct kunit_case swnode_test_cases[] = { + KUNIT_CASE(swnode_devlink_test_single_ref), + KUNIT_CASE(swnode_devlink_test_multiple_refs), + KUNIT_CASE(swnode_devlink_test_unregistered_ref), + KUNIT_CASE(swnode_devlink_test_remote_endpoint_excluded), + KUNIT_CASE(swnode_devlink_test_ref_array), + KUNIT_CASE(swnode_devlink_test_probe_order), + { } +}; + +static struct kunit_suite swnode_test_suite = { + .name = "software-node-links", + .test_cases = swnode_test_cases, +}; + +kunit_test_suite(swnode_test_suite); + +MODULE_DESCRIPTION("Test module for software node fw_devlink support"); +MODULE_AUTHOR("Bartosz Golaszewski "); +MODULE_LICENSE("GPL"); -- 2.47.3