Commit 5a218ceb authored by Carlos Chinea's avatar Carlos Chinea

HSI: hsi: Rework hsi_controller release

Use the proper release mechanism for hsi_controller and
hsi_ports structures. Free the structures through their
associated device release callbacks.
Signed-off-by: default avatarCarlos Chinea <carlos.chinea@nokia.com>
Acked-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 66f75a5d
...@@ -140,12 +140,17 @@ static int hsi_remove_port(struct device *dev, void *data __maybe_unused) ...@@ -140,12 +140,17 @@ static int hsi_remove_port(struct device *dev, void *data __maybe_unused)
return 0; return 0;
} }
static void hsi_controller_release(struct device *dev __maybe_unused) static void hsi_controller_release(struct device *dev)
{ {
struct hsi_controller *hsi = to_hsi_controller(dev);
kfree(hsi->port);
kfree(hsi);
} }
static void hsi_port_release(struct device *dev __maybe_unused) static void hsi_port_release(struct device *dev)
{ {
kfree(to_hsi_port(dev));
} }
/** /**
...@@ -172,18 +177,14 @@ int hsi_register_controller(struct hsi_controller *hsi) ...@@ -172,18 +177,14 @@ int hsi_register_controller(struct hsi_controller *hsi)
hsi->device.type = &hsi_ctrl; hsi->device.type = &hsi_ctrl;
hsi->device.bus = &hsi_bus_type; hsi->device.bus = &hsi_bus_type;
hsi->device.release = hsi_controller_release; err = device_add(&hsi->device);
err = device_register(&hsi->device);
if (err < 0) if (err < 0)
return err; return err;
for (i = 0; i < hsi->num_ports; i++) { for (i = 0; i < hsi->num_ports; i++) {
hsi->port[i].device.parent = &hsi->device; hsi->port[i]->device.parent = &hsi->device;
hsi->port[i].device.bus = &hsi_bus_type; hsi->port[i]->device.bus = &hsi_bus_type;
hsi->port[i].device.release = hsi_port_release; hsi->port[i]->device.type = &hsi_port;
hsi->port[i].device.type = &hsi_port; err = device_add(&hsi->port[i]->device);
INIT_LIST_HEAD(&hsi->port[i].clients);
spin_lock_init(&hsi->port[i].clock);
err = device_register(&hsi->port[i].device);
if (err < 0) if (err < 0)
goto out; goto out;
} }
...@@ -192,7 +193,9 @@ int hsi_register_controller(struct hsi_controller *hsi) ...@@ -192,7 +193,9 @@ int hsi_register_controller(struct hsi_controller *hsi)
return 0; return 0;
out: out:
hsi_unregister_controller(hsi); while (i-- > 0)
device_del(&hsi->port[i]->device);
device_del(&hsi->device);
return err; return err;
} }
...@@ -222,6 +225,29 @@ static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused) ...@@ -222,6 +225,29 @@ static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused)
return 0; return 0;
} }
/**
* hsi_put_controller - Free an HSI controller
*
* @hsi: Pointer to the HSI controller to freed
*
* HSI controller drivers should only use this function if they need
* to free their allocated hsi_controller structures before a successful
* call to hsi_register_controller. Other use is not allowed.
*/
void hsi_put_controller(struct hsi_controller *hsi)
{
unsigned int i;
if (!hsi)
return;
for (i = 0; i < hsi->num_ports; i++)
if (hsi->port && hsi->port[i])
put_device(&hsi->port[i]->device);
put_device(&hsi->device);
}
EXPORT_SYMBOL_GPL(hsi_put_controller);
/** /**
* hsi_alloc_controller - Allocate an HSI controller and its ports * hsi_alloc_controller - Allocate an HSI controller and its ports
* @n_ports: Number of ports on the HSI controller * @n_ports: Number of ports on the HSI controller
...@@ -232,54 +258,52 @@ static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused) ...@@ -232,54 +258,52 @@ static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused)
struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags) struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags)
{ {
struct hsi_controller *hsi; struct hsi_controller *hsi;
struct hsi_port *port; struct hsi_port **port;
unsigned int i; unsigned int i;
if (!n_ports) if (!n_ports)
return NULL; return NULL;
port = kzalloc(sizeof(*port)*n_ports, flags);
if (!port)
return NULL;
hsi = kzalloc(sizeof(*hsi), flags); hsi = kzalloc(sizeof(*hsi), flags);
if (!hsi) if (!hsi)
goto out; return NULL;
for (i = 0; i < n_ports; i++) { port = kzalloc(sizeof(*port)*n_ports, flags);
dev_set_name(&port[i].device, "port%d", i); if (!port) {
port[i].num = i; kfree(hsi);
port[i].async = hsi_dummy_msg; return NULL;
port[i].setup = hsi_dummy_cl;
port[i].flush = hsi_dummy_cl;
port[i].start_tx = hsi_dummy_cl;
port[i].stop_tx = hsi_dummy_cl;
port[i].release = hsi_dummy_cl;
mutex_init(&port[i].lock);
} }
hsi->num_ports = n_ports; hsi->num_ports = n_ports;
hsi->port = port; hsi->port = port;
hsi->device.release = hsi_controller_release;
device_initialize(&hsi->device);
for (i = 0; i < n_ports; i++) {
port[i] = kzalloc(sizeof(**port), flags);
if (port[i] == NULL)
goto out;
port[i]->num = i;
port[i]->async = hsi_dummy_msg;
port[i]->setup = hsi_dummy_cl;
port[i]->flush = hsi_dummy_cl;
port[i]->start_tx = hsi_dummy_cl;
port[i]->stop_tx = hsi_dummy_cl;
port[i]->release = hsi_dummy_cl;
mutex_init(&port[i]->lock);
INIT_LIST_HEAD(&hsi->port[i]->clients);
spin_lock_init(&hsi->port[i]->clock);
dev_set_name(&port[i]->device, "port%d", i);
hsi->port[i]->device.release = hsi_port_release;
device_initialize(&hsi->port[i]->device);
}
return hsi; return hsi;
out: out:
kfree(port); hsi_put_controller(hsi);
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(hsi_alloc_controller); EXPORT_SYMBOL_GPL(hsi_alloc_controller);
/**
* hsi_free_controller - Free an HSI controller
* @hsi: Pointer to HSI controller
*/
void hsi_free_controller(struct hsi_controller *hsi)
{
if (!hsi)
return;
kfree(hsi->port);
kfree(hsi);
}
EXPORT_SYMBOL_GPL(hsi_free_controller);
/** /**
* hsi_free_msg - Free an HSI message * hsi_free_msg - Free an HSI message
* @msg: Pointer to the HSI message * @msg: Pointer to the HSI message
......
...@@ -270,13 +270,13 @@ struct hsi_controller { ...@@ -270,13 +270,13 @@ struct hsi_controller {
struct module *owner; struct module *owner;
unsigned int id; unsigned int id;
unsigned int num_ports; unsigned int num_ports;
struct hsi_port *port; struct hsi_port **port;
}; };
#define to_hsi_controller(dev) container_of(dev, struct hsi_controller, device) #define to_hsi_controller(dev) container_of(dev, struct hsi_controller, device)
struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags); struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags);
void hsi_free_controller(struct hsi_controller *hsi); void hsi_put_controller(struct hsi_controller *hsi);
int hsi_register_controller(struct hsi_controller *hsi); int hsi_register_controller(struct hsi_controller *hsi);
void hsi_unregister_controller(struct hsi_controller *hsi); void hsi_unregister_controller(struct hsi_controller *hsi);
...@@ -294,7 +294,7 @@ static inline void *hsi_controller_drvdata(struct hsi_controller *hsi) ...@@ -294,7 +294,7 @@ static inline void *hsi_controller_drvdata(struct hsi_controller *hsi)
static inline struct hsi_port *hsi_find_port_num(struct hsi_controller *hsi, static inline struct hsi_port *hsi_find_port_num(struct hsi_controller *hsi,
unsigned int num) unsigned int num)
{ {
return (num < hsi->num_ports) ? &hsi->port[num] : NULL; return (num < hsi->num_ports) ? hsi->port[num] : NULL;
} }
/* /*
......
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