Commit 04604673 authored by Johan Hovold's avatar Johan Hovold Committed by Kishon Vijay Abraham I
Browse files

phy: tegra: fix device-tree node lookups



Fix child-node lookups during probe, which ended up searching the whole
device tree depth-first starting at the parents rather than just
matching on their children.

To make things worse, some parent nodes could end up being being
prematurely freed (by tegra_xusb_pad_register()) as
of_find_node_by_name() drops a reference to its first argument.

Fixes: 53d2a715 ("phy: Add Tegra XUSB pad controller support")
Cc: stable <stable@vger.kernel.org>     # 4.7
Cc: Thierry Reding <treding@nvidia.com>
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent 4fbd8d19
Loading
Loading
Loading
Loading
+29 −29
Original line number Diff line number Diff line
@@ -75,14 +75,14 @@ MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match);
static struct device_node *
tegra_xusb_find_pad_node(struct tegra_xusb_padctl *padctl, const char *name)
{
	/*
	 * of_find_node_by_name() drops a reference, so make sure to grab one.
	 */
	struct device_node *np = of_node_get(padctl->dev->of_node);
	struct device_node *pads, *np;

	np = of_find_node_by_name(np, "pads");
	if (np)
		np = of_find_node_by_name(np, name);
	pads = of_get_child_by_name(padctl->dev->of_node, "pads");
	if (!pads)
		return NULL;

	np = of_get_child_by_name(pads, name);
	of_node_put(pads);

	return np;
}
@@ -90,16 +90,16 @@ tegra_xusb_find_pad_node(struct tegra_xusb_padctl *padctl, const char *name)
static struct device_node *
tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad *pad, unsigned int index)
{
	/*
	 * of_find_node_by_name() drops a reference, so make sure to grab one.
	 */
	struct device_node *np = of_node_get(pad->dev.of_node);
	struct device_node *np, *lanes;

	np = of_find_node_by_name(np, "lanes");
	if (!np)
	lanes = of_get_child_by_name(pad->dev.of_node, "lanes");
	if (!lanes)
		return NULL;

	return of_find_node_by_name(np, pad->soc->lanes[index].name);
	np = of_get_child_by_name(lanes, pad->soc->lanes[index].name);
	of_node_put(lanes);

	return np;
}

static int
@@ -195,7 +195,7 @@ int tegra_xusb_pad_register(struct tegra_xusb_pad *pad,
	unsigned int i;
	int err;

	children = of_find_node_by_name(pad->dev.of_node, "lanes");
	children = of_get_child_by_name(pad->dev.of_node, "lanes");
	if (!children)
		return -ENODEV;

@@ -444,21 +444,21 @@ static struct device_node *
tegra_xusb_find_port_node(struct tegra_xusb_padctl *padctl, const char *type,
			  unsigned int index)
{
	/*
	 * of_find_node_by_name() drops a reference, so make sure to grab one.
	 */
	struct device_node *np = of_node_get(padctl->dev->of_node);

	np = of_find_node_by_name(np, "ports");
	if (np) {
	struct device_node *ports, *np;
	char *name;

	ports = of_get_child_by_name(padctl->dev->of_node, "ports");
	if (!ports)
		return NULL;

	name = kasprintf(GFP_KERNEL, "%s-%u", type, index);
		if (!name)
	if (!name) {
		of_node_put(ports);
		return ERR_PTR(-ENOMEM);
		np = of_find_node_by_name(np, name);
		kfree(name);
	}
	np = of_get_child_by_name(ports, name);
	kfree(name);
	of_node_put(ports);

	return np;
}
@@ -847,7 +847,7 @@ static void tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl)

static int tegra_xusb_padctl_probe(struct platform_device *pdev)
{
	struct device_node *np = of_node_get(pdev->dev.of_node);
	struct device_node *np = pdev->dev.of_node;
	const struct tegra_xusb_padctl_soc *soc;
	struct tegra_xusb_padctl *padctl;
	const struct of_device_id *match;
@@ -855,7 +855,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
	int err;

	/* for backwards compatibility with old device trees */
	np = of_find_node_by_name(np, "pads");
	np = of_get_child_by_name(np, "pads");
	if (!np) {
		dev_warn(&pdev->dev, "deprecated DT, using legacy driver\n");
		return tegra_xusb_padctl_legacy_probe(pdev);