mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-04 03:33:58 +08:00
PCI: j721e: Initialize pcie->cdns_pcie before using it
Christian reported a NULL pointer dereference in j721e_pcie_probe() caused by19e863828a
("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:19e863828a
("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>
This commit is contained in:
parent
e783362eb5
commit
053ca37c87
@ -356,8 +356,8 @@ static int j721e_pcie_probe(struct platform_device *pdev)
|
||||
const struct j721e_pcie_data *data;
|
||||
struct cdns_pcie *cdns_pcie;
|
||||
struct j721e_pcie *pcie;
|
||||
struct cdns_pcie_rc *rc;
|
||||
struct cdns_pcie_ep *ep;
|
||||
struct cdns_pcie_rc *rc = NULL;
|
||||
struct cdns_pcie_ep *ep = NULL;
|
||||
struct gpio_desc *gpiod;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
@ -376,6 +376,46 @@ static int j721e_pcie_probe(struct platform_device *pdev)
|
||||
if (!pcie)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (mode) {
|
||||
case PCI_MODE_RC:
|
||||
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST))
|
||||
return -ENODEV;
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!data->byte_access_allowed)
|
||||
bridge->ops = &cdns_ti_pcie_host_ops;
|
||||
rc = pci_host_bridge_priv(bridge);
|
||||
rc->quirk_retrain_flag = data->quirk_retrain_flag;
|
||||
rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
|
||||
|
||||
cdns_pcie = &rc->pcie;
|
||||
cdns_pcie->dev = dev;
|
||||
cdns_pcie->ops = &j721e_pcie_ops;
|
||||
pcie->cdns_pcie = cdns_pcie;
|
||||
break;
|
||||
case PCI_MODE_EP:
|
||||
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP))
|
||||
return -ENODEV;
|
||||
|
||||
ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
|
||||
if (!ep)
|
||||
return -ENOMEM;
|
||||
|
||||
ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
|
||||
|
||||
cdns_pcie = &ep->pcie;
|
||||
cdns_pcie->dev = dev;
|
||||
cdns_pcie->ops = &j721e_pcie_ops;
|
||||
pcie->cdns_pcie = cdns_pcie;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "INVALID device type %d\n", mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pcie->mode = mode;
|
||||
pcie->linkdown_irq_regfield = data->linkdown_irq_regfield;
|
||||
|
||||
@ -426,28 +466,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
switch (mode) {
|
||||
case PCI_MODE_RC:
|
||||
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
|
||||
ret = -ENODEV;
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
|
||||
if (!bridge) {
|
||||
ret = -ENOMEM;
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
if (!data->byte_access_allowed)
|
||||
bridge->ops = &cdns_ti_pcie_host_ops;
|
||||
rc = pci_host_bridge_priv(bridge);
|
||||
rc->quirk_retrain_flag = data->quirk_retrain_flag;
|
||||
rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
|
||||
|
||||
cdns_pcie = &rc->pcie;
|
||||
cdns_pcie->dev = dev;
|
||||
cdns_pcie->ops = &j721e_pcie_ops;
|
||||
pcie->cdns_pcie = cdns_pcie;
|
||||
|
||||
gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpiod)) {
|
||||
ret = PTR_ERR(gpiod);
|
||||
@ -497,23 +515,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
break;
|
||||
case PCI_MODE_EP:
|
||||
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
|
||||
ret = -ENODEV;
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
|
||||
if (!ep) {
|
||||
ret = -ENOMEM;
|
||||
goto err_get_sync;
|
||||
}
|
||||
ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
|
||||
|
||||
cdns_pcie = &ep->pcie;
|
||||
cdns_pcie->dev = dev;
|
||||
cdns_pcie->ops = &j721e_pcie_ops;
|
||||
pcie->cdns_pcie = cdns_pcie;
|
||||
|
||||
ret = cdns_pcie_init_phy(dev, cdns_pcie);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to init phy\n");
|
||||
@ -525,8 +526,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
|
||||
goto err_pcie_setup;
|
||||
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "INVALID device type %d\n", mode);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user