of-fpga-region.c (12368B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * FPGA Region - Device Tree support for FPGA programming under Linux 4 * 5 * Copyright (C) 2013-2016 Altera Corporation 6 * Copyright (C) 2017 Intel Corporation 7 */ 8#include <linux/fpga/fpga-bridge.h> 9#include <linux/fpga/fpga-mgr.h> 10#include <linux/fpga/fpga-region.h> 11#include <linux/idr.h> 12#include <linux/kernel.h> 13#include <linux/list.h> 14#include <linux/module.h> 15#include <linux/of_platform.h> 16#include <linux/slab.h> 17#include <linux/spinlock.h> 18 19static const struct of_device_id fpga_region_of_match[] = { 20 { .compatible = "fpga-region", }, 21 {}, 22}; 23MODULE_DEVICE_TABLE(of, fpga_region_of_match); 24 25/** 26 * of_fpga_region_find - find FPGA region 27 * @np: device node of FPGA Region 28 * 29 * Caller will need to put_device(®ion->dev) when done. 30 * 31 * Return: FPGA Region struct or NULL 32 */ 33static struct fpga_region *of_fpga_region_find(struct device_node *np) 34{ 35 return fpga_region_class_find(NULL, np, device_match_of_node); 36} 37 38/** 39 * of_fpga_region_get_mgr - get reference for FPGA manager 40 * @np: device node of FPGA region 41 * 42 * Get FPGA Manager from "fpga-mgr" property or from ancestor region. 43 * 44 * Caller should call fpga_mgr_put() when done with manager. 45 * 46 * Return: fpga manager struct or IS_ERR() condition containing error code. 47 */ 48static struct fpga_manager *of_fpga_region_get_mgr(struct device_node *np) 49{ 50 struct device_node *mgr_node; 51 struct fpga_manager *mgr; 52 53 of_node_get(np); 54 while (np) { 55 if (of_device_is_compatible(np, "fpga-region")) { 56 mgr_node = of_parse_phandle(np, "fpga-mgr", 0); 57 if (mgr_node) { 58 mgr = of_fpga_mgr_get(mgr_node); 59 of_node_put(mgr_node); 60 of_node_put(np); 61 return mgr; 62 } 63 } 64 np = of_get_next_parent(np); 65 } 66 of_node_put(np); 67 68 return ERR_PTR(-EINVAL); 69} 70 71/** 72 * of_fpga_region_get_bridges - create a list of bridges 73 * @region: FPGA region 74 * 75 * Create a list of bridges including the parent bridge and the bridges 76 * specified by "fpga-bridges" property. Note that the 77 * fpga_bridges_enable/disable/put functions are all fine with an empty list 78 * if that happens. 79 * 80 * Caller should call fpga_bridges_put(®ion->bridge_list) when 81 * done with the bridges. 82 * 83 * Return: 0 for success (even if there are no bridges specified) 84 * or -EBUSY if any of the bridges are in use. 85 */ 86static int of_fpga_region_get_bridges(struct fpga_region *region) 87{ 88 struct device *dev = ®ion->dev; 89 struct device_node *region_np = dev->of_node; 90 struct fpga_image_info *info = region->info; 91 struct device_node *br, *np, *parent_br = NULL; 92 int i, ret; 93 94 /* If parent is a bridge, add to list */ 95 ret = of_fpga_bridge_get_to_list(region_np->parent, info, 96 ®ion->bridge_list); 97 98 /* -EBUSY means parent is a bridge that is under use. Give up. */ 99 if (ret == -EBUSY) 100 return ret; 101 102 /* Zero return code means parent was a bridge and was added to list. */ 103 if (!ret) 104 parent_br = region_np->parent; 105 106 /* If overlay has a list of bridges, use it. */ 107 br = of_parse_phandle(info->overlay, "fpga-bridges", 0); 108 if (br) { 109 of_node_put(br); 110 np = info->overlay; 111 } else { 112 np = region_np; 113 } 114 115 for (i = 0; ; i++) { 116 br = of_parse_phandle(np, "fpga-bridges", i); 117 if (!br) 118 break; 119 120 /* If parent bridge is in list, skip it. */ 121 if (br == parent_br) { 122 of_node_put(br); 123 continue; 124 } 125 126 /* If node is a bridge, get it and add to list */ 127 ret = of_fpga_bridge_get_to_list(br, info, 128 ®ion->bridge_list); 129 of_node_put(br); 130 131 /* If any of the bridges are in use, give up */ 132 if (ret == -EBUSY) { 133 fpga_bridges_put(®ion->bridge_list); 134 return -EBUSY; 135 } 136 } 137 138 return 0; 139} 140 141/** 142 * child_regions_with_firmware - Used to check the child region info. 143 * @overlay: device node of the overlay 144 * 145 * If the overlay adds child FPGA regions, they are not allowed to have 146 * firmware-name property. 147 * 148 * Return: 0 for OK or -EINVAL if child FPGA region adds firmware-name. 149 */ 150static int child_regions_with_firmware(struct device_node *overlay) 151{ 152 struct device_node *child_region; 153 const char *child_firmware_name; 154 int ret = 0; 155 156 of_node_get(overlay); 157 158 child_region = of_find_matching_node(overlay, fpga_region_of_match); 159 while (child_region) { 160 if (!of_property_read_string(child_region, "firmware-name", 161 &child_firmware_name)) { 162 ret = -EINVAL; 163 break; 164 } 165 child_region = of_find_matching_node(child_region, 166 fpga_region_of_match); 167 } 168 169 of_node_put(child_region); 170 171 if (ret) 172 pr_err("firmware-name not allowed in child FPGA region: %pOF", 173 child_region); 174 175 return ret; 176} 177 178/** 179 * of_fpga_region_parse_ov - parse and check overlay applied to region 180 * 181 * @region: FPGA region 182 * @overlay: overlay applied to the FPGA region 183 * 184 * Given an overlay applied to an FPGA region, parse the FPGA image specific 185 * info in the overlay and do some checking. 186 * 187 * Return: 188 * NULL if overlay doesn't direct us to program the FPGA. 189 * fpga_image_info struct if there is an image to program. 190 * error code for invalid overlay. 191 */ 192static struct fpga_image_info * 193of_fpga_region_parse_ov(struct fpga_region *region, 194 struct device_node *overlay) 195{ 196 struct device *dev = ®ion->dev; 197 struct fpga_image_info *info; 198 const char *firmware_name; 199 int ret; 200 201 if (region->info) { 202 dev_err(dev, "Region already has overlay applied.\n"); 203 return ERR_PTR(-EINVAL); 204 } 205 206 /* 207 * Reject overlay if child FPGA Regions added in the overlay have 208 * firmware-name property (would mean that an FPGA region that has 209 * not been added to the live tree yet is doing FPGA programming). 210 */ 211 ret = child_regions_with_firmware(overlay); 212 if (ret) 213 return ERR_PTR(ret); 214 215 info = fpga_image_info_alloc(dev); 216 if (!info) 217 return ERR_PTR(-ENOMEM); 218 219 info->overlay = overlay; 220 221 /* Read FPGA region properties from the overlay */ 222 if (of_property_read_bool(overlay, "partial-fpga-config")) 223 info->flags |= FPGA_MGR_PARTIAL_RECONFIG; 224 225 if (of_property_read_bool(overlay, "external-fpga-config")) 226 info->flags |= FPGA_MGR_EXTERNAL_CONFIG; 227 228 if (of_property_read_bool(overlay, "encrypted-fpga-config")) 229 info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM; 230 231 if (!of_property_read_string(overlay, "firmware-name", 232 &firmware_name)) { 233 info->firmware_name = devm_kstrdup(dev, firmware_name, 234 GFP_KERNEL); 235 if (!info->firmware_name) 236 return ERR_PTR(-ENOMEM); 237 } 238 239 of_property_read_u32(overlay, "region-unfreeze-timeout-us", 240 &info->enable_timeout_us); 241 242 of_property_read_u32(overlay, "region-freeze-timeout-us", 243 &info->disable_timeout_us); 244 245 of_property_read_u32(overlay, "config-complete-timeout-us", 246 &info->config_complete_timeout_us); 247 248 /* If overlay is not programming the FPGA, don't need FPGA image info */ 249 if (!info->firmware_name) { 250 ret = 0; 251 goto ret_no_info; 252 } 253 254 /* 255 * If overlay informs us FPGA was externally programmed, specifying 256 * firmware here would be ambiguous. 257 */ 258 if (info->flags & FPGA_MGR_EXTERNAL_CONFIG) { 259 dev_err(dev, "error: specified firmware and external-fpga-config"); 260 ret = -EINVAL; 261 goto ret_no_info; 262 } 263 264 return info; 265ret_no_info: 266 fpga_image_info_free(info); 267 return ERR_PTR(ret); 268} 269 270/** 271 * of_fpga_region_notify_pre_apply - pre-apply overlay notification 272 * 273 * @region: FPGA region that the overlay was applied to 274 * @nd: overlay notification data 275 * 276 * Called when an overlay targeted to an FPGA Region is about to be applied. 277 * Parses the overlay for properties that influence how the FPGA will be 278 * programmed and does some checking. If the checks pass, programs the FPGA. 279 * If the checks fail, overlay is rejected and does not get added to the 280 * live tree. 281 * 282 * Return: 0 for success or negative error code for failure. 283 */ 284static int of_fpga_region_notify_pre_apply(struct fpga_region *region, 285 struct of_overlay_notify_data *nd) 286{ 287 struct device *dev = ®ion->dev; 288 struct fpga_image_info *info; 289 int ret; 290 291 info = of_fpga_region_parse_ov(region, nd->overlay); 292 if (IS_ERR(info)) 293 return PTR_ERR(info); 294 295 /* If overlay doesn't program the FPGA, accept it anyway. */ 296 if (!info) 297 return 0; 298 299 if (region->info) { 300 dev_err(dev, "Region already has overlay applied.\n"); 301 return -EINVAL; 302 } 303 304 region->info = info; 305 ret = fpga_region_program_fpga(region); 306 if (ret) { 307 /* error; reject overlay */ 308 fpga_image_info_free(info); 309 region->info = NULL; 310 } 311 312 return ret; 313} 314 315/** 316 * of_fpga_region_notify_post_remove - post-remove overlay notification 317 * 318 * @region: FPGA region that was targeted by the overlay that was removed 319 * @nd: overlay notification data 320 * 321 * Called after an overlay has been removed if the overlay's target was a 322 * FPGA region. 323 */ 324static void of_fpga_region_notify_post_remove(struct fpga_region *region, 325 struct of_overlay_notify_data *nd) 326{ 327 fpga_bridges_disable(®ion->bridge_list); 328 fpga_bridges_put(®ion->bridge_list); 329 fpga_image_info_free(region->info); 330 region->info = NULL; 331} 332 333/** 334 * of_fpga_region_notify - reconfig notifier for dynamic DT changes 335 * @nb: notifier block 336 * @action: notifier action 337 * @arg: reconfig data 338 * 339 * This notifier handles programming an FPGA when a "firmware-name" property is 340 * added to an fpga-region. 341 * 342 * Return: NOTIFY_OK or error if FPGA programming fails. 343 */ 344static int of_fpga_region_notify(struct notifier_block *nb, 345 unsigned long action, void *arg) 346{ 347 struct of_overlay_notify_data *nd = arg; 348 struct fpga_region *region; 349 int ret; 350 351 switch (action) { 352 case OF_OVERLAY_PRE_APPLY: 353 pr_debug("%s OF_OVERLAY_PRE_APPLY\n", __func__); 354 break; 355 case OF_OVERLAY_POST_APPLY: 356 pr_debug("%s OF_OVERLAY_POST_APPLY\n", __func__); 357 return NOTIFY_OK; /* not for us */ 358 case OF_OVERLAY_PRE_REMOVE: 359 pr_debug("%s OF_OVERLAY_PRE_REMOVE\n", __func__); 360 return NOTIFY_OK; /* not for us */ 361 case OF_OVERLAY_POST_REMOVE: 362 pr_debug("%s OF_OVERLAY_POST_REMOVE\n", __func__); 363 break; 364 default: /* should not happen */ 365 return NOTIFY_OK; 366 } 367 368 region = of_fpga_region_find(nd->target); 369 if (!region) 370 return NOTIFY_OK; 371 372 ret = 0; 373 switch (action) { 374 case OF_OVERLAY_PRE_APPLY: 375 ret = of_fpga_region_notify_pre_apply(region, nd); 376 break; 377 378 case OF_OVERLAY_POST_REMOVE: 379 of_fpga_region_notify_post_remove(region, nd); 380 break; 381 } 382 383 put_device(®ion->dev); 384 385 if (ret) 386 return notifier_from_errno(ret); 387 388 return NOTIFY_OK; 389} 390 391static struct notifier_block fpga_region_of_nb = { 392 .notifier_call = of_fpga_region_notify, 393}; 394 395static int of_fpga_region_probe(struct platform_device *pdev) 396{ 397 struct device *dev = &pdev->dev; 398 struct device_node *np = dev->of_node; 399 struct fpga_region *region; 400 struct fpga_manager *mgr; 401 int ret; 402 403 /* Find the FPGA mgr specified by region or parent region. */ 404 mgr = of_fpga_region_get_mgr(np); 405 if (IS_ERR(mgr)) 406 return -EPROBE_DEFER; 407 408 region = fpga_region_register(dev, mgr, of_fpga_region_get_bridges); 409 if (IS_ERR(region)) { 410 ret = PTR_ERR(region); 411 goto eprobe_mgr_put; 412 } 413 414 of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); 415 platform_set_drvdata(pdev, region); 416 417 dev_info(dev, "FPGA Region probed\n"); 418 419 return 0; 420 421eprobe_mgr_put: 422 fpga_mgr_put(mgr); 423 return ret; 424} 425 426static int of_fpga_region_remove(struct platform_device *pdev) 427{ 428 struct fpga_region *region = platform_get_drvdata(pdev); 429 struct fpga_manager *mgr = region->mgr; 430 431 fpga_region_unregister(region); 432 fpga_mgr_put(mgr); 433 434 return 0; 435} 436 437static struct platform_driver of_fpga_region_driver = { 438 .probe = of_fpga_region_probe, 439 .remove = of_fpga_region_remove, 440 .driver = { 441 .name = "of-fpga-region", 442 .of_match_table = of_match_ptr(fpga_region_of_match), 443 }, 444}; 445 446/** 447 * of_fpga_region_init - init function for fpga_region class 448 * Creates the fpga_region class and registers a reconfig notifier. 449 * 450 * Return: 0 on success, negative error code otherwise. 451 */ 452static int __init of_fpga_region_init(void) 453{ 454 int ret; 455 456 ret = of_overlay_notifier_register(&fpga_region_of_nb); 457 if (ret) 458 return ret; 459 460 ret = platform_driver_register(&of_fpga_region_driver); 461 if (ret) 462 goto err_plat; 463 464 return 0; 465 466err_plat: 467 of_overlay_notifier_unregister(&fpga_region_of_nb); 468 return ret; 469} 470 471static void __exit of_fpga_region_exit(void) 472{ 473 platform_driver_unregister(&of_fpga_region_driver); 474 of_overlay_notifier_unregister(&fpga_region_of_nb); 475} 476 477subsys_initcall(of_fpga_region_init); 478module_exit(of_fpga_region_exit); 479 480MODULE_DESCRIPTION("FPGA Region"); 481MODULE_AUTHOR("Alan Tull <atull@kernel.org>"); 482MODULE_LICENSE("GPL v2");