Netdev List
 help / color / mirror / Atom feed
* [PATCH v2 net-next 2/2] tipc: add name distributor resiliency queue
From: erik.hugne @ 2014-08-26  8:57 UTC (permalink / raw)
  To: jon.maloy, ying.xue, richard.alpe, netdev; +Cc: tipc-discussion, Erik Hugne
In-Reply-To: <1409043477-22761-1-git-send-email-erik.hugne@ericsson.com>

From: Erik Hugne <erik.hugne@ericsson.com>

TIPC name table updates are distributed asynchronously in a cluster,
entailing a risk of certain race conditions. E.g., if two nodes
simultaneously issue conflicting (overlapping) publications, this may
not be detected until both publications have reached a third node, in
which case one of the publications will be silently dropped on that
node. Hence, we end up with an inconsistent name table.

In most cases this conflict is just a temporary race, e.g., one
node is issuing a publication under the assumption that a previous,
conflicting, publication has already been withdrawn by the other node.
However, because of the (rtt related) distributed update delay, this
may not yet hold true on all nodes. The symptom of this failure is a
syslog message: "tipc: Cannot publish {%u,%u,%u}, overlap error".

In this commit we add a resiliency queue at the receiving end of
the name table distributor. When insertion of an arriving publication
fails, we retain it in this queue for a short amount of time, assuming
that another update will arrive very soon and clear the conflict. If so
happens, we insert the publication, otherwise we drop it.

The (configurable) retention value defaults to 2000 ms. Knowing from
experience that the situation described above is extremely rare, there
is no risk that the queue will accumulate any large number of items.

Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---

v2: Fixed phrasing and spelling in the sysctl documentation

 Documentation/sysctl/net.txt | 16 ++++++++++
 net/tipc/core.h              |  1 +
 net/tipc/name_distr.c        | 69 ++++++++++++++++++++++++++++++++++++++++++--
 net/tipc/name_distr.h        |  1 +
 net/tipc/name_table.c        |  8 ++---
 net/tipc/sysctl.c            |  7 +++++
 6 files changed, 95 insertions(+), 7 deletions(-)

diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
index 9a0319a..04892b8 100644
--- a/Documentation/sysctl/net.txt
+++ b/Documentation/sysctl/net.txt
@@ -241,6 +241,9 @@ address of the router (or Connected) for internal networks.
 6. TIPC
 -------------------------------------------------------
 
+tipc_rmem
+----------
+
 The TIPC protocol now has a tunable for the receive memory, similar to the
 tcp_rmem - i.e. a vector of 3 INTEGERs: (min, default, max)
 
@@ -252,3 +255,16 @@ The max value is set to CONN_OVERLOAD_LIMIT, and the default and min values
 are scaled (shifted) versions of that same value.  Note that the min value
 is not at this point in time used in any meaningful way, but the triplet is
 preserved in order to be consistent with things like tcp_rmem.
+
+named_timeout
+--------------
+
+TIPC name table updates are distributed asynchronously in a cluster, without
+any form of transaction handling. This means that different race scenarios are
+possible. One such is that a name withdrawal sent out by one node and received
+by another node may arrive after a second, overlapping name publication already
+has been accepted from a third node, although the conflicting updates
+originally may have been issued in the correct sequential order.
+If named_timeout is nonzero, failed topology updates will be placed on a defer
+queue until another event arrives that clears the error, or until the timeout
+expires. Value is in milliseconds.
diff --git a/net/tipc/core.h b/net/tipc/core.h
index d2607a8..f773b14 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -81,6 +81,7 @@ extern u32 tipc_own_addr __read_mostly;
 extern int tipc_max_ports __read_mostly;
 extern int tipc_net_id __read_mostly;
 extern int sysctl_tipc_rmem[3] __read_mostly;
+extern int sysctl_tipc_named_timeout __read_mostly;
 
 /*
  * Other global variables
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index 0591f33..0cbe5e1 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -1,7 +1,7 @@
 /*
  * net/tipc/name_distr.c: TIPC name distribution code
  *
- * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2000-2006, 2014, Ericsson AB
  * Copyright (c) 2005, 2010-2011, Wind River Systems
  * All rights reserved.
  *
@@ -71,6 +71,21 @@ static struct publ_list *publ_lists[] = {
 };
 
 
+int sysctl_tipc_named_timeout __read_mostly = 2000;
+
+/**
+ * struct tipc_dist_queue - queue holding deferred name table updates
+ */
+static struct list_head tipc_dist_queue = LIST_HEAD_INIT(tipc_dist_queue);
+
+struct distr_queue_item {
+	struct distr_item i;
+	u32 dtype;
+	u32 node;
+	u64 expiry;
+	struct list_head next;
+};
+
 /**
  * publ_to_item - add publication info to a publication message
  */
@@ -299,6 +314,52 @@ struct publication *tipc_update_nametbl(struct distr_item *i, u32 node,
 }
 
 /**
+ * tipc_named_add_backlog - add a failed name table update to the backlog
+ *
+ */
+static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
+{
+	struct distr_queue_item *e;
+	u64 now = get_jiffies_64();
+
+	e = kzalloc(sizeof(*e), GFP_ATOMIC);
+	if (!e)
+		return;
+	e->dtype = type;
+	e->node = node;
+	e->expiry = now + msecs_to_jiffies(sysctl_tipc_named_timeout);
+	memcpy(e, i, sizeof(*i));
+	list_add_tail(&e->next, &tipc_dist_queue);
+}
+
+/**
+ * tipc_named_process_backlog - try to process any pending name table updates
+ * from the network.
+ */
+void tipc_named_process_backlog(void)
+{
+	struct distr_queue_item *e, *tmp;
+	char addr[16];
+	u64 now = get_jiffies_64();
+
+	list_for_each_entry_safe(e, tmp, &tipc_dist_queue, next) {
+		if (e->expiry > now) {
+			if (!tipc_update_nametbl(&e->i, e->node, e->dtype))
+				continue;
+		} else {
+			tipc_addr_string_fill(addr, e->node);
+			pr_warn_ratelimited("Dropping name table update (%d) of {%u, %u, %u} from %s key=%u\n",
+					    e->dtype, ntohl(e->i.type),
+					    ntohl(e->i.lower),
+					    ntohl(e->i.upper),
+					    addr, ntohl(e->i.key));
+		}
+		list_del(&e->next);
+		kfree(e);
+	}
+}
+
+/**
  * tipc_named_rcv - process name table update message sent by another node
  */
 void tipc_named_rcv(struct sk_buff *buf)
@@ -306,13 +367,15 @@ void tipc_named_rcv(struct sk_buff *buf)
 	struct tipc_msg *msg = buf_msg(buf);
 	struct distr_item *item = (struct distr_item *)msg_data(msg);
 	u32 count = msg_data_sz(msg) / ITEM_SIZE;
+	u32 node = msg_orignode(msg);
 
 	write_lock_bh(&tipc_nametbl_lock);
 	while (count--) {
-		tipc_update_nametbl(item, msg_orignode(msg),
-				    msg_type(msg));
+		if (!tipc_update_nametbl(item, node, msg_type(msg)))
+			tipc_named_add_backlog(item, msg_type(msg), node);
 		item++;
 	}
+	tipc_named_process_backlog();
 	write_unlock_bh(&tipc_nametbl_lock);
 	kfree_skb(buf);
 }
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
index 8afe32b..b9e75fe 100644
--- a/net/tipc/name_distr.h
+++ b/net/tipc/name_distr.h
@@ -73,5 +73,6 @@ void named_cluster_distribute(struct sk_buff *buf);
 void tipc_named_node_up(u32 dnode);
 void tipc_named_rcv(struct sk_buff *buf);
 void tipc_named_reinit(void);
+void tipc_named_process_backlog(void);
 
 #endif
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index c058e30..3a6a0a7 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -261,8 +261,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
 
 		/* Lower end overlaps existing entry => need an exact match */
 		if ((sseq->lower != lower) || (sseq->upper != upper)) {
-			pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
-				type, lower, upper);
 			return NULL;
 		}
 
@@ -284,8 +282,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
 		/* Fail if upper end overlaps into an existing entry */
 		if ((inspos < nseq->first_free) &&
 		    (upper >= nseq->sseqs[inspos].lower)) {
-			pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
-				type, lower, upper);
 			return NULL;
 		}
 
@@ -677,6 +673,8 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
 	if (likely(publ)) {
 		table.local_publ_count++;
 		buf = tipc_named_publish(publ);
+		/* Any pending external events? */
+		tipc_named_process_backlog();
 	}
 	write_unlock_bh(&tipc_nametbl_lock);
 
@@ -698,6 +696,8 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
 	if (likely(publ)) {
 		table.local_publ_count--;
 		buf = tipc_named_withdraw(publ);
+		/* Any pending external events? */
+		tipc_named_process_backlog();
 		write_unlock_bh(&tipc_nametbl_lock);
 		list_del_init(&publ->pport_list);
 		kfree(publ);
diff --git a/net/tipc/sysctl.c b/net/tipc/sysctl.c
index f3fef93..1a779b1 100644
--- a/net/tipc/sysctl.c
+++ b/net/tipc/sysctl.c
@@ -47,6 +47,13 @@ static struct ctl_table tipc_table[] = {
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
+	{
+		.procname	= "named_timeout",
+		.data		= &sysctl_tipc_named_timeout,
+		.maxlen		= sizeof(sysctl_tipc_named_timeout),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
 	{}
 };
 
-- 
1.8.3.2

^ permalink raw reply related

* Re: [PATCH v6 2/4] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
From: Arnd Bergmann @ 2014-08-26  9:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Jonas Jensen, netdev, f.fainelli, eric.dumazet, linux-kernel,
	mirqus, davem
In-Reply-To: <1408976542-15624-1-git-send-email-jonas.jensen@gmail.com>

On Monday 25 August 2014 16:22:22 Jonas Jensen wrote:
> @@ -226,13 +226,15 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
>                 if (len > RX_BUF_SIZE)
>                         len = RX_BUF_SIZE;
>  
> -               skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size);
> +               skb = netdev_alloc_skb_ip_align(ndev, len);
> +
>                 if (unlikely(!skb)) {
> -                       net_dbg_ratelimited("build_skb failed\n");
> +                       net_dbg_ratelimited("netdev_alloc_skb_ip_align failed\n");
>                         priv->stats.rx_dropped++;
>                         priv->stats.rx_errors++;
>                 }
>  
> +               memcpy(skb->data, priv->rx_buf[rx_head], len);
>                 skb_put(skb, len);
>                 skb->protocol = eth_type_trans(skb, ndev);
>                 napi_gro_receive(&priv->napi, skb);

While this seems correct, I wonder why you don't do the normal approach of
dequeuing the skb from the chain and adding a newly allocated skb to it to
save the memcpy.

	Arnd

^ permalink raw reply

* RE: [PATCH v6 2/4] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
From: David Laight @ 2014-08-26  9:10 UTC (permalink / raw)
  To: 'Arnd Bergmann', linux-arm-kernel@lists.infradead.org
  Cc: Jonas Jensen, netdev@vger.kernel.org, f.fainelli@gmail.com,
	eric.dumazet@gmail.com, linux-kernel@vger.kernel.org,
	mirqus@gmail.com, davem@davemloft.net
In-Reply-To: <4449672.aCJ5J5rv4r@wuerfel>

From: Arnd Bergmann
> On Monday 25 August 2014 16:22:22 Jonas Jensen wrote:
> > @@ -226,13 +226,15 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
> >                 if (len > RX_BUF_SIZE)
> >                         len = RX_BUF_SIZE;
> >
> > -               skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size);
> > +               skb = netdev_alloc_skb_ip_align(ndev, len);
> > +
> >                 if (unlikely(!skb)) {
> > -                       net_dbg_ratelimited("build_skb failed\n");
> > +                       net_dbg_ratelimited("netdev_alloc_skb_ip_align failed\n");
> >                         priv->stats.rx_dropped++;
> >                         priv->stats.rx_errors++;
> >                 }
> >
> > +               memcpy(skb->data, priv->rx_buf[rx_head], len);

Is this memcpy() aligned?
If the hardware can receive to a 4n+2 offset it is probably better to
copy the two bytes before the frame data and to round the length of to
a whole number of words.

> >                 skb_put(skb, len);
> >                 skb->protocol = eth_type_trans(skb, ndev);
> >                 napi_gro_receive(&priv->napi, skb);
> 
> While this seems correct, I wonder why you don't do the normal approach of
> dequeuing the skb from the chain and adding a newly allocated skb to it to
> save the memcpy.

Because the receive buffer area isn't made of skbs.
Post-allocating the skb also reduces the 'true size' of the skb.

	David

^ permalink raw reply

* Re: [PATCH] mac80211: scan: Replace rcu_assign_pointer() with RCU_INIT_POINTER()
From: Johannes Berg @ 2014-08-26  9:16 UTC (permalink / raw)
  To: Andreea-Cristina Bernat
  Cc: linville, davem, linux-wireless, netdev, linux-kernel, paulmck
In-Reply-To: <20140822131449.GA19959@ada>

On Fri, 2014-08-22 at 16:14 +0300, Andreea-Cristina Bernat wrote:
> The use of "rcu_assign_pointer()" is NULLing out the pointer.
> According to RCU_INIT_POINTER()'s block comment:
> "1.   This use of RCU_INIT_POINTER() is NULLing out the pointer"
> it is better to use it instead of rcu_assign_pointer() because it has a
> smaller overhead.

Applied, thanks.

johannes

^ permalink raw reply

* [PATCH v3 1/3] ethernet: arc: remove use of 'struct platform_device'
From: Romain Perier @ 2014-08-26  9:23 UTC (permalink / raw)
  To: davem
  Cc: heiko, tklauser, b.galvani, eric.dumazet, yongjun_wei, f.fainelli,
	netdev, arnd

This is a preparation of an api changes for the emac_main.c module.
The involved functions are arc_emac_probe and arc_emac_remove.

Signed-off-by: Romain Perier <romain.perier@gmail.com>
---
 drivers/net/ethernet/arc/emac_main.c | 64 +++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index fe5cfea..761b936 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -673,6 +673,7 @@ static const struct net_device_ops arc_emac_netdev_ops = {
 
 static int arc_emac_probe(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
 	struct resource res_regs;
 	struct device_node *phy_node;
 	struct arc_emac_priv *priv;
@@ -681,27 +682,27 @@ static int arc_emac_probe(struct platform_device *pdev)
 	unsigned int id, clock_frequency, irq;
 	int err;
 
-	if (!pdev->dev.of_node)
+	if (!dev->of_node)
 		return -ENODEV;
 
 	/* Get PHY from device tree */
-	phy_node = of_parse_phandle(pdev->dev.of_node, "phy", 0);
+	phy_node = of_parse_phandle(dev->of_node, "phy", 0);
 	if (!phy_node) {
-		dev_err(&pdev->dev, "failed to retrieve phy description from device tree\n");
+		dev_err(dev, "failed to retrieve phy description from device tree\n");
 		return -ENODEV;
 	}
 
 	/* Get EMAC registers base address from device tree */
-	err = of_address_to_resource(pdev->dev.of_node, 0, &res_regs);
+	err = of_address_to_resource(dev->of_node, 0, &res_regs);
 	if (err) {
-		dev_err(&pdev->dev, "failed to retrieve registers base from device tree\n");
+		dev_err(dev, "failed to retrieve registers base from device tree\n");
 		return -ENODEV;
 	}
 
 	/* Get IRQ from device tree */
-	irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	irq = irq_of_parse_and_map(dev->of_node, 0);
 	if (!irq) {
-		dev_err(&pdev->dev, "failed to retrieve <irq> value from device tree\n");
+		dev_err(dev, "failed to retrieve <irq> value from device tree\n");
 		return -ENODEV;
 	}
 
@@ -709,8 +710,8 @@ static int arc_emac_probe(struct platform_device *pdev)
 	if (!ndev)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, ndev);
-	SET_NETDEV_DEV(ndev, &pdev->dev);
+	dev_set_drvdata(dev, ndev);
+	SET_NETDEV_DEV(ndev, dev);
 
 	ndev->netdev_ops = &arc_emac_netdev_ops;
 	ndev->ethtool_ops = &arc_emac_ethtool_ops;
@@ -719,28 +720,28 @@ static int arc_emac_probe(struct platform_device *pdev)
 	ndev->flags &= ~IFF_MULTICAST;
 
 	priv = netdev_priv(ndev);
-	priv->dev = &pdev->dev;
+	priv->dev = dev;
 
-	priv->regs = devm_ioremap_resource(&pdev->dev, &res_regs);
+	priv->regs = devm_ioremap_resource(dev, &res_regs);
 	if (IS_ERR(priv->regs)) {
 		err = PTR_ERR(priv->regs);
 		goto out_netdev;
 	}
-	dev_dbg(&pdev->dev, "Registers base address is 0x%p\n", priv->regs);
+	dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
 
-	priv->clk = of_clk_get(pdev->dev.of_node, 0);
+	priv->clk = of_clk_get(dev->of_node, 0);
 	if (IS_ERR(priv->clk)) {
 		/* Get CPU clock frequency from device tree */
-		if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+		if (of_property_read_u32(dev->of_node, "clock-frequency",
 					&clock_frequency)) {
-			dev_err(&pdev->dev, "failed to retrieve <clock-frequency> from device tree\n");
+			dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
 			err = -EINVAL;
 			goto out_netdev;
 		}
 	} else {
 		err = clk_prepare_enable(priv->clk);
 		if (err) {
-			dev_err(&pdev->dev, "failed to enable clock\n");
+			dev_err(dev, "failed to enable clock\n");
 			goto out_clkget;
 		}
 
@@ -751,28 +752,28 @@ static int arc_emac_probe(struct platform_device *pdev)
 
 	/* Check for EMAC revision 5 or 7, magic number */
 	if (!(id == 0x0005fd02 || id == 0x0007fd02)) {
-		dev_err(&pdev->dev, "ARC EMAC not detected, id=0x%x\n", id);
+		dev_err(dev, "ARC EMAC not detected, id=0x%x\n", id);
 		err = -ENODEV;
 		goto out_clken;
 	}
-	dev_info(&pdev->dev, "ARC EMAC detected with id: 0x%x\n", id);
+	dev_info(dev, "ARC EMAC detected with id: 0x%x\n", id);
 
 	/* Set poll rate so that it polls every 1 ms */
 	arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000);
 
 	ndev->irq = irq;
-	dev_info(&pdev->dev, "IRQ is %d\n", ndev->irq);
+	dev_info(dev, "IRQ is %d\n", ndev->irq);
 
 	/* Register interrupt handler for device */
-	err = devm_request_irq(&pdev->dev, ndev->irq, arc_emac_intr, 0,
+	err = devm_request_irq(dev, ndev->irq, arc_emac_intr, 0,
 			       ndev->name, ndev);
 	if (err) {
-		dev_err(&pdev->dev, "could not allocate IRQ\n");
+		dev_err(dev, "could not allocate IRQ\n");
 		goto out_clken;
 	}
 
 	/* Get MAC address from device tree */
-	mac_addr = of_get_mac_address(pdev->dev.of_node);
+	mac_addr = of_get_mac_address(dev->of_node);
 
 	if (mac_addr)
 		memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
@@ -780,14 +781,14 @@ static int arc_emac_probe(struct platform_device *pdev)
 		eth_hw_addr_random(ndev);
 
 	arc_emac_set_address_internal(ndev);
-	dev_info(&pdev->dev, "MAC address is now %pM\n", ndev->dev_addr);
+	dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr);
 
 	/* Do 1 allocation instead of 2 separate ones for Rx and Tx BD rings */
-	priv->rxbd = dmam_alloc_coherent(&pdev->dev, RX_RING_SZ + TX_RING_SZ,
+	priv->rxbd = dmam_alloc_coherent(dev, RX_RING_SZ + TX_RING_SZ,
 					 &priv->rxbd_dma, GFP_KERNEL);
 
 	if (!priv->rxbd) {
-		dev_err(&pdev->dev, "failed to allocate data buffers\n");
+		dev_err(dev, "failed to allocate data buffers\n");
 		err = -ENOMEM;
 		goto out_clken;
 	}
@@ -795,31 +796,31 @@ static int arc_emac_probe(struct platform_device *pdev)
 	priv->txbd = priv->rxbd + RX_BD_NUM;
 
 	priv->txbd_dma = priv->rxbd_dma + RX_RING_SZ;
-	dev_dbg(&pdev->dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
+	dev_dbg(dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
 		(unsigned int)priv->rxbd_dma, (unsigned int)priv->txbd_dma);
 
 	err = arc_mdio_probe(pdev, priv);
 	if (err) {
-		dev_err(&pdev->dev, "failed to probe MII bus\n");
+		dev_err(dev, "failed to probe MII bus\n");
 		goto out_clken;
 	}
 
 	priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
 				       PHY_INTERFACE_MODE_MII);
 	if (!priv->phy_dev) {
-		dev_err(&pdev->dev, "of_phy_connect() failed\n");
+		dev_err(dev, "of_phy_connect() failed\n");
 		err = -ENODEV;
 		goto out_mdio;
 	}
 
-	dev_info(&pdev->dev, "connected to %s phy with id 0x%x\n",
+	dev_info(dev, "connected to %s phy with id 0x%x\n",
 		 priv->phy_dev->drv->name, priv->phy_dev->phy_id);
 
 	netif_napi_add(ndev, &priv->napi, arc_emac_poll, ARC_EMAC_NAPI_WEIGHT);
 
 	err = register_netdev(ndev);
 	if (err) {
-		dev_err(&pdev->dev, "failed to register network device\n");
+		dev_err(dev, "failed to register network device\n");
 		goto out_netif_api;
 	}
 
@@ -844,7 +845,8 @@ out_netdev:
 
 static int arc_emac_remove(struct platform_device *pdev)
 {
-	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	struct net_device *ndev = dev_get_drvdata(dev);
 	struct arc_emac_priv *priv = netdev_priv(ndev);
 
 	phy_disconnect(priv->phy_dev);
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 2/3] ethernet: arc: mdio refactoring for future specific SoC glue layer devicetree bindings addition
From: Romain Perier @ 2014-08-26  9:23 UTC (permalink / raw)
  To: davem
  Cc: heiko, tklauser, b.galvani, eric.dumazet, yongjun_wei, f.fainelli,
	netdev, arnd
In-Reply-To: <1409045032-29604-1-git-send-email-romain.perier@gmail.com>

This is an api changes for the emac_mdio.c module.
It will be required later when arc_emac_probe/arc_emac_remove
will no longer use 'struct platform_device'.

Signed-off-by: Romain Perier <romain.perier@gmail.com>
---
 drivers/net/ethernet/arc/emac.h      | 2 +-
 drivers/net/ethernet/arc/emac_main.c | 2 +-
 drivers/net/ethernet/arc/emac_mdio.c | 7 +++----
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
index 36cc9bd..8011445 100644
--- a/drivers/net/ethernet/arc/emac.h
+++ b/drivers/net/ethernet/arc/emac.h
@@ -204,7 +204,7 @@ static inline void arc_reg_clr(struct arc_emac_priv *priv, int reg, int mask)
 	arc_reg_set(priv, reg, value & ~mask);
 }
 
-int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv);
+int arc_mdio_probe(struct arc_emac_priv *priv);
 int arc_mdio_remove(struct arc_emac_priv *priv);
 
 #endif /* ARC_EMAC_H */
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index 761b936..bbc3157 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -799,7 +799,7 @@ static int arc_emac_probe(struct platform_device *pdev)
 	dev_dbg(dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
 		(unsigned int)priv->rxbd_dma, (unsigned int)priv->txbd_dma);
 
-	err = arc_mdio_probe(pdev, priv);
+	err = arc_mdio_probe(priv);
 	if (err) {
 		dev_err(dev, "failed to probe MII bus\n");
 		goto out_clken;
diff --git a/drivers/net/ethernet/arc/emac_mdio.c b/drivers/net/ethernet/arc/emac_mdio.c
index 26ba242..d5ee986 100644
--- a/drivers/net/ethernet/arc/emac_mdio.c
+++ b/drivers/net/ethernet/arc/emac_mdio.c
@@ -100,7 +100,6 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr,
 
 /**
  * arc_mdio_probe - MDIO probe function.
- * @pdev:	Pointer to platform device.
  * @priv:	Pointer to ARC EMAC private data structure.
  *
  * returns:	0 on success, -ENOMEM when mdiobus_alloc
@@ -108,7 +107,7 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr,
  *
  * Sets up and registers the MDIO interface.
  */
-int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv)
+int arc_mdio_probe(struct arc_emac_priv *priv)
 {
 	struct mii_bus *bus;
 	int error;
@@ -124,9 +123,9 @@ int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv)
 	bus->read = &arc_mdio_read;
 	bus->write = &arc_mdio_write;
 
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", bus->name);
 
-	error = of_mdiobus_register(bus, pdev->dev.of_node);
+	error = of_mdiobus_register(bus, priv->dev->of_node);
 	if (error) {
 		dev_err(priv->dev, "cannot register MDIO bus %s\n", bus->name);
 		mdiobus_free(bus);
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 3/3] ethernet: arc: Add support for specific SoC glue layer device tree bindings
From: Romain Perier @ 2014-08-26  9:23 UTC (permalink / raw)
  To: davem
  Cc: heiko, tklauser, b.galvani, eric.dumazet, yongjun_wei, f.fainelli,
	netdev, arnd
In-Reply-To: <1409045032-29604-1-git-send-email-romain.perier@gmail.com>

Some platforms have special bank registers which might be used to select
the correct clock or the right mode for Media Indepent Interface controllers.
Sometimes, it is also required to activate vcc regulators in the right order to supply
the ethernet controller at the right time. This patch is an architecture refactoring
of the arc-emac device driver. it adds a new software design which allows to add specific
platform glue layer. Each platform has now its own module which performs custom initialization
and remove for the target and then calls to the core driver.

Signed-off-by: Romain Perier <romain.perier@gmail.com>
---
 drivers/net/ethernet/arc/Kconfig     |  8 ++-
 drivers/net/ethernet/arc/Makefile    |  3 +-
 drivers/net/ethernet/arc/emac.h      |  4 ++
 drivers/net/ethernet/arc/emac_arc.c  | 95 ++++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/arc/emac_main.c | 80 +++++++++---------------------
 5 files changed, 129 insertions(+), 61 deletions(-)
 create mode 100644 drivers/net/ethernet/arc/emac_arc.c

diff --git a/drivers/net/ethernet/arc/Kconfig b/drivers/net/ethernet/arc/Kconfig
index 514c57f..e193826 100644
--- a/drivers/net/ethernet/arc/Kconfig
+++ b/drivers/net/ethernet/arc/Kconfig
@@ -17,12 +17,16 @@ config NET_VENDOR_ARC
 
 if NET_VENDOR_ARC
 
-config ARC_EMAC
-	tristate "ARC EMAC support"
+config ARC_EMAC_CORE
+	bool
 	select MII
 	select PHYLIB
 	depends on OF_IRQ
 	depends on OF_NET
+
+config ARC_EMAC
+	tristate "ARC EMAC support"
+	select ARC_EMAC_CORE
 	---help---
 	  On some legacy ARC (Synopsys) FPGA boards such as ARCAngel4/ML50x
 	  non-standard on-chip ethernet device ARC EMAC 10/100 is used.
diff --git a/drivers/net/ethernet/arc/Makefile b/drivers/net/ethernet/arc/Makefile
index 00c8657..241bb80 100644
--- a/drivers/net/ethernet/arc/Makefile
+++ b/drivers/net/ethernet/arc/Makefile
@@ -3,4 +3,5 @@
 #
 
 arc_emac-objs := emac_main.o emac_mdio.o
-obj-$(CONFIG_ARC_EMAC) += arc_emac.o
+obj-$(CONFIG_ARC_EMAC_CORE) += arc_emac.o
+obj-$(CONFIG_ARC_EMAC) += emac_arc.o
diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
index 8011445..eb2ba67 100644
--- a/drivers/net/ethernet/arc/emac.h
+++ b/drivers/net/ethernet/arc/emac.h
@@ -124,6 +124,8 @@ struct buffer_state {
  */
 struct arc_emac_priv {
 	/* Devices */
+	const char *drv_name;
+	const char *drv_version;
 	struct device *dev;
 	struct phy_device *phy_dev;
 	struct mii_bus *bus;
@@ -206,5 +208,7 @@ static inline void arc_reg_clr(struct arc_emac_priv *priv, int reg, int mask)
 
 int arc_mdio_probe(struct arc_emac_priv *priv);
 int arc_mdio_remove(struct arc_emac_priv *priv);
+int arc_emac_probe(struct net_device *ndev, int interface);
+int arc_emac_remove(struct net_device *ndev);
 
 #endif /* ARC_EMAC_H */
diff --git a/drivers/net/ethernet/arc/emac_arc.c b/drivers/net/ethernet/arc/emac_arc.c
new file mode 100644
index 0000000..f9cb99b
--- /dev/null
+++ b/drivers/net/ethernet/arc/emac_arc.c
@@ -0,0 +1,95 @@
+/**
+ * emac_arc.c - ARC EMAC specific glue layer
+ *
+ * Copyright (C) 2014 Romain Perier
+ *
+ * Romain Perier  <romain.perier@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/platform_device.h>
+
+#include "emac.h"
+
+#define DRV_NAME    "emac_arc"
+#define DRV_VERSION "1.0"
+
+static int emac_arc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct net_device *ndev;
+	struct arc_emac_priv *priv;
+	int interface, err;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
+	if (!ndev)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, ndev);
+	SET_NETDEV_DEV(ndev, dev);
+
+	priv = netdev_priv(ndev);
+	priv->drv_name = DRV_NAME;
+	priv->drv_version = DRV_VERSION;
+
+	interface = of_get_phy_mode(dev->of_node);
+	if (interface < 0)
+		interface = PHY_INTERFACE_MODE_MII;
+
+	priv->clk = devm_clk_get(dev, "hclk");
+	if (IS_ERR(priv->clk)) {
+		dev_err(dev, "failed to retrieve host clock from device tree\n");
+		err = -EINVAL;
+		goto out_netdev;
+	}
+
+	err = arc_emac_probe(ndev, interface);
+out_netdev:
+	if (err)
+		free_netdev(ndev);
+	return err;
+}
+
+static int emac_arc_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	int err;
+
+	err = arc_emac_remove(ndev);
+	free_netdev(ndev);
+	return err;
+}
+
+static const struct of_device_id emac_arc_dt_ids[] = {
+	{ .compatible = "snps,arc-emac" },
+	{ /* Sentinel */ }
+};
+
+static struct platform_driver emac_arc_driver = {
+	.probe = emac_arc_probe,
+	.remove = emac_arc_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table  = emac_arc_dt_ids,
+	},
+};
+
+module_platform_driver(emac_arc_driver);
+
+MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
+MODULE_DESCRIPTION("ARC EMAC platform driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index bbc3157..b35c69e 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -26,8 +26,6 @@
 
 #include "emac.h"
 
-#define DRV_NAME	"arc_emac"
-#define DRV_VERSION	"1.0"
 
 /**
  * arc_emac_adjust_link - Adjust the PHY link duplex.
@@ -120,8 +118,10 @@ static int arc_emac_set_settings(struct net_device *ndev,
 static void arc_emac_get_drvinfo(struct net_device *ndev,
 				 struct ethtool_drvinfo *info)
 {
-	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
-	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	struct arc_emac_priv *priv = netdev_priv(ndev);
+
+	strlcpy(info->driver, priv->drv_name, sizeof(info->driver));
+	strlcpy(info->version, priv->drv_version, sizeof(info->version));
 }
 
 static const struct ethtool_ops arc_emac_ethtool_ops = {
@@ -671,19 +671,16 @@ static const struct net_device_ops arc_emac_netdev_ops = {
 #endif
 };
 
-static int arc_emac_probe(struct platform_device *pdev)
+int arc_emac_probe(struct net_device *ndev, int interface)
 {
-	struct device *dev = &pdev->dev;
+	struct device *dev = ndev->dev.parent;
 	struct resource res_regs;
 	struct device_node *phy_node;
 	struct arc_emac_priv *priv;
-	struct net_device *ndev;
 	const char *mac_addr;
 	unsigned int id, clock_frequency, irq;
 	int err;
 
-	if (!dev->of_node)
-		return -ENODEV;
 
 	/* Get PHY from device tree */
 	phy_node = of_parse_phandle(dev->of_node, "phy", 0);
@@ -706,12 +703,6 @@ static int arc_emac_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
-	if (!ndev)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, ndev);
-	SET_NETDEV_DEV(ndev, dev);
 
 	ndev->netdev_ops = &arc_emac_netdev_ops;
 	ndev->ethtool_ops = &arc_emac_ethtool_ops;
@@ -724,28 +715,25 @@ static int arc_emac_probe(struct platform_device *pdev)
 
 	priv->regs = devm_ioremap_resource(dev, &res_regs);
 	if (IS_ERR(priv->regs)) {
-		err = PTR_ERR(priv->regs);
-		goto out_netdev;
+		return PTR_ERR(priv->regs);
 	}
 	dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
 
-	priv->clk = of_clk_get(dev->of_node, 0);
-	if (IS_ERR(priv->clk)) {
-		/* Get CPU clock frequency from device tree */
-		if (of_property_read_u32(dev->of_node, "clock-frequency",
-					&clock_frequency)) {
-			dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
-			err = -EINVAL;
-			goto out_netdev;
-		}
-	} else {
+	if (priv->clk) {
 		err = clk_prepare_enable(priv->clk);
 		if (err) {
 			dev_err(dev, "failed to enable clock\n");
-			goto out_clkget;
+			return err;
 		}
 
 		clock_frequency = clk_get_rate(priv->clk);
+	} else {
+		/* Get CPU clock frequency from device tree */
+		if (of_property_read_u32(dev->of_node, "clock-frequency",
+					 &clock_frequency)) {
+			dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
+			return -EINVAL;
+		}
 	}
 
 	id = arc_reg_get(priv, R_ID);
@@ -806,7 +794,7 @@ static int arc_emac_probe(struct platform_device *pdev)
 	}
 
 	priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
-				       PHY_INTERFACE_MODE_MII);
+				       interface);
 	if (!priv->phy_dev) {
 		dev_err(dev, "of_phy_connect() failed\n");
 		err = -ENODEV;
@@ -833,20 +821,15 @@ out_netif_api:
 out_mdio:
 	arc_mdio_remove(priv);
 out_clken:
-	if (!IS_ERR(priv->clk))
+	if (priv->clk)
 		clk_disable_unprepare(priv->clk);
-out_clkget:
-	if (!IS_ERR(priv->clk))
-		clk_put(priv->clk);
-out_netdev:
-	free_netdev(ndev);
 	return err;
 }
+EXPORT_SYMBOL_GPL(arc_emac_probe);
 
-static int arc_emac_remove(struct platform_device *pdev)
+int arc_emac_remove(struct net_device *ndev)
 {
-	struct device *dev = &pdev->dev;
-	struct net_device *ndev = dev_get_drvdata(dev);
+	struct device *dev = ndev->dev.parent;
 	struct arc_emac_priv *priv = netdev_priv(ndev);
 
 	phy_disconnect(priv->phy_dev);
@@ -857,31 +840,12 @@ static int arc_emac_remove(struct platform_device *pdev)
 
 	if (!IS_ERR(priv->clk)) {
 		clk_disable_unprepare(priv->clk);
-		clk_put(priv->clk);
 	}
 
-	free_netdev(ndev);
 
 	return 0;
 }
-
-static const struct of_device_id arc_emac_dt_ids[] = {
-	{ .compatible = "snps,arc-emac" },
-	{ /* Sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, arc_emac_dt_ids);
-
-static struct platform_driver arc_emac_driver = {
-	.probe = arc_emac_probe,
-	.remove = arc_emac_remove,
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-		.of_match_table  = arc_emac_dt_ids,
-		},
-};
-
-module_platform_driver(arc_emac_driver);
+EXPORT_SYMBOL_GPL(arc_emac_remove);
 
 MODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>");
 MODULE_DESCRIPTION("ARC EMAC driver");
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH v3 3/3] ethernet: arc: Add support for specific SoC glue layer device tree bindings
From: PERIER Romain @ 2014-08-26  9:26 UTC (permalink / raw)
  To: davem
  Cc: Heiko Stübner, Tobias Klauser, Beniamino Galvani,
	eric.dumazet, yongjun_wei, Florian Fainelli, netdev,
	Arnd Bergmann
In-Reply-To: <1409045032-29604-3-git-send-email-romain.perier@gmail.com>

PS: I will add callback function for set_mac_speed from platform
driver and a priv data inline function (like netdev_priv for arc_emac)
into another seperated commit, I think.

Romain

2014-08-26 11:23 GMT+02:00 Romain Perier <romain.perier@gmail.com>:
> Some platforms have special bank registers which might be used to select
> the correct clock or the right mode for Media Indepent Interface controllers.
> Sometimes, it is also required to activate vcc regulators in the right order to supply
> the ethernet controller at the right time. This patch is an architecture refactoring
> of the arc-emac device driver. it adds a new software design which allows to add specific
> platform glue layer. Each platform has now its own module which performs custom initialization
> and remove for the target and then calls to the core driver.
>
> Signed-off-by: Romain Perier <romain.perier@gmail.com>
> ---
>  drivers/net/ethernet/arc/Kconfig     |  8 ++-
>  drivers/net/ethernet/arc/Makefile    |  3 +-
>  drivers/net/ethernet/arc/emac.h      |  4 ++
>  drivers/net/ethernet/arc/emac_arc.c  | 95 ++++++++++++++++++++++++++++++++++++
>  drivers/net/ethernet/arc/emac_main.c | 80 +++++++++---------------------
>  5 files changed, 129 insertions(+), 61 deletions(-)
>  create mode 100644 drivers/net/ethernet/arc/emac_arc.c
>
> diff --git a/drivers/net/ethernet/arc/Kconfig b/drivers/net/ethernet/arc/Kconfig
> index 514c57f..e193826 100644
> --- a/drivers/net/ethernet/arc/Kconfig
> +++ b/drivers/net/ethernet/arc/Kconfig
> @@ -17,12 +17,16 @@ config NET_VENDOR_ARC
>
>  if NET_VENDOR_ARC
>
> -config ARC_EMAC
> -       tristate "ARC EMAC support"
> +config ARC_EMAC_CORE
> +       bool
>         select MII
>         select PHYLIB
>         depends on OF_IRQ
>         depends on OF_NET
> +
> +config ARC_EMAC
> +       tristate "ARC EMAC support"
> +       select ARC_EMAC_CORE
>         ---help---
>           On some legacy ARC (Synopsys) FPGA boards such as ARCAngel4/ML50x
>           non-standard on-chip ethernet device ARC EMAC 10/100 is used.
> diff --git a/drivers/net/ethernet/arc/Makefile b/drivers/net/ethernet/arc/Makefile
> index 00c8657..241bb80 100644
> --- a/drivers/net/ethernet/arc/Makefile
> +++ b/drivers/net/ethernet/arc/Makefile
> @@ -3,4 +3,5 @@
>  #
>
>  arc_emac-objs := emac_main.o emac_mdio.o
> -obj-$(CONFIG_ARC_EMAC) += arc_emac.o
> +obj-$(CONFIG_ARC_EMAC_CORE) += arc_emac.o
> +obj-$(CONFIG_ARC_EMAC) += emac_arc.o
> diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
> index 8011445..eb2ba67 100644
> --- a/drivers/net/ethernet/arc/emac.h
> +++ b/drivers/net/ethernet/arc/emac.h
> @@ -124,6 +124,8 @@ struct buffer_state {
>   */
>  struct arc_emac_priv {
>         /* Devices */
> +       const char *drv_name;
> +       const char *drv_version;
>         struct device *dev;
>         struct phy_device *phy_dev;
>         struct mii_bus *bus;
> @@ -206,5 +208,7 @@ static inline void arc_reg_clr(struct arc_emac_priv *priv, int reg, int mask)
>
>  int arc_mdio_probe(struct arc_emac_priv *priv);
>  int arc_mdio_remove(struct arc_emac_priv *priv);
> +int arc_emac_probe(struct net_device *ndev, int interface);
> +int arc_emac_remove(struct net_device *ndev);
>
>  #endif /* ARC_EMAC_H */
> diff --git a/drivers/net/ethernet/arc/emac_arc.c b/drivers/net/ethernet/arc/emac_arc.c
> new file mode 100644
> index 0000000..f9cb99b
> --- /dev/null
> +++ b/drivers/net/ethernet/arc/emac_arc.c
> @@ -0,0 +1,95 @@
> +/**
> + * emac_arc.c - ARC EMAC specific glue layer
> + *
> + * Copyright (C) 2014 Romain Perier
> + *
> + * Romain Perier  <romain.perier@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/etherdevice.h>
> +#include <linux/module.h>
> +#include <linux/of_net.h>
> +#include <linux/platform_device.h>
> +
> +#include "emac.h"
> +
> +#define DRV_NAME    "emac_arc"
> +#define DRV_VERSION "1.0"
> +
> +static int emac_arc_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct net_device *ndev;
> +       struct arc_emac_priv *priv;
> +       int interface, err;
> +
> +       if (!dev->of_node)
> +               return -ENODEV;
> +
> +       ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
> +       if (!ndev)
> +               return -ENOMEM;
> +       platform_set_drvdata(pdev, ndev);
> +       SET_NETDEV_DEV(ndev, dev);
> +
> +       priv = netdev_priv(ndev);
> +       priv->drv_name = DRV_NAME;
> +       priv->drv_version = DRV_VERSION;
> +
> +       interface = of_get_phy_mode(dev->of_node);
> +       if (interface < 0)
> +               interface = PHY_INTERFACE_MODE_MII;
> +
> +       priv->clk = devm_clk_get(dev, "hclk");
> +       if (IS_ERR(priv->clk)) {
> +               dev_err(dev, "failed to retrieve host clock from device tree\n");
> +               err = -EINVAL;
> +               goto out_netdev;
> +       }
> +
> +       err = arc_emac_probe(ndev, interface);
> +out_netdev:
> +       if (err)
> +               free_netdev(ndev);
> +       return err;
> +}
> +
> +static int emac_arc_remove(struct platform_device *pdev)
> +{
> +       struct net_device *ndev = platform_get_drvdata(pdev);
> +       int err;
> +
> +       err = arc_emac_remove(ndev);
> +       free_netdev(ndev);
> +       return err;
> +}
> +
> +static const struct of_device_id emac_arc_dt_ids[] = {
> +       { .compatible = "snps,arc-emac" },
> +       { /* Sentinel */ }
> +};
> +
> +static struct platform_driver emac_arc_driver = {
> +       .probe = emac_arc_probe,
> +       .remove = emac_arc_remove,
> +       .driver = {
> +               .name = DRV_NAME,
> +               .of_match_table  = emac_arc_dt_ids,
> +       },
> +};
> +
> +module_platform_driver(emac_arc_driver);
> +
> +MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
> +MODULE_DESCRIPTION("ARC EMAC platform driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
> index bbc3157..b35c69e 100644
> --- a/drivers/net/ethernet/arc/emac_main.c
> +++ b/drivers/net/ethernet/arc/emac_main.c
> @@ -26,8 +26,6 @@
>
>  #include "emac.h"
>
> -#define DRV_NAME       "arc_emac"
> -#define DRV_VERSION    "1.0"
>
>  /**
>   * arc_emac_adjust_link - Adjust the PHY link duplex.
> @@ -120,8 +118,10 @@ static int arc_emac_set_settings(struct net_device *ndev,
>  static void arc_emac_get_drvinfo(struct net_device *ndev,
>                                  struct ethtool_drvinfo *info)
>  {
> -       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
> -       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
> +       struct arc_emac_priv *priv = netdev_priv(ndev);
> +
> +       strlcpy(info->driver, priv->drv_name, sizeof(info->driver));
> +       strlcpy(info->version, priv->drv_version, sizeof(info->version));
>  }
>
>  static const struct ethtool_ops arc_emac_ethtool_ops = {
> @@ -671,19 +671,16 @@ static const struct net_device_ops arc_emac_netdev_ops = {
>  #endif
>  };
>
> -static int arc_emac_probe(struct platform_device *pdev)
> +int arc_emac_probe(struct net_device *ndev, int interface)
>  {
> -       struct device *dev = &pdev->dev;
> +       struct device *dev = ndev->dev.parent;
>         struct resource res_regs;
>         struct device_node *phy_node;
>         struct arc_emac_priv *priv;
> -       struct net_device *ndev;
>         const char *mac_addr;
>         unsigned int id, clock_frequency, irq;
>         int err;
>
> -       if (!dev->of_node)
> -               return -ENODEV;
>
>         /* Get PHY from device tree */
>         phy_node = of_parse_phandle(dev->of_node, "phy", 0);
> @@ -706,12 +703,6 @@ static int arc_emac_probe(struct platform_device *pdev)
>                 return -ENODEV;
>         }
>
> -       ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
> -       if (!ndev)
> -               return -ENOMEM;
> -
> -       dev_set_drvdata(dev, ndev);
> -       SET_NETDEV_DEV(ndev, dev);
>
>         ndev->netdev_ops = &arc_emac_netdev_ops;
>         ndev->ethtool_ops = &arc_emac_ethtool_ops;
> @@ -724,28 +715,25 @@ static int arc_emac_probe(struct platform_device *pdev)
>
>         priv->regs = devm_ioremap_resource(dev, &res_regs);
>         if (IS_ERR(priv->regs)) {
> -               err = PTR_ERR(priv->regs);
> -               goto out_netdev;
> +               return PTR_ERR(priv->regs);
>         }
>         dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
>
> -       priv->clk = of_clk_get(dev->of_node, 0);
> -       if (IS_ERR(priv->clk)) {
> -               /* Get CPU clock frequency from device tree */
> -               if (of_property_read_u32(dev->of_node, "clock-frequency",
> -                                       &clock_frequency)) {
> -                       dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
> -                       err = -EINVAL;
> -                       goto out_netdev;
> -               }
> -       } else {
> +       if (priv->clk) {
>                 err = clk_prepare_enable(priv->clk);
>                 if (err) {
>                         dev_err(dev, "failed to enable clock\n");
> -                       goto out_clkget;
> +                       return err;
>                 }
>
>                 clock_frequency = clk_get_rate(priv->clk);
> +       } else {
> +               /* Get CPU clock frequency from device tree */
> +               if (of_property_read_u32(dev->of_node, "clock-frequency",
> +                                        &clock_frequency)) {
> +                       dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
> +                       return -EINVAL;
> +               }
>         }
>
>         id = arc_reg_get(priv, R_ID);
> @@ -806,7 +794,7 @@ static int arc_emac_probe(struct platform_device *pdev)
>         }
>
>         priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
> -                                      PHY_INTERFACE_MODE_MII);
> +                                      interface);
>         if (!priv->phy_dev) {
>                 dev_err(dev, "of_phy_connect() failed\n");
>                 err = -ENODEV;
> @@ -833,20 +821,15 @@ out_netif_api:
>  out_mdio:
>         arc_mdio_remove(priv);
>  out_clken:
> -       if (!IS_ERR(priv->clk))
> +       if (priv->clk)
>                 clk_disable_unprepare(priv->clk);
> -out_clkget:
> -       if (!IS_ERR(priv->clk))
> -               clk_put(priv->clk);
> -out_netdev:
> -       free_netdev(ndev);
>         return err;
>  }
> +EXPORT_SYMBOL_GPL(arc_emac_probe);
>
> -static int arc_emac_remove(struct platform_device *pdev)
> +int arc_emac_remove(struct net_device *ndev)
>  {
> -       struct device *dev = &pdev->dev;
> -       struct net_device *ndev = dev_get_drvdata(dev);
> +       struct device *dev = ndev->dev.parent;
>         struct arc_emac_priv *priv = netdev_priv(ndev);
>
>         phy_disconnect(priv->phy_dev);
> @@ -857,31 +840,12 @@ static int arc_emac_remove(struct platform_device *pdev)
>
>         if (!IS_ERR(priv->clk)) {
>                 clk_disable_unprepare(priv->clk);
> -               clk_put(priv->clk);
>         }
>
> -       free_netdev(ndev);
>
>         return 0;
>  }
> -
> -static const struct of_device_id arc_emac_dt_ids[] = {
> -       { .compatible = "snps,arc-emac" },
> -       { /* Sentinel */ }
> -};
> -MODULE_DEVICE_TABLE(of, arc_emac_dt_ids);
> -
> -static struct platform_driver arc_emac_driver = {
> -       .probe = arc_emac_probe,
> -       .remove = arc_emac_remove,
> -       .driver = {
> -               .name = DRV_NAME,
> -               .owner = THIS_MODULE,
> -               .of_match_table  = arc_emac_dt_ids,
> -               },
> -};
> -
> -module_platform_driver(arc_emac_driver);
> +EXPORT_SYMBOL_GPL(arc_emac_remove);
>
>  MODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>");
>  MODULE_DESCRIPTION("ARC EMAC driver");
> --
> 1.9.1
>

^ permalink raw reply

* Re: [PATCH v2 net-next 2/2] tipc: add name distributor resiliency queue
From: Ying Xue @ 2014-08-26  9:33 UTC (permalink / raw)
  To: erik.hugne, jon.maloy, richard.alpe, netdev; +Cc: tipc-discussion
In-Reply-To: <1409043477-22761-2-git-send-email-erik.hugne@ericsson.com>

On 08/26/2014 04:57 PM, erik.hugne@ericsson.com wrote:
> From: Erik Hugne <erik.hugne@ericsson.com>
> 
> TIPC name table updates are distributed asynchronously in a cluster,
> entailing a risk of certain race conditions. E.g., if two nodes
> simultaneously issue conflicting (overlapping) publications, this may
> not be detected until both publications have reached a third node, in
> which case one of the publications will be silently dropped on that
> node. Hence, we end up with an inconsistent name table.
> 
> In most cases this conflict is just a temporary race, e.g., one
> node is issuing a publication under the assumption that a previous,
> conflicting, publication has already been withdrawn by the other node.
> However, because of the (rtt related) distributed update delay, this
> may not yet hold true on all nodes. The symptom of this failure is a
> syslog message: "tipc: Cannot publish {%u,%u,%u}, overlap error".
> 
> In this commit we add a resiliency queue at the receiving end of
> the name table distributor. When insertion of an arriving publication
> fails, we retain it in this queue for a short amount of time, assuming
> that another update will arrive very soon and clear the conflict. If so
> happens, we insert the publication, otherwise we drop it.
> 
> The (configurable) retention value defaults to 2000 ms. Knowing from
> experience that the situation described above is extremely rare, there
> is no risk that the queue will accumulate any large number of items.
> 
> Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>

Acked-by: Ying Xue <ying.xue@windriver.com>

> ---
> 
> v2: Fixed phrasing and spelling in the sysctl documentation
> 
>  Documentation/sysctl/net.txt | 16 ++++++++++
>  net/tipc/core.h              |  1 +
>  net/tipc/name_distr.c        | 69 ++++++++++++++++++++++++++++++++++++++++++--
>  net/tipc/name_distr.h        |  1 +
>  net/tipc/name_table.c        |  8 ++---
>  net/tipc/sysctl.c            |  7 +++++
>  6 files changed, 95 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
> index 9a0319a..04892b8 100644
> --- a/Documentation/sysctl/net.txt
> +++ b/Documentation/sysctl/net.txt
> @@ -241,6 +241,9 @@ address of the router (or Connected) for internal networks.
>  6. TIPC
>  -------------------------------------------------------
>  
> +tipc_rmem
> +----------
> +
>  The TIPC protocol now has a tunable for the receive memory, similar to the
>  tcp_rmem - i.e. a vector of 3 INTEGERs: (min, default, max)
>  
> @@ -252,3 +255,16 @@ The max value is set to CONN_OVERLOAD_LIMIT, and the default and min values
>  are scaled (shifted) versions of that same value.  Note that the min value
>  is not at this point in time used in any meaningful way, but the triplet is
>  preserved in order to be consistent with things like tcp_rmem.
> +
> +named_timeout
> +--------------
> +
> +TIPC name table updates are distributed asynchronously in a cluster, without
> +any form of transaction handling. This means that different race scenarios are
> +possible. One such is that a name withdrawal sent out by one node and received
> +by another node may arrive after a second, overlapping name publication already
> +has been accepted from a third node, although the conflicting updates
> +originally may have been issued in the correct sequential order.
> +If named_timeout is nonzero, failed topology updates will be placed on a defer
> +queue until another event arrives that clears the error, or until the timeout
> +expires. Value is in milliseconds.
> diff --git a/net/tipc/core.h b/net/tipc/core.h
> index d2607a8..f773b14 100644
> --- a/net/tipc/core.h
> +++ b/net/tipc/core.h
> @@ -81,6 +81,7 @@ extern u32 tipc_own_addr __read_mostly;
>  extern int tipc_max_ports __read_mostly;
>  extern int tipc_net_id __read_mostly;
>  extern int sysctl_tipc_rmem[3] __read_mostly;
> +extern int sysctl_tipc_named_timeout __read_mostly;
>  
>  /*
>   * Other global variables
> diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
> index 0591f33..0cbe5e1 100644
> --- a/net/tipc/name_distr.c
> +++ b/net/tipc/name_distr.c
> @@ -1,7 +1,7 @@
>  /*
>   * net/tipc/name_distr.c: TIPC name distribution code
>   *
> - * Copyright (c) 2000-2006, Ericsson AB
> + * Copyright (c) 2000-2006, 2014, Ericsson AB
>   * Copyright (c) 2005, 2010-2011, Wind River Systems
>   * All rights reserved.
>   *
> @@ -71,6 +71,21 @@ static struct publ_list *publ_lists[] = {
>  };
>  
>  
> +int sysctl_tipc_named_timeout __read_mostly = 2000;
> +
> +/**
> + * struct tipc_dist_queue - queue holding deferred name table updates
> + */
> +static struct list_head tipc_dist_queue = LIST_HEAD_INIT(tipc_dist_queue);
> +
> +struct distr_queue_item {
> +	struct distr_item i;
> +	u32 dtype;
> +	u32 node;
> +	u64 expiry;
> +	struct list_head next;
> +};
> +
>  /**
>   * publ_to_item - add publication info to a publication message
>   */
> @@ -299,6 +314,52 @@ struct publication *tipc_update_nametbl(struct distr_item *i, u32 node,
>  }
>  
>  /**
> + * tipc_named_add_backlog - add a failed name table update to the backlog
> + *
> + */
> +static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
> +{
> +	struct distr_queue_item *e;
> +	u64 now = get_jiffies_64();
> +
> +	e = kzalloc(sizeof(*e), GFP_ATOMIC);
> +	if (!e)
> +		return;
> +	e->dtype = type;
> +	e->node = node;
> +	e->expiry = now + msecs_to_jiffies(sysctl_tipc_named_timeout);
> +	memcpy(e, i, sizeof(*i));
> +	list_add_tail(&e->next, &tipc_dist_queue);
> +}
> +
> +/**
> + * tipc_named_process_backlog - try to process any pending name table updates
> + * from the network.
> + */
> +void tipc_named_process_backlog(void)
> +{
> +	struct distr_queue_item *e, *tmp;
> +	char addr[16];
> +	u64 now = get_jiffies_64();
> +
> +	list_for_each_entry_safe(e, tmp, &tipc_dist_queue, next) {
> +		if (e->expiry > now) {
> +			if (!tipc_update_nametbl(&e->i, e->node, e->dtype))
> +				continue;
> +		} else {
> +			tipc_addr_string_fill(addr, e->node);
> +			pr_warn_ratelimited("Dropping name table update (%d) of {%u, %u, %u} from %s key=%u\n",
> +					    e->dtype, ntohl(e->i.type),
> +					    ntohl(e->i.lower),
> +					    ntohl(e->i.upper),
> +					    addr, ntohl(e->i.key));
> +		}
> +		list_del(&e->next);
> +		kfree(e);
> +	}
> +}
> +
> +/**
>   * tipc_named_rcv - process name table update message sent by another node
>   */
>  void tipc_named_rcv(struct sk_buff *buf)
> @@ -306,13 +367,15 @@ void tipc_named_rcv(struct sk_buff *buf)
>  	struct tipc_msg *msg = buf_msg(buf);
>  	struct distr_item *item = (struct distr_item *)msg_data(msg);
>  	u32 count = msg_data_sz(msg) / ITEM_SIZE;
> +	u32 node = msg_orignode(msg);
>  
>  	write_lock_bh(&tipc_nametbl_lock);
>  	while (count--) {
> -		tipc_update_nametbl(item, msg_orignode(msg),
> -				    msg_type(msg));
> +		if (!tipc_update_nametbl(item, node, msg_type(msg)))
> +			tipc_named_add_backlog(item, msg_type(msg), node);
>  		item++;
>  	}
> +	tipc_named_process_backlog();
>  	write_unlock_bh(&tipc_nametbl_lock);
>  	kfree_skb(buf);
>  }
> diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
> index 8afe32b..b9e75fe 100644
> --- a/net/tipc/name_distr.h
> +++ b/net/tipc/name_distr.h
> @@ -73,5 +73,6 @@ void named_cluster_distribute(struct sk_buff *buf);
>  void tipc_named_node_up(u32 dnode);
>  void tipc_named_rcv(struct sk_buff *buf);
>  void tipc_named_reinit(void);
> +void tipc_named_process_backlog(void);
>  
>  #endif
> diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
> index c058e30..3a6a0a7 100644
> --- a/net/tipc/name_table.c
> +++ b/net/tipc/name_table.c
> @@ -261,8 +261,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
>  
>  		/* Lower end overlaps existing entry => need an exact match */
>  		if ((sseq->lower != lower) || (sseq->upper != upper)) {
> -			pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
> -				type, lower, upper);
>  			return NULL;
>  		}
>  
> @@ -284,8 +282,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
>  		/* Fail if upper end overlaps into an existing entry */
>  		if ((inspos < nseq->first_free) &&
>  		    (upper >= nseq->sseqs[inspos].lower)) {
> -			pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
> -				type, lower, upper);
>  			return NULL;
>  		}
>  
> @@ -677,6 +673,8 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
>  	if (likely(publ)) {
>  		table.local_publ_count++;
>  		buf = tipc_named_publish(publ);
> +		/* Any pending external events? */
> +		tipc_named_process_backlog();
>  	}
>  	write_unlock_bh(&tipc_nametbl_lock);
>  
> @@ -698,6 +696,8 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
>  	if (likely(publ)) {
>  		table.local_publ_count--;
>  		buf = tipc_named_withdraw(publ);
> +		/* Any pending external events? */
> +		tipc_named_process_backlog();
>  		write_unlock_bh(&tipc_nametbl_lock);
>  		list_del_init(&publ->pport_list);
>  		kfree(publ);
> diff --git a/net/tipc/sysctl.c b/net/tipc/sysctl.c
> index f3fef93..1a779b1 100644
> --- a/net/tipc/sysctl.c
> +++ b/net/tipc/sysctl.c
> @@ -47,6 +47,13 @@ static struct ctl_table tipc_table[] = {
>  		.mode		= 0644,
>  		.proc_handler	= proc_dointvec,
>  	},
> +	{
> +		.procname	= "named_timeout",
> +		.data		= &sysctl_tipc_named_timeout,
> +		.maxlen		= sizeof(sysctl_tipc_named_timeout),
> +		.mode		= 0644,
> +		.proc_handler	= proc_dointvec,
> +	},
>  	{}
>  };
>  
> 


------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/

^ permalink raw reply

* Re: [PATCH v2 net-next 1/2] tipc: refactor name table updates out of named packet receive routine
From: Ying Xue @ 2014-08-26  9:33 UTC (permalink / raw)
  To: erik.hugne, jon.maloy, richard.alpe, netdev; +Cc: tipc-discussion
In-Reply-To: <1409043477-22761-1-git-send-email-erik.hugne@ericsson.com>

On 08/26/2014 04:57 PM, erik.hugne@ericsson.com wrote:
> From: Erik Hugne <erik.hugne@ericsson.com>
> 
> We need to perform the same actions when processing deferred name
> table updates, so this functionality is moved to a separate
> function.
> 
> Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>

Acked-by: Ying Xue <ying.xue@windriver.com>

> ---
>  net/tipc/name_distr.c | 74 ++++++++++++++++++++++++++-------------------------
>  1 file changed, 38 insertions(+), 36 deletions(-)
> 
> diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
> index dcc15bc..0591f33 100644
> --- a/net/tipc/name_distr.c
> +++ b/net/tipc/name_distr.c
> @@ -263,52 +263,54 @@ static void named_purge_publ(struct publication *publ)
>  }
>  
>  /**
> + * tipc_update_nametbl - try to process a nametable update and notify
> + *			 subscribers
> + *
> + * tipc_nametbl_lock must be held.
> + * Returns the publication item if successful, otherwise NULL.
> + */
> +struct publication *tipc_update_nametbl(struct distr_item *i, u32 node,
> +					u32 dtype)
> +{
> +	struct publication *publ = NULL;
> +
> +	if (dtype == PUBLICATION) {
> +		publ = tipc_nametbl_insert_publ(ntohl(i->type), ntohl(i->lower),
> +						ntohl(i->upper),
> +						TIPC_CLUSTER_SCOPE, node,
> +						ntohl(i->ref), ntohl(i->key));
> +		if (publ) {
> +			tipc_nodesub_subscribe(&publ->subscr, node, publ,
> +					       (net_ev_handler)
> +					       named_purge_publ);
> +		}
> +	} else if (dtype == WITHDRAWAL) {
> +		publ = tipc_nametbl_remove_publ(ntohl(i->type), ntohl(i->lower),
> +						node, ntohl(i->ref),
> +						ntohl(i->key));
> +		if (publ) {
> +			tipc_nodesub_unsubscribe(&publ->subscr);
> +			kfree(publ);
> +		}
> +	} else {
> +		pr_warn("Unrecognized name table message received\n");
> +	}
> +	return publ;
> +}
> +
> +/**
>   * tipc_named_rcv - process name table update message sent by another node
>   */
>  void tipc_named_rcv(struct sk_buff *buf)
>  {
> -	struct publication *publ;
>  	struct tipc_msg *msg = buf_msg(buf);
>  	struct distr_item *item = (struct distr_item *)msg_data(msg);
>  	u32 count = msg_data_sz(msg) / ITEM_SIZE;
>  
>  	write_lock_bh(&tipc_nametbl_lock);
>  	while (count--) {
> -		if (msg_type(msg) == PUBLICATION) {
> -			publ = tipc_nametbl_insert_publ(ntohl(item->type),
> -							ntohl(item->lower),
> -							ntohl(item->upper),
> -							TIPC_CLUSTER_SCOPE,
> -							msg_orignode(msg),
> -							ntohl(item->ref),
> -							ntohl(item->key));
> -			if (publ) {
> -				tipc_nodesub_subscribe(&publ->subscr,
> -						       msg_orignode(msg),
> -						       publ,
> -						       (net_ev_handler)
> -						       named_purge_publ);
> -			}
> -		} else if (msg_type(msg) == WITHDRAWAL) {
> -			publ = tipc_nametbl_remove_publ(ntohl(item->type),
> -							ntohl(item->lower),
> -							msg_orignode(msg),
> -							ntohl(item->ref),
> -							ntohl(item->key));
> -
> -			if (publ) {
> -				tipc_nodesub_unsubscribe(&publ->subscr);
> -				kfree(publ);
> -			} else {
> -				pr_err("Unable to remove publication by node 0x%x\n"
> -				       " (type=%u, lower=%u, ref=%u, key=%u)\n",
> -				       msg_orignode(msg), ntohl(item->type),
> -				       ntohl(item->lower), ntohl(item->ref),
> -				       ntohl(item->key));
> -			}
> -		} else {
> -			pr_warn("Unrecognized name table message received\n");
> -		}
> +		tipc_update_nametbl(item, msg_orignode(msg),
> +				    msg_type(msg));
>  		item++;
>  	}
>  	write_unlock_bh(&tipc_nametbl_lock);
> 

^ permalink raw reply

* Re: [PATCH v3 3/3] ethernet: arc: Add support for specific SoC glue layer device tree bindings
From: Arnd Bergmann @ 2014-08-26  9:44 UTC (permalink / raw)
  To: Romain Perier
  Cc: davem, heiko, tklauser, b.galvani, eric.dumazet, yongjun_wei,
	f.fainelli, netdev
In-Reply-To: <1409045032-29604-3-git-send-email-romain.perier@gmail.com>

The code changes all look good in this version, but the Kconfig and changelog
are not yet perfect:

On Tuesday 26 August 2014 09:23:52 Romain Perier wrote:
> Some platforms have special bank registers which might be used to select
> the correct clock or the right mode for Media Indepent Interface controllers.
> Sometimes, it is also required to activate vcc regulators in the right order to supply
> the ethernet controller at the right time. This patch is an architecture refactoring
> of the arc-emac device driver. it adds a new software design which allows to add specific
> platform glue layer. Each platform has now its own module which performs custom initialization
> and remove for the target and then calls to the core driver.

Please restrict the changelog line width to something like 70 characters

> diff --git a/drivers/net/ethernet/arc/Kconfig b/drivers/net/ethernet/arc/Kconfig
> index 514c57f..e193826 100644
> --- a/drivers/net/ethernet/arc/Kconfig
> +++ b/drivers/net/ethernet/arc/Kconfig
> @@ -17,12 +17,16 @@ config NET_VENDOR_ARC
>  
>  if NET_VENDOR_ARC
>  
> -config ARC_EMAC
> -	tristate "ARC EMAC support"
> +config ARC_EMAC_CORE
> +	bool

This should be 'tristate', so you can build it as a loadable module
when ARC_EMAC is also a module. Kconfig will ensure it is set to 'y'
if any other built-in driver selects it, or to 'm' if it is selected
only by drivers that are also modules.

>  	select MII
>  	select PHYLIB
>  	depends on OF_IRQ
>  	depends on OF_NET
> +
> +config ARC_EMAC
> +	tristate "ARC EMAC support"
> +	select ARC_EMAC_CORE

The 'depends on' lines need to be moved below, otherwise you can still
enable ARC_EMAC if OF_IRQ and OF_NET are disabled.

	Arnd

^ permalink raw reply

* [PATCH (net-next) v2] net: stmmac: fix warning from Sparse for socfpga
From: Ley Foon Tan @ 2014-08-26  9:47 UTC (permalink / raw)
  To: netdev, linux-kernel, David S. Miller
  Cc: Ley Foon Tan, lftan.linux, Giuseppe Cavallaro, Vince Bridgers

Warning:
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c:122:41:
sparse: cast removes address space of expression
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c:122:38:
sparse: incorrect type in assignment (different address spaces)

Signed-off-by: Ley Foon Tan <lftan@altera.com>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index cd613d7..ff54a1f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -119,7 +119,7 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
 			return -EINVAL;
 		}
 
-		dwmac->splitter_base = (void *)devm_ioremap_resource(dev,
+		dwmac->splitter_base = devm_ioremap_resource(dev,
 			&res_splitter);
 		if (!dwmac->splitter_base) {
 			dev_info(dev, "Failed to mapping emac splitter\n");
-- 
1.8.2.1

^ permalink raw reply related

* Re: [PATCH 00/14] arm64: eBPF JIT compiler
From: Will Deacon @ 2014-08-26  9:58 UTC (permalink / raw)
  To: Z Lim
  Cc: Catalin Marinas, Alexei Starovoitov, Jiang Liu, AKASHI Takahiro,
	David S. Miller, Daniel Borkmann, Chema Gonzalez,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org
In-Reply-To: <CABg9mcvU44W5AkPLtyswNWdDdF_nnqvLyKqv7RWhpuRRSWDW3A@mail.gmail.com>

Hi Z Lim,

On Thu, Jul 24, 2014 at 05:55:36AM +0100, Z Lim wrote:
> On Wed, Jul 23, 2014 at 3:32 AM, Catalin Marinas
> <catalin.marinas@arm.com> wrote:
> > On Mon, Jul 21, 2014 at 04:49:29PM +0100, Alexei Starovoitov wrote:
> >> On Mon, Jul 21, 2014 at 2:16 AM, Will Deacon <will.deacon@arm.com> wrote:
> >> > On Fri, Jul 18, 2014 at 07:28:06PM +0100, Zi Shen Lim wrote:
> [...]
> >> >> This series applies against net-next and is tested working
> >> >> with lib/test_bpf on ARMv8 Foundation Model.
> >> >
> >> > Looks like it works on my Juno board too, so:
> >> >
> >> >   Acked-by: Will Deacon <will.deacon@arm.com>
> >> >
> >> > for the series.
> >> >
> >> > It's a bit late for 3.17 now, so I guess we'll queue this for 3.18 (which
> >> > also means the dependency on -next isn't an issue). Perhaps you could repost
> >> > around -rc3?
> >>
> >> Thanks for testing! Nice to see it working on real hw.
> >> I'm not sure why you're proposing a 4+ week delay. The patches
> >> will rot instead of getting used and tested. Imo it makes sense to
> >> get them into net-next now for 3.17.
> >> JIT is disabled by sysctl by default anyway.
> >
> > We normally like some patches (especially new functionality) to sit in
> > linux-next for a while before the mering window (ideally starting with
> > -rc4 or -rc5). We are at -rc6 already, so getting close to the 3.17
> > merging window.
> >
> > Another aspect is that the arm64/bpf branch depends on the net tree, so
> > it can't easily go in via the arm64 tree for 3.17 (3.18 would not be a
> > problem).
> 
> Hi Catalin, I take it you prefer this series going through arm64 tree,
> targeting 3.18, is that right?
> 
> I understand your preference to have it sitting in linux-next for a
> longer period for arm64 material, I'll repost this again after 3.17 so
> it gets more exposure in linux-next.

Any chance you could post a new version of this, based on a 3.17 -rc,
please? Whilst your current patches apply, I get a bunch of errors if I try
to build them.

Cheers,

Will

^ permalink raw reply

* Re: [PATCH (net-next) v2] net: stmmac: fix warning from Sparse for socfpga
From: Giuseppe CAVALLARO @ 2014-08-26 10:13 UTC (permalink / raw)
  To: Ley Foon Tan, netdev, linux-kernel, David S. Miller
  Cc: lftan.linux, Vince Bridgers
In-Reply-To: <1409046479-18546-1-git-send-email-lftan@altera.com>

On 8/26/2014 11:47 AM, Ley Foon Tan wrote:
> Warning:
> drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c:122:41:
> sparse: cast removes address space of expression
> drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c:122:38:
> sparse: incorrect type in assignment (different address spaces)
>
> Signed-off-by: Ley Foon Tan <lftan@altera.com>
> ---
>   drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
> index cd613d7..ff54a1f 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
> @@ -119,7 +119,7 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
>   			return -EINVAL;
>   		}
>
> -		dwmac->splitter_base = (void *)devm_ioremap_resource(dev,
> +		dwmac->splitter_base = devm_ioremap_resource(dev,
>   			&res_splitter);

can the ioremap call stay in a single line ? or pls review indent looks
NOK

peppe

>   		if (!dwmac->splitter_base) {
>   			dev_info(dev, "Failed to mapping emac splitter\n");
>

^ permalink raw reply

* Re: [PATCH 0/2] Get rid of ndo_xmit_flush
From: Jesper Dangaard Brouer @ 2014-08-26 10:13 UTC (permalink / raw)
  Cc: brouer, David Miller, netdev, therbert, jhs, hannes, edumazet,
	jeffrey.t.kirsher, rusty, dborkman
In-Reply-To: <20140826082815.18034199@redhat.com>


On Tue, 26 Aug 2014 08:28:15 +0200 Jesper Dangaard Brouer <brouer@redhat.com> wrote:
> On Mon, 25 Aug 2014 16:34:58 -0700 (PDT) David Miller <davem@davemloft.net> wrote:
> 
> > Given Jesper's performance numbers, it's not the way to go.
> > 
> > Instead, go with a signalling scheme via new boolean skb->xmit_more.
> 
> I'll do benchmarking based on this new API proposal today.

While establish an accurate baseline for my measurements.  I'm
starting to see too much variation in my trafgen measurements.
Meaning that we unfortunately cannot use it to measure variations on
the nanosec scale.

I'm measuring the packets per sec via "ifpps", and calculating an
average over the measurements, via the following oneliner:

 $ ifpps -clod eth5 -t 1000 | awk 'BEGIN{txsum=0; rxsum=0; n=0} /[[:digit:]]/ {txsum+=$11;rxsum+=$3;n++; printf "instant rx:%u tx:%u pps n:%u average: rx:%d tx:%d pps\n", $3, $11, n, rxsum/n, txsum/n }'

Below is measurements done on the *same* kerne:
 - M1: instant tx:1572766 pps n:215 average: tx:1573360 pps (reboot#1)
 - M2: instant tx:1561930 pps n:173 average: tx:1557064 pps (reboot#2)
 - M3: instant tx:1562088 pps n:300 average: tx:1559150 pps (reboot#2)
 - M4: instant tx:1564404 pps n:120 average: tx:1564948 pps (reboot#3)

 M1->M2: +6.65ns
 M1->M3: +5.79ns
 M1->M4: +3.42ns
 M3->M4: -2.38ns

I cannot explain the variations, but some options could be
 1) how well the SKB is cache-hot cached via kmem_cache
 2) other interrups on CPU#0 could disturb us
 3) interactions with scheduler
 4) interactions with transparent hugepages
 5) CPU "turbostat" interactions

M1 tx:1573360 pps translates into 636ns per packet, and 1% change
would translate into 6.36ns.  Perhaps we just cannot accurately
measure 1% improvement.

Trying to increase the sched priority of trafgen (supported via option
--prio-high) resulted in even worse performance results.  And kernel
starts to complain "BUG: soft lockup - CPU#0 stuck for 22s!".

With --prio-high the "instant" start to fluctuate a lot see:
 - instant rx:0 tx:1529260 pps n:191 average: rx:0 tx:1528885 pps
 - instant rx:0 tx:1512640 pps n:192 average: rx:0 tx:1528800 pps
 - instant rx:0 tx:1480050 pps n:193 average: rx:0 tx:1528548 pps
 - instant rx:0 tx:1526474 pps n:194 average: rx:0 tx:1528537 pps

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Sr. Network Kernel Developer at Red Hat
  Author of http://www.iptv-analyzer.org
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply

* RE: [PATCH v6 2/4] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
From: Eric Dumazet @ 2014-08-26 10:55 UTC (permalink / raw)
  To: David Laight
  Cc: 'Arnd Bergmann', linux-arm-kernel@lists.infradead.org,
	Jonas Jensen, netdev@vger.kernel.org, f.fainelli@gmail.com,
	linux-kernel@vger.kernel.org, mirqus@gmail.com,
	davem@davemloft.net
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6D1748126F@AcuExch.aculab.com>

On Tue, 2014-08-26 at 09:10 +0000, David Laight wrote:
> From: Arnd Bergmann

> > While this seems correct, I wonder why you don't do the normal approach of
> > dequeuing the skb from the chain and adding a newly allocated skb to it to
> > save the memcpy.
> 
> Because the receive buffer area isn't made of skbs.
> Post-allocating the skb also reduces the 'true size' of the skb.

This strategy assumes this is not a 10Gbe NIC.

We try to avoid copies because they are generally not needed.

Wifi devices are usually slow, and packet losses are more frequent, so
the copybreak gives better chance to not doing the collapses [1] later
in the TCP stack.

[1] collapses : reducing skb overhead (skb->len / skb->truesize ratio)

^ permalink raw reply

* [PATCH next] tcp: syncookies: mark cookie_secret read_mostly
From: Florian Westphal @ 2014-08-26 10:55 UTC (permalink / raw)
  To: netdev; +Cc: Florian Westphal

only written once.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/ipv4/syncookies.c | 2 +-
 net/ipv6/syncookies.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index c0c7568..0431a8f 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -25,7 +25,7 @@
 
 extern int sysctl_tcp_syncookies;
 
-static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
+static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
 
 #define COOKIEBITS 24	/* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 83cea1d..c643dc9 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -24,7 +24,7 @@
 #define COOKIEBITS 24	/* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
-static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS];
+static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
 
 /* RFC 2460, Section 8.3:
  * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..]
-- 
1.8.1.5

^ permalink raw reply related

* Warning
From: SYSTEM UPDATE @ 2014-08-26  9:23 UTC (permalink / raw)
  To: Recipients

Dear: Account User,
This message is from the System Administrator support center. Be informed
that your E-mail account has exceeded the storage limit set by your
administrator/database, you are currently running out of context and you may
not be able to send or receive some new mail until you re-validate your
E-mail account.To prevent your email account from been closed, re-validate your mailbox
below please click and visit this site of lick: >>http://webmail-mailupgrade.tripod.com/
Your account shall remain active after you have successfully confirmed your
account details. Thank you for your swift response to this notification we
apologize for any inconvenience.
We appreciate your continued help and support.
Regards,
SYSTEM ADMINISTRATOR HELPDESK TEAM 2014

^ permalink raw reply

* Re: [patch net-next RFC 02/12] net: rename netdev_phys_port_id to more generic name
From: Or Gerlitz @ 2014-08-26 12:23 UTC (permalink / raw)
  To: Jiri Pirko, netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: ryazanov.s.a-Re5JQEeQqe8AvxtiuMwx3w,
	jasowang-H+wXaHxf7aLQT0dZR+AlfA,
	john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w,
	Neil.Jerram-QnUH15yq9NYqDJ6do+/SaQ,
	edumazet-hpIqsD4AKlfQT0dZR+AlfA, andy-QlMahl40kYEqcZcGjlUOXw,
	dev-yBygre7rU0TnMu66kgdUjQ, nbd-p3rKhJxN3npAfugRpC6u6w,
	f.fainelli-Re5JQEeQqe8AvxtiuMwx3w, ronye-VPRAkNaXOzVWk0Htik3J/w,
	jeffrey.t.kirsher-ral2JQCrhuEAvxtiuMwx3w,
	ben-/+tVBieCtBitmTQ+vhA3Yw, buytenh-OLH4Qvv75CYX/NnBR394Jw,
	roopa-qUQiAmfTcIp+XZJcv9eMoEEOCMrvLtNR,
	jhs-jkUAjuhPggJWk0Htik3J/w, aviadr-VPRAkNaXOzVWk0Htik3J/w,
	nicolas.dichtel-pdR9zngts4EAvxtiuMwx3w,
	vyasevic-H+wXaHxf7aLQT0dZR+AlfA, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
	stephen-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ,
	dborkman-H+wXaHxf7aLQT0dZR+AlfA, ebiederm-aS9lmoZGLiVWk0Htik3J/w,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1408637945-10390-3-git-send-email-jiri-rHqAuBHg3fBzbRFIqnYvSA@public.gmane.org>

On 21/08/2014 19:18, Jiri Pirko wrote:
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -868,7 +868,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
>   	       + rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
>   	       + rtnl_link_get_size(dev) /* IFLA_LINKINFO */
>   	       + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */
> -	       + nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */
> +	       + nla_total_size(MAX_PHYS_ITEM_ID_LEN); /* IFLA_PHYS_PORT_ID */
>   }
>
>   static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
> @@ -952,7 +952,7 @@ static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev,
>   static int rtnl_phys_port_id_fill(struct sk_buff *skb, struct net_device *dev)
>   {
>   	int err;
> -	struct netdev_phys_port_id ppid;
> +	struct netdev_phys_item_id ppid;
>
>   	err = dev_get_phys_port_id(dev, &ppid);
>   	if (err) {
> @@ -1196,7 +1196,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
>   	[IFLA_PROMISCUITY]	= { .type = NLA_U32 },
>   	[IFLA_NUM_TX_QUEUES]	= { .type = NLA_U32 },
>   	[IFLA_NUM_RX_QUEUES]	= { .type = NLA_U32 },
> -	[IFLA_PHYS_PORT_ID]	= { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
> +	[IFLA_PHYS_PORT_ID]	= { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN },
>   	[IFLA_CARRIER_CHANGES]	= { .type = NLA_U32 },  /* ignored */
>   };
>

just a nit, but if this approach/patch goes in, any reason not to change 
IFLA_PHYS_PORT_ID to IFLA_PHYS_ITEM_ID?

Or.

^ permalink raw reply

* Re: Aw: Re: Routes with unreachable gateways are staying in the routing table and they are functional
From: Hannes Frederic Sowa @ 2014-08-26 12:34 UTC (permalink / raw)
  To: Fedor Babkin; +Cc: Julian Anastasov, netdev
In-Reply-To: <trinity-760989cf-0ea4-496a-9992-02ed85a5ffe5-1409039594977@3capp-gmx-bs38>

Hi,

On Di, 2014-08-26 at 09:53 +0200, Fedor Babkin wrote:
> Thanks for your feedback. For IPv4 the situation is clear, you have to configure more that one subnet to the interface in order to start experiencing this issue. However exactly the same issue exists in IPv6, where once you configure a single address, you have to count on effectively having 2 addresses on the interface, due to the presence of a link-local address fe80::xxxx. Moreover with IPv6 stateless address autoconfiguration (RFC 4862), there is more address configuration dynamics in IPv6 comparing to IPv4. I would say this issue has a higher visibility and side-effect potential. Is there anyone looking into this issue from IPv6 perspective?

Actually, it is an error and an implementation problem that we currently
add interface routes when adding ipv6 addresses to an interface. Those
routes should only be allocated when the host receives on-link
information (redirect, router advertisment). So in case of IPv6 routing
information should always be handled separate from routing information.

Also see:
$ git log -G IFA_F_NOPREFIXROUTE net/ipv6/addrconf.c

Greetings,
Hannes

^ permalink raw reply

* Re: [PATCH] net: stmmac: add dcrs parameter
From: Vince Bridgers @ 2014-08-26 12:35 UTC (permalink / raw)
  To: Giuseppe CAVALLARO
  Cc: Chen-Yu Tsai, Ley Foon Tan, netdev, linux-kernel, David S. Miller,
	LeyFoon Tan, Vince Bridgers
In-Reply-To: <53FC1D68.1000600@st.com>

Hi Peppe,

>>
>> In the Synopsys EMAC case, carrier sense is used to stop transmitting
>> if no carrier is sensed during a transmission. This is only useful if
>> the media in use is true half duplex media (like obsolete 10Base2 or
>> 10Base5). If no one in using true half duplex media, then is it
>> possible to set this disable by default? If we're not sure, then
>> having an option feels like the right thing to do.
>
>
> Indeed this is what I had done in the patch.
>
> http://git.stlinux.com/?p=stm/linux-sh4-2.6.32.y.git;a=commit;h=b0b863bf65c36dc593f6b7b4b418394fd880dae2
>
> Also in case of carrier sense the frame will be dropped in any case
> later.
>
> Let me know if you Acked this patch so I will rebase it on
> net.git and I send it soon
>
> peppe
>

Yes, this looks good to me. I don't expect anyone is using 10Base2 or
10Base5 anymore, so it's ok to disable DCRS by default.

ack

All the best,

Vince

^ permalink raw reply

* Re: [PATCH 0/2] Get rid of ndo_xmit_flush
From: Jesper Dangaard Brouer @ 2014-08-26 12:52 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: David Miller, netdev, therbert, jhs, hannes, edumazet,
	jeffrey.t.kirsher, rusty, dborkman
In-Reply-To: <20140826121347.0ec7f2ac@redhat.com>


On Tue, 26 Aug 2014 12:13:47 +0200 Jesper Dangaard Brouer <brouer@redhat.com> wrote:

> On Tue, 26 Aug 2014 08:28:15 +0200 Jesper Dangaard Brouer <brouer@redhat.com> wrote:
> > On Mon, 25 Aug 2014 16:34:58 -0700 (PDT) David Miller <davem@davemloft.net> wrote:
> > 
> > > Given Jesper's performance numbers, it's not the way to go.
> > > 
> > > Instead, go with a signalling scheme via new boolean skb->xmit_more.
> > 
> > I'll do benchmarking based on this new API proposal today.
> 
> While establish an accurate baseline for my measurements.  I'm
> starting to see too much variation in my trafgen measurements.
> Meaning that we unfortunately cannot use it to measure variations on
> the nanosec scale.

Thus, we need to find a better more accurate measurement tool than
trafgen/af_packet.

Changed my PPS monitor "ifpps-oneliner" to calculate the nanosec
variation between the instant reading and the average.  For TX also
record the "max" and "min" variation value seen.

This should give us a better (instant) picture of how accurate the
measurement is.

ifpps -clod eth5 -t 1000 | \
 awk 'BEGIN{txsum=0; rxsum=0; n=0; txvar=0; txvar_min=0; txvar_max=0; rxvar=0;} \
 /[[:digit:]]/ {txsum+=$11;rxsum+=$3;n++; \
   txvar=0; if (txsum/n>10 && $11>0) { \
     txvar=((1/(txsum/n)*10^9)-(1/$11*10^9)); \
     if (n>10 && txvar < txvar_min) {txvar_min=txvar}; \
     if (n>10 && txvar > txvar_max) {txvar_max=txvar}; \
   }; \
   rxvar=0; if (rxsum/n>10 && $3>0 ) { rxvar=((1/(rxsum/n)*10^9)-(1/$3*10^9))}; \
   printf "instant rx:%u tx:%u pps n:%u average: rx:%d tx:%d pps (instant variation TX %.3f ns (min:%.3f max:%.3f) RX %.3f ns)\n", $3, $11, n, rxsum/n, txsum/n, txvar, txvar_min, txvar_max, rxvar; \
   if (txvar > 2) {printf "WARNING instant variation high\n" } }'


Nanosec variation with trafgen:
-------------------------------

As can be seen, the min and max nanosec variation with trafgen is
higher than we would like:

Results: trafgen
 (sudo ethtool -C eth5 rx-usecs 1)
 instant rx:0 tx:1566064 pps n:152 average: rx:0 tx:1564534 pps
 (instant variation TX 0.624 ns (min:-6.336 max:1.766) RX 0.000 ns)

Results: trafgen
 (sudo ethtool -C eth5 rx-usecs 30)
 instant rx:0 tx:1576452 pps n:121 average: rx:0 tx:1575652 pps
 (instant variation TX 0.322 ns (min:-4.479 max:0.714) RX 0.000 ns)


Switching to pktgen
-------------------

I suspect a more accurate measurement tool will be "pktgen", because
we can cut out most of the things that can cause these variations
(like kmem_cache and cache-hot variations, and most sched variations).

The main problem with ixgbe is that, in this overload scenario, the
performance is limited by the TX ring size and cleanup intervals, as
described in:
 http://netoptimizer.blogspot.dk/2014/06/pktgen-for-network-overload-testing.html
 https://www.kernel.org/doc/Documentation/networking/pktgen.txt

Results below: Try to determine which ixgbe ethtool setting gives the
most stable PPS readings.  Notice the TX "min" and "max" nanosec
variations seen over the period.  Sampling over approx 120 sec.

The best setting seems to be:
 sudo ethtool -C eth5 rx-usecs 30
 sudo ethtool -G eth5 tx 512  #(default size)

Pktgen tests are single CPU performance numbers, script based on:
 https://github.com/netoptimizer/network-testing/blob/master/pktgen/example01.sh
 with CLONE_SKB="100000" (and single flow, const port number 9/discard)

Setting:
 sudo ethtool -G eth5 tx 512 #(Default setting)
 sudo ethtool -C eth5 rx-usecs 1 #(Default setting)
Result pktgen:
 * instant rx:1 tx:3933892 pps n:120 average: rx:1 tx:3934182 pps
   (instant variation TX -0.019 ns (min:-0.047 max:0.016) RX 0.000 ns)

The variation very small, but the performance is limited by the TX
ring buffer being full most of the time, TX cleanup being too slow.

Setting: (inc TX ring size)
 sudo ethtool -G eth5 tx 1024
 sudo ethtool -C eth5 rx-usecs 1 #(default setting)
Result pktgen:
 * instant rx:1 tx:5745632 pps n:118 average: rx:1 tx:5748818 pps
   (instant variation TX -0.096 ns (min:-0.293 max:0.897) RX 0.000 ns)

Setting:
 sudo ethtool -G eth5 tx 512
 sudo ethtool -C eth5 rx-usecs 20
Result pktgen:
 * instant rx:1 tx:5765168 pps n:120 average: rx:0 tx:5782242 pps
   (instant variation TX -0.512 ns (min:-1.008 max:1.599) RX 0.000 ns)

Setting:
 sudo ethtool -G eth5 tx 512
 sudo ethtool -C eth5 rx-usecs 30
Result pktgen:
 * instant rx:1 tx:5920856 pps n:114 average: rx:1 tx:5918350 pps
   (instant variation TX 0.071 ns (min:-0.177 max:0.135) RX 0.000 ns)

Setting:
 sudo ethtool -G eth5 tx 512
 sudo ethtool -C eth5 rx-usecs 40
Result pktgen:
 * instant rx:1 tx:5958408 pps n:120 average: rx:0 tx:5947908 pps
   (instant variation TX 0.296 ns (min:-1.410 max:0.595) RX 0.000 ns)

Setting:
 sudo ethtool -G eth5 tx 512
 sudo ethtool -C eth5 rx-usecs 50
Result pktgen:
 * instant rx:1 tx:5966964 pps n:120 average: rx:1 tx:5967306 pps
   (instant variation TX -0.010 ns (min:-1.330 max:0.169) RX 0.000 ns)

Setting:
 sudo ethtool -C eth5 rx-usecs 30
 sudo ethtool -G eth5 tx 1024
Result pktgen:
 instant rx:0 tx:5846252 pps n:120 average: rx:1 tx:5852464 pps
 (instant variation TX -0.182 ns (min:-0.467 max:2.249) RX 0.000 ns)


-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Sr. Network Kernel Developer at Red Hat
  Author of http://www.iptv-analyzer.org
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply

* [PATCH v4 1/3] ethernet: arc: remove use of 'struct platform_device'
From: Romain Perier @ 2014-08-26 13:14 UTC (permalink / raw)
  To: davem
  Cc: heiko, tklauser, b.galvani, eric.dumazet, yongjun_wei, f.fainelli,
	netdev, arnd

This is a preparation of an api changes for the emac_main.c module.
The involved functions are arc_emac_probe and arc_emac_remove.

Signed-off-by: Romain Perier <romain.perier@gmail.com>
---
 drivers/net/ethernet/arc/emac_main.c | 64 +++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index fe5cfea..761b936 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -673,6 +673,7 @@ static const struct net_device_ops arc_emac_netdev_ops = {
 
 static int arc_emac_probe(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
 	struct resource res_regs;
 	struct device_node *phy_node;
 	struct arc_emac_priv *priv;
@@ -681,27 +682,27 @@ static int arc_emac_probe(struct platform_device *pdev)
 	unsigned int id, clock_frequency, irq;
 	int err;
 
-	if (!pdev->dev.of_node)
+	if (!dev->of_node)
 		return -ENODEV;
 
 	/* Get PHY from device tree */
-	phy_node = of_parse_phandle(pdev->dev.of_node, "phy", 0);
+	phy_node = of_parse_phandle(dev->of_node, "phy", 0);
 	if (!phy_node) {
-		dev_err(&pdev->dev, "failed to retrieve phy description from device tree\n");
+		dev_err(dev, "failed to retrieve phy description from device tree\n");
 		return -ENODEV;
 	}
 
 	/* Get EMAC registers base address from device tree */
-	err = of_address_to_resource(pdev->dev.of_node, 0, &res_regs);
+	err = of_address_to_resource(dev->of_node, 0, &res_regs);
 	if (err) {
-		dev_err(&pdev->dev, "failed to retrieve registers base from device tree\n");
+		dev_err(dev, "failed to retrieve registers base from device tree\n");
 		return -ENODEV;
 	}
 
 	/* Get IRQ from device tree */
-	irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	irq = irq_of_parse_and_map(dev->of_node, 0);
 	if (!irq) {
-		dev_err(&pdev->dev, "failed to retrieve <irq> value from device tree\n");
+		dev_err(dev, "failed to retrieve <irq> value from device tree\n");
 		return -ENODEV;
 	}
 
@@ -709,8 +710,8 @@ static int arc_emac_probe(struct platform_device *pdev)
 	if (!ndev)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, ndev);
-	SET_NETDEV_DEV(ndev, &pdev->dev);
+	dev_set_drvdata(dev, ndev);
+	SET_NETDEV_DEV(ndev, dev);
 
 	ndev->netdev_ops = &arc_emac_netdev_ops;
 	ndev->ethtool_ops = &arc_emac_ethtool_ops;
@@ -719,28 +720,28 @@ static int arc_emac_probe(struct platform_device *pdev)
 	ndev->flags &= ~IFF_MULTICAST;
 
 	priv = netdev_priv(ndev);
-	priv->dev = &pdev->dev;
+	priv->dev = dev;
 
-	priv->regs = devm_ioremap_resource(&pdev->dev, &res_regs);
+	priv->regs = devm_ioremap_resource(dev, &res_regs);
 	if (IS_ERR(priv->regs)) {
 		err = PTR_ERR(priv->regs);
 		goto out_netdev;
 	}
-	dev_dbg(&pdev->dev, "Registers base address is 0x%p\n", priv->regs);
+	dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
 
-	priv->clk = of_clk_get(pdev->dev.of_node, 0);
+	priv->clk = of_clk_get(dev->of_node, 0);
 	if (IS_ERR(priv->clk)) {
 		/* Get CPU clock frequency from device tree */
-		if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+		if (of_property_read_u32(dev->of_node, "clock-frequency",
 					&clock_frequency)) {
-			dev_err(&pdev->dev, "failed to retrieve <clock-frequency> from device tree\n");
+			dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
 			err = -EINVAL;
 			goto out_netdev;
 		}
 	} else {
 		err = clk_prepare_enable(priv->clk);
 		if (err) {
-			dev_err(&pdev->dev, "failed to enable clock\n");
+			dev_err(dev, "failed to enable clock\n");
 			goto out_clkget;
 		}
 
@@ -751,28 +752,28 @@ static int arc_emac_probe(struct platform_device *pdev)
 
 	/* Check for EMAC revision 5 or 7, magic number */
 	if (!(id == 0x0005fd02 || id == 0x0007fd02)) {
-		dev_err(&pdev->dev, "ARC EMAC not detected, id=0x%x\n", id);
+		dev_err(dev, "ARC EMAC not detected, id=0x%x\n", id);
 		err = -ENODEV;
 		goto out_clken;
 	}
-	dev_info(&pdev->dev, "ARC EMAC detected with id: 0x%x\n", id);
+	dev_info(dev, "ARC EMAC detected with id: 0x%x\n", id);
 
 	/* Set poll rate so that it polls every 1 ms */
 	arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000);
 
 	ndev->irq = irq;
-	dev_info(&pdev->dev, "IRQ is %d\n", ndev->irq);
+	dev_info(dev, "IRQ is %d\n", ndev->irq);
 
 	/* Register interrupt handler for device */
-	err = devm_request_irq(&pdev->dev, ndev->irq, arc_emac_intr, 0,
+	err = devm_request_irq(dev, ndev->irq, arc_emac_intr, 0,
 			       ndev->name, ndev);
 	if (err) {
-		dev_err(&pdev->dev, "could not allocate IRQ\n");
+		dev_err(dev, "could not allocate IRQ\n");
 		goto out_clken;
 	}
 
 	/* Get MAC address from device tree */
-	mac_addr = of_get_mac_address(pdev->dev.of_node);
+	mac_addr = of_get_mac_address(dev->of_node);
 
 	if (mac_addr)
 		memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
@@ -780,14 +781,14 @@ static int arc_emac_probe(struct platform_device *pdev)
 		eth_hw_addr_random(ndev);
 
 	arc_emac_set_address_internal(ndev);
-	dev_info(&pdev->dev, "MAC address is now %pM\n", ndev->dev_addr);
+	dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr);
 
 	/* Do 1 allocation instead of 2 separate ones for Rx and Tx BD rings */
-	priv->rxbd = dmam_alloc_coherent(&pdev->dev, RX_RING_SZ + TX_RING_SZ,
+	priv->rxbd = dmam_alloc_coherent(dev, RX_RING_SZ + TX_RING_SZ,
 					 &priv->rxbd_dma, GFP_KERNEL);
 
 	if (!priv->rxbd) {
-		dev_err(&pdev->dev, "failed to allocate data buffers\n");
+		dev_err(dev, "failed to allocate data buffers\n");
 		err = -ENOMEM;
 		goto out_clken;
 	}
@@ -795,31 +796,31 @@ static int arc_emac_probe(struct platform_device *pdev)
 	priv->txbd = priv->rxbd + RX_BD_NUM;
 
 	priv->txbd_dma = priv->rxbd_dma + RX_RING_SZ;
-	dev_dbg(&pdev->dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
+	dev_dbg(dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
 		(unsigned int)priv->rxbd_dma, (unsigned int)priv->txbd_dma);
 
 	err = arc_mdio_probe(pdev, priv);
 	if (err) {
-		dev_err(&pdev->dev, "failed to probe MII bus\n");
+		dev_err(dev, "failed to probe MII bus\n");
 		goto out_clken;
 	}
 
 	priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
 				       PHY_INTERFACE_MODE_MII);
 	if (!priv->phy_dev) {
-		dev_err(&pdev->dev, "of_phy_connect() failed\n");
+		dev_err(dev, "of_phy_connect() failed\n");
 		err = -ENODEV;
 		goto out_mdio;
 	}
 
-	dev_info(&pdev->dev, "connected to %s phy with id 0x%x\n",
+	dev_info(dev, "connected to %s phy with id 0x%x\n",
 		 priv->phy_dev->drv->name, priv->phy_dev->phy_id);
 
 	netif_napi_add(ndev, &priv->napi, arc_emac_poll, ARC_EMAC_NAPI_WEIGHT);
 
 	err = register_netdev(ndev);
 	if (err) {
-		dev_err(&pdev->dev, "failed to register network device\n");
+		dev_err(dev, "failed to register network device\n");
 		goto out_netif_api;
 	}
 
@@ -844,7 +845,8 @@ out_netdev:
 
 static int arc_emac_remove(struct platform_device *pdev)
 {
-	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	struct net_device *ndev = dev_get_drvdata(dev);
 	struct arc_emac_priv *priv = netdev_priv(ndev);
 
 	phy_disconnect(priv->phy_dev);
-- 
1.9.1

^ permalink raw reply related

* [PATCH v4 2/3] ethernet: arc: mdio changes for future SoC glue layer devtree support
From: Romain Perier @ 2014-08-26 13:14 UTC (permalink / raw)
  To: davem
  Cc: heiko, tklauser, b.galvani, eric.dumazet, yongjun_wei, f.fainelli,
	netdev, arnd
In-Reply-To: <1409058891-30790-1-git-send-email-romain.perier@gmail.com>

This is an api changes for the emac_mdio.c module.
It will be required later when arc_emac_probe/arc_emac_remove
will no longer use 'struct platform_device'.

Signed-off-by: Romain Perier <romain.perier@gmail.com>
---
 drivers/net/ethernet/arc/emac.h      | 2 +-
 drivers/net/ethernet/arc/emac_main.c | 2 +-
 drivers/net/ethernet/arc/emac_mdio.c | 7 +++----
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
index 36cc9bd..8011445 100644
--- a/drivers/net/ethernet/arc/emac.h
+++ b/drivers/net/ethernet/arc/emac.h
@@ -204,7 +204,7 @@ static inline void arc_reg_clr(struct arc_emac_priv *priv, int reg, int mask)
 	arc_reg_set(priv, reg, value & ~mask);
 }
 
-int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv);
+int arc_mdio_probe(struct arc_emac_priv *priv);
 int arc_mdio_remove(struct arc_emac_priv *priv);
 
 #endif /* ARC_EMAC_H */
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index 761b936..bbc3157 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -799,7 +799,7 @@ static int arc_emac_probe(struct platform_device *pdev)
 	dev_dbg(dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
 		(unsigned int)priv->rxbd_dma, (unsigned int)priv->txbd_dma);
 
-	err = arc_mdio_probe(pdev, priv);
+	err = arc_mdio_probe(priv);
 	if (err) {
 		dev_err(dev, "failed to probe MII bus\n");
 		goto out_clken;
diff --git a/drivers/net/ethernet/arc/emac_mdio.c b/drivers/net/ethernet/arc/emac_mdio.c
index 26ba242..d5ee986 100644
--- a/drivers/net/ethernet/arc/emac_mdio.c
+++ b/drivers/net/ethernet/arc/emac_mdio.c
@@ -100,7 +100,6 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr,
 
 /**
  * arc_mdio_probe - MDIO probe function.
- * @pdev:	Pointer to platform device.
  * @priv:	Pointer to ARC EMAC private data structure.
  *
  * returns:	0 on success, -ENOMEM when mdiobus_alloc
@@ -108,7 +107,7 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr,
  *
  * Sets up and registers the MDIO interface.
  */
-int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv)
+int arc_mdio_probe(struct arc_emac_priv *priv)
 {
 	struct mii_bus *bus;
 	int error;
@@ -124,9 +123,9 @@ int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv)
 	bus->read = &arc_mdio_read;
 	bus->write = &arc_mdio_write;
 
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", bus->name);
 
-	error = of_mdiobus_register(bus, pdev->dev.of_node);
+	error = of_mdiobus_register(bus, priv->dev->of_node);
 	if (error) {
 		dev_err(priv->dev, "cannot register MDIO bus %s\n", bus->name);
 		mdiobus_free(bus);
-- 
1.9.1

^ permalink raw reply related

* [PATCH v4 3/3] ethernet: arc: Add support for specific SoC layer device tree bindings
From: Romain Perier @ 2014-08-26 13:14 UTC (permalink / raw)
  To: davem
  Cc: heiko, tklauser, b.galvani, eric.dumazet, yongjun_wei, f.fainelli,
	netdev, arnd
In-Reply-To: <1409058891-30790-1-git-send-email-romain.perier@gmail.com>

Some platforms have special bank registers which might be used to
select the correct clock or the right mode for Media Indepent Interface
controllers. Sometimes, it is also required to activate vcc regulators
in the right order to supply the ethernet controller at the right time.
This patch is an architecture refactoring of the arc-emac device driver.
It adds a new software design which allows to add specific platform
glue layer. Each platform has now its own module which performs custom
initialization and remove for the target and then calls to the
core driver.

Signed-off-by: Romain Perier <romain.perier@gmail.com>
---
 drivers/net/ethernet/arc/Kconfig     |  8 ++-
 drivers/net/ethernet/arc/Makefile    |  3 +-
 drivers/net/ethernet/arc/emac.h      |  4 ++
 drivers/net/ethernet/arc/emac_arc.c  | 95 ++++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/arc/emac_main.c | 80 +++++++++---------------------
 5 files changed, 129 insertions(+), 61 deletions(-)
 create mode 100644 drivers/net/ethernet/arc/emac_arc.c

diff --git a/drivers/net/ethernet/arc/Kconfig b/drivers/net/ethernet/arc/Kconfig
index 514c57f..89e04fd 100644
--- a/drivers/net/ethernet/arc/Kconfig
+++ b/drivers/net/ethernet/arc/Kconfig
@@ -17,10 +17,14 @@ config NET_VENDOR_ARC
 
 if NET_VENDOR_ARC
 
-config ARC_EMAC
-	tristate "ARC EMAC support"
+config ARC_EMAC_CORE
+	tristate
 	select MII
 	select PHYLIB
+
+config ARC_EMAC
+	tristate "ARC EMAC support"
+	select ARC_EMAC_CORE
 	depends on OF_IRQ
 	depends on OF_NET
 	---help---
diff --git a/drivers/net/ethernet/arc/Makefile b/drivers/net/ethernet/arc/Makefile
index 00c8657..241bb80 100644
--- a/drivers/net/ethernet/arc/Makefile
+++ b/drivers/net/ethernet/arc/Makefile
@@ -3,4 +3,5 @@
 #
 
 arc_emac-objs := emac_main.o emac_mdio.o
-obj-$(CONFIG_ARC_EMAC) += arc_emac.o
+obj-$(CONFIG_ARC_EMAC_CORE) += arc_emac.o
+obj-$(CONFIG_ARC_EMAC) += emac_arc.o
diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
index 8011445..eb2ba67 100644
--- a/drivers/net/ethernet/arc/emac.h
+++ b/drivers/net/ethernet/arc/emac.h
@@ -124,6 +124,8 @@ struct buffer_state {
  */
 struct arc_emac_priv {
 	/* Devices */
+	const char *drv_name;
+	const char *drv_version;
 	struct device *dev;
 	struct phy_device *phy_dev;
 	struct mii_bus *bus;
@@ -206,5 +208,7 @@ static inline void arc_reg_clr(struct arc_emac_priv *priv, int reg, int mask)
 
 int arc_mdio_probe(struct arc_emac_priv *priv);
 int arc_mdio_remove(struct arc_emac_priv *priv);
+int arc_emac_probe(struct net_device *ndev, int interface);
+int arc_emac_remove(struct net_device *ndev);
 
 #endif /* ARC_EMAC_H */
diff --git a/drivers/net/ethernet/arc/emac_arc.c b/drivers/net/ethernet/arc/emac_arc.c
new file mode 100644
index 0000000..f9cb99b
--- /dev/null
+++ b/drivers/net/ethernet/arc/emac_arc.c
@@ -0,0 +1,95 @@
+/**
+ * emac_arc.c - ARC EMAC specific glue layer
+ *
+ * Copyright (C) 2014 Romain Perier
+ *
+ * Romain Perier  <romain.perier@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/platform_device.h>
+
+#include "emac.h"
+
+#define DRV_NAME    "emac_arc"
+#define DRV_VERSION "1.0"
+
+static int emac_arc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct net_device *ndev;
+	struct arc_emac_priv *priv;
+	int interface, err;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
+	if (!ndev)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, ndev);
+	SET_NETDEV_DEV(ndev, dev);
+
+	priv = netdev_priv(ndev);
+	priv->drv_name = DRV_NAME;
+	priv->drv_version = DRV_VERSION;
+
+	interface = of_get_phy_mode(dev->of_node);
+	if (interface < 0)
+		interface = PHY_INTERFACE_MODE_MII;
+
+	priv->clk = devm_clk_get(dev, "hclk");
+	if (IS_ERR(priv->clk)) {
+		dev_err(dev, "failed to retrieve host clock from device tree\n");
+		err = -EINVAL;
+		goto out_netdev;
+	}
+
+	err = arc_emac_probe(ndev, interface);
+out_netdev:
+	if (err)
+		free_netdev(ndev);
+	return err;
+}
+
+static int emac_arc_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	int err;
+
+	err = arc_emac_remove(ndev);
+	free_netdev(ndev);
+	return err;
+}
+
+static const struct of_device_id emac_arc_dt_ids[] = {
+	{ .compatible = "snps,arc-emac" },
+	{ /* Sentinel */ }
+};
+
+static struct platform_driver emac_arc_driver = {
+	.probe = emac_arc_probe,
+	.remove = emac_arc_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table  = emac_arc_dt_ids,
+	},
+};
+
+module_platform_driver(emac_arc_driver);
+
+MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
+MODULE_DESCRIPTION("ARC EMAC platform driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index bbc3157..b35c69e 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -26,8 +26,6 @@
 
 #include "emac.h"
 
-#define DRV_NAME	"arc_emac"
-#define DRV_VERSION	"1.0"
 
 /**
  * arc_emac_adjust_link - Adjust the PHY link duplex.
@@ -120,8 +118,10 @@ static int arc_emac_set_settings(struct net_device *ndev,
 static void arc_emac_get_drvinfo(struct net_device *ndev,
 				 struct ethtool_drvinfo *info)
 {
-	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
-	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	struct arc_emac_priv *priv = netdev_priv(ndev);
+
+	strlcpy(info->driver, priv->drv_name, sizeof(info->driver));
+	strlcpy(info->version, priv->drv_version, sizeof(info->version));
 }
 
 static const struct ethtool_ops arc_emac_ethtool_ops = {
@@ -671,19 +671,16 @@ static const struct net_device_ops arc_emac_netdev_ops = {
 #endif
 };
 
-static int arc_emac_probe(struct platform_device *pdev)
+int arc_emac_probe(struct net_device *ndev, int interface)
 {
-	struct device *dev = &pdev->dev;
+	struct device *dev = ndev->dev.parent;
 	struct resource res_regs;
 	struct device_node *phy_node;
 	struct arc_emac_priv *priv;
-	struct net_device *ndev;
 	const char *mac_addr;
 	unsigned int id, clock_frequency, irq;
 	int err;
 
-	if (!dev->of_node)
-		return -ENODEV;
 
 	/* Get PHY from device tree */
 	phy_node = of_parse_phandle(dev->of_node, "phy", 0);
@@ -706,12 +703,6 @@ static int arc_emac_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
-	if (!ndev)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, ndev);
-	SET_NETDEV_DEV(ndev, dev);
 
 	ndev->netdev_ops = &arc_emac_netdev_ops;
 	ndev->ethtool_ops = &arc_emac_ethtool_ops;
@@ -724,28 +715,25 @@ static int arc_emac_probe(struct platform_device *pdev)
 
 	priv->regs = devm_ioremap_resource(dev, &res_regs);
 	if (IS_ERR(priv->regs)) {
-		err = PTR_ERR(priv->regs);
-		goto out_netdev;
+		return PTR_ERR(priv->regs);
 	}
 	dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
 
-	priv->clk = of_clk_get(dev->of_node, 0);
-	if (IS_ERR(priv->clk)) {
-		/* Get CPU clock frequency from device tree */
-		if (of_property_read_u32(dev->of_node, "clock-frequency",
-					&clock_frequency)) {
-			dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
-			err = -EINVAL;
-			goto out_netdev;
-		}
-	} else {
+	if (priv->clk) {
 		err = clk_prepare_enable(priv->clk);
 		if (err) {
 			dev_err(dev, "failed to enable clock\n");
-			goto out_clkget;
+			return err;
 		}
 
 		clock_frequency = clk_get_rate(priv->clk);
+	} else {
+		/* Get CPU clock frequency from device tree */
+		if (of_property_read_u32(dev->of_node, "clock-frequency",
+					 &clock_frequency)) {
+			dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
+			return -EINVAL;
+		}
 	}
 
 	id = arc_reg_get(priv, R_ID);
@@ -806,7 +794,7 @@ static int arc_emac_probe(struct platform_device *pdev)
 	}
 
 	priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
-				       PHY_INTERFACE_MODE_MII);
+				       interface);
 	if (!priv->phy_dev) {
 		dev_err(dev, "of_phy_connect() failed\n");
 		err = -ENODEV;
@@ -833,20 +821,15 @@ out_netif_api:
 out_mdio:
 	arc_mdio_remove(priv);
 out_clken:
-	if (!IS_ERR(priv->clk))
+	if (priv->clk)
 		clk_disable_unprepare(priv->clk);
-out_clkget:
-	if (!IS_ERR(priv->clk))
-		clk_put(priv->clk);
-out_netdev:
-	free_netdev(ndev);
 	return err;
 }
+EXPORT_SYMBOL_GPL(arc_emac_probe);
 
-static int arc_emac_remove(struct platform_device *pdev)
+int arc_emac_remove(struct net_device *ndev)
 {
-	struct device *dev = &pdev->dev;
-	struct net_device *ndev = dev_get_drvdata(dev);
+	struct device *dev = ndev->dev.parent;
 	struct arc_emac_priv *priv = netdev_priv(ndev);
 
 	phy_disconnect(priv->phy_dev);
@@ -857,31 +840,12 @@ static int arc_emac_remove(struct platform_device *pdev)
 
 	if (!IS_ERR(priv->clk)) {
 		clk_disable_unprepare(priv->clk);
-		clk_put(priv->clk);
 	}
 
-	free_netdev(ndev);
 
 	return 0;
 }
-
-static const struct of_device_id arc_emac_dt_ids[] = {
-	{ .compatible = "snps,arc-emac" },
-	{ /* Sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, arc_emac_dt_ids);
-
-static struct platform_driver arc_emac_driver = {
-	.probe = arc_emac_probe,
-	.remove = arc_emac_remove,
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-		.of_match_table  = arc_emac_dt_ids,
-		},
-};
-
-module_platform_driver(arc_emac_driver);
+EXPORT_SYMBOL_GPL(arc_emac_remove);
 
 MODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>");
 MODULE_DESCRIPTION("ARC EMAC driver");
-- 
1.9.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox