Commit c1700479 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

greybus: hd: fix host-device life time issues

Fix host-device life time issues by separating host-device allocation
from registration.

This is needed both to make sure that all host-device resources are
available before registering the device and to prevent such resources
from being deallocated while the device is still in use during device
removal.

This specifically fixes the following warnings during es1 and es2
disconnect:

usb 1-1.1: No free CPort OUT urbs, having to dynamically allocate one!
Signed-off-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent b4bd3617
...@@ -390,7 +390,7 @@ static void es1_destroy(struct es1_ap_dev *es1) ...@@ -390,7 +390,7 @@ static void es1_destroy(struct es1_ap_dev *es1)
} }
udev = es1->usb_dev; udev = es1->usb_dev;
gb_hd_remove(es1->hd); gb_hd_put(es1->hd);
usb_put_dev(udev); usb_put_dev(udev);
} }
...@@ -403,6 +403,8 @@ static void ap_disconnect(struct usb_interface *interface) ...@@ -403,6 +403,8 @@ static void ap_disconnect(struct usb_interface *interface)
for (i = 0; i < NUM_CPORT_IN_URB; ++i) for (i = 0; i < NUM_CPORT_IN_URB; ++i)
usb_kill_urb(es1->cport_in_urb[i]); usb_kill_urb(es1->cport_in_urb[i]);
gb_hd_del(es1->hd);
es1_destroy(es1); es1_destroy(es1);
} }
...@@ -692,6 +694,10 @@ static int ap_probe(struct usb_interface *interface, ...@@ -692,6 +694,10 @@ static int ap_probe(struct usb_interface *interface,
gb_debugfs_get(), es1, gb_debugfs_get(), es1,
&apb1_log_enable_fops); &apb1_log_enable_fops);
retval = gb_hd_add(hd);
if (retval)
goto error;
for (i = 0; i < NUM_CPORT_IN_URB; ++i) { for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
retval = usb_submit_urb(es1->cport_in_urb[i], GFP_KERNEL); retval = usb_submit_urb(es1->cport_in_urb[i], GFP_KERNEL);
if (retval) if (retval)
...@@ -703,6 +709,7 @@ static int ap_probe(struct usb_interface *interface, ...@@ -703,6 +709,7 @@ static int ap_probe(struct usb_interface *interface,
err_kill_in_urbs: err_kill_in_urbs:
for (--i; i >= 0; --i) for (--i; i >= 0; --i)
usb_kill_urb(es1->cport_in_urb[i]); usb_kill_urb(es1->cport_in_urb[i]);
gb_hd_del(hd);
error: error:
es1_destroy(es1); es1_destroy(es1);
......
...@@ -585,7 +585,7 @@ static void es2_destroy(struct es2_ap_dev *es2) ...@@ -585,7 +585,7 @@ static void es2_destroy(struct es2_ap_dev *es2)
udev = es2->usb_dev; udev = es2->usb_dev;
cport_to_ep = es2->cport_to_ep; cport_to_ep = es2->cport_to_ep;
gb_hd_remove(es2->hd); gb_hd_put(es2->hd);
kfree(cport_to_ep); kfree(cport_to_ep);
usb_put_dev(udev); usb_put_dev(udev);
...@@ -599,6 +599,8 @@ static void ap_disconnect(struct usb_interface *interface) ...@@ -599,6 +599,8 @@ static void ap_disconnect(struct usb_interface *interface)
for (i = 0; i < NUM_BULKS; ++i) for (i = 0; i < NUM_BULKS; ++i)
es2_cport_in_disable(es2, &es2->cport_in[i]); es2_cport_in_disable(es2, &es2->cport_in[i]);
gb_hd_del(es2->hd);
es2_destroy(es2); es2_destroy(es2);
} }
...@@ -942,6 +944,10 @@ static int ap_probe(struct usb_interface *interface, ...@@ -942,6 +944,10 @@ static int ap_probe(struct usb_interface *interface,
gb_debugfs_get(), es2, gb_debugfs_get(), es2,
&apb_log_enable_fops); &apb_log_enable_fops);
retval = gb_hd_add(hd);
if (retval)
goto error;
for (i = 0; i < NUM_BULKS; ++i) { for (i = 0; i < NUM_BULKS; ++i) {
retval = es2_cport_in_enable(es2, &es2->cport_in[i]); retval = es2_cport_in_enable(es2, &es2->cport_in[i]);
if (retval) if (retval)
...@@ -953,6 +959,7 @@ static int ap_probe(struct usb_interface *interface, ...@@ -953,6 +959,7 @@ static int ap_probe(struct usb_interface *interface,
err_disable_cport_in: err_disable_cport_in:
for (--i; i >= 0; --i) for (--i; i >= 0; --i)
es2_cport_in_disable(es2, &es2->cport_in[i]); es2_cport_in_disable(es2, &es2->cport_in[i]);
gb_hd_del(hd);
error: error:
es2_destroy(es2); es2_destroy(es2);
......
...@@ -77,6 +77,12 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver, ...@@ -77,6 +77,12 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
hd->buffer_size_max = buffer_size_max; hd->buffer_size_max = buffer_size_max;
hd->num_cports = num_cports; hd->num_cports = num_cports;
return hd;
}
EXPORT_SYMBOL_GPL(gb_hd_create);
int gb_hd_add(struct gb_host_device *hd)
{
/* /*
* Initialize AP's SVC protocol connection: * Initialize AP's SVC protocol connection:
* *
...@@ -87,16 +93,14 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver, ...@@ -87,16 +93,14 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
* time we will create a fully initialized svc-connection, as we need * time we will create a fully initialized svc-connection, as we need
* endo-id and AP's interface id for that. * endo-id and AP's interface id for that.
*/ */
if (!gb_ap_svc_connection_create(hd)) { if (!gb_ap_svc_connection_create(hd))
kref_put_mutex(&hd->kref, free_hd, &hd_mutex); return -ENOMEM;
return ERR_PTR(-ENOMEM);
}
return hd; return 0;
} }
EXPORT_SYMBOL_GPL(gb_hd_create); EXPORT_SYMBOL_GPL(gb_hd_add);
void gb_hd_remove(struct gb_host_device *hd) void gb_hd_del(struct gb_host_device *hd)
{ {
/* /*
* Tear down all interfaces, modules, and the endo that is associated * Tear down all interfaces, modules, and the endo that is associated
...@@ -109,7 +113,11 @@ void gb_hd_remove(struct gb_host_device *hd) ...@@ -109,7 +113,11 @@ void gb_hd_remove(struct gb_host_device *hd)
/* Is the SVC still using the partially uninitialized connection ? */ /* Is the SVC still using the partially uninitialized connection ? */
if (hd->initial_svc_connection) if (hd->initial_svc_connection)
gb_connection_destroy(hd->initial_svc_connection); gb_connection_destroy(hd->initial_svc_connection);
}
EXPORT_SYMBOL_GPL(gb_hd_del);
void gb_hd_put(struct gb_host_device *hd)
{
kref_put_mutex(&hd->kref, free_hd, &hd_mutex); kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
} }
EXPORT_SYMBOL_GPL(gb_hd_remove); EXPORT_SYMBOL_GPL(gb_hd_put);
...@@ -52,6 +52,8 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver, ...@@ -52,6 +52,8 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
struct device *parent, struct device *parent,
size_t buffer_size_max, size_t buffer_size_max,
size_t num_cports); size_t num_cports);
void gb_hd_remove(struct gb_host_device *hd); int gb_hd_add(struct gb_host_device *hd);
void gb_hd_del(struct gb_host_device *hd);
void gb_hd_put(struct gb_host_device *hd);
#endif /* __HD_H */ #endif /* __HD_H */
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