hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/bus/fsl-mc/dprc-driver.c
....@@ -3,6 +3,7 @@
33 * Freescale data path resource container (DPRC) driver
44 *
55 * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
6
+ * Copyright 2019-2020 NXP
67 * Author: German Rivera <German.Rivera@freescale.com>
78 *
89 */
....@@ -27,7 +28,16 @@
2728 {
2829 return mc_dev->obj_desc.id == obj_desc->id &&
2930 strcmp(mc_dev->obj_desc.type, obj_desc->type) == 0;
31
+}
3032
33
+static bool fsl_mc_obj_desc_is_allocatable(struct fsl_mc_obj_desc *obj)
34
+{
35
+ if (strcmp(obj->type, "dpmcp") == 0 ||
36
+ strcmp(obj->type, "dpcon") == 0 ||
37
+ strcmp(obj->type, "dpbp") == 0)
38
+ return true;
39
+ else
40
+ return false;
3141 }
3242
3343 static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data)
....@@ -71,9 +81,9 @@
7181 * the MC by removing devices that represent MC objects that have
7282 * been dynamically removed in the physical DPRC.
7383 */
74
-static void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev,
75
- struct fsl_mc_obj_desc *obj_desc_array,
76
- int num_child_objects_in_mc)
84
+void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev,
85
+ struct fsl_mc_obj_desc *obj_desc_array,
86
+ int num_child_objects_in_mc)
7787 {
7888 if (num_child_objects_in_mc != 0) {
7989 /*
....@@ -95,6 +105,7 @@
95105 __fsl_mc_device_remove);
96106 }
97107 }
108
+EXPORT_SYMBOL_GPL(dprc_remove_devices);
98109
99110 static int __fsl_mc_device_match(struct device *dev, void *data)
100111 {
....@@ -104,10 +115,8 @@
104115 return fsl_mc_device_match(mc_dev, obj_desc);
105116 }
106117
107
-static struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc
108
- *obj_desc,
109
- struct fsl_mc_device
110
- *mc_bus_dev)
118
+struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc *obj_desc,
119
+ struct fsl_mc_device *mc_bus_dev)
111120 {
112121 struct device *dev;
113122
....@@ -152,6 +161,27 @@
152161 }
153162 }
154163
164
+static void fsl_mc_obj_device_add(struct fsl_mc_device *mc_bus_dev,
165
+ struct fsl_mc_obj_desc *obj_desc)
166
+{
167
+ int error;
168
+ struct fsl_mc_device *child_dev;
169
+
170
+ /*
171
+ * Check if device is already known to Linux:
172
+ */
173
+ child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev);
174
+ if (child_dev) {
175
+ check_plugged_state_change(child_dev, obj_desc);
176
+ put_device(&child_dev->dev);
177
+ } else {
178
+ error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
179
+ &child_dev);
180
+ if (error < 0)
181
+ return;
182
+ }
183
+}
184
+
155185 /**
156186 * dprc_add_new_devices - Adds devices to the logical bus for a DPRC
157187 *
....@@ -168,30 +198,23 @@
168198 struct fsl_mc_obj_desc *obj_desc_array,
169199 int num_child_objects_in_mc)
170200 {
171
- int error;
172201 int i;
173202
203
+ /* probe the allocable objects first */
174204 for (i = 0; i < num_child_objects_in_mc; i++) {
175
- struct fsl_mc_device *child_dev;
176205 struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
177206
178
- if (strlen(obj_desc->type) == 0)
179
- continue;
207
+ if (strlen(obj_desc->type) > 0 &&
208
+ fsl_mc_obj_desc_is_allocatable(obj_desc))
209
+ fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
210
+ }
180211
181
- /*
182
- * Check if device is already known to Linux:
183
- */
184
- child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev);
185
- if (child_dev) {
186
- check_plugged_state_change(child_dev, obj_desc);
187
- put_device(&child_dev->dev);
188
- continue;
189
- }
212
+ for (i = 0; i < num_child_objects_in_mc; i++) {
213
+ struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
190214
191
- error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
192
- &child_dev);
193
- if (error < 0)
194
- continue;
215
+ if (strlen(obj_desc->type) > 0 &&
216
+ !fsl_mc_obj_desc_is_allocatable(obj_desc))
217
+ fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
195218 }
196219 }
197220
....@@ -199,8 +222,8 @@
199222 * dprc_scan_objects - Discover objects in a DPRC
200223 *
201224 * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
202
- * @total_irq_count: If argument is provided the function populates the
203
- * total number of IRQs created by objects in the DPRC.
225
+ * @alloc_interrupts: if true the function allocates the interrupt pool,
226
+ * otherwise the interrupt allocation is delayed
204227 *
205228 * Detects objects added and removed from a DPRC and synchronizes the
206229 * state of the Linux bus driver, MC by adding and removing
....@@ -215,7 +238,7 @@
215238 * of the device drivers for the non-allocatable devices.
216239 */
217240 static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
218
- unsigned int *total_irq_count)
241
+ bool alloc_interrupts)
219242 {
220243 int num_child_objects;
221244 int dprc_get_obj_failures;
....@@ -296,21 +319,20 @@
296319 * Allocate IRQ's before binding the scanned devices with their
297320 * respective drivers.
298321 */
299
- if (dev_get_msi_domain(&mc_bus_dev->dev) && !mc_bus->irq_resources) {
322
+ if (dev_get_msi_domain(&mc_bus_dev->dev)) {
300323 if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
301324 dev_warn(&mc_bus_dev->dev,
302325 "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
303326 irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
304327 }
305328
306
- error = fsl_mc_populate_irq_pool(mc_bus,
307
- FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
308
- if (error < 0)
309
- return error;
329
+ if (alloc_interrupts && !mc_bus->irq_resources) {
330
+ error = fsl_mc_populate_irq_pool(mc_bus_dev,
331
+ FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
332
+ if (error < 0)
333
+ return error;
334
+ }
310335 }
311
-
312
- if (total_irq_count)
313
- *total_irq_count = irq_count;
314336
315337 dprc_remove_devices(mc_bus_dev, child_obj_desc_array,
316338 num_child_objects);
....@@ -333,9 +355,10 @@
333355 * bus driver with the actual state of the MC by adding and removing
334356 * devices as appropriate.
335357 */
336
-static int dprc_scan_container(struct fsl_mc_device *mc_bus_dev)
358
+int dprc_scan_container(struct fsl_mc_device *mc_bus_dev,
359
+ bool alloc_interrupts)
337360 {
338
- int error;
361
+ int error = 0;
339362 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
340363
341364 fsl_mc_init_all_resource_pools(mc_bus_dev);
....@@ -344,16 +367,12 @@
344367 * Discover objects in the DPRC:
345368 */
346369 mutex_lock(&mc_bus->scan_mutex);
347
- error = dprc_scan_objects(mc_bus_dev, NULL);
370
+ error = dprc_scan_objects(mc_bus_dev, alloc_interrupts);
348371 mutex_unlock(&mc_bus->scan_mutex);
349
- if (error < 0) {
350
- fsl_mc_cleanup_all_resource_pools(mc_bus_dev);
351
- return error;
352
- }
353372
354
- return 0;
373
+ return error;
355374 }
356
-
375
+EXPORT_SYMBOL_GPL(dprc_scan_container);
357376 /**
358377 * dprc_irq0_handler - Regular ISR for DPRC interrupt 0
359378 *
....@@ -413,9 +432,8 @@
413432 DPRC_IRQ_EVENT_CONTAINER_DESTROYED |
414433 DPRC_IRQ_EVENT_OBJ_DESTROYED |
415434 DPRC_IRQ_EVENT_OBJ_CREATED)) {
416
- unsigned int irq_count;
417435
418
- error = dprc_scan_objects(mc_dev, &irq_count);
436
+ error = dprc_scan_objects(mc_dev, true);
419437 if (error < 0) {
420438 /*
421439 * If the error is -ENXIO, we ignore it, as it indicates
....@@ -429,12 +447,6 @@
429447 }
430448
431449 goto out;
432
- }
433
-
434
- if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
435
- dev_warn(dev,
436
- "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
437
- irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
438450 }
439451 }
440452
....@@ -576,24 +588,24 @@
576588 }
577589
578590 /**
579
- * dprc_probe - callback invoked when a DPRC is being bound to this driver
591
+ * dprc_setup - opens and creates a mc_io for DPRC
580592 *
581593 * @mc_dev: Pointer to fsl-mc device representing a DPRC
582594 *
583595 * It opens the physical DPRC in the MC.
584
- * It scans the DPRC to discover the MC objects contained in it.
585
- * It creates the interrupt pool for the MC bus associated with the DPRC.
586
- * It configures the interrupts for the DPRC device itself.
596
+ * It configures the DPRC portal used to communicate with MC
587597 */
588
-static int dprc_probe(struct fsl_mc_device *mc_dev)
598
+
599
+int dprc_setup(struct fsl_mc_device *mc_dev)
589600 {
590
- int error;
591
- size_t region_size;
592601 struct device *parent_dev = mc_dev->dev.parent;
593602 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
603
+ struct irq_domain *mc_msi_domain;
594604 bool mc_io_created = false;
595605 bool msi_domain_set = false;
596606 u16 major_ver, minor_ver;
607
+ size_t region_size;
608
+ int error;
597609
598610 if (!is_fsl_mc_bus_dprc(mc_dev))
599611 return -EINVAL;
....@@ -623,31 +635,15 @@
623635 return error;
624636
625637 mc_io_created = true;
638
+ }
626639
627
- /*
628
- * Inherit parent MSI domain:
629
- */
630
- dev_set_msi_domain(&mc_dev->dev,
631
- dev_get_msi_domain(parent_dev));
632
- msi_domain_set = true;
640
+ mc_msi_domain = fsl_mc_find_msi_domain(&mc_dev->dev);
641
+ if (!mc_msi_domain) {
642
+ dev_warn(&mc_dev->dev,
643
+ "WARNING: MC bus without interrupt support\n");
633644 } else {
634
- /*
635
- * This is a root DPRC
636
- */
637
- struct irq_domain *mc_msi_domain;
638
-
639
- if (dev_is_fsl_mc(parent_dev))
640
- return -EINVAL;
641
-
642
- error = fsl_mc_find_msi_domain(parent_dev,
643
- &mc_msi_domain);
644
- if (error < 0) {
645
- dev_warn(&mc_dev->dev,
646
- "WARNING: MC bus without interrupt support\n");
647
- } else {
648
- dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
649
- msi_domain_set = true;
650
- }
645
+ dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
646
+ msi_domain_set = true;
651647 }
652648
653649 error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
....@@ -684,23 +680,6 @@
684680 goto error_cleanup_open;
685681 }
686682
687
- mutex_init(&mc_bus->scan_mutex);
688
-
689
- /*
690
- * Discover MC objects in DPRC object:
691
- */
692
- error = dprc_scan_container(mc_dev);
693
- if (error < 0)
694
- goto error_cleanup_open;
695
-
696
- /*
697
- * Configure interrupt for the DPRC object associated with this MC bus:
698
- */
699
- error = dprc_setup_irq(mc_dev);
700
- if (error < 0)
701
- goto error_cleanup_open;
702
-
703
- dev_info(&mc_dev->dev, "DPRC device bound to driver");
704683 return 0;
705684
706685 error_cleanup_open:
....@@ -715,6 +694,49 @@
715694 mc_dev->mc_io = NULL;
716695 }
717696
697
+ return error;
698
+}
699
+EXPORT_SYMBOL_GPL(dprc_setup);
700
+
701
+/**
702
+ * dprc_probe - callback invoked when a DPRC is being bound to this driver
703
+ *
704
+ * @mc_dev: Pointer to fsl-mc device representing a DPRC
705
+ *
706
+ * It opens the physical DPRC in the MC.
707
+ * It scans the DPRC to discover the MC objects contained in it.
708
+ * It creates the interrupt pool for the MC bus associated with the DPRC.
709
+ * It configures the interrupts for the DPRC device itself.
710
+ */
711
+static int dprc_probe(struct fsl_mc_device *mc_dev)
712
+{
713
+ int error;
714
+
715
+ error = dprc_setup(mc_dev);
716
+ if (error < 0)
717
+ return error;
718
+
719
+ /*
720
+ * Discover MC objects in DPRC object:
721
+ */
722
+ error = dprc_scan_container(mc_dev, true);
723
+ if (error < 0)
724
+ goto dprc_cleanup;
725
+
726
+ /*
727
+ * Configure interrupt for the DPRC object associated with this MC bus:
728
+ */
729
+ error = dprc_setup_irq(mc_dev);
730
+ if (error < 0)
731
+ goto scan_cleanup;
732
+
733
+ dev_info(&mc_dev->dev, "DPRC device bound to driver");
734
+ return 0;
735
+
736
+scan_cleanup:
737
+ device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
738
+dprc_cleanup:
739
+ dprc_cleanup(mc_dev);
718740 return error;
719741 }
720742
....@@ -733,6 +755,53 @@
733755 }
734756
735757 /**
758
+ * dprc_cleanup - function that cleanups a DPRC
759
+ *
760
+ * @mc_dev: Pointer to fsl-mc device representing the DPRC
761
+ *
762
+ * It closes the DPRC device in the MC.
763
+ * It destroys the interrupt pool associated with this MC bus.
764
+ */
765
+
766
+int dprc_cleanup(struct fsl_mc_device *mc_dev)
767
+{
768
+ int error;
769
+
770
+ /* this function should be called only for DPRCs, it
771
+ * is an error to call it for regular objects
772
+ */
773
+ if (!is_fsl_mc_bus_dprc(mc_dev))
774
+ return -EINVAL;
775
+
776
+ if (dev_get_msi_domain(&mc_dev->dev)) {
777
+ fsl_mc_cleanup_irq_pool(mc_dev);
778
+ dev_set_msi_domain(&mc_dev->dev, NULL);
779
+ }
780
+
781
+ fsl_mc_cleanup_all_resource_pools(mc_dev);
782
+
783
+ /* if this step fails we cannot go further with cleanup as there is no way of
784
+ * communicating with the firmware
785
+ */
786
+ if (!mc_dev->mc_io) {
787
+ dev_err(&mc_dev->dev, "mc_io is NULL, tear down cannot be performed in firmware\n");
788
+ return -EINVAL;
789
+ }
790
+
791
+ error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
792
+ if (error < 0)
793
+ dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error);
794
+
795
+ if (!fsl_mc_is_root_dprc(&mc_dev->dev)) {
796
+ fsl_destroy_mc_io(mc_dev->mc_io);
797
+ mc_dev->mc_io = NULL;
798
+ }
799
+
800
+ return 0;
801
+}
802
+EXPORT_SYMBOL_GPL(dprc_cleanup);
803
+
804
+/**
736805 * dprc_remove - callback invoked when a DPRC is being unbound from this driver
737806 *
738807 * @mc_dev: Pointer to fsl-mc device representing the DPRC
....@@ -744,12 +813,9 @@
744813 */
745814 static int dprc_remove(struct fsl_mc_device *mc_dev)
746815 {
747
- int error;
748816 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
749817
750818 if (!is_fsl_mc_bus_dprc(mc_dev))
751
- return -EINVAL;
752
- if (!mc_dev->mc_io)
753819 return -EINVAL;
754820
755821 if (!mc_bus->irq_resources)
....@@ -760,21 +826,7 @@
760826
761827 device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
762828
763
- if (dev_get_msi_domain(&mc_dev->dev)) {
764
- fsl_mc_cleanup_irq_pool(mc_bus);
765
- dev_set_msi_domain(&mc_dev->dev, NULL);
766
- }
767
-
768
- fsl_mc_cleanup_all_resource_pools(mc_dev);
769
-
770
- error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
771
- if (error < 0)
772
- dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error);
773
-
774
- if (!fsl_mc_is_root_dprc(&mc_dev->dev)) {
775
- fsl_destroy_mc_io(mc_dev->mc_io);
776
- mc_dev->mc_io = NULL;
777
- }
829
+ dprc_cleanup(mc_dev);
778830
779831 dev_info(&mc_dev->dev, "DPRC device unbound from driver");
780832 return 0;