All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support
@ 2014-07-02  4:08 Florian Fainelli
  2014-07-02  4:08 ` [PATCH net-next 1/5] net: systemport: update umac_enable_set to take a bitmask Florian Fainelli
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Florian Fainelli @ 2014-07-02  4:08 UTC (permalink / raw)
  To: netdev; +Cc: davem, Florian Fainelli

Hi David,

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

Florian Fainelli (5):
  net: systemport: update umac_enable_set to take a bitmask
  net: systemport: add bcm_sysport_netif_{enable,stop}
  net: systemport: add suspend and resume support
  net: systemport: rename rx_csum_en to rx_chk_en
  net: systemport: add Wake-on-LAN support

 .../bindings/net/broadcom-systemport.txt           |   3 +-
 drivers/net/ethernet/broadcom/bcmsysport.c         | 378 +++++++++++++++++++--
 drivers/net/ethernet/broadcom/bcmsysport.h         |  14 +-
 3 files changed, 361 insertions(+), 34 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH net-next 1/5] net: systemport: update umac_enable_set to take a bitmask
  2014-07-02  4:08 [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support Florian Fainelli
@ 2014-07-02  4:08 ` Florian Fainelli
  2014-07-02  4:08 ` [PATCH net-next 2/5] net: systemport: add bcm_sysport_netif_{enable,stop} Florian Fainelli
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Florian Fainelli @ 2014-07-02  4:08 UTC (permalink / raw)
  To: netdev; +Cc: davem, Florian Fainelli

Quite often we need to enable either the transmitter or the receiver
bits in UMAC_CMD, use umac_enable_set() to do that for us.

This is a preliminary change to introduce suspend/resume support in the
driver.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/ethernet/broadcom/bcmsysport.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 141160ef249a..bbe74494c629 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -1236,15 +1236,15 @@ static void bcm_sysport_set_rx_mode(struct net_device *dev)
 }
 
 static inline void umac_enable_set(struct bcm_sysport_priv *priv,
-					unsigned int enable)
+					u32 mask, unsigned int enable)
 {
 	u32 reg;
 
 	reg = umac_readl(priv, UMAC_CMD);
 	if (enable)
-		reg |= CMD_RX_EN | CMD_TX_EN;
+		reg |= mask;
 	else
-		reg &= ~(CMD_RX_EN | CMD_TX_EN);
+		reg &= ~mask;
 	umac_writel(priv, reg, UMAC_CMD);
 
 	/* UniMAC stops on a packet boundary, wait for a full-sized packet
@@ -1313,7 +1313,7 @@ static int bcm_sysport_open(struct net_device *dev)
 	topctrl_flush(priv);
 
 	/* Disable the UniMAC RX/TX */
-	umac_enable_set(priv, 0);
+	umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 0);
 
 	/* Enable RBUF 2bytes alignment and Receive Status Block */
 	reg = rbuf_readl(priv, RBUF_CONTROL);
@@ -1398,7 +1398,7 @@ static int bcm_sysport_open(struct net_device *dev)
 	napi_enable(&priv->napi);
 
 	/* Turn on UniMAC TX/RX */
-	umac_enable_set(priv, 1);
+	umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 1);
 
 	phy_start(priv->phydev);
 
@@ -1429,7 +1429,6 @@ static int bcm_sysport_stop(struct net_device *dev)
 {
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
 	unsigned int i;
-	u32 reg;
 	int ret;
 
 	/* stop all software from updating hardware */
@@ -1444,9 +1443,7 @@ static int bcm_sysport_stop(struct net_device *dev)
 	intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
 
 	/* Disable UniMAC RX */
-	reg = umac_readl(priv, UMAC_CMD);
-	reg &= ~CMD_RX_EN;
-	umac_writel(priv, reg, UMAC_CMD);
+	umac_enable_set(priv, CMD_RX_EN, 0);
 
 	ret = tdma_enable_set(priv, 0);
 	if (ret) {
@@ -1464,9 +1461,7 @@ static int bcm_sysport_stop(struct net_device *dev)
 	}
 
 	/* Disable UniMAC TX */
-	reg = umac_readl(priv, UMAC_CMD);
-	reg &= ~CMD_TX_EN;
-	umac_writel(priv, reg, UMAC_CMD);
+	umac_enable_set(priv, CMD_TX_EN, 0);
 
 	/* Free RX/TX rings SW structures */
 	for (i = 0; i < dev->num_tx_queues; i++)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH net-next 2/5] net: systemport: add bcm_sysport_netif_{enable,stop}
  2014-07-02  4:08 [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support Florian Fainelli
  2014-07-02  4:08 ` [PATCH net-next 1/5] net: systemport: update umac_enable_set to take a bitmask Florian Fainelli
@ 2014-07-02  4:08 ` Florian Fainelli
  2014-07-02  4:08 ` [PATCH net-next 3/5] net: systemport: add suspend and resume support Florian Fainelli
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Florian Fainelli @ 2014-07-02  4:08 UTC (permalink / raw)
  To: netdev; +Cc: davem, Florian Fainelli

Factor common code that either enables or disables the network
interface with the networking stack. We are going to reuse these
functions for suspend/resume callbacks.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/ethernet/broadcom/bcmsysport.c | 40 ++++++++++++++++++++----------
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index bbe74494c629..8f6ab266b178 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -1295,6 +1295,22 @@ static void topctrl_flush(struct bcm_sysport_priv *priv)
 	topctrl_writel(priv, 0, TX_FLUSH_CNTL);
 }
 
+static void bcm_sysport_netif_start(struct net_device *dev)
+{
+	struct bcm_sysport_priv *priv = netdev_priv(dev);
+
+	/* Enable NAPI */
+	napi_enable(&priv->napi);
+
+	phy_start(priv->phydev);
+
+	/* Enable TX interrupts for the 32 TXQs */
+	intrl2_1_mask_clear(priv, 0xffffffff);
+
+	/* Last call before we start the real business */
+	netif_tx_start_all_queues(dev);
+}
+
 static int bcm_sysport_open(struct net_device *dev)
 {
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
@@ -1394,19 +1410,10 @@ static int bcm_sysport_open(struct net_device *dev)
 	if (ret)
 		goto out_clear_rx_int;
 
-	/* Enable NAPI */
-	napi_enable(&priv->napi);
-
 	/* Turn on UniMAC TX/RX */
 	umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 1);
 
-	phy_start(priv->phydev);
-
-	/* Enable TX interrupts for the 32 TXQs */
-	intrl2_1_mask_clear(priv, 0xffffffff);
-
-	/* Last call before we start the real business */
-	netif_tx_start_all_queues(dev);
+	bcm_sysport_netif_start(dev);
 
 	return 0;
 
@@ -1425,11 +1432,9 @@ out_phy_disconnect:
 	return ret;
 }
 
-static int bcm_sysport_stop(struct net_device *dev)
+static void bcm_sysport_netif_stop(struct net_device *dev)
 {
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
-	unsigned int i;
-	int ret;
 
 	/* stop all software from updating hardware */
 	netif_tx_stop_all_queues(dev);
@@ -1441,6 +1446,15 @@ static int bcm_sysport_stop(struct net_device *dev)
 	intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
 	intrl2_1_mask_set(priv, 0xffffffff);
 	intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+}
+
+static int bcm_sysport_stop(struct net_device *dev)
+{
+	struct bcm_sysport_priv *priv = netdev_priv(dev);
+	unsigned int i;
+	int ret;
+
+	bcm_sysport_netif_stop(dev);
 
 	/* Disable UniMAC RX */
 	umac_enable_set(priv, CMD_RX_EN, 0);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH net-next 3/5] net: systemport: add suspend and resume support
  2014-07-02  4:08 [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support Florian Fainelli
  2014-07-02  4:08 ` [PATCH net-next 1/5] net: systemport: update umac_enable_set to take a bitmask Florian Fainelli
  2014-07-02  4:08 ` [PATCH net-next 2/5] net: systemport: add bcm_sysport_netif_{enable,stop} Florian Fainelli
@ 2014-07-02  4:08 ` Florian Fainelli
  2014-07-02  4:08 ` [PATCH net-next 4/5] net: systemport: rename rx_csum_en to rx_chk_en Florian Fainelli
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Florian Fainelli @ 2014-07-02  4:08 UTC (permalink / raw)
  To: netdev; +Cc: davem, Florian Fainelli

Implement the hardware recommended suspend/resume procedure for
SYSTEMPORT. We leverage the previous factoring work such that we can
logically break all suspend/resume operations into disctint RX and TX
code paths.

When the system enters S3, we will loose all register contents, so
make sure that we correctly re-program all the hardware and software
views of the RX & TX rings as well.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/ethernet/broadcom/bcmsysport.c | 164 ++++++++++++++++++++++++++++-
 1 file changed, 160 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 8f6ab266b178..9dabcfbfc23a 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -1311,11 +1311,19 @@ static void bcm_sysport_netif_start(struct net_device *dev)
 	netif_tx_start_all_queues(dev);
 }
 
+static void rbuf_init(struct bcm_sysport_priv *priv)
+{
+	u32 reg;
+
+	reg = rbuf_readl(priv, RBUF_CONTROL);
+	reg |= RBUF_4B_ALGN | RBUF_RSB_EN;
+	rbuf_writel(priv, reg, RBUF_CONTROL);
+}
+
 static int bcm_sysport_open(struct net_device *dev)
 {
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
 	unsigned int i;
-	u32 reg;
 	int ret;
 
 	/* Reset UniMAC */
@@ -1332,9 +1340,7 @@ static int bcm_sysport_open(struct net_device *dev)
 	umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 0);
 
 	/* Enable RBUF 2bytes alignment and Receive Status Block */
-	reg = rbuf_readl(priv, RBUF_CONTROL);
-	reg |= RBUF_4B_ALGN | RBUF_RSB_EN;
-	rbuf_writel(priv, reg, RBUF_CONTROL);
+	rbuf_init(priv);
 
 	/* Set maximum frame length */
 	umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
@@ -1640,6 +1646,155 @@ static int bcm_sysport_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int bcm_sysport_suspend(struct device *d)
+{
+	struct net_device *dev = dev_get_drvdata(d);
+	struct bcm_sysport_priv *priv = netdev_priv(dev);
+	unsigned int i;
+	int ret;
+	u32 reg;
+
+	if (!netif_running(dev))
+		return 0;
+
+	bcm_sysport_netif_stop(dev);
+
+	phy_suspend(priv->phydev);
+
+	netif_device_detach(dev);
+
+	/* Disable UniMAC RX */
+	umac_enable_set(priv, CMD_RX_EN, 0);
+
+	ret = rdma_enable_set(priv, 0);
+	if (ret) {
+		netdev_err(dev, "RDMA timeout!\n");
+		return ret;
+	}
+
+	/* Disable RXCHK if enabled */
+	if (priv->rx_csum_en) {
+		reg = rxchk_readl(priv, RXCHK_CONTROL);
+		reg &= ~RXCHK_EN;
+		rxchk_writel(priv, reg, RXCHK_CONTROL);
+	}
+
+	/* Flush RX pipe */
+	topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL);
+
+	ret = tdma_enable_set(priv, 0);
+	if (ret) {
+		netdev_err(dev, "TDMA timeout!\n");
+		return ret;
+	}
+
+	/* Wait for a packet boundary */
+	usleep_range(2000, 3000);
+
+	umac_enable_set(priv, CMD_TX_EN, 0);
+
+	topctrl_writel(priv, TX_FLUSH, TX_FLUSH_CNTL);
+
+	/* Free RX/TX rings SW structures */
+	for (i = 0; i < dev->num_tx_queues; i++)
+		bcm_sysport_fini_tx_ring(priv, i);
+	bcm_sysport_fini_rx_ring(priv);
+
+	return 0;
+}
+
+static int bcm_sysport_resume(struct device *d)
+{
+	struct net_device *dev = dev_get_drvdata(d);
+	struct bcm_sysport_priv *priv = netdev_priv(dev);
+	unsigned int i;
+	u32 reg;
+	int ret;
+
+	if (!netif_running(dev))
+		return 0;
+
+	/* Initialize both hardware and software ring */
+	for (i = 0; i < dev->num_tx_queues; i++) {
+		ret = bcm_sysport_init_tx_ring(priv, i);
+		if (ret) {
+			netdev_err(dev, "failed to initialize TX ring %d\n",
+					i);
+			goto out_free_tx_rings;
+		}
+	}
+
+	/* Initialize linked-list */
+	tdma_writel(priv, TDMA_LL_RAM_INIT_BUSY, TDMA_STATUS);
+
+	/* Initialize RX ring */
+	ret = bcm_sysport_init_rx_ring(priv);
+	if (ret) {
+		netdev_err(dev, "failed to initialize RX ring\n");
+		goto out_free_rx_ring;
+	}
+
+	netif_device_attach(dev);
+
+	/* Enable RX interrupt and TX ring full interrupt */
+	intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL);
+
+	/* RX pipe enable */
+	topctrl_writel(priv, 0, RX_FLUSH_CNTL);
+
+	ret = rdma_enable_set(priv, 1);
+	if (ret) {
+		netdev_err(dev, "failed to enable RDMA\n");
+		goto out_free_rx_ring;
+	}
+
+	/* Enable rxhck */
+	if (priv->rx_csum_en) {
+		reg = rxchk_readl(priv, RXCHK_CONTROL);
+		reg |= RXCHK_EN;
+		rxchk_writel(priv, reg, RXCHK_CONTROL);
+	}
+
+	rbuf_init(priv);
+
+	/* Set maximum frame length */
+	umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
+
+	/* Set MAC address */
+	umac_set_hw_addr(priv, dev->dev_addr);
+
+	umac_enable_set(priv, CMD_RX_EN, 1);
+
+	/* TX pipe enable */
+	topctrl_writel(priv, 0, TX_FLUSH_CNTL);
+
+	umac_enable_set(priv, CMD_TX_EN, 1);
+
+	ret = tdma_enable_set(priv, 1);
+	if (ret) {
+		netdev_err(dev, "TDMA timeout!\n");
+		goto out_free_rx_ring;
+	}
+
+	phy_resume(priv->phydev);
+
+	bcm_sysport_netif_start(dev);
+
+	return 0;
+
+out_free_rx_ring:
+	bcm_sysport_fini_rx_ring(priv);
+out_free_tx_rings:
+	for (i = 0; i < dev->num_tx_queues; i++)
+		bcm_sysport_fini_tx_ring(priv, i);
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(bcm_sysport_pm_ops,
+		bcm_sysport_suspend, bcm_sysport_resume);
+
 static const struct of_device_id bcm_sysport_of_match[] = {
 	{ .compatible = "brcm,systemport-v1.00" },
 	{ .compatible = "brcm,systemport" },
@@ -1653,6 +1808,7 @@ static struct platform_driver bcm_sysport_driver = {
 		.name = "brcm-systemport",
 		.owner = THIS_MODULE,
 		.of_match_table = bcm_sysport_of_match,
+		.pm = &bcm_sysport_pm_ops,
 	},
 };
 module_platform_driver(bcm_sysport_driver);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH net-next 4/5] net: systemport: rename rx_csum_en to rx_chk_en
  2014-07-02  4:08 [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support Florian Fainelli
                   ` (2 preceding siblings ...)
  2014-07-02  4:08 ` [PATCH net-next 3/5] net: systemport: add suspend and resume support Florian Fainelli
@ 2014-07-02  4:08 ` Florian Fainelli
  2014-07-02  4:08 ` [PATCH net-next 5/5] net: systemport: add Wake-on-LAN support Florian Fainelli
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Florian Fainelli @ 2014-07-02  4:08 UTC (permalink / raw)
  To: netdev; +Cc: davem, Florian Fainelli

This boolean tells us whether we are using the RXCHK hardware block,
so use a variable name that reflects that. RXCHK might be used in the
future to implement Wake-on-LAN using ARP or unicast packets.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/ethernet/broadcom/bcmsysport.c | 10 +++++-----
 drivers/net/ethernet/broadcom/bcmsysport.h |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 9dabcfbfc23a..f00793e45330 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -124,9 +124,9 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev,
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
 	u32 reg;
 
-	priv->rx_csum_en = !!(wanted & NETIF_F_RXCSUM);
+	priv->rx_chk_en = !!(wanted & NETIF_F_RXCSUM);
 	reg = rxchk_readl(priv, RXCHK_CONTROL);
-	if (priv->rx_csum_en)
+	if (priv->rx_chk_en)
 		reg |= RXCHK_EN;
 	else
 		reg &= ~RXCHK_EN;
@@ -134,7 +134,7 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev,
 	/* If UniMAC forwards CRC, we need to skip over it to get
 	 * a valid CHK bit to be set in the per-packet status word
 	 */
-	if (priv->rx_csum_en && priv->crc_fwd)
+	if (priv->rx_chk_en && priv->crc_fwd)
 		reg |= RXCHK_SKIP_FCS;
 	else
 		reg &= ~RXCHK_SKIP_FCS;
@@ -1674,7 +1674,7 @@ static int bcm_sysport_suspend(struct device *d)
 	}
 
 	/* Disable RXCHK if enabled */
-	if (priv->rx_csum_en) {
+	if (priv->rx_chk_en) {
 		reg = rxchk_readl(priv, RXCHK_CONTROL);
 		reg &= ~RXCHK_EN;
 		rxchk_writel(priv, reg, RXCHK_CONTROL);
@@ -1750,7 +1750,7 @@ static int bcm_sysport_resume(struct device *d)
 	}
 
 	/* Enable rxhck */
-	if (priv->rx_csum_en) {
+	if (priv->rx_chk_en) {
 		reg = rxchk_readl(priv, RXCHK_CONTROL);
 		reg |= RXCHK_EN;
 		rxchk_writel(priv, reg, RXCHK_CONTROL);
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index 281c08246037..20ea7162478f 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -664,7 +664,7 @@ struct bcm_sysport_priv {
 	int			old_duplex;
 
 	/* Misc fields */
-	unsigned int		rx_csum_en:1;
+	unsigned int		rx_chk_en:1;
 	unsigned int		tsb_en:1;
 	unsigned int		crc_fwd:1;
 	u16			rev;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH net-next 5/5] net: systemport: add Wake-on-LAN support
  2014-07-02  4:08 [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support Florian Fainelli
                   ` (3 preceding siblings ...)
  2014-07-02  4:08 ` [PATCH net-next 4/5] net: systemport: rename rx_csum_en to rx_chk_en Florian Fainelli
@ 2014-07-02  4:08 ` Florian Fainelli
  2014-07-02 16:44 ` [PATCH net-next 0/5] net: systemport: PM and " Florian Fainelli
  2014-07-08  4:03 ` David Miller
  6 siblings, 0 replies; 8+ messages in thread
From: Florian Fainelli @ 2014-07-02  4:08 UTC (permalink / raw)
  To: netdev; +Cc: davem, Florian Fainelli

Support for Wake-on-LAN using Magic Packet with or without SecureOn
password is implemented doing the following:

- setting the password to the relevant UniMAC registers
- flagging the device as a wakeup source for the system, as well as
  its Wake-on-LAN interrupt
- prepare the hardware for entering WoL mode
- enabling the MPD interrupt to wake us

The Device Tree binding documentation is also reflected to specify the
third optional Wake-on-LAN interrupt line.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 .../bindings/net/broadcom-systemport.txt           |   3 +-
 drivers/net/ethernet/broadcom/bcmsysport.c         | 155 ++++++++++++++++++++-
 drivers/net/ethernet/broadcom/bcmsysport.h         |  12 ++
 3 files changed, 166 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/broadcom-systemport.txt b/Documentation/devicetree/bindings/net/broadcom-systemport.txt
index c183ea90d9bc..aa7ad622259d 100644
--- a/Documentation/devicetree/bindings/net/broadcom-systemport.txt
+++ b/Documentation/devicetree/bindings/net/broadcom-systemport.txt
@@ -4,7 +4,8 @@ Required properties:
 - compatible: should be one of "brcm,systemport-v1.00" or "brcm,systemport"
 - reg: address and length of the register set for the device.
 - interrupts: interrupts for the device, first cell must be for the the rx
-  interrupts, and the second cell should be for the transmit queues
+  interrupts, and the second cell should be for the transmit queues. An
+  optional third interrupt cell for Wake-on-LAN can be specified
 - local-mac-address: Ethernet MAC address (48 bits) of this adapter
 - phy-mode: Should be a string describing the PHY interface to the
   Ethernet switch/PHY, see Documentation/devicetree/bindings/net/ethernet.txt
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index f00793e45330..7a1bd2b3bc26 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -384,6 +384,64 @@ static void bcm_sysport_get_stats(struct net_device *dev,
 	}
 }
 
+static void bcm_sysport_get_wol(struct net_device *dev,
+				struct ethtool_wolinfo *wol)
+{
+	struct bcm_sysport_priv *priv = netdev_priv(dev);
+	u32 reg;
+
+	wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
+	wol->wolopts = priv->wolopts;
+
+	if (!(priv->wolopts & WAKE_MAGICSECURE))
+		return;
+
+	/* Return the programmed SecureOn password */
+	reg = umac_readl(priv, UMAC_PSW_MS);
+	put_unaligned_be16(reg, &wol->sopass[0]);
+	reg = umac_readl(priv, UMAC_PSW_LS);
+	put_unaligned_be32(reg, &wol->sopass[2]);
+}
+
+static int bcm_sysport_set_wol(struct net_device *dev,
+				struct ethtool_wolinfo *wol)
+{
+	struct bcm_sysport_priv *priv = netdev_priv(dev);
+	struct device *kdev = &priv->pdev->dev;
+	u32 supported = WAKE_MAGIC | WAKE_MAGICSECURE;
+
+	if (!device_can_wakeup(kdev))
+		return -ENOTSUPP;
+
+	if (wol->wolopts & ~supported)
+		return -EINVAL;
+
+	/* Program the SecureOn password */
+	if (wol->wolopts & WAKE_MAGICSECURE) {
+		umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
+				UMAC_PSW_MS);
+		umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
+				UMAC_PSW_LS);
+	}
+
+	/* Flag the device and relevant IRQ as wakeup capable */
+	if (wol->wolopts) {
+		device_set_wakeup_enable(kdev, 1);
+		enable_irq_wake(priv->wol_irq);
+		priv->wol_irq_disabled = 0;
+	} else {
+		device_set_wakeup_enable(kdev, 0);
+		/* Avoid unbalanced disable_irq_wake calls */
+		if (!priv->wol_irq_disabled)
+			disable_irq_wake(priv->wol_irq);
+		priv->wol_irq_disabled = 1;
+	}
+
+	priv->wolopts = wol->wolopts;
+
+	return 0;
+}
+
 static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb)
 {
 	dev_kfree_skb_any(cb->skb);
@@ -692,6 +750,20 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
 	return work_done;
 }
 
+static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv)
+{
+	u32 reg;
+
+	/* Stop monitoring MPD interrupt */
+	intrl2_0_mask_set(priv, INTRL2_0_MPD);
+
+	/* Clear the MagicPacket detection logic */
+	reg = umac_readl(priv, UMAC_MPD_CTRL);
+	reg &= ~MPD_EN;
+	umac_writel(priv, reg, UMAC_MPD_CTRL);
+
+	netif_dbg(priv, wol, priv->netdev, "resumed from WOL\n");
+}
 
 /* RX and misc interrupt routine */
 static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
@@ -722,6 +794,11 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
 	if (priv->irq0_stat & INTRL2_0_TX_RING_FULL)
 		bcm_sysport_tx_reclaim_all(priv);
 
+	if (priv->irq0_stat & INTRL2_0_MPD) {
+		netdev_info(priv->netdev, "Wake-on-LAN interrupt!\n");
+		bcm_sysport_resume_from_wol(priv);
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -757,6 +834,15 @@ static irqreturn_t bcm_sysport_tx_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t bcm_sysport_wol_isr(int irq, void *dev_id)
+{
+	struct bcm_sysport_priv *priv = dev_id;
+
+	pm_wakeup_event(&priv->pdev->dev, 0);
+
+	return IRQ_HANDLED;
+}
+
 static int bcm_sysport_insert_tsb(struct sk_buff *skb, struct net_device *dev)
 {
 	struct sk_buff *nskb;
@@ -1507,6 +1593,8 @@ static struct ethtool_ops bcm_sysport_ethtool_ops = {
 	.get_strings		= bcm_sysport_get_strings,
 	.get_ethtool_stats	= bcm_sysport_get_stats,
 	.get_sset_count		= bcm_sysport_get_sset_count,
+	.get_wol		= bcm_sysport_get_wol,
+	.set_wol		= bcm_sysport_set_wol,
 };
 
 static const struct net_device_ops bcm_sysport_netdev_ops = {
@@ -1548,6 +1636,7 @@ static int bcm_sysport_probe(struct platform_device *pdev)
 
 	priv->irq0 = platform_get_irq(pdev, 0);
 	priv->irq1 = platform_get_irq(pdev, 1);
+	priv->wol_irq = platform_get_irq(pdev, 2);
 	if (priv->irq0 <= 0 || priv->irq1 <= 0) {
 		dev_err(&pdev->dev, "invalid interrupts\n");
 		ret = -EINVAL;
@@ -1600,6 +1689,13 @@ static int bcm_sysport_probe(struct platform_device *pdev)
 	dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA |
 				NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 
+	/* Request the WOL interrupt and advertise suspend if available */
+	priv->wol_irq_disabled = 1;
+	ret = devm_request_irq(&pdev->dev, priv->wol_irq,
+				bcm_sysport_wol_isr, 0, dev->name, priv);
+	if (!ret)
+		device_set_wakeup_capable(&pdev->dev, 1);
+
 	/* Set the needed headroom once and for all */
 	BUILD_BUG_ON(sizeof(struct bcm_tsb) != 8);
 	dev->needed_headroom += sizeof(struct bcm_tsb);
@@ -1647,12 +1743,55 @@ static int bcm_sysport_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
+static int bcm_sysport_suspend_to_wol(struct bcm_sysport_priv *priv)
+{
+	struct net_device *ndev = priv->netdev;
+	unsigned int timeout = 1000;
+	u32 reg;
+
+	/* Password has already been programmed */
+	reg = umac_readl(priv, UMAC_MPD_CTRL);
+	reg |= MPD_EN;
+	reg &= ~PSW_EN;
+	if (priv->wolopts & WAKE_MAGICSECURE)
+		reg |= PSW_EN;
+	umac_writel(priv, reg, UMAC_MPD_CTRL);
+
+	/* Make sure RBUF entered WoL mode as result */
+	do {
+		reg = rbuf_readl(priv, RBUF_STATUS);
+		if (reg & RBUF_WOL_MODE)
+			break;
+
+		udelay(10);
+	} while (timeout-- > 0);
+
+	/* Do not leave the UniMAC RBUF matching only MPD packets */
+	if (!timeout) {
+		reg = umac_readl(priv, UMAC_MPD_CTRL);
+		reg &= ~MPD_EN;
+		umac_writel(priv, reg, UMAC_MPD_CTRL);
+		netif_err(priv, wol, ndev, "failed to enter WOL mode\n");
+		return -ETIMEDOUT;
+	}
+
+	/* UniMAC receive needs to be turned on */
+	umac_enable_set(priv, CMD_RX_EN, 1);
+
+	/* Enable the interrupt wake-up source */
+	intrl2_0_mask_clear(priv, INTRL2_0_MPD);
+
+	netif_dbg(priv, wol, ndev, "entered WOL mode\n");
+
+	return 0;
+}
+
 static int bcm_sysport_suspend(struct device *d)
 {
 	struct net_device *dev = dev_get_drvdata(d);
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
 	unsigned int i;
-	int ret;
+	int ret = 0;
 	u32 reg;
 
 	if (!netif_running(dev))
@@ -1681,7 +1820,8 @@ static int bcm_sysport_suspend(struct device *d)
 	}
 
 	/* Flush RX pipe */
-	topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL);
+	if (!priv->wolopts)
+		topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL);
 
 	ret = tdma_enable_set(priv, 0);
 	if (ret) {
@@ -1701,7 +1841,11 @@ static int bcm_sysport_suspend(struct device *d)
 		bcm_sysport_fini_tx_ring(priv, i);
 	bcm_sysport_fini_rx_ring(priv);
 
-	return 0;
+	/* Get prepared for Wake-on-LAN */
+	if (device_may_wakeup(d) && priv->wolopts)
+		ret = bcm_sysport_suspend_to_wol(priv);
+
+	return ret;
 }
 
 static int bcm_sysport_resume(struct device *d)
@@ -1715,6 +1859,11 @@ static int bcm_sysport_resume(struct device *d)
 	if (!netif_running(dev))
 		return 0;
 
+	/* We may have been suspended and never received a WOL event that
+	 * would turn off MPD detection, take care of that now
+	 */
+	bcm_sysport_resume_from_wol(priv);
+
 	/* Initialize both hardware and software ring */
 	for (i = 0; i < dev->num_tx_queues; i++) {
 		ret = bcm_sysport_init_tx_ring(priv, i);
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index 20ea7162478f..b08dab828101 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -246,6 +246,15 @@ struct bcm_rsb {
 #define  MIB_RX_CNT_RST			(1 << 0)
 #define  MIB_RUNT_CNT_RST		(1 << 1)
 #define  MIB_TX_CNT_RST			(1 << 2)
+
+#define UMAC_MPD_CTRL			0x620
+#define  MPD_EN				(1 << 0)
+#define  MSEQ_LEN_SHIFT			16
+#define  MSEQ_LEN_MASK			0xff
+#define  PSW_EN				(1 << 27)
+
+#define UMAC_PSW_MS			0x624
+#define UMAC_PSW_LS			0x628
 #define UMAC_MDF_CTRL			0x650
 #define UMAC_MDF_ADDR			0x654
 
@@ -642,6 +651,7 @@ struct bcm_sysport_priv {
 	struct platform_device	*pdev;
 	int			irq0;
 	int			irq1;
+	int			wol_irq;
 
 	/* Transmit rings */
 	struct bcm_sysport_tx_ring tx_rings[TDMA_NUM_RINGS];
@@ -668,6 +678,8 @@ struct bcm_sysport_priv {
 	unsigned int		tsb_en:1;
 	unsigned int		crc_fwd:1;
 	u16			rev;
+	u32			wolopts;
+	unsigned int		wol_irq_disabled:1;
 
 	/* MIB related fields */
 	struct bcm_sysport_mib	mib;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support
  2014-07-02  4:08 [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support Florian Fainelli
                   ` (4 preceding siblings ...)
  2014-07-02  4:08 ` [PATCH net-next 5/5] net: systemport: add Wake-on-LAN support Florian Fainelli
@ 2014-07-02 16:44 ` Florian Fainelli
  2014-07-08  4:03 ` David Miller
  6 siblings, 0 replies; 8+ messages in thread
From: Florian Fainelli @ 2014-07-02 16:44 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Florian Fainelli

2014-07-01 21:08 GMT-07:00 Florian Fainelli <f.fainelli@gmail.com>:
> Hi David,
>
> This patchset brings Power Management and Wake-on-LAN support to the
> Broadcom SYSTEM PORT driver.

David, feel free to drop this patch series, I will submit a
preliminary patchset that fixes the checkpatch.pl errors/warnings in
the systemport driver before moving on to add these features again.

Thank you!

>
> S2 and S3 modes are supported, while we only support Wake-on-LAN using
> MagicPackets for now
>
> Florian Fainelli (5):
>   net: systemport: update umac_enable_set to take a bitmask
>   net: systemport: add bcm_sysport_netif_{enable,stop}
>   net: systemport: add suspend and resume support
>   net: systemport: rename rx_csum_en to rx_chk_en
>   net: systemport: add Wake-on-LAN support
>
>  .../bindings/net/broadcom-systemport.txt           |   3 +-
>  drivers/net/ethernet/broadcom/bcmsysport.c         | 378 +++++++++++++++++++--
>  drivers/net/ethernet/broadcom/bcmsysport.h         |  14 +-
>  3 files changed, 361 insertions(+), 34 deletions(-)
>
> --
> 1.9.1
>



-- 
Florian

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support
  2014-07-02  4:08 [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support Florian Fainelli
                   ` (5 preceding siblings ...)
  2014-07-02 16:44 ` [PATCH net-next 0/5] net: systemport: PM and " Florian Fainelli
@ 2014-07-08  4:03 ` David Miller
  6 siblings, 0 replies; 8+ messages in thread
From: David Miller @ 2014-07-08  4:03 UTC (permalink / raw)
  To: f.fainelli; +Cc: netdev

From: Florian Fainelli <f.fainelli@gmail.com>
Date: Tue,  1 Jul 2014 21:08:35 -0700

> 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

Series applied, thanks.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-07-08  4:03 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-02  4:08 [PATCH net-next 0/5] net: systemport: PM and Wake-on-LAN support Florian Fainelli
2014-07-02  4:08 ` [PATCH net-next 1/5] net: systemport: update umac_enable_set to take a bitmask Florian Fainelli
2014-07-02  4:08 ` [PATCH net-next 2/5] net: systemport: add bcm_sysport_netif_{enable,stop} Florian Fainelli
2014-07-02  4:08 ` [PATCH net-next 3/5] net: systemport: add suspend and resume support Florian Fainelli
2014-07-02  4:08 ` [PATCH net-next 4/5] net: systemport: rename rx_csum_en to rx_chk_en Florian Fainelli
2014-07-02  4:08 ` [PATCH net-next 5/5] net: systemport: add Wake-on-LAN support Florian Fainelli
2014-07-02 16:44 ` [PATCH net-next 0/5] net: systemport: PM and " Florian Fainelli
2014-07-08  4:03 ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.