Skip to content

Commit 053ca37

Browse files
committed
PCI: j721e: Initialize pcie->cdns_pcie before using it
Christian reported a NULL pointer dereference in j721e_pcie_probe() caused by 19e8638 ("PCI: j721e: Drop redundant struct device *"), which removed struct j721e_pcie.dev since there's another copy in struct cdns_pcie.dev reachable via j721e_pcie->cdns_pcie->dev. The problem is that j721e_pcie->cdns_pcie was dereferenced before being initialized: j721e_pcie_probe pcie = devm_kzalloc() # struct j721e_pcie j721e_pcie_ctrl_init(pcie) dev = pcie->cdns_pcie->dev <-- dereference cdns_pcie switch (mode) { case PCI_MODE_RC: cdns_pcie = ... # alloc as part of pci_host_bridge pcie->cdns_pcie = cdns_pcie <-- initialize pcie->cdns_pcie Move the cdns_pcie initialization earlier so it is done before it is used. This also simplifies the error exits. Fixes: 19e8638 ("PCI: j721e: Drop redundant struct device *") Link: https://lore.kernel.org/r/20220127222951.GA144828@bhelgaas Link: https://lore.kernel.org/r/20220124122132.435743-1-christian.gmeiner@gmail.com Reported-by: Christian Gmeiner <christian.gmeiner@gmail.com> Tested-by: Christian Gmeiner <christian.gmeiner@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
1 parent e783362 commit 053ca37

File tree

1 file changed

+42
-43
lines changed

1 file changed

+42
-43
lines changed

drivers/pci/controller/cadence/pci-j721e.c

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,8 @@ static int j721e_pcie_probe(struct platform_device *pdev)
356356
const struct j721e_pcie_data *data;
357357
struct cdns_pcie *cdns_pcie;
358358
struct j721e_pcie *pcie;
359-
struct cdns_pcie_rc *rc;
360-
struct cdns_pcie_ep *ep;
359+
struct cdns_pcie_rc *rc = NULL;
360+
struct cdns_pcie_ep *ep = NULL;
361361
struct gpio_desc *gpiod;
362362
void __iomem *base;
363363
struct clk *clk;
@@ -376,6 +376,46 @@ static int j721e_pcie_probe(struct platform_device *pdev)
376376
if (!pcie)
377377
return -ENOMEM;
378378

379+
switch (mode) {
380+
case PCI_MODE_RC:
381+
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST))
382+
return -ENODEV;
383+
384+
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
385+
if (!bridge)
386+
return -ENOMEM;
387+
388+
if (!data->byte_access_allowed)
389+
bridge->ops = &cdns_ti_pcie_host_ops;
390+
rc = pci_host_bridge_priv(bridge);
391+
rc->quirk_retrain_flag = data->quirk_retrain_flag;
392+
rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
393+
394+
cdns_pcie = &rc->pcie;
395+
cdns_pcie->dev = dev;
396+
cdns_pcie->ops = &j721e_pcie_ops;
397+
pcie->cdns_pcie = cdns_pcie;
398+
break;
399+
case PCI_MODE_EP:
400+
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP))
401+
return -ENODEV;
402+
403+
ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
404+
if (!ep)
405+
return -ENOMEM;
406+
407+
ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
408+
409+
cdns_pcie = &ep->pcie;
410+
cdns_pcie->dev = dev;
411+
cdns_pcie->ops = &j721e_pcie_ops;
412+
pcie->cdns_pcie = cdns_pcie;
413+
break;
414+
default:
415+
dev_err(dev, "INVALID device type %d\n", mode);
416+
return 0;
417+
}
418+
379419
pcie->mode = mode;
380420
pcie->linkdown_irq_regfield = data->linkdown_irq_regfield;
381421

@@ -426,28 +466,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
426466

427467
switch (mode) {
428468
case PCI_MODE_RC:
429-
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
430-
ret = -ENODEV;
431-
goto err_get_sync;
432-
}
433-
434-
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
435-
if (!bridge) {
436-
ret = -ENOMEM;
437-
goto err_get_sync;
438-
}
439-
440-
if (!data->byte_access_allowed)
441-
bridge->ops = &cdns_ti_pcie_host_ops;
442-
rc = pci_host_bridge_priv(bridge);
443-
rc->quirk_retrain_flag = data->quirk_retrain_flag;
444-
rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
445-
446-
cdns_pcie = &rc->pcie;
447-
cdns_pcie->dev = dev;
448-
cdns_pcie->ops = &j721e_pcie_ops;
449-
pcie->cdns_pcie = cdns_pcie;
450-
451469
gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
452470
if (IS_ERR(gpiod)) {
453471
ret = PTR_ERR(gpiod);
@@ -497,23 +515,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
497515

498516
break;
499517
case PCI_MODE_EP:
500-
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
501-
ret = -ENODEV;
502-
goto err_get_sync;
503-
}
504-
505-
ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
506-
if (!ep) {
507-
ret = -ENOMEM;
508-
goto err_get_sync;
509-
}
510-
ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
511-
512-
cdns_pcie = &ep->pcie;
513-
cdns_pcie->dev = dev;
514-
cdns_pcie->ops = &j721e_pcie_ops;
515-
pcie->cdns_pcie = cdns_pcie;
516-
517518
ret = cdns_pcie_init_phy(dev, cdns_pcie);
518519
if (ret) {
519520
dev_err(dev, "Failed to init phy\n");
@@ -525,8 +526,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
525526
goto err_pcie_setup;
526527

527528
break;
528-
default:
529-
dev_err(dev, "INVALID device type %d\n", mode);
530529
}
531530

532531
return 0;

0 commit comments

Comments
 (0)