diff mbox series

net: phy: call phy_disable_interrupts() in phy_attach_direct() instead

Message ID 1599564440-8158-1-git-send-email-yoshihiro.shimoda.uh@renesas.com (mailing list archive)
State Superseded
Delegated to: Geert Uytterhoeven
Headers show
Series net: phy: call phy_disable_interrupts() in phy_attach_direct() instead | expand

Commit Message

Yoshihiro Shimoda Sept. 8, 2020, 11:27 a.m. UTC
Since the micrel phy driver calls phy_init_hw() as a workaround,
the commit 9886a4dbd2aa ("net: phy: call phy_disable_interrupts()
in phy_init_hw()") disables the interrupt unexpectedly. So,
call phy_disable_interrupts() in phy_attach_direct() instead.
Otherwise, the phy cannot link up after the ethernet cable was
disconnected.

Note that other drivers (like at803x.c) also calls phy_init_hw().
So, perhaps, the driver caused a similar issue too.

Fixes: 9886a4dbd2aa ("net: phy: call phy_disable_interrupts() in phy_init_hw()")
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 I observed this issue on my environment (r8a77951-salvator-xs).

 drivers/net/phy/phy_device.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Comments

kernel test robot Sept. 8, 2020, 4 p.m. UTC | #1
Hi Yoshihiro,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.9-rc4 next-20200903]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Yoshihiro-Shimoda/net-phy-call-phy_disable_interrupts-in-phy_attach_direct-instead/20200908-193045
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git f4d51dffc6c01a9e94650d95ce0104964f8ae822
config: xtensa-allyesconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=xtensa 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/net/phy/phy_device.c: In function 'phy_attach_direct':
>> drivers/net/phy/phy_device.c:1422:2: error: 'ret' undeclared (first use in this function); did you mean 'net'?
    1422 |  ret = phy_disable_interrupts(phydev);
         |  ^~~
         |  net
   drivers/net/phy/phy_device.c:1422:2: note: each undeclared identifier is reported only once for each function it appears in

# https://github.com/0day-ci/linux/commit/fbb61c39d1981f669df1639bb1b726f255217bc0
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Yoshihiro-Shimoda/net-phy-call-phy_disable_interrupts-in-phy_attach_direct-instead/20200908-193045
git checkout fbb61c39d1981f669df1639bb1b726f255217bc0
vim +1422 drivers/net/phy/phy_device.c

  1302	
  1303	/**
  1304	 * phy_attach_direct - attach a network device to a given PHY device pointer
  1305	 * @dev: network device to attach
  1306	 * @phydev: Pointer to phy_device to attach
  1307	 * @flags: PHY device's dev_flags
  1308	 * @interface: PHY device's interface
  1309	 *
  1310	 * Description: Called by drivers to attach to a particular PHY
  1311	 *     device. The phy_device is found, and properly hooked up
  1312	 *     to the phy_driver.  If no driver is attached, then a
  1313	 *     generic driver is used.  The phy_device is given a ptr to
  1314	 *     the attaching device, and given a callback for link status
  1315	 *     change.  The phy_device is returned to the attaching driver.
  1316	 *     This function takes a reference on the phy device.
  1317	 */
  1318	int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
  1319			      u32 flags, phy_interface_t interface)
  1320	{
  1321		struct mii_bus *bus = phydev->mdio.bus;
  1322		struct device *d = &phydev->mdio.dev;
  1323		struct module *ndev_owner = NULL;
  1324		bool using_genphy = false;
  1325		int err;
  1326	
  1327		/* For Ethernet device drivers that register their own MDIO bus, we
  1328		 * will have bus->owner match ndev_mod, so we do not want to increment
  1329		 * our own module->refcnt here, otherwise we would not be able to
  1330		 * unload later on.
  1331		 */
  1332		if (dev)
  1333			ndev_owner = dev->dev.parent->driver->owner;
  1334		if (ndev_owner != bus->owner && !try_module_get(bus->owner)) {
  1335			phydev_err(phydev, "failed to get the bus module\n");
  1336			return -EIO;
  1337		}
  1338	
  1339		get_device(d);
  1340	
  1341		/* Assume that if there is no driver, that it doesn't
  1342		 * exist, and we should use the genphy driver.
  1343		 */
  1344		if (!d->driver) {
  1345			if (phydev->is_c45)
  1346				d->driver = &genphy_c45_driver.mdiodrv.driver;
  1347			else
  1348				d->driver = &genphy_driver.mdiodrv.driver;
  1349	
  1350			using_genphy = true;
  1351		}
  1352	
  1353		if (!try_module_get(d->driver->owner)) {
  1354			phydev_err(phydev, "failed to get the device driver module\n");
  1355			err = -EIO;
  1356			goto error_put_device;
  1357		}
  1358	
  1359		if (using_genphy) {
  1360			err = d->driver->probe(d);
  1361			if (err >= 0)
  1362				err = device_bind_driver(d);
  1363	
  1364			if (err)
  1365				goto error_module_put;
  1366		}
  1367	
  1368		if (phydev->attached_dev) {
  1369			dev_err(&dev->dev, "PHY already attached\n");
  1370			err = -EBUSY;
  1371			goto error;
  1372		}
  1373	
  1374		phydev->phy_link_change = phy_link_change;
  1375		if (dev) {
  1376			phydev->attached_dev = dev;
  1377			dev->phydev = phydev;
  1378	
  1379			if (phydev->sfp_bus_attached)
  1380				dev->sfp_bus = phydev->sfp_bus;
  1381		}
  1382	
  1383		/* Some Ethernet drivers try to connect to a PHY device before
  1384		 * calling register_netdevice() -> netdev_register_kobject() and
  1385		 * does the dev->dev.kobj initialization. Here we only check for
  1386		 * success which indicates that the network device kobject is
  1387		 * ready. Once we do that we still need to keep track of whether
  1388		 * links were successfully set up or not for phy_detach() to
  1389		 * remove them accordingly.
  1390		 */
  1391		phydev->sysfs_links = false;
  1392	
  1393		phy_sysfs_create_links(phydev);
  1394	
  1395		if (!phydev->attached_dev) {
  1396			err = sysfs_create_file(&phydev->mdio.dev.kobj,
  1397						&dev_attr_phy_standalone.attr);
  1398			if (err)
  1399				phydev_err(phydev, "error creating 'phy_standalone' sysfs entry\n");
  1400		}
  1401	
  1402		phydev->dev_flags |= flags;
  1403	
  1404		phydev->interface = interface;
  1405	
  1406		phydev->state = PHY_READY;
  1407	
  1408		/* Initial carrier state is off as the phy is about to be
  1409		 * (re)initialized.
  1410		 */
  1411		if (dev)
  1412			netif_carrier_off(phydev->attached_dev);
  1413	
  1414		/* Do initial configuration here, now that
  1415		 * we have certain key parameters
  1416		 * (dev_flags and interface)
  1417		 */
  1418		err = phy_init_hw(phydev);
  1419		if (err)
  1420			goto error;
  1421	
> 1422		ret = phy_disable_interrupts(phydev);
  1423		if (ret)
  1424			return ret;
  1425	
  1426		phy_resume(phydev);
  1427		phy_led_triggers_register(phydev);
  1428	
  1429		return err;
  1430	
  1431	error:
  1432		/* phy_detach() does all of the cleanup below */
  1433		phy_detach(phydev);
  1434		return err;
  1435	
  1436	error_module_put:
  1437		module_put(d->driver->owner);
  1438	error_put_device:
  1439		put_device(d);
  1440		if (ndev_owner != bus->owner)
  1441			module_put(bus->owner);
  1442		return err;
  1443	}
  1444	EXPORT_SYMBOL(phy_attach_direct);
  1445	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Sept. 8, 2020, 5:40 p.m. UTC | #2
Hi Yoshihiro,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.9-rc4 next-20200908]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Yoshihiro-Shimoda/net-phy-call-phy_disable_interrupts-in-phy_attach_direct-instead/20200908-193045
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git f4d51dffc6c01a9e94650d95ce0104964f8ae822
config: x86_64-randconfig-r031-20200908 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project df63eedef64d715ce1f31843f7de9c11fe1e597f)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/net/phy/phy_device.c:1422:2: error: use of undeclared identifier 'ret'
           ret = phy_disable_interrupts(phydev);
           ^
   drivers/net/phy/phy_device.c:1423:6: error: use of undeclared identifier 'ret'
           if (ret)
               ^
   drivers/net/phy/phy_device.c:1424:10: error: use of undeclared identifier 'ret'
                   return ret;
                          ^
   3 errors generated.

# https://github.com/0day-ci/linux/commit/fbb61c39d1981f669df1639bb1b726f255217bc0
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Yoshihiro-Shimoda/net-phy-call-phy_disable_interrupts-in-phy_attach_direct-instead/20200908-193045
git checkout fbb61c39d1981f669df1639bb1b726f255217bc0
vim +/ret +1422 drivers/net/phy/phy_device.c

  1302	
  1303	/**
  1304	 * phy_attach_direct - attach a network device to a given PHY device pointer
  1305	 * @dev: network device to attach
  1306	 * @phydev: Pointer to phy_device to attach
  1307	 * @flags: PHY device's dev_flags
  1308	 * @interface: PHY device's interface
  1309	 *
  1310	 * Description: Called by drivers to attach to a particular PHY
  1311	 *     device. The phy_device is found, and properly hooked up
  1312	 *     to the phy_driver.  If no driver is attached, then a
  1313	 *     generic driver is used.  The phy_device is given a ptr to
  1314	 *     the attaching device, and given a callback for link status
  1315	 *     change.  The phy_device is returned to the attaching driver.
  1316	 *     This function takes a reference on the phy device.
  1317	 */
  1318	int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
  1319			      u32 flags, phy_interface_t interface)
  1320	{
  1321		struct mii_bus *bus = phydev->mdio.bus;
  1322		struct device *d = &phydev->mdio.dev;
  1323		struct module *ndev_owner = NULL;
  1324		bool using_genphy = false;
  1325		int err;
  1326	
  1327		/* For Ethernet device drivers that register their own MDIO bus, we
  1328		 * will have bus->owner match ndev_mod, so we do not want to increment
  1329		 * our own module->refcnt here, otherwise we would not be able to
  1330		 * unload later on.
  1331		 */
  1332		if (dev)
  1333			ndev_owner = dev->dev.parent->driver->owner;
  1334		if (ndev_owner != bus->owner && !try_module_get(bus->owner)) {
  1335			phydev_err(phydev, "failed to get the bus module\n");
  1336			return -EIO;
  1337		}
  1338	
  1339		get_device(d);
  1340	
  1341		/* Assume that if there is no driver, that it doesn't
  1342		 * exist, and we should use the genphy driver.
  1343		 */
  1344		if (!d->driver) {
  1345			if (phydev->is_c45)
  1346				d->driver = &genphy_c45_driver.mdiodrv.driver;
  1347			else
  1348				d->driver = &genphy_driver.mdiodrv.driver;
  1349	
  1350			using_genphy = true;
  1351		}
  1352	
  1353		if (!try_module_get(d->driver->owner)) {
  1354			phydev_err(phydev, "failed to get the device driver module\n");
  1355			err = -EIO;
  1356			goto error_put_device;
  1357		}
  1358	
  1359		if (using_genphy) {
  1360			err = d->driver->probe(d);
  1361			if (err >= 0)
  1362				err = device_bind_driver(d);
  1363	
  1364			if (err)
  1365				goto error_module_put;
  1366		}
  1367	
  1368		if (phydev->attached_dev) {
  1369			dev_err(&dev->dev, "PHY already attached\n");
  1370			err = -EBUSY;
  1371			goto error;
  1372		}
  1373	
  1374		phydev->phy_link_change = phy_link_change;
  1375		if (dev) {
  1376			phydev->attached_dev = dev;
  1377			dev->phydev = phydev;
  1378	
  1379			if (phydev->sfp_bus_attached)
  1380				dev->sfp_bus = phydev->sfp_bus;
  1381		}
  1382	
  1383		/* Some Ethernet drivers try to connect to a PHY device before
  1384		 * calling register_netdevice() -> netdev_register_kobject() and
  1385		 * does the dev->dev.kobj initialization. Here we only check for
  1386		 * success which indicates that the network device kobject is
  1387		 * ready. Once we do that we still need to keep track of whether
  1388		 * links were successfully set up or not for phy_detach() to
  1389		 * remove them accordingly.
  1390		 */
  1391		phydev->sysfs_links = false;
  1392	
  1393		phy_sysfs_create_links(phydev);
  1394	
  1395		if (!phydev->attached_dev) {
  1396			err = sysfs_create_file(&phydev->mdio.dev.kobj,
  1397						&dev_attr_phy_standalone.attr);
  1398			if (err)
  1399				phydev_err(phydev, "error creating 'phy_standalone' sysfs entry\n");
  1400		}
  1401	
  1402		phydev->dev_flags |= flags;
  1403	
  1404		phydev->interface = interface;
  1405	
  1406		phydev->state = PHY_READY;
  1407	
  1408		/* Initial carrier state is off as the phy is about to be
  1409		 * (re)initialized.
  1410		 */
  1411		if (dev)
  1412			netif_carrier_off(phydev->attached_dev);
  1413	
  1414		/* Do initial configuration here, now that
  1415		 * we have certain key parameters
  1416		 * (dev_flags and interface)
  1417		 */
  1418		err = phy_init_hw(phydev);
  1419		if (err)
  1420			goto error;
  1421	
> 1422		ret = phy_disable_interrupts(phydev);
  1423		if (ret)
  1424			return ret;
  1425	
  1426		phy_resume(phydev);
  1427		phy_led_triggers_register(phydev);
  1428	
  1429		return err;
  1430	
  1431	error:
  1432		/* phy_detach() does all of the cleanup below */
  1433		phy_detach(phydev);
  1434		return err;
  1435	
  1436	error_module_put:
  1437		module_put(d->driver->owner);
  1438	error_put_device:
  1439		put_device(d);
  1440		if (ndev_owner != bus->owner)
  1441			module_put(bus->owner);
  1442		return err;
  1443	}
  1444	EXPORT_SYMBOL(phy_attach_direct);
  1445	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
David Miller Sept. 9, 2020, 3:01 a.m. UTC | #3
From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Date: Tue,  8 Sep 2020 20:27:20 +0900

> @@ -1423,6 +1419,10 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
>  	if (err)
>  		goto error;
>  
> +	ret = phy_disable_interrupts(phydev);
> +	if (ret)
> +		return ret;
> +

How did you test this?

I am very serious.

There is no 'ret' variable in this function, you do not add one, and
therefore this does not even compile.

If you are patching against a different tree than the networking GIT
tree, that is a major mistake as well.

That also is why it is very important to specify the destination GIT
tree in your subject line such as "[PATCH net]" or "[PATCH net-next]".

Thank you.
diff mbox series

Patch

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8adfbad..d96dafb 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1143,10 +1143,6 @@  int phy_init_hw(struct phy_device *phydev)
 	if (ret < 0)
 		return ret;
 
-	ret = phy_disable_interrupts(phydev);
-	if (ret)
-		return ret;
-
 	if (phydev->drv->config_init)
 		ret = phydev->drv->config_init(phydev);
 
@@ -1423,6 +1419,10 @@  int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
 	if (err)
 		goto error;
 
+	ret = phy_disable_interrupts(phydev);
+	if (ret)
+		return ret;
+
 	phy_resume(phydev);
 	phy_led_triggers_register(phydev);