Commit 2f8da84d authored by Thierry Reding's avatar Thierry Reding

phy: tegra: Fix regulator leak

Devices are created for each port of the XUSB pad controller. Each USB 2
and USB 3 port can potentially have an associated VBUS power supply that
needs to be removed when the device is removed.

Since port devices never bind to a driver, the driver core will not get
to perform the cleanup of device-managed resources that usually happens
on driver unbind.

Now, the driver core will also perform device-managed resource cleanup
for driver-less devices when they are released. However, when a device
link is created between the regulator and the port device, as part of
regulator_get(), the regulator takes a reference to the port device and
prevents it from being released unless regulator_put() is called, which
will never happen.

Avoid this by using the non-device-managed API and manually releasing
the regulator reference when the port is unregistered.
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 56283564
...@@ -1422,6 +1422,7 @@ tegra124_usb2_port_map(struct tegra_xusb_port *port) ...@@ -1422,6 +1422,7 @@ tegra124_usb2_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = { static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = {
.remove = tegra_xusb_usb2_port_remove,
.enable = tegra124_usb2_port_enable, .enable = tegra124_usb2_port_enable,
.disable = tegra124_usb2_port_disable, .disable = tegra124_usb2_port_disable,
.map = tegra124_usb2_port_map, .map = tegra124_usb2_port_map,
...@@ -1647,6 +1648,7 @@ tegra124_usb3_port_map(struct tegra_xusb_port *port) ...@@ -1647,6 +1648,7 @@ tegra124_usb3_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = { static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = {
.remove = tegra_xusb_usb3_port_remove,
.enable = tegra124_usb3_port_enable, .enable = tegra124_usb3_port_enable,
.disable = tegra124_usb3_port_disable, .disable = tegra124_usb3_port_disable,
.map = tegra124_usb3_port_map, .map = tegra124_usb3_port_map,
......
...@@ -615,6 +615,7 @@ tegra186_usb2_port_map(struct tegra_xusb_port *port) ...@@ -615,6 +615,7 @@ tegra186_usb2_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = { static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = {
.remove = tegra_xusb_usb2_port_remove,
.enable = tegra186_usb2_port_enable, .enable = tegra186_usb2_port_enable,
.disable = tegra186_usb2_port_disable, .disable = tegra186_usb2_port_disable,
.map = tegra186_usb2_port_map, .map = tegra186_usb2_port_map,
...@@ -674,6 +675,7 @@ tegra186_usb3_port_map(struct tegra_xusb_port *port) ...@@ -674,6 +675,7 @@ tegra186_usb3_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = { static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = {
.remove = tegra_xusb_usb3_port_remove,
.enable = tegra186_usb3_port_enable, .enable = tegra186_usb3_port_enable,
.disable = tegra186_usb3_port_disable, .disable = tegra186_usb3_port_disable,
.map = tegra186_usb3_port_map, .map = tegra186_usb3_port_map,
......
...@@ -1953,6 +1953,7 @@ tegra210_usb2_port_map(struct tegra_xusb_port *port) ...@@ -1953,6 +1953,7 @@ tegra210_usb2_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = { static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = {
.remove = tegra_xusb_usb2_port_remove,
.enable = tegra210_usb2_port_enable, .enable = tegra210_usb2_port_enable,
.disable = tegra210_usb2_port_disable, .disable = tegra210_usb2_port_disable,
.map = tegra210_usb2_port_map, .map = tegra210_usb2_port_map,
...@@ -2119,6 +2120,7 @@ tegra210_usb3_port_map(struct tegra_xusb_port *port) ...@@ -2119,6 +2120,7 @@ tegra210_usb3_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = { static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
.remove = tegra_xusb_usb3_port_remove,
.enable = tegra210_usb3_port_enable, .enable = tegra210_usb3_port_enable,
.disable = tegra210_usb3_port_disable, .disable = tegra210_usb3_port_disable,
.map = tegra210_usb3_port_map, .map = tegra210_usb3_port_map,
......
...@@ -554,6 +554,9 @@ static void tegra_xusb_port_unregister(struct tegra_xusb_port *port) ...@@ -554,6 +554,9 @@ static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
usb_remove_phy(&port->usb_phy); usb_remove_phy(&port->usb_phy);
} }
if (port->ops->remove)
port->ops->remove(port);
device_unregister(&port->dev); device_unregister(&port->dev);
} }
...@@ -734,7 +737,7 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) ...@@ -734,7 +737,7 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
} }
} }
usb2->supply = devm_regulator_get(&port->dev, "vbus"); usb2->supply = regulator_get(&port->dev, "vbus");
return PTR_ERR_OR_ZERO(usb2->supply); return PTR_ERR_OR_ZERO(usb2->supply);
} }
...@@ -784,6 +787,13 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl, ...@@ -784,6 +787,13 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
return err; return err;
} }
void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port)
{
struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
regulator_put(usb2->supply);
}
static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi) static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi)
{ {
struct tegra_xusb_port *port = &ulpi->base; struct tegra_xusb_port *port = &ulpi->base;
...@@ -912,7 +922,7 @@ static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3) ...@@ -912,7 +922,7 @@ static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
return -EINVAL; return -EINVAL;
} }
usb3->supply = devm_regulator_get(&port->dev, "vbus"); usb3->supply = regulator_get(&port->dev, "vbus");
return PTR_ERR_OR_ZERO(usb3->supply); return PTR_ERR_OR_ZERO(usb3->supply);
} }
...@@ -963,6 +973,13 @@ static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl, ...@@ -963,6 +973,13 @@ static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
return err; return err;
} }
void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port)
{
struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
regulator_put(usb3->supply);
}
static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl) static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl)
{ {
struct tegra_xusb_port *port, *tmp; struct tegra_xusb_port *port, *tmp;
......
...@@ -308,6 +308,7 @@ to_usb2_port(struct tegra_xusb_port *port) ...@@ -308,6 +308,7 @@ to_usb2_port(struct tegra_xusb_port *port)
struct tegra_xusb_usb2_port * struct tegra_xusb_usb2_port *
tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl, tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl,
unsigned int index); unsigned int index);
void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port);
struct tegra_xusb_ulpi_port { struct tegra_xusb_ulpi_port {
struct tegra_xusb_port base; struct tegra_xusb_port base;
...@@ -355,8 +356,10 @@ to_usb3_port(struct tegra_xusb_port *port) ...@@ -355,8 +356,10 @@ to_usb3_port(struct tegra_xusb_port *port)
struct tegra_xusb_usb3_port * struct tegra_xusb_usb3_port *
tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl,
unsigned int index); unsigned int index);
void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port);
struct tegra_xusb_port_ops { struct tegra_xusb_port_ops {
void (*remove)(struct tegra_xusb_port *port);
int (*enable)(struct tegra_xusb_port *port); int (*enable)(struct tegra_xusb_port *port);
void (*disable)(struct tegra_xusb_port *port); void (*disable)(struct tegra_xusb_port *port);
struct tegra_xusb_lane *(*map)(struct tegra_xusb_port *port); struct tegra_xusb_lane *(*map)(struct tegra_xusb_port *port);
......
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