1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries 4 */ 5 6 #include <linux/array_size.h> 7 #include <linux/device.h> 8 #include <linux/fwnode.h> 9 #include <linux/list.h> 10 #include <linux/platform_device.h> 11 #include <linux/property.h> 12 #include <linux/time.h> 13 #include <linux/types.h> 14 #include <linux/wait.h> 15 16 #include <kunit/fwnode.h> 17 #include <kunit/platform_device.h> 18 #include <kunit/test.h> 19 20 static int swnode_count_suppliers(struct fwnode_handle *fwnode) 21 { 22 struct fwnode_link *link; 23 unsigned int count = 0; 24 25 /* 26 * The suppliers and consumers lists should typically only be accessed 27 * with the fwnode_link_lock taken but it's private to the driver core. 28 * 29 * These are tests and at this point nobody should be modifying them so 30 * let's just access the list. 31 */ 32 list_for_each_entry(link, &fwnode->suppliers, c_hook) 33 count++; 34 35 return count; 36 } 37 38 /* True if a supplier link con->sup exists, checked from both list ends. */ 39 static bool swnode_has_link(struct fwnode_handle *consumer, 40 struct fwnode_handle *supplier) 41 { 42 bool from_con = false, from_sup = false; 43 struct fwnode_link *link; 44 45 list_for_each_entry(link, &consumer->suppliers, c_hook) { 46 if (link->supplier == supplier && link->consumer == consumer) 47 from_con = true; 48 } 49 50 list_for_each_entry(link, &supplier->consumers, s_hook) { 51 if (link->supplier == supplier && link->consumer == consumer) 52 from_sup = true; 53 } 54 55 return from_con && from_sup; 56 } 57 58 /* A single reference creates exactly one supplier link, on both list ends. */ 59 static void swnode_devlink_test_single_ref(struct kunit *test) 60 { 61 static const struct software_node supp_swnode = { 62 .name = "swnode-devlink-test-supplier", 63 }; 64 65 struct fwnode_handle *cons_fwnode, *supp_fwnode; 66 int ret; 67 68 const struct property_entry props[] = { 69 PROPERTY_ENTRY_REF("supplier", &supp_swnode), 70 { } 71 }; 72 73 supp_fwnode = kunit_software_node_register(test, &supp_swnode); 74 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, supp_fwnode); 75 76 cons_fwnode = kunit_fwnode_create_software_node(test, props, NULL); 77 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cons_fwnode); 78 79 ret = fwnode_call_int_op(cons_fwnode, add_links); 80 KUNIT_EXPECT_EQ(test, ret, 0); 81 82 KUNIT_EXPECT_EQ(test, swnode_count_suppliers(cons_fwnode), 1); 83 KUNIT_EXPECT_TRUE(test, swnode_has_link(cons_fwnode, supp_fwnode)); 84 } 85 86 /* Multiple distinct references create multiple supplier links. */ 87 static void swnode_devlink_test_multiple_refs(struct kunit *test) 88 { 89 static const struct software_node supp1_swnode = { 90 .name = "swnode-devlink-test-supplier-1", 91 }; 92 static const struct software_node supp2_swnode = { 93 .name = "swnode-devlink-test-supplier-2", 94 }; 95 static const struct software_node *supp_nodes[] = { 96 &supp1_swnode, &supp2_swnode, NULL 97 }; 98 99 const struct property_entry props[] = { 100 PROPERTY_ENTRY_REF("foo", &supp1_swnode), 101 PROPERTY_ENTRY_REF("bar", &supp2_swnode), 102 { } 103 }; 104 105 struct fwnode_handle *fwnode; 106 int ret; 107 108 ret = kunit_software_node_register_node_group(test, supp_nodes); 109 KUNIT_ASSERT_EQ(test, ret, 0); 110 111 fwnode = kunit_fwnode_create_software_node(test, props, NULL); 112 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); 113 114 ret = fwnode_call_int_op(fwnode, add_links); 115 KUNIT_EXPECT_EQ(test, ret, 0); 116 117 KUNIT_EXPECT_EQ(test, swnode_count_suppliers(fwnode), 2); 118 KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode, software_node_fwnode(&supp1_swnode))); 119 KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode, software_node_fwnode(&supp2_swnode))); 120 } 121 122 /* A reference to an unregistered node creates no link (graceful skip). */ 123 static void swnode_devlink_test_unregistered_ref(struct kunit *test) 124 { 125 static const struct software_node supp_swnode = { 126 .name = "swnode-devlink-test-supplier", 127 }; 128 129 const struct property_entry props[] = { 130 PROPERTY_ENTRY_REF("supplier", &supp_swnode), 131 { } 132 }; 133 134 struct fwnode_handle *fwnode; 135 int ret; 136 137 fwnode = kunit_fwnode_create_software_node(test, props, NULL); 138 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); 139 140 ret = fwnode_call_int_op(fwnode, add_links); 141 KUNIT_EXPECT_EQ(test, ret, 0); 142 KUNIT_EXPECT_EQ(test, swnode_count_suppliers(fwnode), 0); 143 } 144 145 /* Graph "remote-endpoint" references are excluded. */ 146 static void swnode_devlink_test_remote_endpoint_excluded(struct kunit *test) 147 { 148 static const struct software_node ep_swnode = { 149 .name = "swnode-devlink-test-end-point" 150 }; 151 152 const struct property_entry props[] = { 153 PROPERTY_ENTRY_REF("remote-endpoint", &ep_swnode), 154 { } 155 }; 156 157 struct fwnode_handle *cons_fwnode, *supp_fwnode; 158 int ret; 159 160 supp_fwnode = kunit_software_node_register(test, &ep_swnode); 161 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, supp_fwnode); 162 163 cons_fwnode = kunit_fwnode_create_software_node(test, props, NULL); 164 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cons_fwnode); 165 166 ret = fwnode_call_int_op(cons_fwnode, add_links); 167 KUNIT_EXPECT_EQ(test, ret, 0); 168 KUNIT_EXPECT_EQ(test, swnode_count_suppliers(cons_fwnode), 0); 169 } 170 171 /* A reference array creates one link per registered element. */ 172 static void swnode_devlink_test_ref_array(struct kunit *test) 173 { 174 static const struct software_node supp1_swnode = { 175 .name = "swnode-devlink-test-supplier-1", 176 }; 177 static const struct software_node supp2_swnode = { 178 .name = "swnode-devlink-test-supplier-2", 179 }; 180 static const struct software_node *supp_nodes[] = { 181 &supp1_swnode, &supp2_swnode, NULL 182 }; 183 static const struct software_node_ref_args refs[] = { 184 SOFTWARE_NODE_REFERENCE(&supp1_swnode), 185 SOFTWARE_NODE_REFERENCE(&supp2_swnode, 4, 2), 186 }; 187 188 const struct property_entry props[] = { 189 PROPERTY_ENTRY_REF_ARRAY("suppliers", refs), 190 { } 191 }; 192 193 struct fwnode_handle *fwnode; 194 int ret; 195 196 ret = kunit_software_node_register_node_group(test, supp_nodes); 197 KUNIT_ASSERT_EQ(test, ret, 0); 198 199 fwnode = kunit_fwnode_create_software_node(test, props, NULL); 200 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); 201 202 ret = fwnode_call_int_op(fwnode, add_links); 203 KUNIT_EXPECT_EQ(test, ret, 0); 204 205 KUNIT_EXPECT_EQ(test, swnode_count_suppliers(fwnode), 2); 206 KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode, software_node_fwnode(&supp1_swnode))); 207 KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode, software_node_fwnode(&supp2_swnode))); 208 } 209 210 /* 211 * End-to-end test: fw_devlink must defer a consumer's probe until its 212 * supplier has probed. 213 * 214 * The reference created by software_node_add_links() is only useful if the 215 * driver core promotes it to a real device_link and uses it to order probing. 216 * This test drives actual probing through the platform bus and asserts the 217 * supplier binds before the consumer. 218 */ 219 220 #define SWNODE_DEVLINK_TEST_SUPPLIER "swnode-link-supplier" 221 #define SWNODE_DEVLINK_TEST_CONSUMER "swnode-link-consumer" 222 #define SWNODE_DEVLINK_TEST_TIMEOUT_MS (2 * MSEC_PER_SEC) 223 224 struct swnode_test_probe_order { 225 /* Names in the order their drivers' .probe ran. */ 226 const char *probed[2]; 227 unsigned int count; 228 wait_queue_head_t wq; 229 }; 230 231 static int swnode_test_record_probe(struct platform_device *pdev) 232 { 233 struct swnode_test_probe_order *order = platform_get_drvdata(pdev); 234 235 if (order && order->count < ARRAY_SIZE(order->probed)) { 236 order->probed[order->count++] = dev_name(&pdev->dev); 237 wake_up_interruptible(&order->wq); 238 } 239 240 return 0; 241 } 242 243 static struct platform_driver swnode_test_supplier_driver = { 244 .probe = swnode_test_record_probe, 245 .driver = { 246 .name = SWNODE_DEVLINK_TEST_SUPPLIER, 247 }, 248 }; 249 250 static struct platform_driver swnode_test_consumer_driver = { 251 .probe = swnode_test_record_probe, 252 .driver = { 253 .name = SWNODE_DEVLINK_TEST_CONSUMER, 254 }, 255 }; 256 257 static void swnode_devlink_test_probe_order(struct kunit *test) 258 { 259 static const struct software_node supplier_swnode = { 260 .name = "swnode-devlink-test-supplier", 261 }; 262 263 const struct property_entry consumer_props[] = { 264 PROPERTY_ENTRY_REF("supplier-ref", &supplier_swnode), 265 { } 266 }; 267 268 struct platform_device *supplier, *consumer; 269 struct swnode_test_probe_order *order; 270 struct fwnode_handle *fwnode; 271 int ret; 272 273 order = kunit_kzalloc(test, sizeof(*order), GFP_KERNEL); 274 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, order); 275 init_waitqueue_head(&order->wq); 276 277 fwnode = kunit_software_node_register(test, &supplier_swnode); 278 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); 279 280 ret = kunit_platform_driver_register(test, &swnode_test_supplier_driver); 281 KUNIT_ASSERT_EQ(test, ret, 0); 282 ret = kunit_platform_driver_register(test, &swnode_test_consumer_driver); 283 KUNIT_ASSERT_EQ(test, ret, 0); 284 285 supplier = kunit_platform_device_alloc(test, SWNODE_DEVLINK_TEST_SUPPLIER, 286 PLATFORM_DEVID_NONE); 287 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, supplier); 288 consumer = kunit_platform_device_alloc(test, SWNODE_DEVLINK_TEST_CONSUMER, 289 PLATFORM_DEVID_NONE); 290 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, consumer); 291 292 platform_set_drvdata(supplier, order); 293 platform_set_drvdata(consumer, order); 294 295 ret = kunit_device_add_software_node(test, &supplier->dev, &supplier_swnode); 296 KUNIT_ASSERT_EQ(test, ret, 0); 297 ret = device_create_managed_software_node(&consumer->dev, 298 consumer_props, NULL); 299 KUNIT_ASSERT_EQ(test, ret, 0); 300 301 ret = kunit_platform_device_add(test, consumer); 302 KUNIT_ASSERT_EQ(test, ret, 0); 303 ret = kunit_platform_device_add(test, supplier); 304 KUNIT_ASSERT_EQ(test, ret, 0); 305 306 ret = wait_event_interruptible_timeout(order->wq, 307 order->count == 2, 308 msecs_to_jiffies(SWNODE_DEVLINK_TEST_TIMEOUT_MS)); 309 KUNIT_ASSERT_GT(test, ret, 0); 310 311 KUNIT_EXPECT_STREQ(test, order->probed[0], SWNODE_DEVLINK_TEST_SUPPLIER); 312 KUNIT_EXPECT_STREQ(test, order->probed[1], SWNODE_DEVLINK_TEST_CONSUMER); 313 314 /* Tear down the consumer (and its device link) before the supplier. */ 315 kunit_platform_device_unregister(test, consumer); 316 } 317 318 static struct kunit_case swnode_test_cases[] = { 319 KUNIT_CASE(swnode_devlink_test_single_ref), 320 KUNIT_CASE(swnode_devlink_test_multiple_refs), 321 KUNIT_CASE(swnode_devlink_test_unregistered_ref), 322 KUNIT_CASE(swnode_devlink_test_remote_endpoint_excluded), 323 KUNIT_CASE(swnode_devlink_test_ref_array), 324 KUNIT_CASE(swnode_devlink_test_probe_order), 325 { } 326 }; 327 328 static struct kunit_suite swnode_test_suite = { 329 .name = "software-node-links", 330 .test_cases = swnode_test_cases, 331 }; 332 333 kunit_test_suite(swnode_test_suite); 334 335 MODULE_DESCRIPTION("Test module for software node fw_devlink support"); 336 MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>"); 337 MODULE_LICENSE("GPL"); 338