Skip to content

Commit 5eef9f5

Browse files
jannaumarcan
authored andcommitted
gpu: drm: apple: Use components to avoid deferred probing
There was a report of a race between DRM device registration (and removal of the simpledrm device) and GDM startup. The component based device binding ensures that all necessary devices are bind in the probe method of the last missing component. Technically the piodma-mapper should be a component of dcp but since it is only used for its iommu it can be a component of the display subsystem. Signed-off-by: Janne Grunau <j@jannau.net>
1 parent f57499f commit 5eef9f5

4 files changed

Lines changed: 249 additions & 95 deletions

File tree

drivers/gpu/drm/apple/apple_drv.c

Lines changed: 145 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
* Copyright (C) 2014 Endless Mobile
88
*/
99

10-
#include <linux/module.h>
10+
#include <linux/component.h>
1111
#include <linux/dma-mapping.h>
12+
#include <linux/module.h>
1213
#include <linux/of_address.h>
1314
#include <linux/of_device.h>
1415

@@ -390,46 +391,55 @@ static int apple_get_fb_resource(struct device *dev, const char *name,
390391
return ret;
391392
}
392393

394+
static const struct of_device_id apple_dcp_id_tbl[] = {
395+
{ .compatible = "apple,dcp" },
396+
{},
397+
};
393398

394-
static int apple_platform_probe(struct platform_device *pdev)
399+
static int apple_drm_init_dcp(struct device *dev)
395400
{
396-
struct device *dev = &pdev->dev;
397-
struct apple_drm_private *apple;
398-
struct resource fb_r;
399-
resource_size_t fb_size;
401+
struct apple_drm_private *apple = dev_get_drvdata(dev);
400402
struct platform_device *dcp[MAX_COPROCESSORS];
401-
int ret, nr_dcp, i;
402-
403-
for (nr_dcp = 0; nr_dcp < MAX_COPROCESSORS; ++nr_dcp) {
404-
struct device_node *np;
405-
struct device_link *dcp_link;
403+
struct device_node *np;
404+
int ret, num_dcp = 0;
406405

407-
np = of_parse_phandle(dev->of_node, "apple,coprocessors",
408-
nr_dcp);
409-
410-
if (!np)
411-
break;
406+
for_each_matching_node(np, apple_dcp_id_tbl) {
407+
if (!of_device_is_available(np)) {
408+
of_node_put(np);
409+
continue;
410+
}
412411

413-
dcp[nr_dcp] = of_find_device_by_node(np);
412+
dcp[num_dcp] = of_find_device_by_node(np);
413+
of_node_put(np);
414+
if (!dcp[num_dcp])
415+
continue;
414416

415-
if (!dcp[nr_dcp])
416-
return -ENODEV;
417+
ret = apple_probe_per_dcp(dev, &apple->drm, dcp[num_dcp],
418+
num_dcp);
419+
if (ret)
420+
continue;
417421

418-
dcp_link = device_link_add(dev, &dcp[nr_dcp]->dev,
419-
DL_FLAG_AUTOREMOVE_CONSUMER);
420-
if (!dcp_link) {
421-
dev_err(dev, "Failed to link to DCP %d device", nr_dcp);
422-
return -EINVAL;
423-
}
422+
ret = dcp_start(dcp[num_dcp]);
423+
if (ret)
424+
continue;
424425

425-
if (dcp_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
426-
return -EPROBE_DEFER;
426+
num_dcp++;
427427
}
428428

429-
/* Need at least 1 DCP for a display subsystem */
430-
if (nr_dcp < 1)
429+
if (num_dcp < 1)
431430
return -ENODEV;
432431

432+
433+
return 0;
434+
}
435+
436+
static int apple_drm_init(struct device *dev)
437+
{
438+
struct apple_drm_private *apple;
439+
struct resource fb_r;
440+
resource_size_t fb_size;
441+
int ret;
442+
433443
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
434444
if (ret)
435445
return ret;
@@ -438,21 +448,25 @@ static int apple_platform_probe(struct platform_device *pdev)
438448
if (ret)
439449
return ret;
440450

441-
fb_size = fb_r.end - fb_r.start + 1;
442-
ret = drm_aperture_remove_conflicting_framebuffers(fb_r.start, fb_size,
443-
false, &apple_drm_driver);
444-
if (ret) {
445-
dev_err(dev, "Failed remove fb: %d\n", ret);
446-
return ret;
447-
}
448-
449451
apple = devm_drm_dev_alloc(dev, &apple_drm_driver,
450452
struct apple_drm_private, drm);
451453
if (IS_ERR(apple))
452454
return PTR_ERR(apple);
453455

454456
dev_set_drvdata(dev, apple);
455457

458+
ret = component_bind_all(dev, apple);
459+
if (ret)
460+
return ret;
461+
462+
fb_size = fb_r.end - fb_r.start + 1;
463+
ret = drm_aperture_remove_conflicting_framebuffers(fb_r.start, fb_size,
464+
false, &apple_drm_driver);
465+
if (ret) {
466+
dev_err(dev, "Failed remove fb: %d\n", ret);
467+
goto err_unbind;
468+
}
469+
456470
ret = drmm_mode_config_init(&apple->drm);
457471
if (ret)
458472
goto err_unload;
@@ -477,17 +491,9 @@ static int apple_platform_probe(struct platform_device *pdev)
477491
apple->drm.mode_config.funcs = &apple_mode_config_funcs;
478492
apple->drm.mode_config.helper_private = &apple_mode_config_helpers;
479493

480-
for (i = 0; i < nr_dcp; ++i) {
481-
ret = apple_probe_per_dcp(dev, &apple->drm, dcp[i], i);
482-
483-
if (ret)
484-
goto err_unload;
485-
486-
ret = dcp_start(dcp[i]);
487-
488-
if (ret)
489-
goto err_unload;
490-
}
494+
ret = apple_drm_init_dcp(dev);
495+
if (ret)
496+
goto err_unload;
491497

492498
drm_mode_config_reset(&apple->drm);
493499

@@ -501,14 +507,96 @@ static int apple_platform_probe(struct platform_device *pdev)
501507

502508
err_unload:
503509
drm_dev_put(&apple->drm);
510+
err_unbind:
511+
component_unbind_all(dev, NULL);
504512
return ret;
505513
}
506514

507-
static int apple_platform_remove(struct platform_device *pdev)
515+
static void apple_drm_uninit(struct device *dev)
508516
{
509-
struct apple_drm_private *apple = platform_get_drvdata(pdev);
517+
struct apple_drm_private *apple = dev_get_drvdata(dev);
510518

511519
drm_dev_unregister(&apple->drm);
520+
drm_atomic_helper_shutdown(&apple->drm);
521+
522+
component_unbind_all(dev, NULL);
523+
524+
dev_set_drvdata(dev, NULL);
525+
}
526+
527+
static int apple_drm_bind(struct device *dev)
528+
{
529+
return apple_drm_init(dev);
530+
}
531+
532+
static void apple_drm_unbind(struct device *dev)
533+
{
534+
apple_drm_uninit(dev);
535+
}
536+
537+
const struct component_master_ops apple_drm_ops = {
538+
.bind = apple_drm_bind,
539+
.unbind = apple_drm_unbind,
540+
};
541+
542+
static const struct of_device_id apple_component_id_tbl[] = {
543+
{ .compatible = "apple,dcp-piodma" },
544+
{},
545+
};
546+
547+
static int add_display_components(struct device *dev,
548+
struct component_match **matchptr)
549+
{
550+
struct device_node *np;
551+
552+
for_each_matching_node(np, apple_component_id_tbl) {
553+
if (of_device_is_available(np))
554+
drm_of_component_match_add(dev, matchptr,
555+
component_compare_of, np);
556+
of_node_put(np);
557+
}
558+
559+
return 0;
560+
}
561+
562+
static int add_dcp_components(struct device *dev,
563+
struct component_match **matchptr)
564+
{
565+
struct device_node *np;
566+
int num = 0;
567+
568+
for_each_matching_node(np, apple_dcp_id_tbl) {
569+
if (of_device_is_available(np)) {
570+
drm_of_component_match_add(dev, matchptr,
571+
component_compare_of, np);
572+
num++;
573+
}
574+
of_node_put(np);
575+
}
576+
577+
return num;
578+
}
579+
580+
static int apple_platform_probe(struct platform_device *pdev)
581+
{
582+
struct device *mdev = &pdev->dev;
583+
struct component_match *match = NULL;
584+
int num_dcp;
585+
586+
/* add PIODMA mapper components */
587+
add_display_components(mdev, &match);
588+
589+
/* add DCP components, handle less than 1 as probe error */
590+
num_dcp = add_dcp_components(mdev, &match);
591+
if (num_dcp < 1)
592+
return -ENODEV;
593+
594+
return component_master_add_with_match(mdev, &apple_drm_ops, match);
595+
}
596+
597+
static int apple_platform_remove(struct platform_device *pdev)
598+
{
599+
component_master_del(&pdev->dev, &apple_drm_ops);
512600

513601
return 0;
514602
}
@@ -524,14 +612,19 @@ static int apple_platform_suspend(struct device *dev)
524612
{
525613
struct apple_drm_private *apple = dev_get_drvdata(dev);
526614

527-
return drm_mode_config_helper_suspend(&apple->drm);
615+
if (apple)
616+
return drm_mode_config_helper_suspend(&apple->drm);
617+
618+
return 0;
528619
}
529620

530621
static int apple_platform_resume(struct device *dev)
531622
{
532623
struct apple_drm_private *apple = dev_get_drvdata(dev);
533624

534-
drm_mode_config_helper_resume(&apple->drm);
625+
if (apple)
626+
drm_mode_config_helper_resume(&apple->drm);
627+
535628
return 0;
536629
}
537630

drivers/gpu/drm/apple/dcp-internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ struct dcp_brightness {
8484
struct apple_dcp {
8585
struct device *dev;
8686
struct platform_device *piodma;
87-
struct device_link *piodma_link;
8887
struct apple_rtkit *rtk;
8988
struct apple_crtc *crtc;
9089
struct apple_connector *connector;

0 commit comments

Comments
 (0)