summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2015-10-06 05:52:39 +0300
committerJoel Stanley <joel@jms.id.au>2015-10-06 06:50:05 +0300
commit82d7d5a325ba3b8dc053c8ce7caa6326f00879ea (patch)
treee3070985144892755da3147706ff179048bbdd8d
parent51b30d4df2402462fd3637e25c35408c885e1942 (diff)
downloadlinux-82d7d5a325ba3b8dc053c8ce7caa6326f00879ea.tar.xz
net/faraday: Enable NCSI interface
The NIC has the possibility to connect to NCSI package and channel. This supports NCSI enabled interface. When the network device is registered, the accompanying NCSI device is registered. When the interface is to be brought up, the NCSI device is started to probe NCSI topology and choose one active channel automatically. On the other handle, when the interface is to be brought down, the interface will be shuted down when the NCSI device is teared down. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c91
1 files changed, 67 insertions, 24 deletions
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 778bee8e33dd..1b13fd4d7271 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -31,6 +31,7 @@
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <net/ip.h>
+#include <net/ncsi.h>
#include "ftgmac100.h"
@@ -68,6 +69,7 @@ struct ftgmac100 {
struct net_device *netdev;
struct device *dev;
+ struct ncsi_dev *ndev;
struct napi_struct napi;
struct mii_bus *mii_bus;
@@ -1038,7 +1040,11 @@ static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
struct net_device *netdev = dev_id;
struct ftgmac100 *priv = netdev_priv(netdev);
- if (likely(netif_running(netdev))) {
+ /* When running in NCSI mode, the interface should be
+ * ready to receive or transmit NCSI packet before it's
+ * opened.
+ */
+ if (likely(priv->use_ncsi || netif_running(netdev))) {
/* Disable interrupts for polling */
iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
napi_schedule(&priv->napi);
@@ -1162,8 +1168,18 @@ static int ftgmac100_open(struct net_device *netdev)
/* enable all interrupts */
iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTGMAC100_OFFSET_IER);
+ /* Start the NCSI device */
+ if (priv->use_ncsi){
+ err = ncsi_start_dev(priv->ndev);
+ if (err)
+ goto err_ncsi;
+ }
return 0;
+err_ncsi:
+ napi_disable(&priv->napi);
+ netif_stop_queue(netdev);
+ iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
err_hw:
free_irq(priv->irq, netdev);
err_irq:
@@ -1172,7 +1188,7 @@ err_alloc:
return err;
}
-static int ftgmac100_stop(struct net_device *netdev)
+static int ftgmac100_stop_dev(struct net_device *netdev)
{
struct ftgmac100 *priv = netdev_priv(netdev);
@@ -1191,6 +1207,18 @@ static int ftgmac100_stop(struct net_device *netdev)
return 0;
}
+static int ftgmac100_stop(struct net_device *netdev)
+{
+ struct ftgmac100 *priv = netdev_priv(netdev);
+
+ /* Stop NCSI device */
+ if (priv->use_ncsi) {
+ ncsi_stop_dev(priv->ndev);
+ return 0;
+ }
+
+ return ftgmac100_stop_dev(netdev);
+}
static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
@@ -1291,6 +1319,21 @@ static const struct net_device_ops ftgmac100_netdev_ops = {
.ndo_do_ioctl = ftgmac100_do_ioctl,
};
+static void ftgmac100_ncsi_handler(struct ncsi_dev *nd)
+{
+ struct net_device *netdev = nd->nd_dev;
+
+ if (nd->nd_state != ncsi_dev_state_functional)
+ return;
+
+ if (nd->nd_link_up) {
+ pr_info("NCSI dev is up\n");
+ netif_start_queue(netdev);
+ } else {
+ pr_info("NCSI dev is down\n");
+ ftgmac100_stop_dev(netdev);
+ }
+}
/******************************************************************************
* struct platform_driver functions
*****************************************************************************/
@@ -1300,7 +1343,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
int irq;
struct net_device *netdev;
struct ftgmac100 *priv;
- int err;
+ int err = 0;
if (!pdev)
return -ENODEV;
@@ -1320,7 +1363,17 @@ static int ftgmac100_probe(struct platform_device *pdev)
goto err_alloc_etherdev;
}
+ /* Check for NCSI mode */
+ priv = netdev_priv(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
+ if (pdev->dev.of_node &&
+ of_get_property(pdev->dev.of_node, "use-nc-si", NULL)) {
+ dev_info(&pdev->dev, "Using NCSI interface\n");
+ priv->phydev = NULL;
+ priv->use_ncsi = true;
+ } else {
+ priv->use_ncsi = false;
+ }
netdev->ethtool_ops = &ftgmac100_ethtool_ops;
netdev->netdev_ops = &ftgmac100_netdev_ops;
@@ -1329,7 +1382,6 @@ static int ftgmac100_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, netdev);
/* setup private data */
- priv = netdev_priv(netdev);
priv->netdev = netdev;
priv->dev = &pdev->dev;
@@ -1356,24 +1408,14 @@ static int ftgmac100_probe(struct platform_device *pdev)
priv->irq = irq;
- /* Check for NC-SI mode */
- if (pdev->dev.of_node &&
- of_get_property(pdev->dev.of_node, "use-nc-si", NULL))
- priv->use_ncsi = true;
- else
- priv->use_ncsi = false;
+ /* Read MAC address or setup a new one */
+ ftgmac100_setup_mac(priv);
- /* If we use NC-SI, we need to set that up, which isn't implemented yet
- * so we pray things were setup by the bootloader and just mark our link
- * as up (otherwise we can't get packets through).
- *
- * Eventually, we'll have a proper NC-SI stack as a helper we can
- * instanciate
- */
+ /* Register NCSI device */
if (priv->use_ncsi) {
- /* XXX */
- priv->phydev = NULL;
- dev_info(&pdev->dev, "Using NC-SI interface\n");
+ priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
+ if (!priv->ndev)
+ goto err_ncsi_dev;
} else {
err = ftgmac100_setup_mdio(priv);
@@ -1384,9 +1426,6 @@ static int ftgmac100_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "Error %d setting up MDIO\n", err);
}
- /* Read MAC address or setup a new one */
- ftgmac100_setup_mac(priv);
-
/* Register network device */
err = register_netdev(netdev);
if (err) {
@@ -1399,7 +1438,11 @@ static int ftgmac100_probe(struct platform_device *pdev)
return 0;
err_register_netdev:
- ftgmac100_destroy_mdio(priv);
+ if (!priv->use_ncsi)
+ ftgmac100_destroy_mdio(priv);
+ else
+ ncsi_unregister_dev(priv->ndev);
+err_ncsi_dev:
iounmap(priv->base);
err_ioremap:
release_resource(priv->res);