mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
hwrng: geode - Fix PCI device refcount leak
[ Upstream commit9f6ec8dc57] 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:
committed by
Greg Kroah-Hartman
parent
5998e5c30e
commit
aa96aff394
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user