2019-05-29 07:18:05 -07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2011-12-21 03:58:19 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
This contains the functions to handle the platform driver.
|
|
|
|
|
|
|
|
Copyright (C) 2007-2011 STMicroelectronics Ltd
|
|
|
|
|
|
|
|
|
|
|
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
|
|
|
*******************************************************************************/
|
|
|
|
|
2023-06-23 12:04:14 +02:00
|
|
|
#include <linux/device.h>
|
2011-12-21 03:58:19 +00:00
|
|
|
#include <linux/platform_device.h>
|
net: stmmac: fix system hang caused by eee_ctrl_timer during suspend/resume
commit 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after
napi disabled"), this patch tries to fix system hang caused by eee_ctrl_timer,
unfortunately, it only can resolve it for system reboot stress test. System
hang also can be reproduced easily during system suspend/resume stess test
when mount NFS on i.MX8MP EVK board.
In stmmac driver, eee feature is combined to phylink framework. When do
system suspend, phylink_stop() would queue delayed work, it invokes
stmmac_mac_link_down(), where to deactivate eee_ctrl_timer synchronizly.
In above commit, try to fix issue by deactivating eee_ctrl_timer obviously,
but it is not enough. Looking into eee_ctrl_timer expire callback
stmmac_eee_ctrl_timer(), it could enable hareware eee mode again. What is
unexpected is that LPI interrupt (MAC_Interrupt_Enable.LPIEN bit) is always
asserted. This interrupt has chance to be issued when LPI state entry/exit
from the MAC, and at that time, clock could have been already disabled.
The result is that system hang when driver try to touch register from
interrupt handler.
The reason why above commit can fix system hang issue in stmmac_release()
is that, deactivate eee_ctrl_timer not just after napi disabled, further
after irq freed.
In conclusion, hardware would generate LPI interrupt when clock has been
disabled during suspend or resume, since hardware is in eee mode and LPI
interrupt enabled.
Interrupts from MAC, MTL and DMA level are enabled and never been disabled
when system suspend, so postpone clocks management from suspend stage to
noirq suspend stage should be more safe.
Fixes: 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after napi disabled")
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-09-08 15:43:35 +08:00
|
|
|
#include <linux/pm_runtime.h>
|
2015-04-30 21:47:42 -04:00
|
|
|
#include <linux/module.h>
|
2011-12-21 03:58:19 +00:00
|
|
|
#include <linux/io.h>
|
2012-03-13 04:56:37 +00:00
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/of_net.h>
|
2015-05-27 11:02:47 -07:00
|
|
|
#include <linux/of_mdio.h>
|
2014-11-07 16:46:42 +02:00
|
|
|
|
2011-12-21 03:58:19 +00:00
|
|
|
#include "stmmac.h"
|
2014-11-07 16:46:42 +02:00
|
|
|
#include "stmmac_platform.h"
|
2011-12-21 03:58:19 +00:00
|
|
|
|
2012-03-13 04:56:37 +00:00
|
|
|
#ifdef CONFIG_OF
|
2014-07-31 15:49:17 -05:00
|
|
|
|
2014-11-18 09:47:01 +01:00
|
|
|
/**
|
|
|
|
* dwmac1000_validate_mcast_bins - validates the number of Multicast filter bins
|
2019-09-05 16:00:53 +03:00
|
|
|
* @dev: struct device of the platform device
|
2014-11-18 09:47:01 +01:00
|
|
|
* @mcast_bins: Multicast filtering bins
|
|
|
|
* Description:
|
|
|
|
* this function validates the number of Multicast filtering bins specified
|
2014-07-31 15:49:17 -05:00
|
|
|
* by the configuration through the device tree. The Synopsys GMAC supports
|
|
|
|
* 64 bins, 128 bins, or 256 bins. "bins" refer to the division of CRC
|
|
|
|
* number space. 64 bins correspond to 6 bits of the CRC, 128 corresponds
|
|
|
|
* to 7 bits, and 256 refers to 8 bits of the CRC. Any other setting is
|
|
|
|
* invalid and will cause the filtering algorithm to use Multicast
|
|
|
|
* promiscuous mode.
|
|
|
|
*/
|
2019-09-05 16:00:53 +03:00
|
|
|
static int dwmac1000_validate_mcast_bins(struct device *dev, int mcast_bins)
|
2014-07-31 15:49:17 -05:00
|
|
|
{
|
|
|
|
int x = mcast_bins;
|
|
|
|
|
|
|
|
switch (x) {
|
|
|
|
case HASH_TABLE_SIZE:
|
|
|
|
case 128:
|
|
|
|
case 256:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
x = 0;
|
2019-09-05 16:00:53 +03:00
|
|
|
dev_info(dev, "Hash table entries set to unexpected value %d\n",
|
|
|
|
mcast_bins);
|
2014-07-31 15:49:17 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2014-11-18 09:47:01 +01:00
|
|
|
/**
|
|
|
|
* dwmac1000_validate_ucast_entries - validate the Unicast address entries
|
2019-09-05 16:00:53 +03:00
|
|
|
* @dev: struct device of the platform device
|
2014-11-18 09:47:01 +01:00
|
|
|
* @ucast_entries: number of Unicast address entries
|
|
|
|
* Description:
|
|
|
|
* This function validates the number of Unicast address entries supported
|
2014-07-31 15:49:17 -05:00
|
|
|
* by a particular Synopsys 10/100/1000 controller. The Synopsys controller
|
2018-09-13 18:32:21 +09:00
|
|
|
* supports 1..32, 64, or 128 Unicast filter entries for it's Unicast filter
|
2014-07-31 15:49:17 -05:00
|
|
|
* logic. This function validates a valid, supported configuration is
|
|
|
|
* selected, and defaults to 1 Unicast address if an unsupported
|
|
|
|
* configuration is selected.
|
|
|
|
*/
|
2019-09-05 16:00:53 +03:00
|
|
|
static int dwmac1000_validate_ucast_entries(struct device *dev,
|
|
|
|
int ucast_entries)
|
2014-07-31 15:49:17 -05:00
|
|
|
{
|
|
|
|
int x = ucast_entries;
|
|
|
|
|
|
|
|
switch (x) {
|
2018-09-13 18:32:21 +09:00
|
|
|
case 1 ... 32:
|
2014-07-31 15:49:17 -05:00
|
|
|
case 64:
|
|
|
|
case 128:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
x = 1;
|
2019-09-05 16:00:53 +03:00
|
|
|
dev_info(dev, "Unicast table entries set to unexpected value %d\n",
|
|
|
|
ucast_entries);
|
2014-07-31 15:49:17 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2016-02-29 14:27:28 +01:00
|
|
|
/**
|
|
|
|
* stmmac_axi_setup - parse DT parameters for programming the AXI register
|
|
|
|
* @pdev: platform device
|
|
|
|
* Description:
|
|
|
|
* if required, from device-tree the AXI internal register can be tuned
|
|
|
|
* by using platform parameters.
|
|
|
|
*/
|
|
|
|
static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
struct stmmac_axi *axi;
|
|
|
|
|
|
|
|
np = of_parse_phandle(pdev->dev.of_node, "snps,axi-config", 0);
|
|
|
|
if (!np)
|
|
|
|
return NULL;
|
|
|
|
|
2017-03-07 15:27:36 +00:00
|
|
|
axi = devm_kzalloc(&pdev->dev, sizeof(*axi), GFP_KERNEL);
|
2016-08-01 15:02:42 +08:00
|
|
|
if (!axi) {
|
|
|
|
of_node_put(np);
|
2016-02-29 14:27:28 +01:00
|
|
|
return ERR_PTR(-ENOMEM);
|
2016-08-01 15:02:42 +08:00
|
|
|
}
|
2016-02-29 14:27:28 +01:00
|
|
|
|
|
|
|
axi->axi_lpi_en = of_property_read_bool(np, "snps,lpi_en");
|
|
|
|
axi->axi_xit_frm = of_property_read_bool(np, "snps,xit_frm");
|
2022-12-03 00:17:39 +08:00
|
|
|
axi->axi_kbbe = of_property_read_bool(np, "snps,kbbe");
|
|
|
|
axi->axi_fb = of_property_read_bool(np, "snps,fb");
|
|
|
|
axi->axi_mb = of_property_read_bool(np, "snps,mb");
|
|
|
|
axi->axi_rb = of_property_read_bool(np, "snps,rb");
|
2016-02-29 14:27:28 +01:00
|
|
|
|
2016-12-05 18:12:54 +01:00
|
|
|
if (of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt))
|
|
|
|
axi->axi_wr_osr_lmt = 1;
|
|
|
|
if (of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt))
|
|
|
|
axi->axi_rd_osr_lmt = 1;
|
2016-02-29 14:27:28 +01:00
|
|
|
of_property_read_u32_array(np, "snps,blen", axi->axi_blen, AXI_BLEN);
|
2016-08-01 15:02:42 +08:00
|
|
|
of_node_put(np);
|
2016-02-29 14:27:28 +01:00
|
|
|
|
|
|
|
return axi;
|
|
|
|
}
|
|
|
|
|
2017-03-10 18:24:51 +00:00
|
|
|
/**
|
|
|
|
* stmmac_mtl_setup - parse DT parameters for multiple queues configuration
|
|
|
|
* @pdev: platform device
|
drivers/net/ethernet: clean up mis-targeted comments
As part of the W=1 cleanups for ethernet, a million [*] driver
comments had to be cleaned up to get the W=1 compilation to
succeed. This change finally makes the drivers/net/ethernet tree
compile with W=1 set on the command line. NOTE: The kernel uses
kdoc style (see Documentation/process/kernel-doc.rst) when
documenting code, not doxygen or other styles.
After this patch the x86_64 build has no warnings from W=1, however
scripts/kernel-doc says there are 1545 more warnings in source files, that
I need to develop a script to fix in a followup patch.
The errors fixed here are all kdoc of a few classes, with a few outliers:
In file included from drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c:10:
drivers/net/ethernet/qlogic/netxen/netxen_nic.h:1193:18: warning: ‘FW_DUMP_LEVELS’ defined but not used [-Wunused-const-variable=]
1193 | static const u32 FW_DUMP_LEVELS[] = { 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
| ^~~~~~~~~~~~~~
... repeats 4 times...
drivers/net/ethernet/sun/cassini.c:2084:24: warning: suggest braces around empty body in an ‘else’ statement [-Wempty-body]
2084 | RX_USED_ADD(page, i);
drivers/net/ethernet/natsemi/ns83820.c: In function ‘phy_intr’:
drivers/net/ethernet/natsemi/ns83820.c:603:6: warning: variable ‘tbisr’ set but not used [-Wunused-but-set-variable]
603 | u32 tbisr, tanar, tanlpar;
| ^~~~~
drivers/net/ethernet/natsemi/ns83820.c: In function ‘ns83820_get_link_ksettings’:
drivers/net/ethernet/natsemi/ns83820.c:1207:11: warning: variable ‘tanar’ set but not used [-Wunused-but-set-variable]
1207 | u32 cfg, tanar, tbicr;
| ^~~~~
drivers/net/ethernet/packetengines/yellowfin.c:1063:18: warning: variable ‘yf_size’ set but not used [-Wunused-but-set-variable]
1063 | int data_size, yf_size;
| ^~~~~~~
Normal kdoc fixes:
warning: Function parameter or member 'x' not described in 'y'
warning: Excess function parameter 'x' description in 'y'
warning: Cannot understand <string> on line <NNN> - I thought it was a doc line
[*] - ok it wasn't quite a million, but it felt like it.
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-25 15:24:45 -07:00
|
|
|
* @plat: enet data
|
2017-03-10 18:24:51 +00:00
|
|
|
*/
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
static int stmmac_mtl_setup(struct platform_device *pdev,
|
|
|
|
struct plat_stmmacenet_data *plat)
|
2017-03-10 18:24:51 +00:00
|
|
|
{
|
|
|
|
struct device_node *q_node;
|
|
|
|
struct device_node *rx_node;
|
|
|
|
struct device_node *tx_node;
|
|
|
|
u8 queue = 0;
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
int ret = 0;
|
2017-03-10 18:24:51 +00:00
|
|
|
|
2017-03-21 16:12:10 +01:00
|
|
|
/* For backwards-compatibility with device trees that don't have any
|
|
|
|
* snps,mtl-rx-config or snps,mtl-tx-config properties, we fall back
|
|
|
|
* to one RX and TX queues each.
|
|
|
|
*/
|
|
|
|
plat->rx_queues_to_use = 1;
|
|
|
|
plat->tx_queues_to_use = 1;
|
|
|
|
|
2017-10-26 10:07:12 +01:00
|
|
|
/* First Queue must always be in DCB mode. As MTL_QUEUE_DCB = 1 we need
|
|
|
|
* to always set this, otherwise Queue will be classified as AVB
|
|
|
|
* (because MTL_QUEUE_AVB = 0).
|
|
|
|
*/
|
|
|
|
plat->rx_queues_cfg[0].mode_to_use = MTL_QUEUE_DCB;
|
|
|
|
plat->tx_queues_cfg[0].mode_to_use = MTL_QUEUE_DCB;
|
|
|
|
|
2017-03-10 18:24:51 +00:00
|
|
|
rx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-rx-config", 0);
|
|
|
|
if (!rx_node)
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
return ret;
|
2017-03-10 18:24:51 +00:00
|
|
|
|
|
|
|
tx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-tx-config", 0);
|
|
|
|
if (!tx_node) {
|
|
|
|
of_node_put(rx_node);
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
return ret;
|
2017-03-10 18:24:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Processing RX queues common config */
|
2017-11-02 12:52:13 +05:30
|
|
|
if (of_property_read_u32(rx_node, "snps,rx-queues-to-use",
|
|
|
|
&plat->rx_queues_to_use))
|
2017-03-10 18:24:51 +00:00
|
|
|
plat->rx_queues_to_use = 1;
|
|
|
|
|
|
|
|
if (of_property_read_bool(rx_node, "snps,rx-sched-sp"))
|
|
|
|
plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
|
|
|
|
else if (of_property_read_bool(rx_node, "snps,rx-sched-wsp"))
|
|
|
|
plat->rx_sched_algorithm = MTL_RX_ALGORITHM_WSP;
|
|
|
|
else
|
|
|
|
plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
|
|
|
|
|
|
|
|
/* Processing individual RX queue config */
|
|
|
|
for_each_child_of_node(rx_node, q_node) {
|
|
|
|
if (queue >= plat->rx_queues_to_use)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (of_property_read_bool(q_node, "snps,dcb-algorithm"))
|
2017-03-10 18:24:59 +00:00
|
|
|
plat->rx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB;
|
2017-03-10 18:24:51 +00:00
|
|
|
else if (of_property_read_bool(q_node, "snps,avb-algorithm"))
|
2017-03-10 18:24:59 +00:00
|
|
|
plat->rx_queues_cfg[queue].mode_to_use = MTL_QUEUE_AVB;
|
2017-03-10 18:24:51 +00:00
|
|
|
else
|
2017-03-10 18:24:59 +00:00
|
|
|
plat->rx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB;
|
2017-03-10 18:24:51 +00:00
|
|
|
|
2017-11-02 12:52:13 +05:30
|
|
|
if (of_property_read_u32(q_node, "snps,map-to-dma-channel",
|
|
|
|
&plat->rx_queues_cfg[queue].chan))
|
2017-03-10 18:24:51 +00:00
|
|
|
plat->rx_queues_cfg[queue].chan = queue;
|
|
|
|
/* TODO: Dynamic mapping to be included in the future */
|
|
|
|
|
2017-03-17 16:11:06 +00:00
|
|
|
if (of_property_read_u32(q_node, "snps,priority",
|
|
|
|
&plat->rx_queues_cfg[queue].prio)) {
|
|
|
|
plat->rx_queues_cfg[queue].prio = 0;
|
|
|
|
plat->rx_queues_cfg[queue].use_prio = false;
|
|
|
|
} else {
|
|
|
|
plat->rx_queues_cfg[queue].use_prio = true;
|
|
|
|
}
|
|
|
|
|
2017-03-17 16:11:07 +00:00
|
|
|
/* RX queue specific packet type routing */
|
|
|
|
if (of_property_read_bool(q_node, "snps,route-avcp"))
|
|
|
|
plat->rx_queues_cfg[queue].pkt_route = PACKET_AVCPQ;
|
|
|
|
else if (of_property_read_bool(q_node, "snps,route-ptp"))
|
|
|
|
plat->rx_queues_cfg[queue].pkt_route = PACKET_PTPQ;
|
|
|
|
else if (of_property_read_bool(q_node, "snps,route-dcbcp"))
|
|
|
|
plat->rx_queues_cfg[queue].pkt_route = PACKET_DCBCPQ;
|
|
|
|
else if (of_property_read_bool(q_node, "snps,route-up"))
|
|
|
|
plat->rx_queues_cfg[queue].pkt_route = PACKET_UPQ;
|
|
|
|
else if (of_property_read_bool(q_node, "snps,route-multi-broad"))
|
|
|
|
plat->rx_queues_cfg[queue].pkt_route = PACKET_MCBCQ;
|
|
|
|
else
|
|
|
|
plat->rx_queues_cfg[queue].pkt_route = 0x0;
|
|
|
|
|
2017-03-10 18:24:51 +00:00
|
|
|
queue++;
|
|
|
|
}
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
if (queue != plat->rx_queues_to_use) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
dev_err(&pdev->dev, "Not all RX queues were configured\n");
|
|
|
|
goto out;
|
|
|
|
}
|
2017-03-10 18:24:51 +00:00
|
|
|
|
|
|
|
/* Processing TX queues common config */
|
2017-11-02 12:52:13 +05:30
|
|
|
if (of_property_read_u32(tx_node, "snps,tx-queues-to-use",
|
|
|
|
&plat->tx_queues_to_use))
|
2017-03-10 18:24:51 +00:00
|
|
|
plat->tx_queues_to_use = 1;
|
|
|
|
|
|
|
|
if (of_property_read_bool(tx_node, "snps,tx-sched-wrr"))
|
|
|
|
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
|
|
|
|
else if (of_property_read_bool(tx_node, "snps,tx-sched-wfq"))
|
|
|
|
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WFQ;
|
|
|
|
else if (of_property_read_bool(tx_node, "snps,tx-sched-dwrr"))
|
|
|
|
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_DWRR;
|
|
|
|
else
|
|
|
|
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_SP;
|
|
|
|
|
|
|
|
queue = 0;
|
|
|
|
|
|
|
|
/* Processing individual TX queue config */
|
|
|
|
for_each_child_of_node(tx_node, q_node) {
|
|
|
|
if (queue >= plat->tx_queues_to_use)
|
|
|
|
break;
|
|
|
|
|
2017-11-02 12:52:13 +05:30
|
|
|
if (of_property_read_u32(q_node, "snps,weight",
|
|
|
|
&plat->tx_queues_cfg[queue].weight))
|
2017-03-10 18:24:51 +00:00
|
|
|
plat->tx_queues_cfg[queue].weight = 0x10 + queue;
|
|
|
|
|
2017-03-10 18:24:59 +00:00
|
|
|
if (of_property_read_bool(q_node, "snps,dcb-algorithm")) {
|
|
|
|
plat->tx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB;
|
|
|
|
} else if (of_property_read_bool(q_node,
|
|
|
|
"snps,avb-algorithm")) {
|
|
|
|
plat->tx_queues_cfg[queue].mode_to_use = MTL_QUEUE_AVB;
|
|
|
|
|
|
|
|
/* Credit Base Shaper parameters used by AVB */
|
|
|
|
if (of_property_read_u32(q_node, "snps,send_slope",
|
|
|
|
&plat->tx_queues_cfg[queue].send_slope))
|
|
|
|
plat->tx_queues_cfg[queue].send_slope = 0x0;
|
|
|
|
if (of_property_read_u32(q_node, "snps,idle_slope",
|
|
|
|
&plat->tx_queues_cfg[queue].idle_slope))
|
|
|
|
plat->tx_queues_cfg[queue].idle_slope = 0x0;
|
|
|
|
if (of_property_read_u32(q_node, "snps,high_credit",
|
|
|
|
&plat->tx_queues_cfg[queue].high_credit))
|
|
|
|
plat->tx_queues_cfg[queue].high_credit = 0x0;
|
|
|
|
if (of_property_read_u32(q_node, "snps,low_credit",
|
|
|
|
&plat->tx_queues_cfg[queue].low_credit))
|
|
|
|
plat->tx_queues_cfg[queue].low_credit = 0x0;
|
|
|
|
} else {
|
|
|
|
plat->tx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB;
|
|
|
|
}
|
|
|
|
|
2017-03-17 16:11:06 +00:00
|
|
|
if (of_property_read_u32(q_node, "snps,priority",
|
|
|
|
&plat->tx_queues_cfg[queue].prio)) {
|
|
|
|
plat->tx_queues_cfg[queue].prio = 0;
|
|
|
|
plat->tx_queues_cfg[queue].use_prio = false;
|
|
|
|
} else {
|
|
|
|
plat->tx_queues_cfg[queue].use_prio = true;
|
|
|
|
}
|
|
|
|
|
2023-09-16 14:33:12 +08:00
|
|
|
plat->tx_queues_cfg[queue].coe_unsupported =
|
|
|
|
of_property_read_bool(q_node, "snps,coe-unsupported");
|
|
|
|
|
2017-03-10 18:24:51 +00:00
|
|
|
queue++;
|
|
|
|
}
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
if (queue != plat->tx_queues_to_use) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
dev_err(&pdev->dev, "Not all TX queues were configured\n");
|
|
|
|
goto out;
|
|
|
|
}
|
2017-03-10 18:24:51 +00:00
|
|
|
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
out:
|
2017-03-10 18:24:51 +00:00
|
|
|
of_node_put(rx_node);
|
|
|
|
of_node_put(tx_node);
|
|
|
|
of_node_put(q_node);
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
|
|
|
|
return ret;
|
2017-03-10 18:24:51 +00:00
|
|
|
}
|
|
|
|
|
2016-04-01 09:07:16 +02:00
|
|
|
/**
|
net: stmmac: don't create a MDIO bus if unnecessary
Currently a MDIO bus is created if the devicetree description is either:
1. Not fixed-link
2. fixed-link but contains a MDIO bus as well
The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case, where the MDIO bus is not described at all, currently
stmmac will make a MDIO bus and scan its address space to discover
phys (of which there are none). This process takes time scanning a bus
that is known to be empty, delaying time to complete probe.
There are also a lot of upstream devicetrees[2] that expect a MDIO bus
to be created, scanned for phys, and the first one found connected
to the MAC. This case can be inferred from the platform description by
not having a phy-handle && not being fixed-link. This hits case "1" in
the current driver's logic, and must be handled in any logic change here
since it is a valid legacy dt-binding.
Let's improve the logic to create a MDIO bus if either:
- Devicetree contains a MDIO bus
- !fixed-link && !phy-handle (legacy handling)
This way the case where no MDIO bus should be made is handled, as well
as retaining backwards compatibility with the valid cases.
Below devicetree snippets can be found that explain some of
the cases above more concretely.
Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:
&fec1 {
phy-mode = "rmii";
fixed-link {
speed = <100>;
full-duplex;
};
mdio1: mdio {
switch0: switch0@0 {
compatible = "marvell,mv88e6190";
pinctrl-0 = <&pinctrl_gpio_switch0>;
};
};
};
Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:
ðernet0 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy0>;
mdio {
compatible = "snps,dwmac-mdio";
sgmii_phy0: phy@8 {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0x8>;
device_type = "ethernet-phy";
};
sgmii_phy1: phy@a {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0xa>;
device_type = "ethernet-phy";
};
};
};
ðernet1 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy1>;
};
Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:
&gmac {
phy-supply = <&vcc_lan>;
phy-mode = "rmii";
snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
};
[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-12-12 16:07:36 -06:00
|
|
|
* stmmac_of_get_mdio() - Gets the MDIO bus from the devicetree.
|
|
|
|
* @np: devicetree node
|
2016-04-01 09:07:16 +02:00
|
|
|
*
|
net: stmmac: don't create a MDIO bus if unnecessary
Currently a MDIO bus is created if the devicetree description is either:
1. Not fixed-link
2. fixed-link but contains a MDIO bus as well
The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case, where the MDIO bus is not described at all, currently
stmmac will make a MDIO bus and scan its address space to discover
phys (of which there are none). This process takes time scanning a bus
that is known to be empty, delaying time to complete probe.
There are also a lot of upstream devicetrees[2] that expect a MDIO bus
to be created, scanned for phys, and the first one found connected
to the MAC. This case can be inferred from the platform description by
not having a phy-handle && not being fixed-link. This hits case "1" in
the current driver's logic, and must be handled in any logic change here
since it is a valid legacy dt-binding.
Let's improve the logic to create a MDIO bus if either:
- Devicetree contains a MDIO bus
- !fixed-link && !phy-handle (legacy handling)
This way the case where no MDIO bus should be made is handled, as well
as retaining backwards compatibility with the valid cases.
Below devicetree snippets can be found that explain some of
the cases above more concretely.
Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:
&fec1 {
phy-mode = "rmii";
fixed-link {
speed = <100>;
full-duplex;
};
mdio1: mdio {
switch0: switch0@0 {
compatible = "marvell,mv88e6190";
pinctrl-0 = <&pinctrl_gpio_switch0>;
};
};
};
Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:
ðernet0 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy0>;
mdio {
compatible = "snps,dwmac-mdio";
sgmii_phy0: phy@8 {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0x8>;
device_type = "ethernet-phy";
};
sgmii_phy1: phy@a {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0xa>;
device_type = "ethernet-phy";
};
};
};
ðernet1 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy1>;
};
Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:
&gmac {
phy-supply = <&vcc_lan>;
phy-mode = "rmii";
snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
};
[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-12-12 16:07:36 -06:00
|
|
|
* The MDIO bus will be searched for in the following ways:
|
|
|
|
* 1. The compatible is "snps,dwc-qos-ethernet-4.10" && a "mdio" named
|
|
|
|
* child node exists
|
|
|
|
* 2. A child node with the "snps,dwmac-mdio" compatible is present
|
|
|
|
*
|
|
|
|
* Return: The MDIO node if present otherwise NULL
|
2016-04-01 09:07:16 +02:00
|
|
|
*/
|
net: stmmac: don't create a MDIO bus if unnecessary
Currently a MDIO bus is created if the devicetree description is either:
1. Not fixed-link
2. fixed-link but contains a MDIO bus as well
The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case, where the MDIO bus is not described at all, currently
stmmac will make a MDIO bus and scan its address space to discover
phys (of which there are none). This process takes time scanning a bus
that is known to be empty, delaying time to complete probe.
There are also a lot of upstream devicetrees[2] that expect a MDIO bus
to be created, scanned for phys, and the first one found connected
to the MAC. This case can be inferred from the platform description by
not having a phy-handle && not being fixed-link. This hits case "1" in
the current driver's logic, and must be handled in any logic change here
since it is a valid legacy dt-binding.
Let's improve the logic to create a MDIO bus if either:
- Devicetree contains a MDIO bus
- !fixed-link && !phy-handle (legacy handling)
This way the case where no MDIO bus should be made is handled, as well
as retaining backwards compatibility with the valid cases.
Below devicetree snippets can be found that explain some of
the cases above more concretely.
Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:
&fec1 {
phy-mode = "rmii";
fixed-link {
speed = <100>;
full-duplex;
};
mdio1: mdio {
switch0: switch0@0 {
compatible = "marvell,mv88e6190";
pinctrl-0 = <&pinctrl_gpio_switch0>;
};
};
};
Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:
ðernet0 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy0>;
mdio {
compatible = "snps,dwmac-mdio";
sgmii_phy0: phy@8 {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0x8>;
device_type = "ethernet-phy";
};
sgmii_phy1: phy@a {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0xa>;
device_type = "ethernet-phy";
};
};
};
ðernet1 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy1>;
};
Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:
&gmac {
phy-supply = <&vcc_lan>;
phy-mode = "rmii";
snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
};
[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-12-12 16:07:36 -06:00
|
|
|
static struct device_node *stmmac_of_get_mdio(struct device_node *np)
|
2016-04-01 09:07:16 +02:00
|
|
|
{
|
2017-05-31 09:18:36 +02:00
|
|
|
static const struct of_device_id need_mdio_ids[] = {
|
|
|
|
{ .compatible = "snps,dwc-qos-ethernet-4.10" },
|
2017-09-21 08:24:27 +02:00
|
|
|
{},
|
2017-05-31 09:18:36 +02:00
|
|
|
};
|
net: stmmac: don't create a MDIO bus if unnecessary
Currently a MDIO bus is created if the devicetree description is either:
1. Not fixed-link
2. fixed-link but contains a MDIO bus as well
The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case, where the MDIO bus is not described at all, currently
stmmac will make a MDIO bus and scan its address space to discover
phys (of which there are none). This process takes time scanning a bus
that is known to be empty, delaying time to complete probe.
There are also a lot of upstream devicetrees[2] that expect a MDIO bus
to be created, scanned for phys, and the first one found connected
to the MAC. This case can be inferred from the platform description by
not having a phy-handle && not being fixed-link. This hits case "1" in
the current driver's logic, and must be handled in any logic change here
since it is a valid legacy dt-binding.
Let's improve the logic to create a MDIO bus if either:
- Devicetree contains a MDIO bus
- !fixed-link && !phy-handle (legacy handling)
This way the case where no MDIO bus should be made is handled, as well
as retaining backwards compatibility with the valid cases.
Below devicetree snippets can be found that explain some of
the cases above more concretely.
Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:
&fec1 {
phy-mode = "rmii";
fixed-link {
speed = <100>;
full-duplex;
};
mdio1: mdio {
switch0: switch0@0 {
compatible = "marvell,mv88e6190";
pinctrl-0 = <&pinctrl_gpio_switch0>;
};
};
};
Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:
ðernet0 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy0>;
mdio {
compatible = "snps,dwmac-mdio";
sgmii_phy0: phy@8 {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0x8>;
device_type = "ethernet-phy";
};
sgmii_phy1: phy@a {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0xa>;
device_type = "ethernet-phy";
};
};
};
ðernet1 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy1>;
};
Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:
&gmac {
phy-supply = <&vcc_lan>;
phy-mode = "rmii";
snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
};
[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-12-12 16:07:36 -06:00
|
|
|
struct device_node *mdio_node = NULL;
|
2016-04-01 09:07:16 +02:00
|
|
|
|
2017-05-31 09:18:36 +02:00
|
|
|
if (of_match_node(need_mdio_ids, np)) {
|
net: stmmac: don't create a MDIO bus if unnecessary
Currently a MDIO bus is created if the devicetree description is either:
1. Not fixed-link
2. fixed-link but contains a MDIO bus as well
The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case, where the MDIO bus is not described at all, currently
stmmac will make a MDIO bus and scan its address space to discover
phys (of which there are none). This process takes time scanning a bus
that is known to be empty, delaying time to complete probe.
There are also a lot of upstream devicetrees[2] that expect a MDIO bus
to be created, scanned for phys, and the first one found connected
to the MAC. This case can be inferred from the platform description by
not having a phy-handle && not being fixed-link. This hits case "1" in
the current driver's logic, and must be handled in any logic change here
since it is a valid legacy dt-binding.
Let's improve the logic to create a MDIO bus if either:
- Devicetree contains a MDIO bus
- !fixed-link && !phy-handle (legacy handling)
This way the case where no MDIO bus should be made is handled, as well
as retaining backwards compatibility with the valid cases.
Below devicetree snippets can be found that explain some of
the cases above more concretely.
Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:
&fec1 {
phy-mode = "rmii";
fixed-link {
speed = <100>;
full-duplex;
};
mdio1: mdio {
switch0: switch0@0 {
compatible = "marvell,mv88e6190";
pinctrl-0 = <&pinctrl_gpio_switch0>;
};
};
};
Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:
ðernet0 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy0>;
mdio {
compatible = "snps,dwmac-mdio";
sgmii_phy0: phy@8 {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0x8>;
device_type = "ethernet-phy";
};
sgmii_phy1: phy@a {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0xa>;
device_type = "ethernet-phy";
};
};
};
ðernet1 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy1>;
};
Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:
&gmac {
phy-supply = <&vcc_lan>;
phy-mode = "rmii";
snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
};
[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-12-12 16:07:36 -06:00
|
|
|
mdio_node = of_get_child_by_name(np, "mdio");
|
2017-01-09 12:35:10 +00:00
|
|
|
} else {
|
|
|
|
/**
|
|
|
|
* If snps,dwmac-mdio is passed from DT, always register
|
|
|
|
* the MDIO
|
|
|
|
*/
|
net: stmmac: don't create a MDIO bus if unnecessary
Currently a MDIO bus is created if the devicetree description is either:
1. Not fixed-link
2. fixed-link but contains a MDIO bus as well
The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case, where the MDIO bus is not described at all, currently
stmmac will make a MDIO bus and scan its address space to discover
phys (of which there are none). This process takes time scanning a bus
that is known to be empty, delaying time to complete probe.
There are also a lot of upstream devicetrees[2] that expect a MDIO bus
to be created, scanned for phys, and the first one found connected
to the MAC. This case can be inferred from the platform description by
not having a phy-handle && not being fixed-link. This hits case "1" in
the current driver's logic, and must be handled in any logic change here
since it is a valid legacy dt-binding.
Let's improve the logic to create a MDIO bus if either:
- Devicetree contains a MDIO bus
- !fixed-link && !phy-handle (legacy handling)
This way the case where no MDIO bus should be made is handled, as well
as retaining backwards compatibility with the valid cases.
Below devicetree snippets can be found that explain some of
the cases above more concretely.
Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:
&fec1 {
phy-mode = "rmii";
fixed-link {
speed = <100>;
full-duplex;
};
mdio1: mdio {
switch0: switch0@0 {
compatible = "marvell,mv88e6190";
pinctrl-0 = <&pinctrl_gpio_switch0>;
};
};
};
Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:
ðernet0 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy0>;
mdio {
compatible = "snps,dwmac-mdio";
sgmii_phy0: phy@8 {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0x8>;
device_type = "ethernet-phy";
};
sgmii_phy1: phy@a {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0xa>;
device_type = "ethernet-phy";
};
};
};
ðernet1 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy1>;
};
Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:
&gmac {
phy-supply = <&vcc_lan>;
phy-mode = "rmii";
snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
};
[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-12-12 16:07:36 -06:00
|
|
|
for_each_child_of_node(np, mdio_node) {
|
|
|
|
if (of_device_is_compatible(mdio_node,
|
2017-01-09 12:35:10 +00:00
|
|
|
"snps,dwmac-mdio"))
|
2017-01-12 21:46:32 +03:00
|
|
|
break;
|
2017-01-09 12:35:10 +00:00
|
|
|
}
|
2016-04-01 09:07:16 +02:00
|
|
|
}
|
|
|
|
|
net: stmmac: don't create a MDIO bus if unnecessary
Currently a MDIO bus is created if the devicetree description is either:
1. Not fixed-link
2. fixed-link but contains a MDIO bus as well
The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case, where the MDIO bus is not described at all, currently
stmmac will make a MDIO bus and scan its address space to discover
phys (of which there are none). This process takes time scanning a bus
that is known to be empty, delaying time to complete probe.
There are also a lot of upstream devicetrees[2] that expect a MDIO bus
to be created, scanned for phys, and the first one found connected
to the MAC. This case can be inferred from the platform description by
not having a phy-handle && not being fixed-link. This hits case "1" in
the current driver's logic, and must be handled in any logic change here
since it is a valid legacy dt-binding.
Let's improve the logic to create a MDIO bus if either:
- Devicetree contains a MDIO bus
- !fixed-link && !phy-handle (legacy handling)
This way the case where no MDIO bus should be made is handled, as well
as retaining backwards compatibility with the valid cases.
Below devicetree snippets can be found that explain some of
the cases above more concretely.
Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:
&fec1 {
phy-mode = "rmii";
fixed-link {
speed = <100>;
full-duplex;
};
mdio1: mdio {
switch0: switch0@0 {
compatible = "marvell,mv88e6190";
pinctrl-0 = <&pinctrl_gpio_switch0>;
};
};
};
Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:
ðernet0 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy0>;
mdio {
compatible = "snps,dwmac-mdio";
sgmii_phy0: phy@8 {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0x8>;
device_type = "ethernet-phy";
};
sgmii_phy1: phy@a {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0xa>;
device_type = "ethernet-phy";
};
};
};
ðernet1 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy1>;
};
Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:
&gmac {
phy-supply = <&vcc_lan>;
phy-mode = "rmii";
snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
};
[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-12-12 16:07:36 -06:00
|
|
|
return mdio_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* stmmac_mdio_setup() - Populate platform related MDIO structures.
|
|
|
|
* @plat: driver data platform structure
|
|
|
|
* @np: devicetree node
|
|
|
|
* @dev: device pointer
|
|
|
|
*
|
|
|
|
* This searches for MDIO information from the devicetree.
|
|
|
|
* If an MDIO node is found, it's assigned to plat->mdio_node and
|
|
|
|
* plat->mdio_bus_data is allocated.
|
|
|
|
* If no connection can be determined, just plat->mdio_bus_data is allocated
|
|
|
|
* to indicate a bus should be created and scanned for a phy.
|
|
|
|
* If it's determined there's no MDIO bus needed, both are left NULL.
|
|
|
|
*
|
|
|
|
* This expects that plat->phy_node has already been searched for.
|
|
|
|
*
|
|
|
|
* Return: 0 on success, errno otherwise.
|
|
|
|
*/
|
|
|
|
static int stmmac_mdio_setup(struct plat_stmmacenet_data *plat,
|
|
|
|
struct device_node *np, struct device *dev)
|
|
|
|
{
|
|
|
|
bool legacy_mdio;
|
|
|
|
|
|
|
|
plat->mdio_node = stmmac_of_get_mdio(np);
|
|
|
|
if (plat->mdio_node)
|
2016-04-01 09:07:16 +02:00
|
|
|
dev_dbg(dev, "Found MDIO subnode\n");
|
|
|
|
|
net: stmmac: don't create a MDIO bus if unnecessary
Currently a MDIO bus is created if the devicetree description is either:
1. Not fixed-link
2. fixed-link but contains a MDIO bus as well
The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case, where the MDIO bus is not described at all, currently
stmmac will make a MDIO bus and scan its address space to discover
phys (of which there are none). This process takes time scanning a bus
that is known to be empty, delaying time to complete probe.
There are also a lot of upstream devicetrees[2] that expect a MDIO bus
to be created, scanned for phys, and the first one found connected
to the MAC. This case can be inferred from the platform description by
not having a phy-handle && not being fixed-link. This hits case "1" in
the current driver's logic, and must be handled in any logic change here
since it is a valid legacy dt-binding.
Let's improve the logic to create a MDIO bus if either:
- Devicetree contains a MDIO bus
- !fixed-link && !phy-handle (legacy handling)
This way the case where no MDIO bus should be made is handled, as well
as retaining backwards compatibility with the valid cases.
Below devicetree snippets can be found that explain some of
the cases above more concretely.
Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:
&fec1 {
phy-mode = "rmii";
fixed-link {
speed = <100>;
full-duplex;
};
mdio1: mdio {
switch0: switch0@0 {
compatible = "marvell,mv88e6190";
pinctrl-0 = <&pinctrl_gpio_switch0>;
};
};
};
Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:
ðernet0 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy0>;
mdio {
compatible = "snps,dwmac-mdio";
sgmii_phy0: phy@8 {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0x8>;
device_type = "ethernet-phy";
};
sgmii_phy1: phy@a {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0xa>;
device_type = "ethernet-phy";
};
};
};
ðernet1 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy1>;
};
Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:
&gmac {
phy-supply = <&vcc_lan>;
phy-mode = "rmii";
snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
};
[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-12-12 16:07:36 -06:00
|
|
|
/* Legacy devicetrees allowed for no MDIO bus description and expect
|
|
|
|
* the bus to be scanned for devices. If there's no phy or fixed-link
|
|
|
|
* described assume this is the case since there must be something
|
|
|
|
* connected to the MAC.
|
|
|
|
*/
|
|
|
|
legacy_mdio = !of_phy_is_fixed_link(np) && !plat->phy_node;
|
|
|
|
if (legacy_mdio)
|
|
|
|
dev_info(dev, "Deprecated MDIO bus assumption used\n");
|
|
|
|
|
|
|
|
if (plat->mdio_node || legacy_mdio) {
|
|
|
|
plat->mdio_bus_data = devm_kzalloc(dev,
|
|
|
|
sizeof(*plat->mdio_bus_data),
|
|
|
|
GFP_KERNEL);
|
2019-07-26 12:27:40 +02:00
|
|
|
if (!plat->mdio_bus_data)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
plat->mdio_bus_data->needs_reset = true;
|
|
|
|
}
|
|
|
|
|
2016-04-01 09:07:16 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-06 16:02:55 +03:00
|
|
|
/**
|
|
|
|
* stmmac_of_get_mac_mode - retrieves the interface of the MAC
|
drivers/net/ethernet: clean up mis-targeted comments
As part of the W=1 cleanups for ethernet, a million [*] driver
comments had to be cleaned up to get the W=1 compilation to
succeed. This change finally makes the drivers/net/ethernet tree
compile with W=1 set on the command line. NOTE: The kernel uses
kdoc style (see Documentation/process/kernel-doc.rst) when
documenting code, not doxygen or other styles.
After this patch the x86_64 build has no warnings from W=1, however
scripts/kernel-doc says there are 1545 more warnings in source files, that
I need to develop a script to fix in a followup patch.
The errors fixed here are all kdoc of a few classes, with a few outliers:
In file included from drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c:10:
drivers/net/ethernet/qlogic/netxen/netxen_nic.h:1193:18: warning: ‘FW_DUMP_LEVELS’ defined but not used [-Wunused-const-variable=]
1193 | static const u32 FW_DUMP_LEVELS[] = { 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
| ^~~~~~~~~~~~~~
... repeats 4 times...
drivers/net/ethernet/sun/cassini.c:2084:24: warning: suggest braces around empty body in an ‘else’ statement [-Wempty-body]
2084 | RX_USED_ADD(page, i);
drivers/net/ethernet/natsemi/ns83820.c: In function ‘phy_intr’:
drivers/net/ethernet/natsemi/ns83820.c:603:6: warning: variable ‘tbisr’ set but not used [-Wunused-but-set-variable]
603 | u32 tbisr, tanar, tanlpar;
| ^~~~~
drivers/net/ethernet/natsemi/ns83820.c: In function ‘ns83820_get_link_ksettings’:
drivers/net/ethernet/natsemi/ns83820.c:1207:11: warning: variable ‘tanar’ set but not used [-Wunused-but-set-variable]
1207 | u32 cfg, tanar, tbicr;
| ^~~~~
drivers/net/ethernet/packetengines/yellowfin.c:1063:18: warning: variable ‘yf_size’ set but not used [-Wunused-but-set-variable]
1063 | int data_size, yf_size;
| ^~~~~~~
Normal kdoc fixes:
warning: Function parameter or member 'x' not described in 'y'
warning: Excess function parameter 'x' description in 'y'
warning: Cannot understand <string> on line <NNN> - I thought it was a doc line
[*] - ok it wasn't quite a million, but it felt like it.
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-25 15:24:45 -07:00
|
|
|
* @np: - device-tree node
|
2019-09-06 16:02:55 +03:00
|
|
|
* Description:
|
|
|
|
* Similar to `of_get_phy_mode()`, this function will retrieve (from
|
|
|
|
* the device-tree) the interface mode on the MAC side. This assumes
|
|
|
|
* that there is mode converter in-between the MAC & PHY
|
|
|
|
* (e.g. GMII-to-RGMII).
|
|
|
|
*/
|
|
|
|
static int stmmac_of_get_mac_mode(struct device_node *np)
|
|
|
|
{
|
|
|
|
const char *pm;
|
|
|
|
int err, i;
|
|
|
|
|
|
|
|
err = of_property_read_string(np, "mac-mode", &pm);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) {
|
|
|
|
if (!strcasecmp(pm, phy_modes(i)))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2023-09-16 15:58:29 +08:00
|
|
|
/**
|
|
|
|
* stmmac_remove_config_dt - undo the effects of stmmac_probe_config_dt()
|
|
|
|
* @pdev: platform_device structure
|
|
|
|
* @plat: driver data platform structure
|
|
|
|
*
|
|
|
|
* Release resources claimed by stmmac_probe_config_dt().
|
|
|
|
*/
|
|
|
|
static void stmmac_remove_config_dt(struct platform_device *pdev,
|
|
|
|
struct plat_stmmacenet_data *plat)
|
|
|
|
{
|
|
|
|
clk_disable_unprepare(plat->stmmac_clk);
|
|
|
|
clk_disable_unprepare(plat->pclk);
|
|
|
|
of_node_put(plat->phy_node);
|
|
|
|
of_node_put(plat->mdio_node);
|
|
|
|
}
|
|
|
|
|
2014-11-18 09:47:01 +01:00
|
|
|
/**
|
|
|
|
* stmmac_probe_config_dt - parse device-tree driver parameters
|
|
|
|
* @pdev: platform_device structure
|
|
|
|
* @mac: MAC address to use
|
|
|
|
* Description:
|
|
|
|
* this function is to read the driver parameters from device-tree and
|
|
|
|
* set some private fields that will be used by the main at runtime.
|
|
|
|
*/
|
2023-09-16 15:58:29 +08:00
|
|
|
static struct plat_stmmacenet_data *
|
of: net: pass the dst buffer to of_get_mac_address()
of_get_mac_address() returns a "const void*" pointer to a MAC address.
Lately, support to fetch the MAC address by an NVMEM provider was added.
But this will only work with platform devices. It will not work with
PCI devices (e.g. of an integrated root complex) and esp. not with DSA
ports.
There is an of_* variant of the nvmem binding which works without
devices. The returned data of a nvmem_cell_read() has to be freed after
use. On the other hand the return of_get_mac_address() points to some
static data without a lifetime. The trick for now, was to allocate a
device resource managed buffer which is then returned. This will only
work if we have an actual device.
Change it, so that the caller of of_get_mac_address() has to supply a
buffer where the MAC address is written to. Unfortunately, this will
touch all drivers which use the of_get_mac_address().
Usually the code looks like:
const char *addr;
addr = of_get_mac_address(np);
if (!IS_ERR(addr))
ether_addr_copy(ndev->dev_addr, addr);
This can then be simply rewritten as:
of_get_mac_address(np, ndev->dev_addr);
Sometimes is_valid_ether_addr() is used to test the MAC address.
of_get_mac_address() already makes sure, it just returns a valid MAC
address. Thus we can just test its return code. But we have to be
careful if there are still other sources for the MAC address before the
of_get_mac_address(). In this case we have to keep the
is_valid_ether_addr() call.
The following coccinelle patch was used to convert common cases to the
new style. Afterwards, I've manually gone over the drivers and fixed the
return code variable: either used a new one or if one was already
available use that. Mansour Moufid, thanks for that coccinelle patch!
<spml>
@a@
identifier x;
expression y, z;
@@
- x = of_get_mac_address(y);
+ x = of_get_mac_address(y, z);
<...
- ether_addr_copy(z, x);
...>
@@
identifier a.x;
@@
- if (<+... x ...+>) {}
@@
identifier a.x;
@@
if (<+... x ...+>) {
...
}
- else {}
@@
identifier a.x;
expression e;
@@
- if (<+... x ...+>@e)
- {}
- else
+ if (!(e))
{...}
@@
expression x, y, z;
@@
- x = of_get_mac_address(y, z);
+ of_get_mac_address(y, z);
... when != x
</spml>
All drivers, except drivers/net/ethernet/aeroflex/greth.c, were
compile-time tested.
Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Michael Walle <michael@walle.cc>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-04-12 19:47:17 +02:00
|
|
|
stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
|
2012-03-13 04:56:37 +00:00
|
|
|
{
|
|
|
|
struct device_node *np = pdev->dev.of_node;
|
2015-07-17 00:26:06 +02:00
|
|
|
struct plat_stmmacenet_data *plat;
|
2013-07-04 10:35:41 +01:00
|
|
|
struct stmmac_dma_cfg *dma_cfg;
|
2021-07-07 15:53:35 +08:00
|
|
|
int phy_mode;
|
2020-11-12 09:27:37 +08:00
|
|
|
void *ret;
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
int rc;
|
2012-03-13 04:56:37 +00:00
|
|
|
|
2015-07-17 00:26:06 +02:00
|
|
|
plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
|
|
|
|
if (!plat)
|
2015-07-17 00:26:08 +02:00
|
|
|
return ERR_PTR(-ENOMEM);
|
2015-07-17 00:26:06 +02:00
|
|
|
|
of: net: pass the dst buffer to of_get_mac_address()
of_get_mac_address() returns a "const void*" pointer to a MAC address.
Lately, support to fetch the MAC address by an NVMEM provider was added.
But this will only work with platform devices. It will not work with
PCI devices (e.g. of an integrated root complex) and esp. not with DSA
ports.
There is an of_* variant of the nvmem binding which works without
devices. The returned data of a nvmem_cell_read() has to be freed after
use. On the other hand the return of_get_mac_address() points to some
static data without a lifetime. The trick for now, was to allocate a
device resource managed buffer which is then returned. This will only
work if we have an actual device.
Change it, so that the caller of of_get_mac_address() has to supply a
buffer where the MAC address is written to. Unfortunately, this will
touch all drivers which use the of_get_mac_address().
Usually the code looks like:
const char *addr;
addr = of_get_mac_address(np);
if (!IS_ERR(addr))
ether_addr_copy(ndev->dev_addr, addr);
This can then be simply rewritten as:
of_get_mac_address(np, ndev->dev_addr);
Sometimes is_valid_ether_addr() is used to test the MAC address.
of_get_mac_address() already makes sure, it just returns a valid MAC
address. Thus we can just test its return code. But we have to be
careful if there are still other sources for the MAC address before the
of_get_mac_address(). In this case we have to keep the
is_valid_ether_addr() call.
The following coccinelle patch was used to convert common cases to the
new style. Afterwards, I've manually gone over the drivers and fixed the
return code variable: either used a new one or if one was already
available use that. Mansour Moufid, thanks for that coccinelle patch!
<spml>
@a@
identifier x;
expression y, z;
@@
- x = of_get_mac_address(y);
+ x = of_get_mac_address(y, z);
<...
- ether_addr_copy(z, x);
...>
@@
identifier a.x;
@@
- if (<+... x ...+>) {}
@@
identifier a.x;
@@
if (<+... x ...+>) {
...
}
- else {}
@@
identifier a.x;
expression e;
@@
- if (<+... x ...+>@e)
- {}
- else
+ if (!(e))
{...}
@@
expression x, y, z;
@@
- x = of_get_mac_address(y, z);
+ of_get_mac_address(y, z);
... when != x
</spml>
All drivers, except drivers/net/ethernet/aeroflex/greth.c, were
compile-time tested.
Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Michael Walle <michael@walle.cc>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-04-12 19:47:17 +02:00
|
|
|
rc = of_get_mac_address(np, mac);
|
|
|
|
if (rc) {
|
|
|
|
if (rc == -EPROBE_DEFER)
|
|
|
|
return ERR_PTR(rc);
|
2019-07-27 21:21:37 +02:00
|
|
|
|
of: net: pass the dst buffer to of_get_mac_address()
of_get_mac_address() returns a "const void*" pointer to a MAC address.
Lately, support to fetch the MAC address by an NVMEM provider was added.
But this will only work with platform devices. It will not work with
PCI devices (e.g. of an integrated root complex) and esp. not with DSA
ports.
There is an of_* variant of the nvmem binding which works without
devices. The returned data of a nvmem_cell_read() has to be freed after
use. On the other hand the return of_get_mac_address() points to some
static data without a lifetime. The trick for now, was to allocate a
device resource managed buffer which is then returned. This will only
work if we have an actual device.
Change it, so that the caller of of_get_mac_address() has to supply a
buffer where the MAC address is written to. Unfortunately, this will
touch all drivers which use the of_get_mac_address().
Usually the code looks like:
const char *addr;
addr = of_get_mac_address(np);
if (!IS_ERR(addr))
ether_addr_copy(ndev->dev_addr, addr);
This can then be simply rewritten as:
of_get_mac_address(np, ndev->dev_addr);
Sometimes is_valid_ether_addr() is used to test the MAC address.
of_get_mac_address() already makes sure, it just returns a valid MAC
address. Thus we can just test its return code. But we have to be
careful if there are still other sources for the MAC address before the
of_get_mac_address(). In this case we have to keep the
is_valid_ether_addr() call.
The following coccinelle patch was used to convert common cases to the
new style. Afterwards, I've manually gone over the drivers and fixed the
return code variable: either used a new one or if one was already
available use that. Mansour Moufid, thanks for that coccinelle patch!
<spml>
@a@
identifier x;
expression y, z;
@@
- x = of_get_mac_address(y);
+ x = of_get_mac_address(y, z);
<...
- ether_addr_copy(z, x);
...>
@@
identifier a.x;
@@
- if (<+... x ...+>) {}
@@
identifier a.x;
@@
if (<+... x ...+>) {
...
}
- else {}
@@
identifier a.x;
expression e;
@@
- if (<+... x ...+>@e)
- {}
- else
+ if (!(e))
{...}
@@
expression x, y, z;
@@
- x = of_get_mac_address(y, z);
+ of_get_mac_address(y, z);
... when != x
</spml>
All drivers, except drivers/net/ethernet/aeroflex/greth.c, were
compile-time tested.
Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Michael Walle <michael@walle.cc>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-04-12 19:47:17 +02:00
|
|
|
eth_zero_addr(mac);
|
2019-07-27 21:21:37 +02:00
|
|
|
}
|
|
|
|
|
2021-07-07 15:53:35 +08:00
|
|
|
phy_mode = device_get_phy_mode(&pdev->dev);
|
|
|
|
if (phy_mode < 0)
|
|
|
|
return ERR_PTR(phy_mode);
|
2019-09-06 16:02:55 +03:00
|
|
|
|
2021-07-07 15:53:35 +08:00
|
|
|
plat->phy_interface = phy_mode;
|
2023-08-29 14:29:50 +01:00
|
|
|
rc = stmmac_of_get_mac_mode(np);
|
|
|
|
plat->mac_interface = rc < 0 ? plat->phy_interface : rc;
|
2019-06-14 17:06:57 +02:00
|
|
|
|
|
|
|
/* Some wrapper drivers still rely on phy_node. Let's save it while
|
|
|
|
* they are not converted to phylink. */
|
|
|
|
plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
|
|
|
|
|
|
|
|
/* PHYLINK automatically parses the phy-handle property */
|
2023-08-24 14:37:58 +01:00
|
|
|
plat->port_node = of_fwnode_handle(np);
|
2013-07-04 10:35:41 +01:00
|
|
|
|
2014-01-16 10:51:43 +00:00
|
|
|
/* Get max speed of operation from device tree */
|
2022-04-01 02:48:32 +08:00
|
|
|
of_property_read_u32(np, "max-speed", &plat->max_speed);
|
2014-01-16 10:51:43 +00:00
|
|
|
|
2013-07-04 10:35:41 +01:00
|
|
|
plat->bus_id = of_alias_get_id(np, "ethernet");
|
|
|
|
if (plat->bus_id < 0)
|
|
|
|
plat->bus_id = 0;
|
|
|
|
|
2014-01-17 21:24:45 +08:00
|
|
|
/* Default to phy auto-detection */
|
|
|
|
plat->phy_addr = -1;
|
|
|
|
|
2022-09-24 16:15:14 +05:30
|
|
|
/* Default to get clk_csr from stmmac_clk_csr_set(),
|
2019-05-24 14:26:08 +08:00
|
|
|
* or get clk_csr from device tree.
|
|
|
|
*/
|
|
|
|
plat->clk_csr = -1;
|
2022-09-29 09:47:58 +08:00
|
|
|
if (of_property_read_u32(np, "snps,clk-csr", &plat->clk_csr))
|
|
|
|
of_property_read_u32(np, "clk_csr", &plat->clk_csr);
|
2019-03-05 09:29:26 +01:00
|
|
|
|
2014-01-17 21:24:45 +08:00
|
|
|
/* "snps,phy-addr" is not a standard property. Mark it as deprecated
|
|
|
|
* and warn of its use. Remove this when phy node support is added.
|
|
|
|
*/
|
|
|
|
if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
|
|
|
|
dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
|
2013-07-04 10:35:41 +01:00
|
|
|
|
net: stmmac: don't create a MDIO bus if unnecessary
Currently a MDIO bus is created if the devicetree description is either:
1. Not fixed-link
2. fixed-link but contains a MDIO bus as well
The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case, where the MDIO bus is not described at all, currently
stmmac will make a MDIO bus and scan its address space to discover
phys (of which there are none). This process takes time scanning a bus
that is known to be empty, delaying time to complete probe.
There are also a lot of upstream devicetrees[2] that expect a MDIO bus
to be created, scanned for phys, and the first one found connected
to the MAC. This case can be inferred from the platform description by
not having a phy-handle && not being fixed-link. This hits case "1" in
the current driver's logic, and must be handled in any logic change here
since it is a valid legacy dt-binding.
Let's improve the logic to create a MDIO bus if either:
- Devicetree contains a MDIO bus
- !fixed-link && !phy-handle (legacy handling)
This way the case where no MDIO bus should be made is handled, as well
as retaining backwards compatibility with the valid cases.
Below devicetree snippets can be found that explain some of
the cases above more concretely.
Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:
&fec1 {
phy-mode = "rmii";
fixed-link {
speed = <100>;
full-duplex;
};
mdio1: mdio {
switch0: switch0@0 {
compatible = "marvell,mv88e6190";
pinctrl-0 = <&pinctrl_gpio_switch0>;
};
};
};
Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:
ðernet0 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy0>;
mdio {
compatible = "snps,dwmac-mdio";
sgmii_phy0: phy@8 {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0x8>;
device_type = "ethernet-phy";
};
sgmii_phy1: phy@a {
compatible = "ethernet-phy-id0141.0dd4";
reg = <0xa>;
device_type = "ethernet-phy";
};
};
};
ðernet1 {
phy-mode = "sgmii";
phy-handle = <&sgmii_phy1>;
};
Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:
&gmac {
phy-supply = <&vcc_lan>;
phy-mode = "rmii";
snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
};
[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-12-12 16:07:36 -06:00
|
|
|
rc = stmmac_mdio_setup(plat, np, &pdev->dev);
|
2018-02-19 18:11:15 +01:00
|
|
|
if (rc)
|
|
|
|
return ERR_PTR(rc);
|
2014-10-14 08:11:54 +02:00
|
|
|
|
2015-04-15 11:17:40 -05:00
|
|
|
of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);
|
|
|
|
|
|
|
|
of_property_read_u32(np, "rx-fifo-depth", &plat->rx_fifo_size);
|
|
|
|
|
2014-10-14 08:11:54 +02:00
|
|
|
plat->force_sf_dma_mode =
|
|
|
|
of_property_read_bool(np, "snps,force_sf_dma_mode");
|
2014-01-17 21:24:44 +08:00
|
|
|
|
2023-07-10 11:00:01 +02:00
|
|
|
if (of_property_read_bool(np, "snps,en-tx-lpi-clockgating"))
|
|
|
|
plat->flags |= STMMAC_FLAG_EN_TX_LPI_CLOCKGATING;
|
2017-01-09 12:35:08 +00:00
|
|
|
|
2014-01-20 05:39:01 -06:00
|
|
|
/* Set the maxmtu to a default of JUMBO_LEN in case the
|
|
|
|
* parameter is not present in the device tree.
|
|
|
|
*/
|
|
|
|
plat->maxmtu = JUMBO_LEN;
|
|
|
|
|
2015-07-17 00:26:06 +02:00
|
|
|
/* Set default value for multicast hash bins */
|
|
|
|
plat->multicast_filter_bins = HASH_TABLE_SIZE;
|
|
|
|
|
|
|
|
/* Set default value for unicast filter entries */
|
|
|
|
plat->unicast_filter_entries = 1;
|
|
|
|
|
2012-03-13 04:56:37 +00:00
|
|
|
/*
|
|
|
|
* Currently only the properties needed on SPEAr600
|
|
|
|
* are provided. All other properties should be added
|
|
|
|
* once needed on other platforms.
|
|
|
|
*/
|
2012-07-18 13:28:26 +00:00
|
|
|
if (of_device_is_compatible(np, "st,spear600-gmac") ||
|
2016-08-29 18:23:40 +02:00
|
|
|
of_device_is_compatible(np, "snps,dwmac-3.50a") ||
|
2012-07-18 13:28:26 +00:00
|
|
|
of_device_is_compatible(np, "snps,dwmac-3.70a") ||
|
|
|
|
of_device_is_compatible(np, "snps,dwmac")) {
|
2014-01-20 05:39:01 -06:00
|
|
|
/* Note that the max-frame-size parameter as defined in the
|
|
|
|
* ePAPR v1.1 spec is defined as max-frame-size, it's
|
|
|
|
* actually used as the IEEE definition of MAC Client
|
|
|
|
* data, or MTU. The ePAPR specification is confusing as
|
|
|
|
* the definition is max-frame-size, but usage examples
|
|
|
|
* are clearly MTUs
|
|
|
|
*/
|
|
|
|
of_property_read_u32(np, "max-frame-size", &plat->maxmtu);
|
2014-07-31 15:49:17 -05:00
|
|
|
of_property_read_u32(np, "snps,multicast-filter-bins",
|
|
|
|
&plat->multicast_filter_bins);
|
|
|
|
of_property_read_u32(np, "snps,perfect-filter-entries",
|
|
|
|
&plat->unicast_filter_entries);
|
|
|
|
plat->unicast_filter_entries = dwmac1000_validate_ucast_entries(
|
2019-09-05 16:00:53 +03:00
|
|
|
&pdev->dev, plat->unicast_filter_entries);
|
2014-07-31 15:49:17 -05:00
|
|
|
plat->multicast_filter_bins = dwmac1000_validate_mcast_bins(
|
2019-09-05 16:00:53 +03:00
|
|
|
&pdev->dev, plat->multicast_filter_bins);
|
2012-03-13 04:56:37 +00:00
|
|
|
plat->has_gmac = 1;
|
|
|
|
plat->pmt = 1;
|
|
|
|
}
|
|
|
|
|
2021-10-08 12:34:39 +02:00
|
|
|
if (of_device_is_compatible(np, "snps,dwmac-3.40a")) {
|
|
|
|
plat->has_gmac = 1;
|
|
|
|
plat->enh_desc = 1;
|
|
|
|
plat->tx_coe = 1;
|
|
|
|
plat->bugged_jumbo = 1;
|
|
|
|
plat->pmt = 1;
|
|
|
|
}
|
|
|
|
|
2016-04-01 11:37:33 +02:00
|
|
|
if (of_device_is_compatible(np, "snps,dwmac-4.00") ||
|
2018-05-25 09:46:40 +02:00
|
|
|
of_device_is_compatible(np, "snps,dwmac-4.10a") ||
|
2020-05-28 16:26:23 +08:00
|
|
|
of_device_is_compatible(np, "snps,dwmac-4.20a") ||
|
2023-04-17 18:02:47 +08:00
|
|
|
of_device_is_compatible(np, "snps,dwmac-5.10a") ||
|
|
|
|
of_device_is_compatible(np, "snps,dwmac-5.20")) {
|
2016-04-01 11:37:33 +02:00
|
|
|
plat->has_gmac4 = 1;
|
net: stmmac: stmmac_platform: use correct setup function for gmac4
devicetree binding for stmmac states:
- compatible: Should be "snps,dwmac-<ip_version>", "snps,dwmac"
For backwards compatibility: "st,spear600-gmac" is also supported.
Previously, when specifying "snps,dwmac-4.10a", "snps,dwmac" as your
compatible string, plat_stmmacenet_data would have both has_gmac and
has_gmac4 set.
This would lead to stmmac_hw_init calling dwmac1000_setup rather than
dwmac4_setup, resulting in a non-functional driver.
This happened since the check for has_gmac is done before the check for
has_gmac4. However, the order should not matter, so it does not make sense
to have both set.
If something is valid for both, you should do as the stmmac_interrupt does:
if (priv->plat->has_gmac || priv->plat->has_gmac4) ...
The places where it was obvious that the author actually meant
if (has_gmac || has_gmac4) rather than if (has_gmac) has been updated.
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
Acked-by: Alexandre TORGUE <alexandre.torgue@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-12-07 13:41:08 +01:00
|
|
|
plat->has_gmac = 0;
|
2016-04-01 11:37:33 +02:00
|
|
|
plat->pmt = 1;
|
2023-07-10 10:59:54 +02:00
|
|
|
if (of_property_read_bool(np, "snps,tso"))
|
|
|
|
plat->flags |= STMMAC_FLAG_TSO_EN;
|
2016-04-01 11:37:33 +02:00
|
|
|
}
|
|
|
|
|
2013-07-04 10:35:41 +01:00
|
|
|
if (of_device_is_compatible(np, "snps,dwmac-3.610") ||
|
|
|
|
of_device_is_compatible(np, "snps,dwmac-3.710")) {
|
|
|
|
plat->enh_desc = 1;
|
|
|
|
plat->bugged_jumbo = 1;
|
|
|
|
plat->force_sf_dma_mode = 1;
|
|
|
|
}
|
|
|
|
|
2018-08-08 09:04:36 +01:00
|
|
|
if (of_device_is_compatible(np, "snps,dwxgmac")) {
|
|
|
|
plat->has_xgmac = 1;
|
|
|
|
plat->pmt = 1;
|
2023-07-10 10:59:54 +02:00
|
|
|
if (of_property_read_bool(np, "snps,tso"))
|
|
|
|
plat->flags |= STMMAC_FLAG_TSO_EN;
|
2018-08-08 09:04:36 +01:00
|
|
|
}
|
|
|
|
|
net: stmmac: stmmac_platform: fix parsing of DT binding
commit 64c3b252e9fc ("net: stmmac: fixed the pbl setting with DT")
changed the parsing of the DT binding.
Before 64c3b252e9fc, snps,fixed-burst and snps,mixed-burst were parsed
regardless if the property snps,pbl existed or not.
After the commit, fixed burst and mixed burst are only parsed if
snps,pbl exists. Now when snps,aal has been added, it too is only
parsed if snps,pbl exists.
Since the DT binding does not specify that fixed burst, mixed burst
or aal depend on snps,pbl being specified, undo changes introduced
by 64c3b252e9fc.
The issue commit 64c3b252e9fc ("net: stmmac: fixed the pbl setting with
DT") tries to address is solved in another way:
The databook specifies that all values other than
1, 2, 4, 8, 16, or 32 results in undefined behavior,
so snps,pbl = <0> is invalid.
If pbl is 0 after parsing, set pbl to DEFAULT_DMA_PBL.
This handles the case where the property is omitted, and also handles
the case where the property is specified without any data.
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
Acked-by: Alexandre Torgue <alexandre.torgue@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-12-07 15:20:05 +01:00
|
|
|
dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!dma_cfg) {
|
|
|
|
stmmac_remove_config_dt(pdev, plat);
|
|
|
|
return ERR_PTR(-ENOMEM);
|
2013-08-24 15:31:43 +09:00
|
|
|
}
|
net: stmmac: stmmac_platform: fix parsing of DT binding
commit 64c3b252e9fc ("net: stmmac: fixed the pbl setting with DT")
changed the parsing of the DT binding.
Before 64c3b252e9fc, snps,fixed-burst and snps,mixed-burst were parsed
regardless if the property snps,pbl existed or not.
After the commit, fixed burst and mixed burst are only parsed if
snps,pbl exists. Now when snps,aal has been added, it too is only
parsed if snps,pbl exists.
Since the DT binding does not specify that fixed burst, mixed burst
or aal depend on snps,pbl being specified, undo changes introduced
by 64c3b252e9fc.
The issue commit 64c3b252e9fc ("net: stmmac: fixed the pbl setting with
DT") tries to address is solved in another way:
The databook specifies that all values other than
1, 2, 4, 8, 16, or 32 results in undefined behavior,
so snps,pbl = <0> is invalid.
If pbl is 0 after parsing, set pbl to DEFAULT_DMA_PBL.
This handles the case where the property is omitted, and also handles
the case where the property is specified without any data.
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
Acked-by: Alexandre Torgue <alexandre.torgue@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-12-07 15:20:05 +01:00
|
|
|
plat->dma_cfg = dma_cfg;
|
|
|
|
|
|
|
|
of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
|
|
|
|
if (!dma_cfg->pbl)
|
|
|
|
dma_cfg->pbl = DEFAULT_DMA_PBL;
|
net: stmmac: add support for independent DMA pbl for tx/rx
GMAC and newer supports independent programmable burst lengths for
DMA tx/rx. Add new optional devicetree properties representing this.
To be backwards compatible, snps,pbl will still be valid, but
snps,txpbl/snps,rxpbl will override the value in snps,pbl if set.
If the IP is synthesized to use the AXI interface, there is a register
and a matching DT property inside the optional stmmac-axi-config DT node
for controlling burst lengths, named snps,blen.
However, using this register, it is not possible to control tx and rx
independently. Also, this register is not available if the IP was
synthesized with, e.g., the AHB interface.
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
Acked-by: Alexandre Torgue <alexandre.torgue@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-12-07 15:20:07 +01:00
|
|
|
of_property_read_u32(np, "snps,txpbl", &dma_cfg->txpbl);
|
|
|
|
of_property_read_u32(np, "snps,rxpbl", &dma_cfg->rxpbl);
|
2016-12-07 15:20:08 +01:00
|
|
|
dma_cfg->pblx8 = !of_property_read_bool(np, "snps,no-pbl-x8");
|
net: stmmac: stmmac_platform: fix parsing of DT binding
commit 64c3b252e9fc ("net: stmmac: fixed the pbl setting with DT")
changed the parsing of the DT binding.
Before 64c3b252e9fc, snps,fixed-burst and snps,mixed-burst were parsed
regardless if the property snps,pbl existed or not.
After the commit, fixed burst and mixed burst are only parsed if
snps,pbl exists. Now when snps,aal has been added, it too is only
parsed if snps,pbl exists.
Since the DT binding does not specify that fixed burst, mixed burst
or aal depend on snps,pbl being specified, undo changes introduced
by 64c3b252e9fc.
The issue commit 64c3b252e9fc ("net: stmmac: fixed the pbl setting with
DT") tries to address is solved in another way:
The databook specifies that all values other than
1, 2, 4, 8, 16, or 32 results in undefined behavior,
so snps,pbl = <0> is invalid.
If pbl is 0 after parsing, set pbl to DEFAULT_DMA_PBL.
This handles the case where the property is omitted, and also handles
the case where the property is specified without any data.
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
Acked-by: Alexandre Torgue <alexandre.torgue@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-12-07 15:20:05 +01:00
|
|
|
|
|
|
|
dma_cfg->aal = of_property_read_bool(np, "snps,aal");
|
|
|
|
dma_cfg->fixed_burst = of_property_read_bool(np, "snps,fixed-burst");
|
|
|
|
dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst");
|
|
|
|
|
2013-08-28 18:55:39 +08:00
|
|
|
plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
|
2023-02-10 22:21:26 +02:00
|
|
|
if (plat->force_thresh_dma_mode && plat->force_sf_dma_mode) {
|
2013-08-28 18:55:39 +08:00
|
|
|
plat->force_sf_dma_mode = 0;
|
2019-09-05 16:00:53 +03:00
|
|
|
dev_warn(&pdev->dev,
|
|
|
|
"force_sf_dma_mode is ignored if force_thresh_dma_mode is set.\n");
|
2013-09-05 18:01:41 -07:00
|
|
|
}
|
2013-07-04 10:35:41 +01:00
|
|
|
|
2016-06-24 15:16:26 +02:00
|
|
|
of_property_read_u32(np, "snps,ps-speed", &plat->mac_port_sel_speed);
|
|
|
|
|
2016-02-29 14:27:28 +01:00
|
|
|
plat->axi = stmmac_axi_setup(pdev);
|
|
|
|
|
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: Niklas Cassel <niklas.cassel@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-19 18:11:14 +01:00
|
|
|
rc = stmmac_mtl_setup(pdev, plat);
|
|
|
|
if (rc) {
|
|
|
|
stmmac_remove_config_dt(pdev, plat);
|
|
|
|
return ERR_PTR(rc);
|
|
|
|
}
|
2017-03-10 18:24:51 +00:00
|
|
|
|
2017-01-09 12:35:09 +00:00
|
|
|
/* clock setup */
|
2019-07-26 12:27:41 +02:00
|
|
|
if (!of_device_is_compatible(np, "snps,dwc-qos-ethernet-4.10")) {
|
|
|
|
plat->stmmac_clk = devm_clk_get(&pdev->dev,
|
|
|
|
STMMAC_RESOURCE_NAME);
|
|
|
|
if (IS_ERR(plat->stmmac_clk)) {
|
|
|
|
dev_warn(&pdev->dev, "Cannot get CSR clock\n");
|
|
|
|
plat->stmmac_clk = NULL;
|
|
|
|
}
|
|
|
|
clk_prepare_enable(plat->stmmac_clk);
|
2017-01-09 12:35:09 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 09:27:37 +08:00
|
|
|
plat->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
|
2017-01-09 12:35:09 +00:00
|
|
|
if (IS_ERR(plat->pclk)) {
|
2020-11-12 09:27:37 +08:00
|
|
|
ret = plat->pclk;
|
|
|
|
goto error_pclk_get;
|
2017-01-09 12:35:09 +00:00
|
|
|
}
|
|
|
|
clk_prepare_enable(plat->pclk);
|
|
|
|
|
|
|
|
/* Fall-back to main clock in case of no PTP ref is passed */
|
2017-03-10 17:34:53 +01:00
|
|
|
plat->clk_ptp_ref = devm_clk_get(&pdev->dev, "ptp_ref");
|
2017-01-09 12:35:09 +00:00
|
|
|
if (IS_ERR(plat->clk_ptp_ref)) {
|
|
|
|
plat->clk_ptp_rate = clk_get_rate(plat->stmmac_clk);
|
|
|
|
plat->clk_ptp_ref = NULL;
|
2020-02-24 18:29:54 +01:00
|
|
|
dev_info(&pdev->dev, "PTP uses main clock\n");
|
2017-01-09 12:35:09 +00:00
|
|
|
} else {
|
|
|
|
plat->clk_ptp_rate = clk_get_rate(plat->clk_ptp_ref);
|
2017-02-02 08:20:12 +01:00
|
|
|
dev_dbg(&pdev->dev, "PTP rate %d\n", plat->clk_ptp_rate);
|
2017-01-09 12:35:09 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 09:27:37 +08:00
|
|
|
plat->stmmac_rst = devm_reset_control_get_optional(&pdev->dev,
|
|
|
|
STMMAC_RESOURCE_NAME);
|
2017-01-09 12:35:09 +00:00
|
|
|
if (IS_ERR(plat->stmmac_rst)) {
|
2020-11-12 09:27:37 +08:00
|
|
|
ret = plat->stmmac_rst;
|
|
|
|
goto error_hw_init;
|
2017-01-09 12:35:09 +00:00
|
|
|
}
|
|
|
|
|
2021-06-08 19:59:06 +01:00
|
|
|
plat->stmmac_ahb_rst = devm_reset_control_get_optional_shared(
|
|
|
|
&pdev->dev, "ahb");
|
|
|
|
if (IS_ERR(plat->stmmac_ahb_rst)) {
|
|
|
|
ret = plat->stmmac_ahb_rst;
|
|
|
|
goto error_hw_init;
|
|
|
|
}
|
|
|
|
|
2015-07-17 00:26:08 +02:00
|
|
|
return plat;
|
2017-01-09 12:35:09 +00:00
|
|
|
|
|
|
|
error_hw_init:
|
|
|
|
clk_disable_unprepare(plat->pclk);
|
|
|
|
error_pclk_get:
|
|
|
|
clk_disable_unprepare(plat->stmmac_clk);
|
|
|
|
|
2020-11-12 09:27:37 +08:00
|
|
|
return ret;
|
2012-03-13 04:56:37 +00:00
|
|
|
}
|
2016-11-30 15:29:55 +01:00
|
|
|
|
2023-06-23 12:04:14 +02:00
|
|
|
static void devm_stmmac_remove_config_dt(void *data)
|
|
|
|
{
|
|
|
|
struct plat_stmmacenet_data *plat = data;
|
|
|
|
|
|
|
|
/* Platform data argument is unused */
|
|
|
|
stmmac_remove_config_dt(NULL, plat);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devm_stmmac_probe_config_dt
|
|
|
|
* @pdev: platform_device structure
|
|
|
|
* @mac: MAC address to use
|
|
|
|
* Description: Devres variant of stmmac_probe_config_dt(). Does not require
|
|
|
|
* the user to call stmmac_remove_config_dt() at driver detach.
|
|
|
|
*/
|
|
|
|
struct plat_stmmacenet_data *
|
|
|
|
devm_stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
|
|
|
|
{
|
|
|
|
struct plat_stmmacenet_data *plat;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
plat = stmmac_probe_config_dt(pdev, mac);
|
|
|
|
if (IS_ERR(plat))
|
|
|
|
return plat;
|
|
|
|
|
|
|
|
ret = devm_add_action_or_reset(&pdev->dev,
|
|
|
|
devm_stmmac_remove_config_dt, plat);
|
|
|
|
if (ret)
|
|
|
|
return ERR_PTR(ret);
|
|
|
|
|
|
|
|
return plat;
|
|
|
|
}
|
2012-03-13 04:56:37 +00:00
|
|
|
#else
|
2023-06-23 12:04:14 +02:00
|
|
|
struct plat_stmmacenet_data *
|
|
|
|
devm_stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
|
|
|
|
{
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
2012-03-13 04:56:37 +00:00
|
|
|
#endif /* CONFIG_OF */
|
2023-06-23 12:04:14 +02:00
|
|
|
EXPORT_SYMBOL_GPL(devm_stmmac_probe_config_dt);
|
2012-03-13 04:56:37 +00:00
|
|
|
|
2015-07-17 00:26:09 +02:00
|
|
|
int stmmac_get_platform_resources(struct platform_device *pdev,
|
|
|
|
struct stmmac_resources *stmmac_res)
|
2011-12-21 03:58:19 +00:00
|
|
|
{
|
2015-07-17 00:26:07 +02:00
|
|
|
memset(stmmac_res, 0, sizeof(*stmmac_res));
|
2015-03-03 13:46:44 +03:00
|
|
|
|
|
|
|
/* Get IRQ information early to have an ability to ask for deferred
|
|
|
|
* probe if needed before we went too far with resource allocation.
|
|
|
|
*/
|
2015-07-17 00:26:07 +02:00
|
|
|
stmmac_res->irq = platform_get_irq_byname(pdev, "macirq");
|
2019-07-30 11:15:51 -07:00
|
|
|
if (stmmac_res->irq < 0)
|
2015-07-17 00:26:07 +02:00
|
|
|
return stmmac_res->irq;
|
2015-03-03 13:46:44 +03:00
|
|
|
|
|
|
|
/* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
|
|
|
|
* The external wake up irq can be passed through the platform code
|
|
|
|
* named as "eth_wake_irq"
|
|
|
|
*
|
|
|
|
* In case the wake up interrupt is not passed from the platform
|
|
|
|
* so the driver will continue to use the mac irq (ndev->irq)
|
|
|
|
*/
|
2020-03-06 17:38:48 +01:00
|
|
|
stmmac_res->wol_irq =
|
|
|
|
platform_get_irq_byname_optional(pdev, "eth_wake_irq");
|
2015-07-17 00:26:07 +02:00
|
|
|
if (stmmac_res->wol_irq < 0) {
|
|
|
|
if (stmmac_res->wol_irq == -EPROBE_DEFER)
|
2015-03-03 13:46:44 +03:00
|
|
|
return -EPROBE_DEFER;
|
2020-03-06 17:38:48 +01:00
|
|
|
dev_info(&pdev->dev, "IRQ eth_wake_irq not found\n");
|
2015-07-17 00:26:07 +02:00
|
|
|
stmmac_res->wol_irq = stmmac_res->irq;
|
2015-03-03 13:46:44 +03:00
|
|
|
}
|
|
|
|
|
2020-03-06 17:38:48 +01:00
|
|
|
stmmac_res->lpi_irq =
|
|
|
|
platform_get_irq_byname_optional(pdev, "eth_lpi");
|
|
|
|
if (stmmac_res->lpi_irq < 0) {
|
|
|
|
if (stmmac_res->lpi_irq == -EPROBE_DEFER)
|
|
|
|
return -EPROBE_DEFER;
|
|
|
|
dev_info(&pdev->dev, "IRQ eth_lpi not found\n");
|
|
|
|
}
|
2011-12-21 03:58:19 +00:00
|
|
|
|
2024-02-09 14:20:12 +05:30
|
|
|
stmmac_res->sfty_irq =
|
|
|
|
platform_get_irq_byname_optional(pdev, "sfty");
|
|
|
|
if (stmmac_res->sfty_irq < 0) {
|
|
|
|
if (stmmac_res->sfty_irq == -EPROBE_DEFER)
|
|
|
|
return -EPROBE_DEFER;
|
|
|
|
dev_info(&pdev->dev, "IRQ sfty not found\n");
|
|
|
|
}
|
|
|
|
|
2020-03-13 22:42:57 +08:00
|
|
|
stmmac_res->addr = devm_platform_ioremap_resource(pdev, 0);
|
2015-07-17 00:26:07 +02:00
|
|
|
|
2015-07-29 00:08:48 +02:00
|
|
|
return PTR_ERR_OR_ZERO(stmmac_res->addr);
|
2015-07-17 00:26:07 +02:00
|
|
|
}
|
2015-07-17 00:26:09 +02:00
|
|
|
EXPORT_SYMBOL_GPL(stmmac_get_platform_resources);
|
2015-07-17 00:26:07 +02:00
|
|
|
|
2023-06-23 12:04:07 +02:00
|
|
|
/**
|
|
|
|
* stmmac_pltfr_init
|
|
|
|
* @pdev: pointer to the platform device
|
|
|
|
* @plat: driver data platform structure
|
|
|
|
* Description: Call the platform's init callback (if any) and propagate
|
|
|
|
* the return value.
|
|
|
|
*/
|
|
|
|
int stmmac_pltfr_init(struct platform_device *pdev,
|
|
|
|
struct plat_stmmacenet_data *plat)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (plat->init)
|
|
|
|
ret = plat->init(pdev, plat->bsp_priv);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(stmmac_pltfr_init);
|
|
|
|
|
2023-06-23 12:04:09 +02:00
|
|
|
/**
|
|
|
|
* stmmac_pltfr_exit
|
|
|
|
* @pdev: pointer to the platform device
|
|
|
|
* @plat: driver data platform structure
|
|
|
|
* Description: Call the platform's exit callback (if any).
|
|
|
|
*/
|
|
|
|
void stmmac_pltfr_exit(struct platform_device *pdev,
|
|
|
|
struct plat_stmmacenet_data *plat)
|
|
|
|
{
|
|
|
|
if (plat->exit)
|
|
|
|
plat->exit(pdev, plat->bsp_priv);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(stmmac_pltfr_exit);
|
|
|
|
|
2023-06-23 12:04:11 +02:00
|
|
|
/**
|
|
|
|
* stmmac_pltfr_probe
|
|
|
|
* @pdev: platform device pointer
|
|
|
|
* @plat: driver data platform structure
|
|
|
|
* @res: stmmac resources structure
|
|
|
|
* Description: This calls the platform's init() callback and probes the
|
|
|
|
* stmmac driver.
|
|
|
|
*/
|
|
|
|
int stmmac_pltfr_probe(struct platform_device *pdev,
|
|
|
|
struct plat_stmmacenet_data *plat,
|
|
|
|
struct stmmac_resources *res)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = stmmac_pltfr_init(pdev, plat);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = stmmac_dvr_probe(&pdev->dev, plat, res);
|
|
|
|
if (ret) {
|
|
|
|
stmmac_pltfr_exit(pdev, plat);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(stmmac_pltfr_probe);
|
|
|
|
|
2023-06-23 12:04:16 +02:00
|
|
|
static void devm_stmmac_pltfr_remove(void *data)
|
|
|
|
{
|
|
|
|
struct platform_device *pdev = data;
|
|
|
|
|
2023-09-16 15:58:28 +08:00
|
|
|
stmmac_pltfr_remove(pdev);
|
2023-06-23 12:04:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devm_stmmac_pltfr_probe
|
|
|
|
* @pdev: pointer to the platform device
|
|
|
|
* @plat: driver data platform structure
|
|
|
|
* @res: stmmac resources
|
|
|
|
* Description: Devres variant of stmmac_pltfr_probe(). Allows users to skip
|
|
|
|
* calling stmmac_pltfr_remove() on driver detach.
|
|
|
|
*/
|
|
|
|
int devm_stmmac_pltfr_probe(struct platform_device *pdev,
|
|
|
|
struct plat_stmmacenet_data *plat,
|
|
|
|
struct stmmac_resources *res)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = stmmac_pltfr_probe(pdev, plat, res);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return devm_add_action_or_reset(&pdev->dev, devm_stmmac_pltfr_remove,
|
|
|
|
pdev);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devm_stmmac_pltfr_probe);
|
|
|
|
|
2023-06-23 12:04:13 +02:00
|
|
|
/**
|
2023-09-16 15:58:28 +08:00
|
|
|
* stmmac_pltfr_remove
|
2023-06-23 12:04:13 +02:00
|
|
|
* @pdev: pointer to the platform device
|
|
|
|
* Description: This undoes the effects of stmmac_pltfr_probe() by removing the
|
|
|
|
* driver and calling the platform's exit() callback.
|
|
|
|
*/
|
2023-09-16 15:58:28 +08:00
|
|
|
void stmmac_pltfr_remove(struct platform_device *pdev)
|
2023-06-23 12:04:13 +02:00
|
|
|
{
|
|
|
|
struct net_device *ndev = platform_get_drvdata(pdev);
|
|
|
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
|
|
|
struct plat_stmmacenet_data *plat = priv->plat;
|
|
|
|
|
|
|
|
stmmac_dvr_remove(&pdev->dev);
|
|
|
|
stmmac_pltfr_exit(pdev, plat);
|
|
|
|
}
|
2015-05-14 12:10:58 +02:00
|
|
|
EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
|
2011-12-21 03:58:19 +00:00
|
|
|
|
2014-11-18 09:47:01 +01:00
|
|
|
/**
|
|
|
|
* stmmac_pltfr_suspend
|
|
|
|
* @dev: device pointer
|
|
|
|
* Description: this function is invoked when suspend the driver and it direcly
|
|
|
|
* call the main suspend function and then, if required, on some platform, it
|
|
|
|
* can call an exit helper.
|
|
|
|
*/
|
2021-03-22 12:23:59 +00:00
|
|
|
static int __maybe_unused stmmac_pltfr_suspend(struct device *dev)
|
2011-12-21 03:58:19 +00:00
|
|
|
{
|
2012-04-18 19:48:19 +00:00
|
|
|
int ret;
|
2011-12-21 03:58:19 +00:00
|
|
|
struct net_device *ndev = dev_get_drvdata(dev);
|
2014-01-16 10:52:44 +00:00
|
|
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
2012-04-18 19:48:19 +00:00
|
|
|
struct platform_device *pdev = to_platform_device(dev);
|
2011-12-21 03:58:19 +00:00
|
|
|
|
2016-05-01 22:58:19 +02:00
|
|
|
ret = stmmac_suspend(dev);
|
2023-06-23 12:04:09 +02:00
|
|
|
stmmac_pltfr_exit(pdev, priv->plat);
|
2012-04-18 19:48:19 +00:00
|
|
|
|
|
|
|
return ret;
|
2011-12-21 03:58:19 +00:00
|
|
|
}
|
|
|
|
|
2014-11-18 09:47:01 +01:00
|
|
|
/**
|
|
|
|
* stmmac_pltfr_resume
|
|
|
|
* @dev: device pointer
|
|
|
|
* Description: this function is invoked when resume the driver before calling
|
|
|
|
* the main resume function, on some platforms, it can call own init helper
|
|
|
|
* if required.
|
|
|
|
*/
|
2021-03-22 12:23:59 +00:00
|
|
|
static int __maybe_unused stmmac_pltfr_resume(struct device *dev)
|
2011-12-21 03:58:19 +00:00
|
|
|
{
|
|
|
|
struct net_device *ndev = dev_get_drvdata(dev);
|
2014-01-16 10:52:44 +00:00
|
|
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
2012-04-18 19:48:19 +00:00
|
|
|
struct platform_device *pdev = to_platform_device(dev);
|
2023-06-23 12:04:07 +02:00
|
|
|
int ret;
|
2012-04-18 19:48:19 +00:00
|
|
|
|
2023-09-21 14:24:43 +08:00
|
|
|
ret = stmmac_pltfr_init(pdev, priv->plat);
|
2023-06-23 12:04:07 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2011-12-21 03:58:19 +00:00
|
|
|
|
2016-05-01 22:58:19 +02:00
|
|
|
return stmmac_resume(dev);
|
2011-12-21 03:58:19 +00:00
|
|
|
}
|
2021-03-15 20:16:46 +08:00
|
|
|
|
2021-03-22 12:23:59 +00:00
|
|
|
static int __maybe_unused stmmac_runtime_suspend(struct device *dev)
|
2021-03-15 20:16:46 +08:00
|
|
|
{
|
|
|
|
struct net_device *ndev = dev_get_drvdata(dev);
|
|
|
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
|
|
|
|
|
|
|
stmmac_bus_clks_config(priv, false);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-22 12:23:59 +00:00
|
|
|
static int __maybe_unused stmmac_runtime_resume(struct device *dev)
|
2021-03-15 20:16:46 +08:00
|
|
|
{
|
|
|
|
struct net_device *ndev = dev_get_drvdata(dev);
|
|
|
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
|
|
|
|
|
|
|
return stmmac_bus_clks_config(priv, true);
|
|
|
|
}
|
2011-12-21 03:58:19 +00:00
|
|
|
|
2021-09-09 17:23:22 +08:00
|
|
|
static int __maybe_unused stmmac_pltfr_noirq_suspend(struct device *dev)
|
net: stmmac: fix system hang caused by eee_ctrl_timer during suspend/resume
commit 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after
napi disabled"), this patch tries to fix system hang caused by eee_ctrl_timer,
unfortunately, it only can resolve it for system reboot stress test. System
hang also can be reproduced easily during system suspend/resume stess test
when mount NFS on i.MX8MP EVK board.
In stmmac driver, eee feature is combined to phylink framework. When do
system suspend, phylink_stop() would queue delayed work, it invokes
stmmac_mac_link_down(), where to deactivate eee_ctrl_timer synchronizly.
In above commit, try to fix issue by deactivating eee_ctrl_timer obviously,
but it is not enough. Looking into eee_ctrl_timer expire callback
stmmac_eee_ctrl_timer(), it could enable hareware eee mode again. What is
unexpected is that LPI interrupt (MAC_Interrupt_Enable.LPIEN bit) is always
asserted. This interrupt has chance to be issued when LPI state entry/exit
from the MAC, and at that time, clock could have been already disabled.
The result is that system hang when driver try to touch register from
interrupt handler.
The reason why above commit can fix system hang issue in stmmac_release()
is that, deactivate eee_ctrl_timer not just after napi disabled, further
after irq freed.
In conclusion, hardware would generate LPI interrupt when clock has been
disabled during suspend or resume, since hardware is in eee mode and LPI
interrupt enabled.
Interrupts from MAC, MTL and DMA level are enabled and never been disabled
when system suspend, so postpone clocks management from suspend stage to
noirq suspend stage should be more safe.
Fixes: 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after napi disabled")
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-09-08 15:43:35 +08:00
|
|
|
{
|
|
|
|
struct net_device *ndev = dev_get_drvdata(dev);
|
|
|
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!netif_running(ndev))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!device_may_wakeup(priv->device) || !priv->plat->pmt) {
|
|
|
|
/* Disable clock in case of PWM is off */
|
|
|
|
clk_disable_unprepare(priv->plat->clk_ptp_ref);
|
|
|
|
|
|
|
|
ret = pm_runtime_force_suspend(dev);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-09 17:23:22 +08:00
|
|
|
static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev)
|
net: stmmac: fix system hang caused by eee_ctrl_timer during suspend/resume
commit 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after
napi disabled"), this patch tries to fix system hang caused by eee_ctrl_timer,
unfortunately, it only can resolve it for system reboot stress test. System
hang also can be reproduced easily during system suspend/resume stess test
when mount NFS on i.MX8MP EVK board.
In stmmac driver, eee feature is combined to phylink framework. When do
system suspend, phylink_stop() would queue delayed work, it invokes
stmmac_mac_link_down(), where to deactivate eee_ctrl_timer synchronizly.
In above commit, try to fix issue by deactivating eee_ctrl_timer obviously,
but it is not enough. Looking into eee_ctrl_timer expire callback
stmmac_eee_ctrl_timer(), it could enable hareware eee mode again. What is
unexpected is that LPI interrupt (MAC_Interrupt_Enable.LPIEN bit) is always
asserted. This interrupt has chance to be issued when LPI state entry/exit
from the MAC, and at that time, clock could have been already disabled.
The result is that system hang when driver try to touch register from
interrupt handler.
The reason why above commit can fix system hang issue in stmmac_release()
is that, deactivate eee_ctrl_timer not just after napi disabled, further
after irq freed.
In conclusion, hardware would generate LPI interrupt when clock has been
disabled during suspend or resume, since hardware is in eee mode and LPI
interrupt enabled.
Interrupts from MAC, MTL and DMA level are enabled and never been disabled
when system suspend, so postpone clocks management from suspend stage to
noirq suspend stage should be more safe.
Fixes: 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after napi disabled")
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-09-08 15:43:35 +08:00
|
|
|
{
|
|
|
|
struct net_device *ndev = dev_get_drvdata(dev);
|
|
|
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!netif_running(ndev))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!device_may_wakeup(priv->device) || !priv->plat->pmt) {
|
|
|
|
/* enable the clk previously disabled */
|
|
|
|
ret = pm_runtime_force_resume(dev);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2022-07-14 14:00:14 +08:00
|
|
|
ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
|
|
|
|
if (ret < 0) {
|
|
|
|
netdev_warn(priv->dev,
|
|
|
|
"failed to enable PTP reference clock: %pe\n",
|
|
|
|
ERR_PTR(ret));
|
|
|
|
return ret;
|
|
|
|
}
|
net: stmmac: fix system hang caused by eee_ctrl_timer during suspend/resume
commit 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after
napi disabled"), this patch tries to fix system hang caused by eee_ctrl_timer,
unfortunately, it only can resolve it for system reboot stress test. System
hang also can be reproduced easily during system suspend/resume stess test
when mount NFS on i.MX8MP EVK board.
In stmmac driver, eee feature is combined to phylink framework. When do
system suspend, phylink_stop() would queue delayed work, it invokes
stmmac_mac_link_down(), where to deactivate eee_ctrl_timer synchronizly.
In above commit, try to fix issue by deactivating eee_ctrl_timer obviously,
but it is not enough. Looking into eee_ctrl_timer expire callback
stmmac_eee_ctrl_timer(), it could enable hareware eee mode again. What is
unexpected is that LPI interrupt (MAC_Interrupt_Enable.LPIEN bit) is always
asserted. This interrupt has chance to be issued when LPI state entry/exit
from the MAC, and at that time, clock could have been already disabled.
The result is that system hang when driver try to touch register from
interrupt handler.
The reason why above commit can fix system hang issue in stmmac_release()
is that, deactivate eee_ctrl_timer not just after napi disabled, further
after irq freed.
In conclusion, hardware would generate LPI interrupt when clock has been
disabled during suspend or resume, since hardware is in eee mode and LPI
interrupt enabled.
Interrupts from MAC, MTL and DMA level are enabled and never been disabled
when system suspend, so postpone clocks management from suspend stage to
noirq suspend stage should be more safe.
Fixes: 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after napi disabled")
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-09-08 15:43:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-15 20:16:46 +08:00
|
|
|
const struct dev_pm_ops stmmac_pltfr_pm_ops = {
|
|
|
|
SET_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_suspend, stmmac_pltfr_resume)
|
|
|
|
SET_RUNTIME_PM_OPS(stmmac_runtime_suspend, stmmac_runtime_resume, NULL)
|
net: stmmac: fix system hang caused by eee_ctrl_timer during suspend/resume
commit 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after
napi disabled"), this patch tries to fix system hang caused by eee_ctrl_timer,
unfortunately, it only can resolve it for system reboot stress test. System
hang also can be reproduced easily during system suspend/resume stess test
when mount NFS on i.MX8MP EVK board.
In stmmac driver, eee feature is combined to phylink framework. When do
system suspend, phylink_stop() would queue delayed work, it invokes
stmmac_mac_link_down(), where to deactivate eee_ctrl_timer synchronizly.
In above commit, try to fix issue by deactivating eee_ctrl_timer obviously,
but it is not enough. Looking into eee_ctrl_timer expire callback
stmmac_eee_ctrl_timer(), it could enable hareware eee mode again. What is
unexpected is that LPI interrupt (MAC_Interrupt_Enable.LPIEN bit) is always
asserted. This interrupt has chance to be issued when LPI state entry/exit
from the MAC, and at that time, clock could have been already disabled.
The result is that system hang when driver try to touch register from
interrupt handler.
The reason why above commit can fix system hang issue in stmmac_release()
is that, deactivate eee_ctrl_timer not just after napi disabled, further
after irq freed.
In conclusion, hardware would generate LPI interrupt when clock has been
disabled during suspend or resume, since hardware is in eee mode and LPI
interrupt enabled.
Interrupts from MAC, MTL and DMA level are enabled and never been disabled
when system suspend, so postpone clocks management from suspend stage to
noirq suspend stage should be more safe.
Fixes: 5f58591323bf ("net: stmmac: delete the eee_ctrl_timer after napi disabled")
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-09-08 15:43:35 +08:00
|
|
|
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_noirq_suspend, stmmac_pltfr_noirq_resume)
|
2021-03-15 20:16:46 +08:00
|
|
|
};
|
2015-05-14 12:10:58 +02:00
|
|
|
EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
|
2015-07-31 19:13:22 +02:00
|
|
|
|
|
|
|
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
|
|
|
|
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
|
|
|
|
MODULE_LICENSE("GPL");
|