mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 03:40:52 +07:00
phy: tegra: Don't use device-managed API to allocate ports
The device-managed allocation API doesn't work well with the life-cycle of device objects. Since ports have device objects allocated within, it can lead to situations where these devices need to stay around until after their parent pad controller has been unbound from its driver. The device-managed memory allocated for the port objects will, however, get freed when the pad controller unbinds from the driver. This can cause use-after-free errors down the road. Note that the device is deleted as part of the driver unbind operation, so there isn't much that can be done with it after that point, but the memory still needs to stay around to ensure none of the references are invalidated. One situation where this arises is when a VBUS supply is associated with a USB 2 or 3 port. When that supply is released using regulator_put() an SRCU call will queue the release of the device link connecting the port and the regulator after a grace period. This means that the regulator is going to keep on to the last reference of the port device even after the pad controller driver was unbound (which is when the memory backing the port device is freed). Fix this by allocating port objects using non-device-managed memory. Add release callbacks for these objects so that their memory gets freed when the last reference goes away. This decouples the port devices' lifetime from the "active" lifetime of the pad controller (i.e. the time during which the pad controller driver owns the device). Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
parent
2f8da84def
commit
e78fdbad1e
@ -1422,6 +1422,7 @@ tegra124_usb2_port_map(struct tegra_xusb_port *port)
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = {
|
||||
.release = tegra_xusb_usb2_port_release,
|
||||
.remove = tegra_xusb_usb2_port_remove,
|
||||
.enable = tegra124_usb2_port_enable,
|
||||
.disable = tegra124_usb2_port_disable,
|
||||
@ -1444,6 +1445,7 @@ tegra124_ulpi_port_map(struct tegra_xusb_port *port)
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra124_ulpi_port_ops = {
|
||||
.release = tegra_xusb_ulpi_port_release,
|
||||
.enable = tegra124_ulpi_port_enable,
|
||||
.disable = tegra124_ulpi_port_disable,
|
||||
.map = tegra124_ulpi_port_map,
|
||||
@ -1465,6 +1467,7 @@ tegra124_hsic_port_map(struct tegra_xusb_port *port)
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra124_hsic_port_ops = {
|
||||
.release = tegra_xusb_hsic_port_release,
|
||||
.enable = tegra124_hsic_port_enable,
|
||||
.disable = tegra124_hsic_port_disable,
|
||||
.map = tegra124_hsic_port_map,
|
||||
@ -1648,6 +1651,7 @@ tegra124_usb3_port_map(struct tegra_xusb_port *port)
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = {
|
||||
.release = tegra_xusb_usb3_port_release,
|
||||
.remove = tegra_xusb_usb3_port_remove,
|
||||
.enable = tegra124_usb3_port_enable,
|
||||
.disable = tegra124_usb3_port_disable,
|
||||
|
@ -615,6 +615,7 @@ tegra186_usb2_port_map(struct tegra_xusb_port *port)
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = {
|
||||
.release = tegra_xusb_usb2_port_release,
|
||||
.remove = tegra_xusb_usb2_port_remove,
|
||||
.enable = tegra186_usb2_port_enable,
|
||||
.disable = tegra186_usb2_port_disable,
|
||||
@ -675,6 +676,7 @@ tegra186_usb3_port_map(struct tegra_xusb_port *port)
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = {
|
||||
.release = tegra_xusb_usb3_port_release,
|
||||
.remove = tegra_xusb_usb3_port_remove,
|
||||
.enable = tegra186_usb3_port_enable,
|
||||
.disable = tegra186_usb3_port_disable,
|
||||
|
@ -1953,6 +1953,7 @@ tegra210_usb2_port_map(struct tegra_xusb_port *port)
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = {
|
||||
.release = tegra_xusb_usb2_port_release,
|
||||
.remove = tegra_xusb_usb2_port_remove,
|
||||
.enable = tegra210_usb2_port_enable,
|
||||
.disable = tegra210_usb2_port_disable,
|
||||
@ -1975,6 +1976,7 @@ tegra210_hsic_port_map(struct tegra_xusb_port *port)
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
|
||||
.release = tegra_xusb_hsic_port_release,
|
||||
.enable = tegra210_hsic_port_enable,
|
||||
.disable = tegra210_hsic_port_disable,
|
||||
.map = tegra210_hsic_port_map,
|
||||
@ -2120,6 +2122,7 @@ tegra210_usb3_port_map(struct tegra_xusb_port *port)
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
|
||||
.release = tegra_xusb_usb3_port_release,
|
||||
.remove = tegra_xusb_usb3_port_remove,
|
||||
.enable = tegra210_usb3_port_enable,
|
||||
.disable = tegra210_usb3_port_disable,
|
||||
|
@ -507,6 +507,10 @@ tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, unsigned int index)
|
||||
|
||||
static void tegra_xusb_port_release(struct device *dev)
|
||||
{
|
||||
struct tegra_xusb_port *port = to_tegra_xusb_port(dev);
|
||||
|
||||
if (port->ops->release)
|
||||
port->ops->release(port);
|
||||
}
|
||||
|
||||
static struct device_type tegra_xusb_port_type = {
|
||||
@ -756,7 +760,7 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
|
||||
if (!np || !of_device_is_available(np))
|
||||
goto out;
|
||||
|
||||
usb2 = devm_kzalloc(padctl->dev, sizeof(*usb2), GFP_KERNEL);
|
||||
usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
|
||||
if (!usb2) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
@ -787,6 +791,13 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
|
||||
return err;
|
||||
}
|
||||
|
||||
void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port)
|
||||
{
|
||||
struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
|
||||
|
||||
kfree(usb2);
|
||||
}
|
||||
|
||||
void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port)
|
||||
{
|
||||
struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
|
||||
@ -815,7 +826,7 @@ static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl,
|
||||
if (!np || !of_device_is_available(np))
|
||||
goto out;
|
||||
|
||||
ulpi = devm_kzalloc(padctl->dev, sizeof(*ulpi), GFP_KERNEL);
|
||||
ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
|
||||
if (!ulpi) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
@ -846,6 +857,13 @@ static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl,
|
||||
return err;
|
||||
}
|
||||
|
||||
void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port)
|
||||
{
|
||||
struct tegra_xusb_ulpi_port *ulpi = to_ulpi_port(port);
|
||||
|
||||
kfree(ulpi);
|
||||
}
|
||||
|
||||
static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic)
|
||||
{
|
||||
/* XXX */
|
||||
@ -863,7 +881,7 @@ static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl,
|
||||
if (!np || !of_device_is_available(np))
|
||||
goto out;
|
||||
|
||||
hsic = devm_kzalloc(padctl->dev, sizeof(*hsic), GFP_KERNEL);
|
||||
hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
|
||||
if (!hsic) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
@ -894,6 +912,13 @@ static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl,
|
||||
return err;
|
||||
}
|
||||
|
||||
void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port)
|
||||
{
|
||||
struct tegra_xusb_hsic_port *hsic = to_hsic_port(port);
|
||||
|
||||
kfree(hsic);
|
||||
}
|
||||
|
||||
static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
|
||||
{
|
||||
struct tegra_xusb_port *port = &usb3->base;
|
||||
@ -942,7 +967,7 @@ static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
|
||||
if (!np || !of_device_is_available(np))
|
||||
goto out;
|
||||
|
||||
usb3 = devm_kzalloc(padctl->dev, sizeof(*usb3), GFP_KERNEL);
|
||||
usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL);
|
||||
if (!usb3) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
@ -973,6 +998,13 @@ static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
|
||||
return err;
|
||||
}
|
||||
|
||||
void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port)
|
||||
{
|
||||
struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
|
||||
|
||||
kfree(usb3);
|
||||
}
|
||||
|
||||
void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port)
|
||||
{
|
||||
struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
|
||||
|
@ -274,6 +274,11 @@ struct tegra_xusb_port {
|
||||
const struct tegra_xusb_port_ops *ops;
|
||||
};
|
||||
|
||||
static inline struct tegra_xusb_port *to_tegra_xusb_port(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct tegra_xusb_port, dev);
|
||||
}
|
||||
|
||||
struct tegra_xusb_lane_map {
|
||||
unsigned int port;
|
||||
const char *type;
|
||||
@ -308,6 +313,7 @@ to_usb2_port(struct tegra_xusb_port *port)
|
||||
struct tegra_xusb_usb2_port *
|
||||
tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl,
|
||||
unsigned int index);
|
||||
void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port);
|
||||
void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port);
|
||||
|
||||
struct tegra_xusb_ulpi_port {
|
||||
@ -323,6 +329,8 @@ to_ulpi_port(struct tegra_xusb_port *port)
|
||||
return container_of(port, struct tegra_xusb_ulpi_port, base);
|
||||
}
|
||||
|
||||
void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port);
|
||||
|
||||
struct tegra_xusb_hsic_port {
|
||||
struct tegra_xusb_port base;
|
||||
};
|
||||
@ -333,6 +341,8 @@ to_hsic_port(struct tegra_xusb_port *port)
|
||||
return container_of(port, struct tegra_xusb_hsic_port, base);
|
||||
}
|
||||
|
||||
void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port);
|
||||
|
||||
struct tegra_xusb_usb3_port {
|
||||
struct tegra_xusb_port base;
|
||||
struct regulator *supply;
|
||||
@ -356,9 +366,11 @@ to_usb3_port(struct tegra_xusb_port *port)
|
||||
struct tegra_xusb_usb3_port *
|
||||
tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl,
|
||||
unsigned int index);
|
||||
void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port);
|
||||
void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port);
|
||||
|
||||
struct tegra_xusb_port_ops {
|
||||
void (*release)(struct tegra_xusb_port *port);
|
||||
void (*remove)(struct tegra_xusb_port *port);
|
||||
int (*enable)(struct tegra_xusb_port *port);
|
||||
void (*disable)(struct tegra_xusb_port *port);
|
||||
|
Loading…
Reference in New Issue
Block a user