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

Merge branch 'systemport-next'

Florian Fainelli says:

====================
net: systemport: PM and Wake-on-LAN support

This patchset brings Power Management and Wake-on-LAN support to the
Broadcom SYSTEM PORT driver.

S2 and S3 modes are supported, while we only support Wake-on-LAN using
MagicPackets for now
====================

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

+361 -34
+2 -1
Documentation/devicetree/bindings/net/broadcom-systemport.txt
··· 4 4 - compatible: should be one of "brcm,systemport-v1.00" or "brcm,systemport" 5 5 - reg: address and length of the register set for the device. 6 6 - interrupts: interrupts for the device, first cell must be for the the rx 7 - interrupts, and the second cell should be for the transmit queues 7 + interrupts, and the second cell should be for the transmit queues. An 8 + optional third interrupt cell for Wake-on-LAN can be specified 8 9 - local-mac-address: Ethernet MAC address (48 bits) of this adapter 9 10 - phy-mode: Should be a string describing the PHY interface to the 10 11 Ethernet switch/PHY, see Documentation/devicetree/bindings/net/ethernet.txt
+346 -32
drivers/net/ethernet/broadcom/bcmsysport.c
··· 124 124 struct bcm_sysport_priv *priv = netdev_priv(dev); 125 125 u32 reg; 126 126 127 - priv->rx_csum_en = !!(wanted & NETIF_F_RXCSUM); 127 + priv->rx_chk_en = !!(wanted & NETIF_F_RXCSUM); 128 128 reg = rxchk_readl(priv, RXCHK_CONTROL); 129 - if (priv->rx_csum_en) 129 + if (priv->rx_chk_en) 130 130 reg |= RXCHK_EN; 131 131 else 132 132 reg &= ~RXCHK_EN; ··· 134 134 /* If UniMAC forwards CRC, we need to skip over it to get 135 135 * a valid CHK bit to be set in the per-packet status word 136 136 */ 137 - if (priv->rx_csum_en && priv->crc_fwd) 137 + if (priv->rx_chk_en && priv->crc_fwd) 138 138 reg |= RXCHK_SKIP_FCS; 139 139 else 140 140 reg &= ~RXCHK_SKIP_FCS; ··· 382 382 p += s->stat_offset; 383 383 data[i] = *(u32 *)p; 384 384 } 385 + } 386 + 387 + static void bcm_sysport_get_wol(struct net_device *dev, 388 + struct ethtool_wolinfo *wol) 389 + { 390 + struct bcm_sysport_priv *priv = netdev_priv(dev); 391 + u32 reg; 392 + 393 + wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE; 394 + wol->wolopts = priv->wolopts; 395 + 396 + if (!(priv->wolopts & WAKE_MAGICSECURE)) 397 + return; 398 + 399 + /* Return the programmed SecureOn password */ 400 + reg = umac_readl(priv, UMAC_PSW_MS); 401 + put_unaligned_be16(reg, &wol->sopass[0]); 402 + reg = umac_readl(priv, UMAC_PSW_LS); 403 + put_unaligned_be32(reg, &wol->sopass[2]); 404 + } 405 + 406 + static int bcm_sysport_set_wol(struct net_device *dev, 407 + struct ethtool_wolinfo *wol) 408 + { 409 + struct bcm_sysport_priv *priv = netdev_priv(dev); 410 + struct device *kdev = &priv->pdev->dev; 411 + u32 supported = WAKE_MAGIC | WAKE_MAGICSECURE; 412 + 413 + if (!device_can_wakeup(kdev)) 414 + return -ENOTSUPP; 415 + 416 + if (wol->wolopts & ~supported) 417 + return -EINVAL; 418 + 419 + /* Program the SecureOn password */ 420 + if (wol->wolopts & WAKE_MAGICSECURE) { 421 + umac_writel(priv, get_unaligned_be16(&wol->sopass[0]), 422 + UMAC_PSW_MS); 423 + umac_writel(priv, get_unaligned_be32(&wol->sopass[2]), 424 + UMAC_PSW_LS); 425 + } 426 + 427 + /* Flag the device and relevant IRQ as wakeup capable */ 428 + if (wol->wolopts) { 429 + device_set_wakeup_enable(kdev, 1); 430 + enable_irq_wake(priv->wol_irq); 431 + priv->wol_irq_disabled = 0; 432 + } else { 433 + device_set_wakeup_enable(kdev, 0); 434 + /* Avoid unbalanced disable_irq_wake calls */ 435 + if (!priv->wol_irq_disabled) 436 + disable_irq_wake(priv->wol_irq); 437 + priv->wol_irq_disabled = 1; 438 + } 439 + 440 + priv->wolopts = wol->wolopts; 441 + 442 + return 0; 385 443 } 386 444 387 445 static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb) ··· 750 692 return work_done; 751 693 } 752 694 695 + static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv) 696 + { 697 + u32 reg; 698 + 699 + /* Stop monitoring MPD interrupt */ 700 + intrl2_0_mask_set(priv, INTRL2_0_MPD); 701 + 702 + /* Clear the MagicPacket detection logic */ 703 + reg = umac_readl(priv, UMAC_MPD_CTRL); 704 + reg &= ~MPD_EN; 705 + umac_writel(priv, reg, UMAC_MPD_CTRL); 706 + 707 + netif_dbg(priv, wol, priv->netdev, "resumed from WOL\n"); 708 + } 753 709 754 710 /* RX and misc interrupt routine */ 755 711 static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id) ··· 793 721 */ 794 722 if (priv->irq0_stat & INTRL2_0_TX_RING_FULL) 795 723 bcm_sysport_tx_reclaim_all(priv); 724 + 725 + if (priv->irq0_stat & INTRL2_0_MPD) { 726 + netdev_info(priv->netdev, "Wake-on-LAN interrupt!\n"); 727 + bcm_sysport_resume_from_wol(priv); 728 + } 796 729 797 730 return IRQ_HANDLED; 798 731 } ··· 830 753 __napi_schedule(&txr->napi); 831 754 } 832 755 } 756 + 757 + return IRQ_HANDLED; 758 + } 759 + 760 + static irqreturn_t bcm_sysport_wol_isr(int irq, void *dev_id) 761 + { 762 + struct bcm_sysport_priv *priv = dev_id; 763 + 764 + pm_wakeup_event(&priv->pdev->dev, 0); 833 765 834 766 return IRQ_HANDLED; 835 767 } ··· 1322 1236 } 1323 1237 1324 1238 static inline void umac_enable_set(struct bcm_sysport_priv *priv, 1325 - unsigned int enable) 1239 + u32 mask, unsigned int enable) 1326 1240 { 1327 1241 u32 reg; 1328 1242 1329 1243 reg = umac_readl(priv, UMAC_CMD); 1330 1244 if (enable) 1331 - reg |= CMD_RX_EN | CMD_TX_EN; 1245 + reg |= mask; 1332 1246 else 1333 - reg &= ~(CMD_RX_EN | CMD_TX_EN); 1247 + reg &= ~mask; 1334 1248 umac_writel(priv, reg, UMAC_CMD); 1335 1249 1336 1250 /* UniMAC stops on a packet boundary, wait for a full-sized packet ··· 1381 1295 topctrl_writel(priv, 0, TX_FLUSH_CNTL); 1382 1296 } 1383 1297 1298 + static void bcm_sysport_netif_start(struct net_device *dev) 1299 + { 1300 + struct bcm_sysport_priv *priv = netdev_priv(dev); 1301 + 1302 + /* Enable NAPI */ 1303 + napi_enable(&priv->napi); 1304 + 1305 + phy_start(priv->phydev); 1306 + 1307 + /* Enable TX interrupts for the 32 TXQs */ 1308 + intrl2_1_mask_clear(priv, 0xffffffff); 1309 + 1310 + /* Last call before we start the real business */ 1311 + netif_tx_start_all_queues(dev); 1312 + } 1313 + 1314 + static void rbuf_init(struct bcm_sysport_priv *priv) 1315 + { 1316 + u32 reg; 1317 + 1318 + reg = rbuf_readl(priv, RBUF_CONTROL); 1319 + reg |= RBUF_4B_ALGN | RBUF_RSB_EN; 1320 + rbuf_writel(priv, reg, RBUF_CONTROL); 1321 + } 1322 + 1384 1323 static int bcm_sysport_open(struct net_device *dev) 1385 1324 { 1386 1325 struct bcm_sysport_priv *priv = netdev_priv(dev); 1387 1326 unsigned int i; 1388 - u32 reg; 1389 1327 int ret; 1390 1328 1391 1329 /* Reset UniMAC */ ··· 1423 1313 topctrl_flush(priv); 1424 1314 1425 1315 /* Disable the UniMAC RX/TX */ 1426 - umac_enable_set(priv, 0); 1316 + umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 0); 1427 1317 1428 1318 /* Enable RBUF 2bytes alignment and Receive Status Block */ 1429 - reg = rbuf_readl(priv, RBUF_CONTROL); 1430 - reg |= RBUF_4B_ALGN | RBUF_RSB_EN; 1431 - rbuf_writel(priv, reg, RBUF_CONTROL); 1319 + rbuf_init(priv); 1432 1320 1433 1321 /* Set maximum frame length */ 1434 1322 umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); ··· 1502 1394 if (ret) 1503 1395 goto out_clear_rx_int; 1504 1396 1505 - /* Enable NAPI */ 1506 - napi_enable(&priv->napi); 1507 - 1508 1397 /* Turn on UniMAC TX/RX */ 1509 - umac_enable_set(priv, 1); 1398 + umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 1); 1510 1399 1511 - phy_start(priv->phydev); 1512 - 1513 - /* Enable TX interrupts for the 32 TXQs */ 1514 - intrl2_1_mask_clear(priv, 0xffffffff); 1515 - 1516 - /* Last call before we start the real business */ 1517 - netif_tx_start_all_queues(dev); 1400 + bcm_sysport_netif_start(dev); 1518 1401 1519 1402 return 0; 1520 1403 ··· 1524 1425 return ret; 1525 1426 } 1526 1427 1527 - static int bcm_sysport_stop(struct net_device *dev) 1428 + static void bcm_sysport_netif_stop(struct net_device *dev) 1528 1429 { 1529 1430 struct bcm_sysport_priv *priv = netdev_priv(dev); 1530 - unsigned int i; 1531 - u32 reg; 1532 - int ret; 1533 1431 1534 1432 /* stop all software from updating hardware */ 1535 1433 netif_tx_stop_all_queues(dev); ··· 1538 1442 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); 1539 1443 intrl2_1_mask_set(priv, 0xffffffff); 1540 1444 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); 1445 + } 1446 + 1447 + static int bcm_sysport_stop(struct net_device *dev) 1448 + { 1449 + struct bcm_sysport_priv *priv = netdev_priv(dev); 1450 + unsigned int i; 1451 + int ret; 1452 + 1453 + bcm_sysport_netif_stop(dev); 1541 1454 1542 1455 /* Disable UniMAC RX */ 1543 - reg = umac_readl(priv, UMAC_CMD); 1544 - reg &= ~CMD_RX_EN; 1545 - umac_writel(priv, reg, UMAC_CMD); 1456 + umac_enable_set(priv, CMD_RX_EN, 0); 1546 1457 1547 1458 ret = tdma_enable_set(priv, 0); 1548 1459 if (ret) { ··· 1567 1464 } 1568 1465 1569 1466 /* Disable UniMAC TX */ 1570 - reg = umac_readl(priv, UMAC_CMD); 1571 - reg &= ~CMD_TX_EN; 1572 - umac_writel(priv, reg, UMAC_CMD); 1467 + umac_enable_set(priv, CMD_TX_EN, 0); 1573 1468 1574 1469 /* Free RX/TX rings SW structures */ 1575 1470 for (i = 0; i < dev->num_tx_queues; i++) ··· 1593 1492 .get_strings = bcm_sysport_get_strings, 1594 1493 .get_ethtool_stats = bcm_sysport_get_stats, 1595 1494 .get_sset_count = bcm_sysport_get_sset_count, 1495 + .get_wol = bcm_sysport_get_wol, 1496 + .set_wol = bcm_sysport_set_wol, 1596 1497 }; 1597 1498 1598 1499 static const struct net_device_ops bcm_sysport_netdev_ops = { ··· 1636 1533 1637 1534 priv->irq0 = platform_get_irq(pdev, 0); 1638 1535 priv->irq1 = platform_get_irq(pdev, 1); 1536 + priv->wol_irq = platform_get_irq(pdev, 2); 1639 1537 if (priv->irq0 <= 0 || priv->irq1 <= 0) { 1640 1538 dev_err(&pdev->dev, "invalid interrupts\n"); 1641 1539 ret = -EINVAL; ··· 1689 1585 dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA | 1690 1586 NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; 1691 1587 1588 + /* Request the WOL interrupt and advertise suspend if available */ 1589 + priv->wol_irq_disabled = 1; 1590 + ret = devm_request_irq(&pdev->dev, priv->wol_irq, 1591 + bcm_sysport_wol_isr, 0, dev->name, priv); 1592 + if (!ret) 1593 + device_set_wakeup_capable(&pdev->dev, 1); 1594 + 1692 1595 /* Set the needed headroom once and for all */ 1693 1596 BUILD_BUG_ON(sizeof(struct bcm_tsb) != 8); 1694 1597 dev->needed_headroom += sizeof(struct bcm_tsb); ··· 1742 1631 return 0; 1743 1632 } 1744 1633 1634 + #ifdef CONFIG_PM_SLEEP 1635 + static int bcm_sysport_suspend_to_wol(struct bcm_sysport_priv *priv) 1636 + { 1637 + struct net_device *ndev = priv->netdev; 1638 + unsigned int timeout = 1000; 1639 + u32 reg; 1640 + 1641 + /* Password has already been programmed */ 1642 + reg = umac_readl(priv, UMAC_MPD_CTRL); 1643 + reg |= MPD_EN; 1644 + reg &= ~PSW_EN; 1645 + if (priv->wolopts & WAKE_MAGICSECURE) 1646 + reg |= PSW_EN; 1647 + umac_writel(priv, reg, UMAC_MPD_CTRL); 1648 + 1649 + /* Make sure RBUF entered WoL mode as result */ 1650 + do { 1651 + reg = rbuf_readl(priv, RBUF_STATUS); 1652 + if (reg & RBUF_WOL_MODE) 1653 + break; 1654 + 1655 + udelay(10); 1656 + } while (timeout-- > 0); 1657 + 1658 + /* Do not leave the UniMAC RBUF matching only MPD packets */ 1659 + if (!timeout) { 1660 + reg = umac_readl(priv, UMAC_MPD_CTRL); 1661 + reg &= ~MPD_EN; 1662 + umac_writel(priv, reg, UMAC_MPD_CTRL); 1663 + netif_err(priv, wol, ndev, "failed to enter WOL mode\n"); 1664 + return -ETIMEDOUT; 1665 + } 1666 + 1667 + /* UniMAC receive needs to be turned on */ 1668 + umac_enable_set(priv, CMD_RX_EN, 1); 1669 + 1670 + /* Enable the interrupt wake-up source */ 1671 + intrl2_0_mask_clear(priv, INTRL2_0_MPD); 1672 + 1673 + netif_dbg(priv, wol, ndev, "entered WOL mode\n"); 1674 + 1675 + return 0; 1676 + } 1677 + 1678 + static int bcm_sysport_suspend(struct device *d) 1679 + { 1680 + struct net_device *dev = dev_get_drvdata(d); 1681 + struct bcm_sysport_priv *priv = netdev_priv(dev); 1682 + unsigned int i; 1683 + int ret = 0; 1684 + u32 reg; 1685 + 1686 + if (!netif_running(dev)) 1687 + return 0; 1688 + 1689 + bcm_sysport_netif_stop(dev); 1690 + 1691 + phy_suspend(priv->phydev); 1692 + 1693 + netif_device_detach(dev); 1694 + 1695 + /* Disable UniMAC RX */ 1696 + umac_enable_set(priv, CMD_RX_EN, 0); 1697 + 1698 + ret = rdma_enable_set(priv, 0); 1699 + if (ret) { 1700 + netdev_err(dev, "RDMA timeout!\n"); 1701 + return ret; 1702 + } 1703 + 1704 + /* Disable RXCHK if enabled */ 1705 + if (priv->rx_chk_en) { 1706 + reg = rxchk_readl(priv, RXCHK_CONTROL); 1707 + reg &= ~RXCHK_EN; 1708 + rxchk_writel(priv, reg, RXCHK_CONTROL); 1709 + } 1710 + 1711 + /* Flush RX pipe */ 1712 + if (!priv->wolopts) 1713 + topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL); 1714 + 1715 + ret = tdma_enable_set(priv, 0); 1716 + if (ret) { 1717 + netdev_err(dev, "TDMA timeout!\n"); 1718 + return ret; 1719 + } 1720 + 1721 + /* Wait for a packet boundary */ 1722 + usleep_range(2000, 3000); 1723 + 1724 + umac_enable_set(priv, CMD_TX_EN, 0); 1725 + 1726 + topctrl_writel(priv, TX_FLUSH, TX_FLUSH_CNTL); 1727 + 1728 + /* Free RX/TX rings SW structures */ 1729 + for (i = 0; i < dev->num_tx_queues; i++) 1730 + bcm_sysport_fini_tx_ring(priv, i); 1731 + bcm_sysport_fini_rx_ring(priv); 1732 + 1733 + /* Get prepared for Wake-on-LAN */ 1734 + if (device_may_wakeup(d) && priv->wolopts) 1735 + ret = bcm_sysport_suspend_to_wol(priv); 1736 + 1737 + return ret; 1738 + } 1739 + 1740 + static int bcm_sysport_resume(struct device *d) 1741 + { 1742 + struct net_device *dev = dev_get_drvdata(d); 1743 + struct bcm_sysport_priv *priv = netdev_priv(dev); 1744 + unsigned int i; 1745 + u32 reg; 1746 + int ret; 1747 + 1748 + if (!netif_running(dev)) 1749 + return 0; 1750 + 1751 + /* We may have been suspended and never received a WOL event that 1752 + * would turn off MPD detection, take care of that now 1753 + */ 1754 + bcm_sysport_resume_from_wol(priv); 1755 + 1756 + /* Initialize both hardware and software ring */ 1757 + for (i = 0; i < dev->num_tx_queues; i++) { 1758 + ret = bcm_sysport_init_tx_ring(priv, i); 1759 + if (ret) { 1760 + netdev_err(dev, "failed to initialize TX ring %d\n", 1761 + i); 1762 + goto out_free_tx_rings; 1763 + } 1764 + } 1765 + 1766 + /* Initialize linked-list */ 1767 + tdma_writel(priv, TDMA_LL_RAM_INIT_BUSY, TDMA_STATUS); 1768 + 1769 + /* Initialize RX ring */ 1770 + ret = bcm_sysport_init_rx_ring(priv); 1771 + if (ret) { 1772 + netdev_err(dev, "failed to initialize RX ring\n"); 1773 + goto out_free_rx_ring; 1774 + } 1775 + 1776 + netif_device_attach(dev); 1777 + 1778 + /* Enable RX interrupt and TX ring full interrupt */ 1779 + intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL); 1780 + 1781 + /* RX pipe enable */ 1782 + topctrl_writel(priv, 0, RX_FLUSH_CNTL); 1783 + 1784 + ret = rdma_enable_set(priv, 1); 1785 + if (ret) { 1786 + netdev_err(dev, "failed to enable RDMA\n"); 1787 + goto out_free_rx_ring; 1788 + } 1789 + 1790 + /* Enable rxhck */ 1791 + if (priv->rx_chk_en) { 1792 + reg = rxchk_readl(priv, RXCHK_CONTROL); 1793 + reg |= RXCHK_EN; 1794 + rxchk_writel(priv, reg, RXCHK_CONTROL); 1795 + } 1796 + 1797 + rbuf_init(priv); 1798 + 1799 + /* Set maximum frame length */ 1800 + umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); 1801 + 1802 + /* Set MAC address */ 1803 + umac_set_hw_addr(priv, dev->dev_addr); 1804 + 1805 + umac_enable_set(priv, CMD_RX_EN, 1); 1806 + 1807 + /* TX pipe enable */ 1808 + topctrl_writel(priv, 0, TX_FLUSH_CNTL); 1809 + 1810 + umac_enable_set(priv, CMD_TX_EN, 1); 1811 + 1812 + ret = tdma_enable_set(priv, 1); 1813 + if (ret) { 1814 + netdev_err(dev, "TDMA timeout!\n"); 1815 + goto out_free_rx_ring; 1816 + } 1817 + 1818 + phy_resume(priv->phydev); 1819 + 1820 + bcm_sysport_netif_start(dev); 1821 + 1822 + return 0; 1823 + 1824 + out_free_rx_ring: 1825 + bcm_sysport_fini_rx_ring(priv); 1826 + out_free_tx_rings: 1827 + for (i = 0; i < dev->num_tx_queues; i++) 1828 + bcm_sysport_fini_tx_ring(priv, i); 1829 + return ret; 1830 + } 1831 + #endif 1832 + 1833 + static SIMPLE_DEV_PM_OPS(bcm_sysport_pm_ops, 1834 + bcm_sysport_suspend, bcm_sysport_resume); 1835 + 1745 1836 static const struct of_device_id bcm_sysport_of_match[] = { 1746 1837 { .compatible = "brcm,systemport-v1.00" }, 1747 1838 { .compatible = "brcm,systemport" }, ··· 1957 1644 .name = "brcm-systemport", 1958 1645 .owner = THIS_MODULE, 1959 1646 .of_match_table = bcm_sysport_of_match, 1647 + .pm = &bcm_sysport_pm_ops, 1960 1648 }, 1961 1649 }; 1962 1650 module_platform_driver(bcm_sysport_driver);
+13 -1
drivers/net/ethernet/broadcom/bcmsysport.h
··· 246 246 #define MIB_RX_CNT_RST (1 << 0) 247 247 #define MIB_RUNT_CNT_RST (1 << 1) 248 248 #define MIB_TX_CNT_RST (1 << 2) 249 + 250 + #define UMAC_MPD_CTRL 0x620 251 + #define MPD_EN (1 << 0) 252 + #define MSEQ_LEN_SHIFT 16 253 + #define MSEQ_LEN_MASK 0xff 254 + #define PSW_EN (1 << 27) 255 + 256 + #define UMAC_PSW_MS 0x624 257 + #define UMAC_PSW_LS 0x628 249 258 #define UMAC_MDF_CTRL 0x650 250 259 #define UMAC_MDF_ADDR 0x654 251 260 ··· 651 642 struct platform_device *pdev; 652 643 int irq0; 653 644 int irq1; 645 + int wol_irq; 654 646 655 647 /* Transmit rings */ 656 648 struct bcm_sysport_tx_ring tx_rings[TDMA_NUM_RINGS]; ··· 674 664 int old_duplex; 675 665 676 666 /* Misc fields */ 677 - unsigned int rx_csum_en:1; 667 + unsigned int rx_chk_en:1; 678 668 unsigned int tsb_en:1; 679 669 unsigned int crc_fwd:1; 680 670 u16 rev; 671 + u32 wolopts; 672 + unsigned int wol_irq_disabled:1; 681 673 682 674 /* MIB related fields */ 683 675 struct bcm_sysport_mib mib;