Commit 2ee2132f authored by Niklas Cassel's avatar Niklas Cassel Committed by David S. Miller

net: stmmac: add error handling in stmmac_mtl_setup()

The device tree binding for stmmac says:

- Multiple TX Queues parameters: below the list of all the parameters to
                                 configure the multiple TX queues:
        - snps,tx-queues-to-use: number of TX queues to be used in the driver
	[...]
        - For each TX queue
		[...]

However, if one specifies snps,tx-queues-to-use = 2,
but omits the queue subnodes, or defines just one queue subnode,
since the driver appears to initialize queues with sane default
values, we will get tx queue timeouts.

This is because the initialization code only initializes
as many queues as it finds subnodes. Potentially leaving
some queues uninitialized.

To avoid hard to debug issues, return an error if the number
of subnodes differ from snps,tx-queues-to-use/snps,rx-queues-to-use.
Signed-off-by: default avatarNiklas Cassel <niklas.cassel@axis.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 13138de0
...@@ -135,13 +135,14 @@ static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev) ...@@ -135,13 +135,14 @@ static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev)
* stmmac_mtl_setup - parse DT parameters for multiple queues configuration * stmmac_mtl_setup - parse DT parameters for multiple queues configuration
* @pdev: platform device * @pdev: platform device
*/ */
static void stmmac_mtl_setup(struct platform_device *pdev, static int stmmac_mtl_setup(struct platform_device *pdev,
struct plat_stmmacenet_data *plat) struct plat_stmmacenet_data *plat)
{ {
struct device_node *q_node; struct device_node *q_node;
struct device_node *rx_node; struct device_node *rx_node;
struct device_node *tx_node; struct device_node *tx_node;
u8 queue = 0; u8 queue = 0;
int ret = 0;
/* For backwards-compatibility with device trees that don't have any /* For backwards-compatibility with device trees that don't have any
* snps,mtl-rx-config or snps,mtl-tx-config properties, we fall back * snps,mtl-rx-config or snps,mtl-tx-config properties, we fall back
...@@ -159,12 +160,12 @@ static void stmmac_mtl_setup(struct platform_device *pdev, ...@@ -159,12 +160,12 @@ static void stmmac_mtl_setup(struct platform_device *pdev,
rx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-rx-config", 0); rx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-rx-config", 0);
if (!rx_node) if (!rx_node)
return; return ret;
tx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-tx-config", 0); tx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-tx-config", 0);
if (!tx_node) { if (!tx_node) {
of_node_put(rx_node); of_node_put(rx_node);
return; return ret;
} }
/* Processing RX queues common config */ /* Processing RX queues common config */
...@@ -220,6 +221,11 @@ static void stmmac_mtl_setup(struct platform_device *pdev, ...@@ -220,6 +221,11 @@ static void stmmac_mtl_setup(struct platform_device *pdev,
queue++; queue++;
} }
if (queue != plat->rx_queues_to_use) {
ret = -EINVAL;
dev_err(&pdev->dev, "Not all RX queues were configured\n");
goto out;
}
/* Processing TX queues common config */ /* Processing TX queues common config */
if (of_property_read_u32(tx_node, "snps,tx-queues-to-use", if (of_property_read_u32(tx_node, "snps,tx-queues-to-use",
...@@ -281,10 +287,18 @@ static void stmmac_mtl_setup(struct platform_device *pdev, ...@@ -281,10 +287,18 @@ static void stmmac_mtl_setup(struct platform_device *pdev,
queue++; queue++;
} }
if (queue != plat->tx_queues_to_use) {
ret = -EINVAL;
dev_err(&pdev->dev, "Not all TX queues were configured\n");
goto out;
}
out:
of_node_put(rx_node); of_node_put(rx_node);
of_node_put(tx_node); of_node_put(tx_node);
of_node_put(q_node); of_node_put(q_node);
return ret;
} }
/** /**
...@@ -376,6 +390,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) ...@@ -376,6 +390,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct plat_stmmacenet_data *plat; struct plat_stmmacenet_data *plat;
struct stmmac_dma_cfg *dma_cfg; struct stmmac_dma_cfg *dma_cfg;
int rc;
plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
if (!plat) if (!plat)
...@@ -499,7 +514,11 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) ...@@ -499,7 +514,11 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
plat->axi = stmmac_axi_setup(pdev); plat->axi = stmmac_axi_setup(pdev);
stmmac_mtl_setup(pdev, plat); rc = stmmac_mtl_setup(pdev, plat);
if (rc) {
stmmac_remove_config_dt(pdev, plat);
return ERR_PTR(rc);
}
/* clock setup */ /* clock setup */
plat->stmmac_clk = devm_clk_get(&pdev->dev, plat->stmmac_clk = devm_clk_get(&pdev->dev,
......
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