Skip to content

Commit

Permalink
MFD: mcp-core: sanitize host creation/removal
Browse files Browse the repository at this point in the history
host_unregister() gives us no chance between removing the device
and the mcp data structure being freed to access the data inbetween,
which drivers may need to do if they need to iounmap() pointers in
their private data structures.

Therefore, re-jig the interfaces, which are now, on creation:

	mcp = mcp_host_alloc()
	if (mcp) {
		ret = mcp_host_add(mcp, data);

		if (!ret)
			mcp_host_free(mcp);
	}

and on removal:

	mcp_host_del(mcp);
	... access mcp ...
	mcp_host_free(mcp);

The free does the final put_device() on the struct device as one would
expect.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Russell King committed Feb 3, 2012
1 parent 0af5e4c commit 30816ac
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 10 deletions.
19 changes: 13 additions & 6 deletions drivers/mfd/mcp-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
if (mcp) {
spin_lock_init(&mcp->lock);
device_initialize(&mcp->attached_device);
mcp->attached_device.parent = parent;
mcp->attached_device.bus = &mcp_bus_type;
mcp->attached_device.dma_mask = parent->dma_mask;
Expand All @@ -217,18 +218,24 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
}
EXPORT_SYMBOL(mcp_host_alloc);

int mcp_host_register(struct mcp *mcp)
int mcp_host_add(struct mcp *mcp)
{
dev_set_name(&mcp->attached_device, "mcp0");
return device_register(&mcp->attached_device);
return device_add(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_register);
EXPORT_SYMBOL(mcp_host_add);

void mcp_host_unregister(struct mcp *mcp)
void mcp_host_del(struct mcp *mcp)
{
device_unregister(&mcp->attached_device);
device_del(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_unregister);
EXPORT_SYMBOL(mcp_host_del);

void mcp_host_free(struct mcp *mcp)
{
put_device(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_free);

int mcp_driver_register(struct mcp_driver *mcpdrv)
{
Expand Down
6 changes: 4 additions & 2 deletions drivers/mfd/mcp-sa11x0.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,11 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
mcp->sclk_rate;

ret = mcp_host_register(mcp);
ret = mcp_host_add(mcp);
if (ret == 0)
goto out;

mcp_host_free(mcp);
release:
release_mem_region(0x80060000, 0x60);
platform_set_drvdata(pdev, NULL);
Expand All @@ -212,7 +213,8 @@ static int mcp_sa11x0_remove(struct platform_device *dev)
struct mcp *mcp = platform_get_drvdata(dev);

platform_set_drvdata(dev, NULL);
mcp_host_unregister(mcp);
mcp_host_del(mcp);
mcp_host_free(mcp);
release_mem_region(0x80060000, 0x60);

return 0;
Expand Down
5 changes: 3 additions & 2 deletions include/linux/mfd/mcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ void mcp_disable(struct mcp *);
#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)

struct mcp *mcp_host_alloc(struct device *, size_t);
int mcp_host_register(struct mcp *);
void mcp_host_unregister(struct mcp *);
int mcp_host_add(struct mcp *);
void mcp_host_del(struct mcp *);
void mcp_host_free(struct mcp *);

struct mcp_driver {
struct device_driver drv;
Expand Down

0 comments on commit 30816ac

Please sign in to comment.