usb: typec: Link all ports during connector registration

The connectors may be registered after the ports, so the
"connector" links need to be created for the ports also when
ever a new connector gets registered.

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20210407065555.88110-5-heikki.krogerus@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Heikki Krogerus 2021-04-07 09:55:55 +03:00 committed by Greg Kroah-Hartman
parent b433c4c789
commit ee64fc599b
3 changed files with 68 additions and 7 deletions

View File

@ -1601,7 +1601,6 @@ static void typec_release(struct device *dev)
ida_destroy(&port->mode_ids);
typec_switch_put(port->sw);
typec_mux_put(port->mux);
free_pld(port->pld);
kfree(port->cap);
kfree(port);
}
@ -2027,7 +2026,9 @@ struct typec_port *typec_register_port(struct device *parent,
return ERR_PTR(ret);
}
port->pld = get_pld(&port->dev);
ret = typec_link_ports(port);
if (ret)
dev_warn(&port->dev, "failed to create symlinks (%d)\n", ret);
return port;
}
@ -2041,8 +2042,10 @@ EXPORT_SYMBOL_GPL(typec_register_port);
*/
void typec_unregister_port(struct typec_port *port)
{
if (!IS_ERR_OR_NULL(port))
if (!IS_ERR_OR_NULL(port)) {
typec_unlink_ports(port);
device_unregister(&port->dev);
}
}
EXPORT_SYMBOL_GPL(typec_unregister_port);

View File

@ -79,7 +79,7 @@ extern const struct device_type typec_port_dev_type;
extern struct class typec_mux_class;
extern struct class typec_class;
void *get_pld(struct device *dev);
void free_pld(void *pld);
int typec_link_ports(struct typec_port *connector);
void typec_unlink_ports(struct typec_port *connector);
#endif /* __USB_TYPEC_CLASS__ */

View File

@ -34,7 +34,7 @@ static int acpi_pld_match(const struct acpi_pld_info *pld1,
return 0;
}
void *get_pld(struct device *dev)
static void *get_pld(struct device *dev)
{
#ifdef CONFIG_ACPI
struct acpi_pld_info *pld;
@ -53,7 +53,7 @@ void *get_pld(struct device *dev)
#endif
}
void free_pld(void *pld)
static void free_pld(void *pld)
{
#ifdef CONFIG_ACPI
ACPI_FREE(pld);
@ -217,3 +217,61 @@ void typec_unlink_port(struct device *port)
class_for_each_device(&typec_class, NULL, port, port_match_and_unlink);
}
EXPORT_SYMBOL_GPL(typec_unlink_port);
static int each_port(struct device *port, void *connector)
{
struct port_node *node;
int ret;
node = create_port_node(port);
if (IS_ERR(node))
return PTR_ERR(node);
if (!connector_match(connector, node)) {
remove_port_node(node);
return 0;
}
ret = link_port(to_typec_port(connector), node);
if (ret) {
remove_port_node(node->pld);
return ret;
}
get_device(connector);
return 0;
}
int typec_link_ports(struct typec_port *con)
{
int ret = 0;
con->pld = get_pld(&con->dev);
if (!con->pld)
return 0;
ret = usb_for_each_port(&con->dev, each_port);
if (ret)
typec_unlink_ports(con);
return ret;
}
void typec_unlink_ports(struct typec_port *con)
{
struct port_node *node;
struct port_node *tmp;
mutex_lock(&con->port_list_lock);
list_for_each_entry_safe(node, tmp, &con->port_list, list) {
__unlink_port(con, node);
remove_port_node(node);
put_device(&con->dev);
}
mutex_unlock(&con->port_list_lock);
free_pld(con->pld);
}