Commit 9f6ec8dc authored by Xiongfeng Wang's avatar Xiongfeng Wang Committed by Herbert Xu

hwrng: geode - Fix PCI device refcount leak

for_each_pci_dev() is implemented by pci_get_device(). The comment of
pci_get_device() says that it will increase the reference count for the
returned pci_dev and also decrease the reference count for the input
pci_dev @from if it is not NULL.

If we break for_each_pci_dev() loop with pdev not NULL, we need to call
pci_dev_put() to decrease the reference count. We add a new struct
'amd_geode_priv' to record pointer of the pci_dev and membase, and then
add missing pci_dev_put() for the normal and error path.

Fixes: ef5d8627 ("[PATCH] Add Geode HW RNG driver")
Signed-off-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent ecadb5b0
...@@ -51,6 +51,10 @@ static const struct pci_device_id pci_tbl[] = { ...@@ -51,6 +51,10 @@ static const struct pci_device_id pci_tbl[] = {
}; };
MODULE_DEVICE_TABLE(pci, pci_tbl); MODULE_DEVICE_TABLE(pci, pci_tbl);
struct amd_geode_priv {
struct pci_dev *pcidev;
void __iomem *membase;
};
static int geode_rng_data_read(struct hwrng *rng, u32 *data) static int geode_rng_data_read(struct hwrng *rng, u32 *data)
{ {
...@@ -90,6 +94,7 @@ static int __init geode_rng_init(void) ...@@ -90,6 +94,7 @@ static int __init geode_rng_init(void)
const struct pci_device_id *ent; const struct pci_device_id *ent;
void __iomem *mem; void __iomem *mem;
unsigned long rng_base; unsigned long rng_base;
struct amd_geode_priv *priv;
for_each_pci_dev(pdev) { for_each_pci_dev(pdev) {
ent = pci_match_id(pci_tbl, pdev); ent = pci_match_id(pci_tbl, pdev);
...@@ -97,17 +102,26 @@ static int __init geode_rng_init(void) ...@@ -97,17 +102,26 @@ static int __init geode_rng_init(void)
goto found; goto found;
} }
/* Device not found. */ /* Device not found. */
goto out; return err;
found: found:
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
err = -ENOMEM;
goto put_dev;
}
rng_base = pci_resource_start(pdev, 0); rng_base = pci_resource_start(pdev, 0);
if (rng_base == 0) if (rng_base == 0)
goto out; goto free_priv;
err = -ENOMEM; err = -ENOMEM;
mem = ioremap(rng_base, 0x58); mem = ioremap(rng_base, 0x58);
if (!mem) if (!mem)
goto out; goto free_priv;
geode_rng.priv = (unsigned long)mem;
geode_rng.priv = (unsigned long)priv;
priv->membase = mem;
priv->pcidev = pdev;
pr_info("AMD Geode RNG detected\n"); pr_info("AMD Geode RNG detected\n");
err = hwrng_register(&geode_rng); err = hwrng_register(&geode_rng);
...@@ -116,20 +130,26 @@ static int __init geode_rng_init(void) ...@@ -116,20 +130,26 @@ static int __init geode_rng_init(void)
err); err);
goto err_unmap; goto err_unmap;
} }
out:
return err; return err;
err_unmap: err_unmap:
iounmap(mem); iounmap(mem);
goto out; free_priv:
kfree(priv);
put_dev:
pci_dev_put(pdev);
return err;
} }
static void __exit geode_rng_exit(void) static void __exit geode_rng_exit(void)
{ {
void __iomem *mem = (void __iomem *)geode_rng.priv; struct amd_geode_priv *priv;
priv = (struct amd_geode_priv *)geode_rng.priv;
hwrng_unregister(&geode_rng); hwrng_unregister(&geode_rng);
iounmap(mem); iounmap(priv->membase);
pci_dev_put(priv->pcidev);
kfree(priv);
} }
module_init(geode_rng_init); module_init(geode_rng_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment