diff options
Diffstat (limited to 'drivers/fpga/fpga-region.c')
-rw-r--r-- | drivers/fpga/fpga-region.c | 105 |
1 files changed, 65 insertions, 40 deletions
diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index 92ab21651aeb..76db81de2cc0 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c | |||
@@ -143,7 +143,6 @@ static struct fpga_manager *of_fpga_region_get_mgr(struct device_node *np) | |||
143 | /** | 143 | /** |
144 | * of_fpga_region_get_bridges - create a list of bridges | 144 | * of_fpga_region_get_bridges - create a list of bridges |
145 | * @region: FPGA region | 145 | * @region: FPGA region |
146 | * @info: FPGA image info | ||
147 | * | 146 | * |
148 | * Create a list of bridges including the parent bridge and the bridges | 147 | * Create a list of bridges including the parent bridge and the bridges |
149 | * specified by "fpga-bridges" property. Note that the | 148 | * specified by "fpga-bridges" property. Note that the |
@@ -156,11 +155,11 @@ static struct fpga_manager *of_fpga_region_get_mgr(struct device_node *np) | |||
156 | * Return 0 for success (even if there are no bridges specified) | 155 | * Return 0 for success (even if there are no bridges specified) |
157 | * or -EBUSY if any of the bridges are in use. | 156 | * or -EBUSY if any of the bridges are in use. |
158 | */ | 157 | */ |
159 | static int of_fpga_region_get_bridges(struct fpga_region *region, | 158 | static int of_fpga_region_get_bridges(struct fpga_region *region) |
160 | struct fpga_image_info *info) | ||
161 | { | 159 | { |
162 | struct device *dev = ®ion->dev; | 160 | struct device *dev = ®ion->dev; |
163 | struct device_node *region_np = dev->of_node; | 161 | struct device_node *region_np = dev->of_node; |
162 | struct fpga_image_info *info = region->info; | ||
164 | struct device_node *br, *np, *parent_br = NULL; | 163 | struct device_node *br, *np, *parent_br = NULL; |
165 | int i, ret; | 164 | int i, ret; |
166 | 165 | ||
@@ -192,7 +191,7 @@ static int of_fpga_region_get_bridges(struct fpga_region *region, | |||
192 | continue; | 191 | continue; |
193 | 192 | ||
194 | /* If node is a bridge, get it and add to list */ | 193 | /* If node is a bridge, get it and add to list */ |
195 | ret = of_fpga_bridge_get_to_list(br, region->info, | 194 | ret = of_fpga_bridge_get_to_list(br, info, |
196 | ®ion->bridge_list); | 195 | ®ion->bridge_list); |
197 | 196 | ||
198 | /* If any of the bridges are in use, give up */ | 197 | /* If any of the bridges are in use, give up */ |
@@ -229,10 +228,16 @@ int fpga_region_program_fpga(struct fpga_region *region) | |||
229 | goto err_put_region; | 228 | goto err_put_region; |
230 | } | 229 | } |
231 | 230 | ||
232 | ret = of_fpga_region_get_bridges(region, info); | 231 | /* |
233 | if (ret) { | 232 | * In some cases, we already have a list of bridges in the |
234 | dev_err(dev, "failed to get FPGA bridges\n"); | 233 | * fpga region struct. Or we don't have any bridges. |
235 | goto err_unlock_mgr; | 234 | */ |
235 | if (region->get_bridges) { | ||
236 | ret = region->get_bridges(region); | ||
237 | if (ret) { | ||
238 | dev_err(dev, "failed to get fpga region bridges\n"); | ||
239 | goto err_unlock_mgr; | ||
240 | } | ||
236 | } | 241 | } |
237 | 242 | ||
238 | ret = fpga_bridges_disable(®ion->bridge_list); | 243 | ret = fpga_bridges_disable(®ion->bridge_list); |
@@ -259,7 +264,8 @@ int fpga_region_program_fpga(struct fpga_region *region) | |||
259 | return 0; | 264 | return 0; |
260 | 265 | ||
261 | err_put_br: | 266 | err_put_br: |
262 | fpga_bridges_put(®ion->bridge_list); | 267 | if (region->get_bridges) |
268 | fpga_bridges_put(®ion->bridge_list); | ||
263 | err_unlock_mgr: | 269 | err_unlock_mgr: |
264 | fpga_mgr_unlock(region->mgr); | 270 | fpga_mgr_unlock(region->mgr); |
265 | err_put_region: | 271 | err_put_region: |
@@ -522,39 +528,20 @@ static struct notifier_block fpga_region_of_nb = { | |||
522 | .notifier_call = of_fpga_region_notify, | 528 | .notifier_call = of_fpga_region_notify, |
523 | }; | 529 | }; |
524 | 530 | ||
525 | static int of_fpga_region_probe(struct platform_device *pdev) | 531 | int fpga_region_register(struct device *dev, struct fpga_region *region) |
526 | { | 532 | { |
527 | struct device *dev = &pdev->dev; | ||
528 | struct device_node *np = dev->of_node; | ||
529 | struct fpga_region *region; | ||
530 | struct fpga_manager *mgr; | ||
531 | int id, ret = 0; | 533 | int id, ret = 0; |
532 | 534 | ||
533 | mgr = of_fpga_region_get_mgr(np); | ||
534 | if (IS_ERR(mgr)) | ||
535 | return -EPROBE_DEFER; | ||
536 | |||
537 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
538 | if (!region) { | ||
539 | ret = -ENOMEM; | ||
540 | goto err_put_mgr; | ||
541 | } | ||
542 | |||
543 | region->mgr = mgr; | ||
544 | |||
545 | id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); | 535 | id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); |
546 | if (id < 0) { | 536 | if (id < 0) |
547 | ret = id; | 537 | return id; |
548 | goto err_kfree; | ||
549 | } | ||
550 | 538 | ||
551 | mutex_init(®ion->mutex); | 539 | mutex_init(®ion->mutex); |
552 | INIT_LIST_HEAD(®ion->bridge_list); | 540 | INIT_LIST_HEAD(®ion->bridge_list); |
553 | |||
554 | device_initialize(®ion->dev); | 541 | device_initialize(®ion->dev); |
555 | region->dev.class = fpga_region_class; | 542 | region->dev.class = fpga_region_class; |
556 | region->dev.parent = dev; | 543 | region->dev.parent = dev; |
557 | region->dev.of_node = np; | 544 | region->dev.of_node = dev->of_node; |
558 | region->dev.id = id; | 545 | region->dev.id = id; |
559 | dev_set_drvdata(dev, region); | 546 | dev_set_drvdata(dev, region); |
560 | 547 | ||
@@ -566,19 +553,58 @@ static int of_fpga_region_probe(struct platform_device *pdev) | |||
566 | if (ret) | 553 | if (ret) |
567 | goto err_remove; | 554 | goto err_remove; |
568 | 555 | ||
556 | return 0; | ||
557 | |||
558 | err_remove: | ||
559 | ida_simple_remove(&fpga_region_ida, id); | ||
560 | return ret; | ||
561 | } | ||
562 | EXPORT_SYMBOL_GPL(fpga_region_register); | ||
563 | |||
564 | int fpga_region_unregister(struct fpga_region *region) | ||
565 | { | ||
566 | device_unregister(®ion->dev); | ||
567 | |||
568 | return 0; | ||
569 | } | ||
570 | EXPORT_SYMBOL_GPL(fpga_region_unregister); | ||
571 | |||
572 | static int of_fpga_region_probe(struct platform_device *pdev) | ||
573 | { | ||
574 | struct device *dev = &pdev->dev; | ||
575 | struct device_node *np = dev->of_node; | ||
576 | struct fpga_region *region; | ||
577 | struct fpga_manager *mgr; | ||
578 | int ret; | ||
579 | |||
580 | /* Find the FPGA mgr specified by region or parent region. */ | ||
581 | mgr = of_fpga_region_get_mgr(np); | ||
582 | if (IS_ERR(mgr)) | ||
583 | return -EPROBE_DEFER; | ||
584 | |||
585 | region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL); | ||
586 | if (!region) { | ||
587 | ret = -ENOMEM; | ||
588 | goto eprobe_mgr_put; | ||
589 | } | ||
590 | |||
591 | region->mgr = mgr; | ||
592 | |||
593 | /* Specify how to get bridges for this type of region. */ | ||
594 | region->get_bridges = of_fpga_region_get_bridges; | ||
595 | |||
596 | ret = fpga_region_register(dev, region); | ||
597 | if (ret) | ||
598 | goto eprobe_mgr_put; | ||
599 | |||
569 | of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); | 600 | of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); |
570 | 601 | ||
571 | dev_info(dev, "FPGA Region probed\n"); | 602 | dev_info(dev, "FPGA Region probed\n"); |
572 | 603 | ||
573 | return 0; | 604 | return 0; |
574 | 605 | ||
575 | err_remove: | 606 | eprobe_mgr_put: |
576 | ida_simple_remove(&fpga_region_ida, id); | ||
577 | err_kfree: | ||
578 | kfree(region); | ||
579 | err_put_mgr: | ||
580 | fpga_mgr_put(mgr); | 607 | fpga_mgr_put(mgr); |
581 | |||
582 | return ret; | 608 | return ret; |
583 | } | 609 | } |
584 | 610 | ||
@@ -586,7 +612,7 @@ static int of_fpga_region_remove(struct platform_device *pdev) | |||
586 | { | 612 | { |
587 | struct fpga_region *region = platform_get_drvdata(pdev); | 613 | struct fpga_region *region = platform_get_drvdata(pdev); |
588 | 614 | ||
589 | device_unregister(®ion->dev); | 615 | fpga_region_unregister(region); |
590 | fpga_mgr_put(region->mgr); | 616 | fpga_mgr_put(region->mgr); |
591 | 617 | ||
592 | return 0; | 618 | return 0; |
@@ -606,7 +632,6 @@ static void fpga_region_dev_release(struct device *dev) | |||
606 | struct fpga_region *region = to_fpga_region(dev); | 632 | struct fpga_region *region = to_fpga_region(dev); |
607 | 633 | ||
608 | ida_simple_remove(&fpga_region_ida, region->dev.id); | 634 | ida_simple_remove(&fpga_region_ida, region->dev.id); |
609 | kfree(region); | ||
610 | } | 635 | } |
611 | 636 | ||
612 | /** | 637 | /** |