linux/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c

985 lines
28 KiB
C
Raw Normal View History

treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 291 Based on 2 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms and conditions of the gnu general public license version 2 as published by the free software foundation this program is distributed in the hope it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details the full gnu general public license is included in this distribution in the file called copying this program is free software you can redistribute it and or modify it under the terms and conditions of the gnu general public license version 2 as published by the free software foundation this program is distributed in the hope [that] it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details the full gnu general public license is included in this distribution in the file called copying extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 57 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190529141901.515993066@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-05-29 07:18:05 -07:00
// SPDX-License-Identifier: GPL-2.0-only
/*******************************************************************************
This contains the functions to handle the platform driver.
Copyright (C) 2007-2011 STMicroelectronics Ltd
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
#include <linux/device.h>
#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>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
#include "stmmac.h"
#include "stmmac_platform.h"
#ifdef CONFIG_OF
/**
* dwmac1000_validate_mcast_bins - validates the number of Multicast filter bins
* @dev: struct device of the platform device
* @mcast_bins: Multicast filtering bins
* Description:
* this function validates the number of Multicast filtering bins specified
* 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.
*/
static int dwmac1000_validate_mcast_bins(struct device *dev, int mcast_bins)
{
int x = mcast_bins;
switch (x) {
case HASH_TABLE_SIZE:
case 128:
case 256:
break;
default:
x = 0;
dev_info(dev, "Hash table entries set to unexpected value %d\n",
mcast_bins);
break;
}
return x;
}
/**
* dwmac1000_validate_ucast_entries - validate the Unicast address entries
* @dev: struct device of the platform device
* @ucast_entries: number of Unicast address entries
* Description:
* This function validates the number of Unicast address entries supported
* by a particular Synopsys 10/100/1000 controller. The Synopsys controller
* supports 1..32, 64, or 128 Unicast filter entries for it's Unicast filter
* logic. This function validates a valid, supported configuration is
* selected, and defaults to 1 Unicast address if an unsupported
* configuration is selected.
*/
static int dwmac1000_validate_ucast_entries(struct device *dev,
int ucast_entries)
{
int x = ucast_entries;
switch (x) {
case 1 ... 32:
case 64:
case 128:
break;
default:
x = 1;
dev_info(dev, "Unicast table entries set to unexpected value %d\n",
ucast_entries);
break;
}
return x;
}
/**
* 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;
axi = devm_kzalloc(&pdev->dev, sizeof(*axi), GFP_KERNEL);
if (!axi) {
of_node_put(np);
return ERR_PTR(-ENOMEM);
}
axi->axi_lpi_en = of_property_read_bool(np, "snps,lpi_en");
axi->axi_xit_frm = of_property_read_bool(np, "snps,xit_frm");
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");
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;
of_property_read_u32_array(np, "snps,blen", axi->axi_blen, AXI_BLEN);
of_node_put(np);
return axi;
}
/**
* 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
*/
static int stmmac_mtl_setup(struct platform_device *pdev,
struct plat_stmmacenet_data *plat)
{
struct device_node *q_node;
struct device_node *rx_node;
struct device_node *tx_node;
u8 queue = 0;
int ret = 0;
/* 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;
/* 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;
rx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-rx-config", 0);
if (!rx_node)
return ret;
tx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-tx-config", 0);
if (!tx_node) {
of_node_put(rx_node);
return ret;
}
/* Processing RX queues common config */
if (of_property_read_u32(rx_node, "snps,rx-queues-to-use",
&plat->rx_queues_to_use))
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"))
plat->rx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB;
else if (of_property_read_bool(q_node, "snps,avb-algorithm"))
plat->rx_queues_cfg[queue].mode_to_use = MTL_QUEUE_AVB;
else
plat->rx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB;
if (of_property_read_u32(q_node, "snps,map-to-dma-channel",
&plat->rx_queues_cfg[queue].chan))
plat->rx_queues_cfg[queue].chan = queue;
/* TODO: Dynamic mapping to be included in the future */
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;
}
/* 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;
queue++;
}
if (queue != plat->rx_queues_to_use) {
ret = -EINVAL;
dev_err(&pdev->dev, "Not all RX queues were configured\n");
goto out;
}
/* Processing TX queues common config */
if (of_property_read_u32(tx_node, "snps,tx-queues-to-use",
&plat->tx_queues_to_use))
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;
if (of_property_read_u32(q_node, "snps,weight",
&plat->tx_queues_cfg[queue].weight))
plat->tx_queues_cfg[queue].weight = 0x10 + queue;
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;
}
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;
}
plat->tx_queues_cfg[queue].coe_unsupported =
of_property_read_bool(q_node, "snps,coe-unsupported");
queue++;
}
if (queue != plat->tx_queues_to_use) {
ret = -EINVAL;
dev_err(&pdev->dev, "Not all TX queues were configured\n");
goto out;
}
out:
of_node_put(rx_node);
of_node_put(tx_node);
of_node_put(q_node);
return ret;
}
/**
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: &ethernet0 { 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"; }; }; }; &ethernet1 { 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
*
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: &ethernet0 { 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"; }; }; }; &ethernet1 { 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
*/
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: &ethernet0 { 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"; }; }; }; &ethernet1 { 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)
{
static const struct of_device_id need_mdio_ids[] = {
{ .compatible = "snps,dwc-qos-ethernet-4.10" },
{},
};
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: &ethernet0 { 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"; }; }; }; &ethernet1 { 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;
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: &ethernet0 { 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"; }; }; }; &ethernet1 { 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");
} 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: &ethernet0 { 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"; }; }; }; &ethernet1 { 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,
"snps,dwmac-mdio"))
break;
}
}
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: &ethernet0 { 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"; }; }; }; &ethernet1 { 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)
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: &ethernet0 { 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"; }; }; }; &ethernet1 { 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);
if (!plat->mdio_bus_data)
return -ENOMEM;
plat->mdio_bus_data->needs_reset = true;
}
return 0;
}
/**
* 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
* 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;
}
/**
* 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);
}
/**
* 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.
*/
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)
{
struct device_node *np = pdev->dev.of_node;
struct plat_stmmacenet_data *plat;
struct stmmac_dma_cfg *dma_cfg;
int phy_mode;
void *ret;
int rc;
plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
if (!plat)
return ERR_PTR(-ENOMEM);
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);
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);
}
phy_mode = device_get_phy_mode(&pdev->dev);
if (phy_mode < 0)
return ERR_PTR(phy_mode);
plat->phy_interface = phy_mode;
rc = stmmac_of_get_mac_mode(np);
plat->mac_interface = rc < 0 ? plat->phy_interface : rc;
/* 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 */
plat->port_node = of_fwnode_handle(np);
/* Get max speed of operation from device tree */
of_property_read_u32(np, "max-speed", &plat->max_speed);
plat->bus_id = of_alias_get_id(np, "ethernet");
if (plat->bus_id < 0)
plat->bus_id = 0;
/* Default to phy auto-detection */
plat->phy_addr = -1;
/* Default to get clk_csr from stmmac_clk_csr_set(),
* or get clk_csr from device tree.
*/
plat->clk_csr = -1;
if (of_property_read_u32(np, "snps,clk-csr", &plat->clk_csr))
of_property_read_u32(np, "clk_csr", &plat->clk_csr);
/* "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");
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: &ethernet0 { 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"; }; }; }; &ethernet1 { 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);
if (rc)
return ERR_PTR(rc);
of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);
of_property_read_u32(np, "rx-fifo-depth", &plat->rx_fifo_size);
plat->force_sf_dma_mode =
of_property_read_bool(np, "snps,force_sf_dma_mode");
if (of_property_read_bool(np, "snps,en-tx-lpi-clockgating"))
plat->flags |= STMMAC_FLAG_EN_TX_LPI_CLOCKGATING;
stmmac: Fix kernel crashes for jumbo frames These changes correct the following issues with jumbo frames on the stmmac driver: 1) The Synopsys EMAC can be configured to support different FIFO sizes at core configuration time. There's no way to query the controller and know the FIFO size, so the driver needs to get this information from the device tree in order to know how to correctly handle MTU changes and setting up dma buffers. The default max-frame-size is as currently used, which is the size of a jumbo frame. 2) The driver was enabling Jumbo frames by default, but was not allocating dma buffers of sufficient size to handle the maximum possible packet size that could be received. This led to memory corruption since DMAs were occurring beyond the extent of the allocated receive buffers for certain types of network traffic. kernel BUG at net/core/skbuff.c:126! Internal error: Oops - BUG: 0 [#1] SMP ARM Modules linked in: CPU: 0 PID: 563 Comm: sockperf Not tainted 3.13.0-rc6-01523-gf7111b9 #31 task: ef35e580 ti: ef252000 task.ti: ef252000 PC is at skb_panic+0x60/0x64 LR is at skb_panic+0x60/0x64 pc : [<c03c7c3c>] lr : [<c03c7c3c>] psr: 60000113 sp : ef253c18 ip : 60000113 fp : 00000000 r10: ef3a5400 r9 : 00000ebc r8 : ef3a546c r7 : ee59f000 r6 : ee59f084 r5 : ee59ff40 r4 : ee59f140 r3 : 000003e2 r2 : 00000007 r1 : c0b9c420 r0 : 0000007d Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c5387d Table: 2e8ac04a DAC: 00000015 Process sockperf (pid: 563, stack limit = 0xef252248) Stack: (0xef253c18 to 0xef254000) 3c00: 00000ebc ee59f000 3c20: ee59f084 ee59ff40 ee59f140 c04a9cd8 ee8c50c0 00000ebc ee59ff40 00000000 3c40: ee59f140 c02d0ef0 00000056 ef1eda80 ee8c50c0 00000ebc 22bbef29 c0318f8c 3c60: 00000056 ef3a547c ffe2c716 c02c9c90 c0ba1298 ef3a5838 ef3a5838 ef3a5400 3c80: 000020c0 ee573840 000055cb ef3f2050 c053f0e0 c0319214 22b9b085 22d92813 3ca0: 00001c80 004b8e00 ef3a5400 ee573840 ef3f2064 22d92813 ef3f2064 000055cb 3cc0: ef3f2050 c031a19c ef252000 00000000 00000000 c0561bc0 00000000 ff00ffff 3ce0: c05621c0 ef3a5400 ef3f2064 ee573840 00000020 ef3f2064 000055cb ef3f2050 3d00: c053f0e0 c031cad0 c053e740 00000e60 00000000 00000000 ee573840 ef3a5400 3d20: ef0a6e00 00000000 ef3f2064 c032507c 00010000 00000020 c0561bc0 c0561bc0 3d40: ee599850 c032799c 00000000 ee573840 c055a380 ef3a5400 00000000 ef3f2064 3d60: ef3f2050 c032799c 0101c7c0 2b6755cb c059a280 c030e4d8 000055cb ffffffff 3d80: ee574fc0 c055a380 ee574000 ee573840 00002b67 ee573840 c03fe9c4 c053fa68 3da0: c055a380 00001f6f 00000000 ee573840 c053f0e0 c0304fdc ef0a6e01 ef3f2050 3dc0: ee573858 ef031000 ee573840 c03055d8 c0ba0c40 ef000f40 00100100 c053f0dc 3de0: c053ffdc c053f0f0 00000008 00000000 ef031000 c02da948 00001140 00000000 3e00: c0563c78 ef253e5f 00000020 ee573840 00000020 c053f0f0 ef313400 ee573840 3e20: c053f0e0 00000000 00000000 c05380c0 ef313400 00001000 00000015 c02df280 3e40: ee574000 ef001e00 00000000 00001080 00000042 005cd980 ef031500 ef031500 3e60: 00000000 c02df824 ef031500 c053e390 c0541084 f00b1e00 c05925e8 c02df864 3e80: 00001f5c ef031440 c053e390 c0278524 00000002 00000000 c0b9eb48 c02df280 3ea0: ee8c7180 00000100 c0542ca8 00000015 00000040 ef031500 ef031500 ef031500 3ec0: c027803c ef252000 00000040 000000ec c05380c0 c0b9eb40 c0b9eb48 c02df940 3ee0: ef060780 ffffa4dd c0564a9c c056343c 002e80a8 00000080 ef031500 00000001 3f00: c053808c ef252000 fffec100 00000003 00000004 002e80a8 0000000c c00258f0 3f20: 002e80a8 c005e704 00000005 00000100 c05634d0 c0538080 c05333e0 00000000 3f40: 0000000a c0565580 c05380c0 ffffa4dc c05434f4 00400100 00000004 c0534cd4 3f60: 00000098 00000000 fffec100 002e80a8 00000004 002e80a8 002a20e0 c0025da8 3f80: c0534cd4 c000f020 fffec10c c053ea60 ef253fb0 c0008530 0000ffe2 b6ef67f4 3fa0: 40000010 ffffffff 00000124 c0012f3c 0000ffe2 002e80f0 0000ffe2 00004000 3fc0: becb6338 becb6334 00000004 00000124 002e80a8 00000004 002e80a8 002a20e0 3fe0: becb6300 becb62f4 002773bb b6ef67f4 40000010 ffffffff 00000000 00000000 [<c03c7c3c>] (skb_panic+0x60/0x64) from [<c02d0ef0>] (skb_put+0x4c/0x50) [<c02d0ef0>] (skb_put+0x4c/0x50) from [<c0318f8c>] (tcp_collapse+0x314/0x3ec) [<c0318f8c>] (tcp_collapse+0x314/0x3ec) from [<c0319214>] (tcp_try_rmem_schedule+0x1b0/0x3c4) [<c0319214>] (tcp_try_rmem_schedule+0x1b0/0x3c4) from [<c031a19c>] (tcp_data_queue+0x480/0xe6c) [<c031a19c>] (tcp_data_queue+0x480/0xe6c) from [<c031cad0>] (tcp_rcv_established+0x180/0x62c) [<c031cad0>] (tcp_rcv_established+0x180/0x62c) from [<c032507c>] (tcp_v4_do_rcv+0x13c/0x31c) [<c032507c>] (tcp_v4_do_rcv+0x13c/0x31c) from [<c032799c>] (tcp_v4_rcv+0x718/0x73c) [<c032799c>] (tcp_v4_rcv+0x718/0x73c) from [<c0304fdc>] (ip_local_deliver+0x98/0x274) [<c0304fdc>] (ip_local_deliver+0x98/0x274) from [<c03055d8>] (ip_rcv+0x420/0x758) [<c03055d8>] (ip_rcv+0x420/0x758) from [<c02da948>] (__netif_receive_skb_core+0x44c/0x5bc) [<c02da948>] (__netif_receive_skb_core+0x44c/0x5bc) from [<c02df280>] (netif_receive_skb+0x48/0xb4) [<c02df280>] (netif_receive_skb+0x48/0xb4) from [<c02df824>] (napi_gro_flush+0x70/0x94) [<c02df824>] (napi_gro_flush+0x70/0x94) from [<c02df864>] (napi_complete+0x1c/0x34) [<c02df864>] (napi_complete+0x1c/0x34) from [<c0278524>] (stmmac_poll+0x4e8/0x5c8) [<c0278524>] (stmmac_poll+0x4e8/0x5c8) from [<c02df940>] (net_rx_action+0xc4/0x1e4) [<c02df940>] (net_rx_action+0xc4/0x1e4) from [<c00258f0>] (__do_softirq+0x12c/0x2e8) [<c00258f0>] (__do_softirq+0x12c/0x2e8) from [<c0025da8>] (irq_exit+0x78/0xac) [<c0025da8>] (irq_exit+0x78/0xac) from [<c000f020>] (handle_IRQ+0x44/0x90) [<c000f020>] (handle_IRQ+0x44/0x90) from [<c0008530>] (gic_handle_irq+0x2c/0x5c) [<c0008530>] (gic_handle_irq+0x2c/0x5c) from [<c0012f3c>] (__irq_usr+0x3c/0x60) 3) The driver was setting the dma buffer size after allocating dma buffers, which caused a system panic when changing the MTU. BUG: Bad page state in process ifconfig pfn:2e850 page:c0b72a00 count:0 mapcount:0 mapping: (null) index:0x0 page flags: 0x200(arch_1) Modules linked in: CPU: 0 PID: 566 Comm: ifconfig Not tainted 3.13.0-rc6-01523-gf7111b9 #29 [<c001547c>] (unwind_backtrace+0x0/0xf8) from [<c00122dc>] (show_stack+0x10/0x14) [<c00122dc>] (show_stack+0x10/0x14) from [<c03c793c>] (dump_stack+0x70/0x88) [<c03c793c>] (dump_stack+0x70/0x88) from [<c00b2620>] (bad_page+0xc8/0x118) [<c00b2620>] (bad_page+0xc8/0x118) from [<c00b302c>] (get_page_from_freelist+0x744/0x870) [<c00b302c>] (get_page_from_freelist+0x744/0x870) from [<c00b40f4>] (__alloc_pages_nodemask+0x118/0x86c) [<c00b40f4>] (__alloc_pages_nodemask+0x118/0x86c) from [<c00b4858>] (__get_free_pages+0x10/0x54) [<c00b4858>] (__get_free_pages+0x10/0x54) from [<c00cba1c>] (kmalloc_order_trace+0x24/0xa0) [<c00cba1c>] (kmalloc_order_trace+0x24/0xa0) from [<c02d199c>] (__kmalloc_reserve.isra.21+0x24/0x70) [<c02d199c>] (__kmalloc_reserve.isra.21+0x24/0x70) from [<c02d240c>] (__alloc_skb+0x68/0x13c) [<c02d240c>] (__alloc_skb+0x68/0x13c) from [<c02d3930>] (__netdev_alloc_skb+0x3c/0xe8) [<c02d3930>] (__netdev_alloc_skb+0x3c/0xe8) from [<c0279378>] (stmmac_open+0x63c/0x1024) [<c0279378>] (stmmac_open+0x63c/0x1024) from [<c02e18cc>] (__dev_open+0xa0/0xfc) [<c02e18cc>] (__dev_open+0xa0/0xfc) from [<c02e1b40>] (__dev_change_flags+0x94/0x158) [<c02e1b40>] (__dev_change_flags+0x94/0x158) from [<c02e1c24>] (dev_change_flags+0x18/0x48) [<c02e1c24>] (dev_change_flags+0x18/0x48) from [<c0337bc0>] (devinet_ioctl+0x638/0x700) [<c0337bc0>] (devinet_ioctl+0x638/0x700) from [<c02c7aec>] (sock_ioctl+0x64/0x290) [<c02c7aec>] (sock_ioctl+0x64/0x290) from [<c0100890>] (do_vfs_ioctl+0x78/0x5b8) [<c0100890>] (do_vfs_ioctl+0x78/0x5b8) from [<c0100e0c>] (SyS_ioctl+0x3c/0x5c) [<c0100e0c>] (SyS_ioctl+0x3c/0x5c) from [<c000e760>] The fixes have been verified using reproducible, automated testing. Signed-off-by: Vince Bridgers <vbridgers2013@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
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;
/* 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;
/*
* Currently only the properties needed on SPEAr600
* are provided. All other properties should be added
* once needed on other platforms.
*/
if (of_device_is_compatible(np, "st,spear600-gmac") ||
of_device_is_compatible(np, "snps,dwmac-3.50a") ||
of_device_is_compatible(np, "snps,dwmac-3.70a") ||
of_device_is_compatible(np, "snps,dwmac")) {
stmmac: Fix kernel crashes for jumbo frames These changes correct the following issues with jumbo frames on the stmmac driver: 1) The Synopsys EMAC can be configured to support different FIFO sizes at core configuration time. There's no way to query the controller and know the FIFO size, so the driver needs to get this information from the device tree in order to know how to correctly handle MTU changes and setting up dma buffers. The default max-frame-size is as currently used, which is the size of a jumbo frame. 2) The driver was enabling Jumbo frames by default, but was not allocating dma buffers of sufficient size to handle the maximum possible packet size that could be received. This led to memory corruption since DMAs were occurring beyond the extent of the allocated receive buffers for certain types of network traffic. kernel BUG at net/core/skbuff.c:126! Internal error: Oops - BUG: 0 [#1] SMP ARM Modules linked in: CPU: 0 PID: 563 Comm: sockperf Not tainted 3.13.0-rc6-01523-gf7111b9 #31 task: ef35e580 ti: ef252000 task.ti: ef252000 PC is at skb_panic+0x60/0x64 LR is at skb_panic+0x60/0x64 pc : [<c03c7c3c>] lr : [<c03c7c3c>] psr: 60000113 sp : ef253c18 ip : 60000113 fp : 00000000 r10: ef3a5400 r9 : 00000ebc r8 : ef3a546c r7 : ee59f000 r6 : ee59f084 r5 : ee59ff40 r4 : ee59f140 r3 : 000003e2 r2 : 00000007 r1 : c0b9c420 r0 : 0000007d Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c5387d Table: 2e8ac04a DAC: 00000015 Process sockperf (pid: 563, stack limit = 0xef252248) Stack: (0xef253c18 to 0xef254000) 3c00: 00000ebc ee59f000 3c20: ee59f084 ee59ff40 ee59f140 c04a9cd8 ee8c50c0 00000ebc ee59ff40 00000000 3c40: ee59f140 c02d0ef0 00000056 ef1eda80 ee8c50c0 00000ebc 22bbef29 c0318f8c 3c60: 00000056 ef3a547c ffe2c716 c02c9c90 c0ba1298 ef3a5838 ef3a5838 ef3a5400 3c80: 000020c0 ee573840 000055cb ef3f2050 c053f0e0 c0319214 22b9b085 22d92813 3ca0: 00001c80 004b8e00 ef3a5400 ee573840 ef3f2064 22d92813 ef3f2064 000055cb 3cc0: ef3f2050 c031a19c ef252000 00000000 00000000 c0561bc0 00000000 ff00ffff 3ce0: c05621c0 ef3a5400 ef3f2064 ee573840 00000020 ef3f2064 000055cb ef3f2050 3d00: c053f0e0 c031cad0 c053e740 00000e60 00000000 00000000 ee573840 ef3a5400 3d20: ef0a6e00 00000000 ef3f2064 c032507c 00010000 00000020 c0561bc0 c0561bc0 3d40: ee599850 c032799c 00000000 ee573840 c055a380 ef3a5400 00000000 ef3f2064 3d60: ef3f2050 c032799c 0101c7c0 2b6755cb c059a280 c030e4d8 000055cb ffffffff 3d80: ee574fc0 c055a380 ee574000 ee573840 00002b67 ee573840 c03fe9c4 c053fa68 3da0: c055a380 00001f6f 00000000 ee573840 c053f0e0 c0304fdc ef0a6e01 ef3f2050 3dc0: ee573858 ef031000 ee573840 c03055d8 c0ba0c40 ef000f40 00100100 c053f0dc 3de0: c053ffdc c053f0f0 00000008 00000000 ef031000 c02da948 00001140 00000000 3e00: c0563c78 ef253e5f 00000020 ee573840 00000020 c053f0f0 ef313400 ee573840 3e20: c053f0e0 00000000 00000000 c05380c0 ef313400 00001000 00000015 c02df280 3e40: ee574000 ef001e00 00000000 00001080 00000042 005cd980 ef031500 ef031500 3e60: 00000000 c02df824 ef031500 c053e390 c0541084 f00b1e00 c05925e8 c02df864 3e80: 00001f5c ef031440 c053e390 c0278524 00000002 00000000 c0b9eb48 c02df280 3ea0: ee8c7180 00000100 c0542ca8 00000015 00000040 ef031500 ef031500 ef031500 3ec0: c027803c ef252000 00000040 000000ec c05380c0 c0b9eb40 c0b9eb48 c02df940 3ee0: ef060780 ffffa4dd c0564a9c c056343c 002e80a8 00000080 ef031500 00000001 3f00: c053808c ef252000 fffec100 00000003 00000004 002e80a8 0000000c c00258f0 3f20: 002e80a8 c005e704 00000005 00000100 c05634d0 c0538080 c05333e0 00000000 3f40: 0000000a c0565580 c05380c0 ffffa4dc c05434f4 00400100 00000004 c0534cd4 3f60: 00000098 00000000 fffec100 002e80a8 00000004 002e80a8 002a20e0 c0025da8 3f80: c0534cd4 c000f020 fffec10c c053ea60 ef253fb0 c0008530 0000ffe2 b6ef67f4 3fa0: 40000010 ffffffff 00000124 c0012f3c 0000ffe2 002e80f0 0000ffe2 00004000 3fc0: becb6338 becb6334 00000004 00000124 002e80a8 00000004 002e80a8 002a20e0 3fe0: becb6300 becb62f4 002773bb b6ef67f4 40000010 ffffffff 00000000 00000000 [<c03c7c3c>] (skb_panic+0x60/0x64) from [<c02d0ef0>] (skb_put+0x4c/0x50) [<c02d0ef0>] (skb_put+0x4c/0x50) from [<c0318f8c>] (tcp_collapse+0x314/0x3ec) [<c0318f8c>] (tcp_collapse+0x314/0x3ec) from [<c0319214>] (tcp_try_rmem_schedule+0x1b0/0x3c4) [<c0319214>] (tcp_try_rmem_schedule+0x1b0/0x3c4) from [<c031a19c>] (tcp_data_queue+0x480/0xe6c) [<c031a19c>] (tcp_data_queue+0x480/0xe6c) from [<c031cad0>] (tcp_rcv_established+0x180/0x62c) [<c031cad0>] (tcp_rcv_established+0x180/0x62c) from [<c032507c>] (tcp_v4_do_rcv+0x13c/0x31c) [<c032507c>] (tcp_v4_do_rcv+0x13c/0x31c) from [<c032799c>] (tcp_v4_rcv+0x718/0x73c) [<c032799c>] (tcp_v4_rcv+0x718/0x73c) from [<c0304fdc>] (ip_local_deliver+0x98/0x274) [<c0304fdc>] (ip_local_deliver+0x98/0x274) from [<c03055d8>] (ip_rcv+0x420/0x758) [<c03055d8>] (ip_rcv+0x420/0x758) from [<c02da948>] (__netif_receive_skb_core+0x44c/0x5bc) [<c02da948>] (__netif_receive_skb_core+0x44c/0x5bc) from [<c02df280>] (netif_receive_skb+0x48/0xb4) [<c02df280>] (netif_receive_skb+0x48/0xb4) from [<c02df824>] (napi_gro_flush+0x70/0x94) [<c02df824>] (napi_gro_flush+0x70/0x94) from [<c02df864>] (napi_complete+0x1c/0x34) [<c02df864>] (napi_complete+0x1c/0x34) from [<c0278524>] (stmmac_poll+0x4e8/0x5c8) [<c0278524>] (stmmac_poll+0x4e8/0x5c8) from [<c02df940>] (net_rx_action+0xc4/0x1e4) [<c02df940>] (net_rx_action+0xc4/0x1e4) from [<c00258f0>] (__do_softirq+0x12c/0x2e8) [<c00258f0>] (__do_softirq+0x12c/0x2e8) from [<c0025da8>] (irq_exit+0x78/0xac) [<c0025da8>] (irq_exit+0x78/0xac) from [<c000f020>] (handle_IRQ+0x44/0x90) [<c000f020>] (handle_IRQ+0x44/0x90) from [<c0008530>] (gic_handle_irq+0x2c/0x5c) [<c0008530>] (gic_handle_irq+0x2c/0x5c) from [<c0012f3c>] (__irq_usr+0x3c/0x60) 3) The driver was setting the dma buffer size after allocating dma buffers, which caused a system panic when changing the MTU. BUG: Bad page state in process ifconfig pfn:2e850 page:c0b72a00 count:0 mapcount:0 mapping: (null) index:0x0 page flags: 0x200(arch_1) Modules linked in: CPU: 0 PID: 566 Comm: ifconfig Not tainted 3.13.0-rc6-01523-gf7111b9 #29 [<c001547c>] (unwind_backtrace+0x0/0xf8) from [<c00122dc>] (show_stack+0x10/0x14) [<c00122dc>] (show_stack+0x10/0x14) from [<c03c793c>] (dump_stack+0x70/0x88) [<c03c793c>] (dump_stack+0x70/0x88) from [<c00b2620>] (bad_page+0xc8/0x118) [<c00b2620>] (bad_page+0xc8/0x118) from [<c00b302c>] (get_page_from_freelist+0x744/0x870) [<c00b302c>] (get_page_from_freelist+0x744/0x870) from [<c00b40f4>] (__alloc_pages_nodemask+0x118/0x86c) [<c00b40f4>] (__alloc_pages_nodemask+0x118/0x86c) from [<c00b4858>] (__get_free_pages+0x10/0x54) [<c00b4858>] (__get_free_pages+0x10/0x54) from [<c00cba1c>] (kmalloc_order_trace+0x24/0xa0) [<c00cba1c>] (kmalloc_order_trace+0x24/0xa0) from [<c02d199c>] (__kmalloc_reserve.isra.21+0x24/0x70) [<c02d199c>] (__kmalloc_reserve.isra.21+0x24/0x70) from [<c02d240c>] (__alloc_skb+0x68/0x13c) [<c02d240c>] (__alloc_skb+0x68/0x13c) from [<c02d3930>] (__netdev_alloc_skb+0x3c/0xe8) [<c02d3930>] (__netdev_alloc_skb+0x3c/0xe8) from [<c0279378>] (stmmac_open+0x63c/0x1024) [<c0279378>] (stmmac_open+0x63c/0x1024) from [<c02e18cc>] (__dev_open+0xa0/0xfc) [<c02e18cc>] (__dev_open+0xa0/0xfc) from [<c02e1b40>] (__dev_change_flags+0x94/0x158) [<c02e1b40>] (__dev_change_flags+0x94/0x158) from [<c02e1c24>] (dev_change_flags+0x18/0x48) [<c02e1c24>] (dev_change_flags+0x18/0x48) from [<c0337bc0>] (devinet_ioctl+0x638/0x700) [<c0337bc0>] (devinet_ioctl+0x638/0x700) from [<c02c7aec>] (sock_ioctl+0x64/0x290) [<c02c7aec>] (sock_ioctl+0x64/0x290) from [<c0100890>] (do_vfs_ioctl+0x78/0x5b8) [<c0100890>] (do_vfs_ioctl+0x78/0x5b8) from [<c0100e0c>] (SyS_ioctl+0x3c/0x5c) [<c0100e0c>] (SyS_ioctl+0x3c/0x5c) from [<c000e760>] The fixes have been verified using reproducible, automated testing. Signed-off-by: Vince Bridgers <vbridgers2013@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
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);
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(
&pdev->dev, plat->unicast_filter_entries);
plat->multicast_filter_bins = dwmac1000_validate_mcast_bins(
&pdev->dev, plat->multicast_filter_bins);
plat->has_gmac = 1;
plat->pmt = 1;
}
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;
}
if (of_device_is_compatible(np, "snps,dwmac-4.00") ||
of_device_is_compatible(np, "snps,dwmac-4.10a") ||
of_device_is_compatible(np, "snps,dwmac-4.20a") ||
of_device_is_compatible(np, "snps,dwmac-5.10a") ||
of_device_is_compatible(np, "snps,dwmac-5.20")) {
plat->has_gmac4 = 1;
plat->has_gmac = 0;
plat->pmt = 1;
if (of_property_read_bool(np, "snps,tso"))
plat->flags |= STMMAC_FLAG_TSO_EN;
}
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;
}
if (of_device_is_compatible(np, "snps,dwxgmac")) {
plat->has_xgmac = 1;
plat->pmt = 1;
if (of_property_read_bool(np, "snps,tso"))
plat->flags |= STMMAC_FLAG_TSO_EN;
}
dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
GFP_KERNEL);
if (!dma_cfg) {
stmmac_remove_config_dt(pdev, plat);
return ERR_PTR(-ENOMEM);
}
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;
of_property_read_u32(np, "snps,txpbl", &dma_cfg->txpbl);
of_property_read_u32(np, "snps,rxpbl", &dma_cfg->rxpbl);
dma_cfg->pblx8 = !of_property_read_bool(np, "snps,no-pbl-x8");
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");
plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
if (plat->force_thresh_dma_mode && plat->force_sf_dma_mode) {
plat->force_sf_dma_mode = 0;
dev_warn(&pdev->dev,
"force_sf_dma_mode is ignored if force_thresh_dma_mode is set.\n");
}
of_property_read_u32(np, "snps,ps-speed", &plat->mac_port_sel_speed);
plat->axi = stmmac_axi_setup(pdev);
rc = stmmac_mtl_setup(pdev, plat);
if (rc) {
stmmac_remove_config_dt(pdev, plat);
return ERR_PTR(rc);
}
/* clock setup */
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);
}
plat->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
if (IS_ERR(plat->pclk)) {
ret = plat->pclk;
goto error_pclk_get;
}
clk_prepare_enable(plat->pclk);
/* Fall-back to main clock in case of no PTP ref is passed */
plat->clk_ptp_ref = devm_clk_get(&pdev->dev, "ptp_ref");
if (IS_ERR(plat->clk_ptp_ref)) {
plat->clk_ptp_rate = clk_get_rate(plat->stmmac_clk);
plat->clk_ptp_ref = NULL;
dev_info(&pdev->dev, "PTP uses main clock\n");
} else {
plat->clk_ptp_rate = clk_get_rate(plat->clk_ptp_ref);
dev_dbg(&pdev->dev, "PTP rate %d\n", plat->clk_ptp_rate);
}
plat->stmmac_rst = devm_reset_control_get_optional(&pdev->dev,
STMMAC_RESOURCE_NAME);
if (IS_ERR(plat->stmmac_rst)) {
ret = plat->stmmac_rst;
goto error_hw_init;
}
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;
}
return plat;
error_hw_init:
clk_disable_unprepare(plat->pclk);
error_pclk_get:
clk_disable_unprepare(plat->stmmac_clk);
return ret;
}
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;
}
#else
struct plat_stmmacenet_data *
devm_stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
{
return ERR_PTR(-EINVAL);
}
#endif /* CONFIG_OF */
EXPORT_SYMBOL_GPL(devm_stmmac_probe_config_dt);
int stmmac_get_platform_resources(struct platform_device *pdev,
struct stmmac_resources *stmmac_res)
{
memset(stmmac_res, 0, sizeof(*stmmac_res));
stmmac: check IRQ availability early on probe Currently we're getting IRQs after lots of resources are already allocated: * netdev * clocks * MDIO bus Also HW gets initialized by the time when checking IRQs as well. Now there's a possibility for master interrupt controller to be not probed yet. This will lead to exit from GMAC probe routine with "- EPROBE_DEFER" and so deferred probe will hapen later on. But since we exited the first GMAC probe without release of all allocated resources there could be conflicts on subsequent probes. For example this is what happens for me: --->8--- stmmaceth e0018000.ethernet: no reset control found stmmac - user ID: 0x10, Synopsys ID: 0x37 Ring mode enabled DMA HW capability register supported Normal descriptors RX Checksum Offload Engine supported (type 2) TX Checksum insertion supported Enable RX Mitigation via HW Watchdog Timer libphy: stmmac: probed eth0: PHY ID 20005c7a at 1 IRQ POLL (stmmac-0:01) active platform e0018000.ethernet: Driver stmmaceth requests probe deferral ... ... ... stmmaceth e0018000.ethernet: no reset control found stmmac - user ID: 0x10, Synopsys ID: 0x37 Ring mode enabled DMA HW capability register supported Normal descriptors RX Checksum Offload Engine supported (type 2) TX Checksum insertion supported Enable RX Mitigation via HW Watchdog Timer ------------[ cut here ]------------ WARNING: CPU: 0 PID: 6 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x4e/0x68() sysfs: cannot create duplicate filename '/devices/platform/axs10x_mb/e0018000.ethernet/mdio_bus/stmmac-0' CPU: 0 PID: 6 Comm: kworker/u2:0 Not tainted 4.0.0-rc1-next-20150303+#8 Workqueue: deferwq deferred_probe_work_func Stack Trace: arc_unwind_core+0xb8/0x114 warn_slowpath_common+0x5a/0x8c warn_slowpath_fmt+0x2e/0x38 sysfs_warn_dup+0x4e/0x68 sysfs_create_dir_ns+0x98/0xa0 kobject_add_internal+0x8c/0x2e8 kobject_add+0x4a/0x8c device_add+0xc6/0x448 mdiobus_register+0x6c/0x164 stmmac_mdio_register+0x112/0x264 stmmac_dvr_probe+0x6c0/0x85c stmmac_pltfr_probe+0x2e4/0x50c platform_drv_probe+0x26/0x5c really_probe+0x76/0x1dc bus_for_each_drv+0x42/0x7c device_attach+0x64/0x6c bus_probe_device+0x74/0xa4 deferred_probe_work_func+0x50/0x84 process_one_work+0xf8/0x2cc worker_thread+0x110/0x478 kthread+0x8a/0x9c ret_from_fork+0x14/0x18 ---[ end trace a2dfaa7d630c8be1 ]--- ------------[ cut here ]------------ WARNING: CPU: 0 PID: 6 at lib/kobject.c:240 kobject_add_internal+0x218/0x2e8() kobject_add_internal failed for stmmac-0 with -EEXIST, don't try to register things with the same name in the same di. CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 4.0.0-rc1-next-20150303+ #8 Workqueue: deferwq deferred_probe_work_func Stack Trace: arc_unwind_core+0xb8/0x114 warn_slowpath_common+0x5a/0x8c warn_slowpath_fmt+0x2e/0x38 kobject_add_internal+0x218/0x2e8 kobject_add+0x4a/0x8c device_add+0xc6/0x448 mdiobus_register+0x6c/0x164 stmmac_mdio_register+0x112/0x264 stmmac_dvr_probe+0x6c0/0x85c stmmac_pltfr_probe+0x2e4/0x50c platform_drv_probe+0x26/0x5c really_probe+0x76/0x1dc bus_for_each_drv+0x42/0x7c device_attach+0x64/0x6c bus_probe_device+0x74/0xa4 deferred_probe_work_func+0x50/0x84 process_one_work+0xf8/0x2cc worker_thread+0x110/0x478 kthread+0x8a/0x9c ret_from_fork+0x14/0x18 ---[ end trace a2dfaa7d630c8be2 ]--- libphy: mii_bus stmmac-0 failed to register : Cannot register as MDIO bus stmmac_pltfr_probe: main driver probe failed stmmaceth: probe of e0018000.ethernet failed with error -22 --->8--- Essential fix is to check for IRQs availability as early as possible and then safely go to deferred probe if IRQs are not there yet. Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com> Cc: Sonic Zhang <sonic.zhang@analog.com> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: David S. Miller <davem@davemloft.net>
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.
*/
stmmac_res->irq = platform_get_irq_byname(pdev, "macirq");
if (stmmac_res->irq < 0)
return stmmac_res->irq;
stmmac: check IRQ availability early on probe Currently we're getting IRQs after lots of resources are already allocated: * netdev * clocks * MDIO bus Also HW gets initialized by the time when checking IRQs as well. Now there's a possibility for master interrupt controller to be not probed yet. This will lead to exit from GMAC probe routine with "- EPROBE_DEFER" and so deferred probe will hapen later on. But since we exited the first GMAC probe without release of all allocated resources there could be conflicts on subsequent probes. For example this is what happens for me: --->8--- stmmaceth e0018000.ethernet: no reset control found stmmac - user ID: 0x10, Synopsys ID: 0x37 Ring mode enabled DMA HW capability register supported Normal descriptors RX Checksum Offload Engine supported (type 2) TX Checksum insertion supported Enable RX Mitigation via HW Watchdog Timer libphy: stmmac: probed eth0: PHY ID 20005c7a at 1 IRQ POLL (stmmac-0:01) active platform e0018000.ethernet: Driver stmmaceth requests probe deferral ... ... ... stmmaceth e0018000.ethernet: no reset control found stmmac - user ID: 0x10, Synopsys ID: 0x37 Ring mode enabled DMA HW capability register supported Normal descriptors RX Checksum Offload Engine supported (type 2) TX Checksum insertion supported Enable RX Mitigation via HW Watchdog Timer ------------[ cut here ]------------ WARNING: CPU: 0 PID: 6 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x4e/0x68() sysfs: cannot create duplicate filename '/devices/platform/axs10x_mb/e0018000.ethernet/mdio_bus/stmmac-0' CPU: 0 PID: 6 Comm: kworker/u2:0 Not tainted 4.0.0-rc1-next-20150303+#8 Workqueue: deferwq deferred_probe_work_func Stack Trace: arc_unwind_core+0xb8/0x114 warn_slowpath_common+0x5a/0x8c warn_slowpath_fmt+0x2e/0x38 sysfs_warn_dup+0x4e/0x68 sysfs_create_dir_ns+0x98/0xa0 kobject_add_internal+0x8c/0x2e8 kobject_add+0x4a/0x8c device_add+0xc6/0x448 mdiobus_register+0x6c/0x164 stmmac_mdio_register+0x112/0x264 stmmac_dvr_probe+0x6c0/0x85c stmmac_pltfr_probe+0x2e4/0x50c platform_drv_probe+0x26/0x5c really_probe+0x76/0x1dc bus_for_each_drv+0x42/0x7c device_attach+0x64/0x6c bus_probe_device+0x74/0xa4 deferred_probe_work_func+0x50/0x84 process_one_work+0xf8/0x2cc worker_thread+0x110/0x478 kthread+0x8a/0x9c ret_from_fork+0x14/0x18 ---[ end trace a2dfaa7d630c8be1 ]--- ------------[ cut here ]------------ WARNING: CPU: 0 PID: 6 at lib/kobject.c:240 kobject_add_internal+0x218/0x2e8() kobject_add_internal failed for stmmac-0 with -EEXIST, don't try to register things with the same name in the same di. CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 4.0.0-rc1-next-20150303+ #8 Workqueue: deferwq deferred_probe_work_func Stack Trace: arc_unwind_core+0xb8/0x114 warn_slowpath_common+0x5a/0x8c warn_slowpath_fmt+0x2e/0x38 kobject_add_internal+0x218/0x2e8 kobject_add+0x4a/0x8c device_add+0xc6/0x448 mdiobus_register+0x6c/0x164 stmmac_mdio_register+0x112/0x264 stmmac_dvr_probe+0x6c0/0x85c stmmac_pltfr_probe+0x2e4/0x50c platform_drv_probe+0x26/0x5c really_probe+0x76/0x1dc bus_for_each_drv+0x42/0x7c device_attach+0x64/0x6c bus_probe_device+0x74/0xa4 deferred_probe_work_func+0x50/0x84 process_one_work+0xf8/0x2cc worker_thread+0x110/0x478 kthread+0x8a/0x9c ret_from_fork+0x14/0x18 ---[ end trace a2dfaa7d630c8be2 ]--- libphy: mii_bus stmmac-0 failed to register : Cannot register as MDIO bus stmmac_pltfr_probe: main driver probe failed stmmaceth: probe of e0018000.ethernet failed with error -22 --->8--- Essential fix is to check for IRQs availability as early as possible and then safely go to deferred probe if IRQs are not there yet. Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com> Cc: Sonic Zhang <sonic.zhang@analog.com> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: David S. Miller <davem@davemloft.net>
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)
*/
stmmac_res->wol_irq =
platform_get_irq_byname_optional(pdev, "eth_wake_irq");
if (stmmac_res->wol_irq < 0) {
if (stmmac_res->wol_irq == -EPROBE_DEFER)
stmmac: check IRQ availability early on probe Currently we're getting IRQs after lots of resources are already allocated: * netdev * clocks * MDIO bus Also HW gets initialized by the time when checking IRQs as well. Now there's a possibility for master interrupt controller to be not probed yet. This will lead to exit from GMAC probe routine with "- EPROBE_DEFER" and so deferred probe will hapen later on. But since we exited the first GMAC probe without release of all allocated resources there could be conflicts on subsequent probes. For example this is what happens for me: --->8--- stmmaceth e0018000.ethernet: no reset control found stmmac - user ID: 0x10, Synopsys ID: 0x37 Ring mode enabled DMA HW capability register supported Normal descriptors RX Checksum Offload Engine supported (type 2) TX Checksum insertion supported Enable RX Mitigation via HW Watchdog Timer libphy: stmmac: probed eth0: PHY ID 20005c7a at 1 IRQ POLL (stmmac-0:01) active platform e0018000.ethernet: Driver stmmaceth requests probe deferral ... ... ... stmmaceth e0018000.ethernet: no reset control found stmmac - user ID: 0x10, Synopsys ID: 0x37 Ring mode enabled DMA HW capability register supported Normal descriptors RX Checksum Offload Engine supported (type 2) TX Checksum insertion supported Enable RX Mitigation via HW Watchdog Timer ------------[ cut here ]------------ WARNING: CPU: 0 PID: 6 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x4e/0x68() sysfs: cannot create duplicate filename '/devices/platform/axs10x_mb/e0018000.ethernet/mdio_bus/stmmac-0' CPU: 0 PID: 6 Comm: kworker/u2:0 Not tainted 4.0.0-rc1-next-20150303+#8 Workqueue: deferwq deferred_probe_work_func Stack Trace: arc_unwind_core+0xb8/0x114 warn_slowpath_common+0x5a/0x8c warn_slowpath_fmt+0x2e/0x38 sysfs_warn_dup+0x4e/0x68 sysfs_create_dir_ns+0x98/0xa0 kobject_add_internal+0x8c/0x2e8 kobject_add+0x4a/0x8c device_add+0xc6/0x448 mdiobus_register+0x6c/0x164 stmmac_mdio_register+0x112/0x264 stmmac_dvr_probe+0x6c0/0x85c stmmac_pltfr_probe+0x2e4/0x50c platform_drv_probe+0x26/0x5c really_probe+0x76/0x1dc bus_for_each_drv+0x42/0x7c device_attach+0x64/0x6c bus_probe_device+0x74/0xa4 deferred_probe_work_func+0x50/0x84 process_one_work+0xf8/0x2cc worker_thread+0x110/0x478 kthread+0x8a/0x9c ret_from_fork+0x14/0x18 ---[ end trace a2dfaa7d630c8be1 ]--- ------------[ cut here ]------------ WARNING: CPU: 0 PID: 6 at lib/kobject.c:240 kobject_add_internal+0x218/0x2e8() kobject_add_internal failed for stmmac-0 with -EEXIST, don't try to register things with the same name in the same di. CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 4.0.0-rc1-next-20150303+ #8 Workqueue: deferwq deferred_probe_work_func Stack Trace: arc_unwind_core+0xb8/0x114 warn_slowpath_common+0x5a/0x8c warn_slowpath_fmt+0x2e/0x38 kobject_add_internal+0x218/0x2e8 kobject_add+0x4a/0x8c device_add+0xc6/0x448 mdiobus_register+0x6c/0x164 stmmac_mdio_register+0x112/0x264 stmmac_dvr_probe+0x6c0/0x85c stmmac_pltfr_probe+0x2e4/0x50c platform_drv_probe+0x26/0x5c really_probe+0x76/0x1dc bus_for_each_drv+0x42/0x7c device_attach+0x64/0x6c bus_probe_device+0x74/0xa4 deferred_probe_work_func+0x50/0x84 process_one_work+0xf8/0x2cc worker_thread+0x110/0x478 kthread+0x8a/0x9c ret_from_fork+0x14/0x18 ---[ end trace a2dfaa7d630c8be2 ]--- libphy: mii_bus stmmac-0 failed to register : Cannot register as MDIO bus stmmac_pltfr_probe: main driver probe failed stmmaceth: probe of e0018000.ethernet failed with error -22 --->8--- Essential fix is to check for IRQs availability as early as possible and then safely go to deferred probe if IRQs are not there yet. Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com> Cc: Sonic Zhang <sonic.zhang@analog.com> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-03 13:46:44 +03:00
return -EPROBE_DEFER;
dev_info(&pdev->dev, "IRQ eth_wake_irq not found\n");
stmmac_res->wol_irq = stmmac_res->irq;
stmmac: check IRQ availability early on probe Currently we're getting IRQs after lots of resources are already allocated: * netdev * clocks * MDIO bus Also HW gets initialized by the time when checking IRQs as well. Now there's a possibility for master interrupt controller to be not probed yet. This will lead to exit from GMAC probe routine with "- EPROBE_DEFER" and so deferred probe will hapen later on. But since we exited the first GMAC probe without release of all allocated resources there could be conflicts on subsequent probes. For example this is what happens for me: --->8--- stmmaceth e0018000.ethernet: no reset control found stmmac - user ID: 0x10, Synopsys ID: 0x37 Ring mode enabled DMA HW capability register supported Normal descriptors RX Checksum Offload Engine supported (type 2) TX Checksum insertion supported Enable RX Mitigation via HW Watchdog Timer libphy: stmmac: probed eth0: PHY ID 20005c7a at 1 IRQ POLL (stmmac-0:01) active platform e0018000.ethernet: Driver stmmaceth requests probe deferral ... ... ... stmmaceth e0018000.ethernet: no reset control found stmmac - user ID: 0x10, Synopsys ID: 0x37 Ring mode enabled DMA HW capability register supported Normal descriptors RX Checksum Offload Engine supported (type 2) TX Checksum insertion supported Enable RX Mitigation via HW Watchdog Timer ------------[ cut here ]------------ WARNING: CPU: 0 PID: 6 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x4e/0x68() sysfs: cannot create duplicate filename '/devices/platform/axs10x_mb/e0018000.ethernet/mdio_bus/stmmac-0' CPU: 0 PID: 6 Comm: kworker/u2:0 Not tainted 4.0.0-rc1-next-20150303+#8 Workqueue: deferwq deferred_probe_work_func Stack Trace: arc_unwind_core+0xb8/0x114 warn_slowpath_common+0x5a/0x8c warn_slowpath_fmt+0x2e/0x38 sysfs_warn_dup+0x4e/0x68 sysfs_create_dir_ns+0x98/0xa0 kobject_add_internal+0x8c/0x2e8 kobject_add+0x4a/0x8c device_add+0xc6/0x448 mdiobus_register+0x6c/0x164 stmmac_mdio_register+0x112/0x264 stmmac_dvr_probe+0x6c0/0x85c stmmac_pltfr_probe+0x2e4/0x50c platform_drv_probe+0x26/0x5c really_probe+0x76/0x1dc bus_for_each_drv+0x42/0x7c device_attach+0x64/0x6c bus_probe_device+0x74/0xa4 deferred_probe_work_func+0x50/0x84 process_one_work+0xf8/0x2cc worker_thread+0x110/0x478 kthread+0x8a/0x9c ret_from_fork+0x14/0x18 ---[ end trace a2dfaa7d630c8be1 ]--- ------------[ cut here ]------------ WARNING: CPU: 0 PID: 6 at lib/kobject.c:240 kobject_add_internal+0x218/0x2e8() kobject_add_internal failed for stmmac-0 with -EEXIST, don't try to register things with the same name in the same di. CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 4.0.0-rc1-next-20150303+ #8 Workqueue: deferwq deferred_probe_work_func Stack Trace: arc_unwind_core+0xb8/0x114 warn_slowpath_common+0x5a/0x8c warn_slowpath_fmt+0x2e/0x38 kobject_add_internal+0x218/0x2e8 kobject_add+0x4a/0x8c device_add+0xc6/0x448 mdiobus_register+0x6c/0x164 stmmac_mdio_register+0x112/0x264 stmmac_dvr_probe+0x6c0/0x85c stmmac_pltfr_probe+0x2e4/0x50c platform_drv_probe+0x26/0x5c really_probe+0x76/0x1dc bus_for_each_drv+0x42/0x7c device_attach+0x64/0x6c bus_probe_device+0x74/0xa4 deferred_probe_work_func+0x50/0x84 process_one_work+0xf8/0x2cc worker_thread+0x110/0x478 kthread+0x8a/0x9c ret_from_fork+0x14/0x18 ---[ end trace a2dfaa7d630c8be2 ]--- libphy: mii_bus stmmac-0 failed to register : Cannot register as MDIO bus stmmac_pltfr_probe: main driver probe failed stmmaceth: probe of e0018000.ethernet failed with error -22 --->8--- Essential fix is to check for IRQs availability as early as possible and then safely go to deferred probe if IRQs are not there yet. Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com> Cc: Sonic Zhang <sonic.zhang@analog.com> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-03 13:46:44 +03: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");
}
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");
}
stmmac_res->addr = devm_platform_ioremap_resource(pdev, 0);
return PTR_ERR_OR_ZERO(stmmac_res->addr);
}
EXPORT_SYMBOL_GPL(stmmac_get_platform_resources);
/**
* 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);
/**
* 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);
/**
* 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);
static void devm_stmmac_pltfr_remove(void *data)
{
struct platform_device *pdev = data;
stmmac_pltfr_remove(pdev);
}
/**
* 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);
/**
* stmmac_pltfr_remove
* @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.
*/
void stmmac_pltfr_remove(struct platform_device *pdev)
{
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);
}
EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
/**
* 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.
*/
static int __maybe_unused stmmac_pltfr_suspend(struct device *dev)
{
int ret;
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
struct platform_device *pdev = to_platform_device(dev);
ret = stmmac_suspend(dev);
stmmac_pltfr_exit(pdev, priv->plat);
return ret;
}
/**
* 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.
*/
static int __maybe_unused stmmac_pltfr_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
struct platform_device *pdev = to_platform_device(dev);
int ret;
net: stmmac: platform: fix the incorrect parameter The second parameter of stmmac_pltfr_init() needs the pointer of "struct plat_stmmacenet_data". So, correct the parameter typo when calling the function. Otherwise, it may cause this alignment exception when doing suspend/resume. [ 49.067201] CPU1 is up [ 49.135258] Internal error: SP/PC alignment exception: 000000008a000000 [#1] PREEMPT SMP [ 49.143346] Modules linked in: soc_imx9 crct10dif_ce polyval_ce nvmem_imx_ocotp_fsb_s400 polyval_generic layerscape_edac_mod snd_soc_fsl_asoc_card snd_soc_imx_audmux snd_soc_imx_card snd_soc_wm8962 el_enclave snd_soc_fsl_micfil rtc_pcf2127 rtc_pcf2131 flexcan can_dev snd_soc_fsl_xcvr snd_soc_fsl_sai imx8_media_dev(C) snd_soc_fsl_utils fuse [ 49.173393] CPU: 0 PID: 565 Comm: sh Tainted: G C 6.5.0-rc4-next-20230804-05047-g5781a6249dae #677 [ 49.183721] Hardware name: NXP i.MX93 11X11 EVK board (DT) [ 49.189190] pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 49.196140] pc : 0x80800052 [ 49.198931] lr : stmmac_pltfr_resume+0x34/0x50 [ 49.203368] sp : ffff800082f8bab0 [ 49.206670] x29: ffff800082f8bab0 x28: ffff0000047d0ec0 x27: ffff80008186c170 [ 49.213794] x26: 0000000b5e4ff1ba x25: ffff800081e5fa74 x24: 0000000000000010 [ 49.220918] x23: ffff800081fe0000 x22: 0000000000000000 x21: 0000000000000000 [ 49.228042] x20: ffff0000001b4010 x19: ffff0000001b4010 x18: 0000000000000006 [ 49.235166] x17: ffff7ffffe007000 x16: ffff800080000000 x15: 0000000000000000 [ 49.242290] x14: 00000000000000fc x13: 0000000000000000 x12: 0000000000000000 [ 49.249414] x11: 0000000000000001 x10: 0000000000000a60 x9 : ffff800082f8b8c0 [ 49.256538] x8 : 0000000000000008 x7 : 0000000000000001 x6 : 000000005f54a200 [ 49.263662] x5 : 0000000001000000 x4 : ffff800081b93680 x3 : ffff800081519be0 [ 49.270786] x2 : 0000000080800052 x1 : 0000000000000000 x0 : ffff0000001b4000 [ 49.277911] Call trace: [ 49.280346] 0x80800052 [ 49.282781] platform_pm_resume+0x2c/0x68 [ 49.286785] dpm_run_callback.constprop.0+0x74/0x134 [ 49.291742] device_resume+0x88/0x194 [ 49.295391] dpm_resume+0x10c/0x230 [ 49.298866] dpm_resume_end+0x18/0x30 [ 49.302515] suspend_devices_and_enter+0x2b8/0x624 [ 49.307299] pm_suspend+0x1fc/0x348 [ 49.310774] state_store+0x80/0x104 [ 49.314258] kobj_attr_store+0x18/0x2c [ 49.318002] sysfs_kf_write+0x44/0x54 [ 49.321659] kernfs_fop_write_iter+0x120/0x1ec [ 49.326088] vfs_write+0x1bc/0x300 [ 49.329485] ksys_write+0x70/0x104 [ 49.332874] __arm64_sys_write+0x1c/0x28 [ 49.336783] invoke_syscall+0x48/0x114 [ 49.340527] el0_svc_common.constprop.0+0xc4/0xe4 [ 49.345224] do_el0_svc+0x38/0x98 [ 49.348526] el0_svc+0x2c/0x84 [ 49.351568] el0t_64_sync_handler+0x100/0x12c [ 49.355910] el0t_64_sync+0x190/0x194 [ 49.359567] Code: ???????? ???????? ???????? ???????? (????????) [ 49.365644] ---[ end trace 0000000000000000 ]--- Fixes: 97117eb51ec8 ("net: stmmac: platform: provide stmmac_pltfr_init()") Signed-off-by: Clark Wang <xiaoning.wang@nxp.com> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com> Reviewed-by: Serge Semin <fancer.lancer@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2023-09-21 14:24:43 +08:00
ret = stmmac_pltfr_init(pdev, priv->plat);
if (ret)
return ret;
return stmmac_resume(dev);
}
static int __maybe_unused stmmac_runtime_suspend(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
stmmac_bus_clks_config(priv, false);
return 0;
}
static int __maybe_unused stmmac_runtime_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
return stmmac_bus_clks_config(priv, true);
}
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;
}
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;
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;
}
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)
};
EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
MODULE_LICENSE("GPL");