Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'phy-stopping-race'

Russell King says:

====================
net: phy: avoid race when erroring stopping PHY

This series addresses a problem reported by Jijie Shao where the PHY
state machine can race with phy_stop() leading to an incorrect state.

The issue centres around phy_state_machine() dropping the phydev->lock
mutex briefly, which allows phy_stop() to get in half-way through the
state machine, and when the state machine resumes, it overwrites
phydev->state with a value incompatible with a stopped PHY. This causes
a subsequent phy_start() to issue a warning.

We address this firstly by using versions of functions that do not take
tne lock, moving them into the locked region. The only function that
this can't be done with is phy_suspend() which needs to call into the
driver without taking the lock.

For phy_suspend(), we split the state machine into two parts - the
initial part which runs under the phydev->lock, and the second part
which runs without the lock.

We finish off by using the split state machine in phy_stop() which
removes another unnecessary unlock-lock sequence from phylib.

Changes from RFC:
- Added Jijie Shao's tested-by
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+110 -94
+110 -94
drivers/net/phy/phy.c
··· 1231 1231 const void *func, int err) 1232 1232 { 1233 1233 WARN(1, "%pS: returned: %d\n", func, err); 1234 - mutex_lock(&phydev->lock); 1235 1234 phy_process_error(phydev); 1236 - mutex_unlock(&phydev->lock); 1237 1235 } 1238 1236 1239 1237 /** ··· 1353 1355 } 1354 1356 EXPORT_SYMBOL(phy_free_interrupt); 1355 1357 1358 + enum phy_state_work { 1359 + PHY_STATE_WORK_NONE, 1360 + PHY_STATE_WORK_ANEG, 1361 + PHY_STATE_WORK_SUSPEND, 1362 + }; 1363 + 1364 + static enum phy_state_work _phy_state_machine(struct phy_device *phydev) 1365 + { 1366 + enum phy_state_work state_work = PHY_STATE_WORK_NONE; 1367 + struct net_device *dev = phydev->attached_dev; 1368 + enum phy_state old_state = phydev->state; 1369 + const void *func = NULL; 1370 + bool finished = false; 1371 + int err = 0; 1372 + 1373 + switch (phydev->state) { 1374 + case PHY_DOWN: 1375 + case PHY_READY: 1376 + break; 1377 + case PHY_UP: 1378 + state_work = PHY_STATE_WORK_ANEG; 1379 + break; 1380 + case PHY_NOLINK: 1381 + case PHY_RUNNING: 1382 + err = phy_check_link_status(phydev); 1383 + func = &phy_check_link_status; 1384 + break; 1385 + case PHY_CABLETEST: 1386 + err = phydev->drv->cable_test_get_status(phydev, &finished); 1387 + if (err) { 1388 + phy_abort_cable_test(phydev); 1389 + netif_testing_off(dev); 1390 + state_work = PHY_STATE_WORK_ANEG; 1391 + phydev->state = PHY_UP; 1392 + break; 1393 + } 1394 + 1395 + if (finished) { 1396 + ethnl_cable_test_finished(phydev); 1397 + netif_testing_off(dev); 1398 + state_work = PHY_STATE_WORK_ANEG; 1399 + phydev->state = PHY_UP; 1400 + } 1401 + break; 1402 + case PHY_HALTED: 1403 + case PHY_ERROR: 1404 + if (phydev->link) { 1405 + phydev->link = 0; 1406 + phy_link_down(phydev); 1407 + } 1408 + state_work = PHY_STATE_WORK_SUSPEND; 1409 + break; 1410 + } 1411 + 1412 + if (state_work == PHY_STATE_WORK_ANEG) { 1413 + err = _phy_start_aneg(phydev); 1414 + func = &_phy_start_aneg; 1415 + } 1416 + 1417 + if (err == -ENODEV) 1418 + return state_work; 1419 + 1420 + if (err < 0) 1421 + phy_error_precise(phydev, func, err); 1422 + 1423 + phy_process_state_change(phydev, old_state); 1424 + 1425 + /* Only re-schedule a PHY state machine change if we are polling the 1426 + * PHY, if PHY_MAC_INTERRUPT is set, then we will be moving 1427 + * between states from phy_mac_interrupt(). 1428 + * 1429 + * In state PHY_HALTED the PHY gets suspended, so rescheduling the 1430 + * state machine would be pointless and possibly error prone when 1431 + * called from phy_disconnect() synchronously. 1432 + */ 1433 + if (phy_polling_mode(phydev) && phy_is_started(phydev)) 1434 + phy_queue_state_machine(phydev, PHY_STATE_TIME); 1435 + 1436 + return state_work; 1437 + } 1438 + 1439 + /* unlocked part of the PHY state machine */ 1440 + static void _phy_state_machine_post_work(struct phy_device *phydev, 1441 + enum phy_state_work state_work) 1442 + { 1443 + if (state_work == PHY_STATE_WORK_SUSPEND) 1444 + phy_suspend(phydev); 1445 + } 1446 + 1447 + /** 1448 + * phy_state_machine - Handle the state machine 1449 + * @work: work_struct that describes the work to be done 1450 + */ 1451 + void phy_state_machine(struct work_struct *work) 1452 + { 1453 + struct delayed_work *dwork = to_delayed_work(work); 1454 + struct phy_device *phydev = 1455 + container_of(dwork, struct phy_device, state_queue); 1456 + enum phy_state_work state_work; 1457 + 1458 + mutex_lock(&phydev->lock); 1459 + state_work = _phy_state_machine(phydev); 1460 + mutex_unlock(&phydev->lock); 1461 + 1462 + _phy_state_machine_post_work(phydev, state_work); 1463 + } 1464 + 1356 1465 /** 1357 1466 * phy_stop - Bring down the PHY link, and stop checking the status 1358 1467 * @phydev: target phy_device struct ··· 1467 1362 void phy_stop(struct phy_device *phydev) 1468 1363 { 1469 1364 struct net_device *dev = phydev->attached_dev; 1365 + enum phy_state_work state_work; 1470 1366 enum phy_state old_state; 1471 1367 1472 1368 if (!phy_is_started(phydev) && phydev->state != PHY_DOWN && ··· 1491 1385 phydev->state = PHY_HALTED; 1492 1386 phy_process_state_change(phydev, old_state); 1493 1387 1388 + state_work = _phy_state_machine(phydev); 1494 1389 mutex_unlock(&phydev->lock); 1495 1390 1496 - phy_state_machine(&phydev->state_queue.work); 1391 + _phy_state_machine_post_work(phydev, state_work); 1497 1392 phy_stop_machine(phydev); 1498 1393 1499 1394 /* Cannot call flush_scheduled_work() here as desired because ··· 1537 1430 mutex_unlock(&phydev->lock); 1538 1431 } 1539 1432 EXPORT_SYMBOL(phy_start); 1540 - 1541 - /** 1542 - * phy_state_machine - Handle the state machine 1543 - * @work: work_struct that describes the work to be done 1544 - */ 1545 - void phy_state_machine(struct work_struct *work) 1546 - { 1547 - struct delayed_work *dwork = to_delayed_work(work); 1548 - struct phy_device *phydev = 1549 - container_of(dwork, struct phy_device, state_queue); 1550 - struct net_device *dev = phydev->attached_dev; 1551 - bool needs_aneg = false, do_suspend = false; 1552 - enum phy_state old_state; 1553 - const void *func = NULL; 1554 - bool finished = false; 1555 - int err = 0; 1556 - 1557 - mutex_lock(&phydev->lock); 1558 - 1559 - old_state = phydev->state; 1560 - 1561 - switch (phydev->state) { 1562 - case PHY_DOWN: 1563 - case PHY_READY: 1564 - break; 1565 - case PHY_UP: 1566 - needs_aneg = true; 1567 - 1568 - break; 1569 - case PHY_NOLINK: 1570 - case PHY_RUNNING: 1571 - err = phy_check_link_status(phydev); 1572 - func = &phy_check_link_status; 1573 - break; 1574 - case PHY_CABLETEST: 1575 - err = phydev->drv->cable_test_get_status(phydev, &finished); 1576 - if (err) { 1577 - phy_abort_cable_test(phydev); 1578 - netif_testing_off(dev); 1579 - needs_aneg = true; 1580 - phydev->state = PHY_UP; 1581 - break; 1582 - } 1583 - 1584 - if (finished) { 1585 - ethnl_cable_test_finished(phydev); 1586 - netif_testing_off(dev); 1587 - needs_aneg = true; 1588 - phydev->state = PHY_UP; 1589 - } 1590 - break; 1591 - case PHY_HALTED: 1592 - case PHY_ERROR: 1593 - if (phydev->link) { 1594 - phydev->link = 0; 1595 - phy_link_down(phydev); 1596 - } 1597 - do_suspend = true; 1598 - break; 1599 - } 1600 - 1601 - mutex_unlock(&phydev->lock); 1602 - 1603 - if (needs_aneg) { 1604 - err = phy_start_aneg(phydev); 1605 - func = &phy_start_aneg; 1606 - } else if (do_suspend) { 1607 - phy_suspend(phydev); 1608 - } 1609 - 1610 - if (err == -ENODEV) 1611 - return; 1612 - 1613 - if (err < 0) 1614 - phy_error_precise(phydev, func, err); 1615 - 1616 - phy_process_state_change(phydev, old_state); 1617 - 1618 - /* Only re-schedule a PHY state machine change if we are polling the 1619 - * PHY, if PHY_MAC_INTERRUPT is set, then we will be moving 1620 - * between states from phy_mac_interrupt(). 1621 - * 1622 - * In state PHY_HALTED the PHY gets suspended, so rescheduling the 1623 - * state machine would be pointless and possibly error prone when 1624 - * called from phy_disconnect() synchronously. 1625 - */ 1626 - mutex_lock(&phydev->lock); 1627 - if (phy_polling_mode(phydev) && phy_is_started(phydev)) 1628 - phy_queue_state_machine(phydev, PHY_STATE_TIME); 1629 - mutex_unlock(&phydev->lock); 1630 - } 1631 1433 1632 1434 /** 1633 1435 * phy_mac_interrupt - MAC says the link has changed