hwrng: geode - Fix PCI device refcount leak
[ Upstream commit 9f6ec8dc574efb7f4f3d7ee9cd59ae307e78f445 ]
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: ef5d862734
("[PATCH] Add Geode HW RNG driver")
Signed-off-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
1199f8e029
commit
5cc818ad53
@ -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 mod_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 mod_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 @@ found:
|
|||||||
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 mod_exit(void)
|
static void __exit mod_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(mod_init);
|
module_init(mod_init);
|
||||||
|
Loading…
Reference in New Issue
Block a user