Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v6 08/10] IPC: message queue receive cleanup
From: Ben Hutchings @ 2012-10-15 20:03 UTC (permalink / raw)
  To: Stanislav Kinsbursky
  Cc: akpm, catalin.marinas, will.deacon, dhowells, manfred, hughd,
	jmorris, mtk.manpages, kosaki.motohiro, paulmck, sds, devel,
	a.p.zijlstra, cmetcalf, linux-driver, ron.mercer, viro, eparis,
	tglx, jitendra.kalsaria, netdev, linux-kernel,
	linux-security-module, ebiederm, casey
In-Reply-To: <20121015160017.28348.44238.stgit@localhost.localdomain>

On Mon, 2012-10-15 at 20:00 +0400, Stanislav Kinsbursky wrote:
> This patch moves all message related manipulation into one function msg_fill().
> Actually, two functions because of the compat one.
> 
> Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
> ---
>  include/linux/msg.h |    5 +++--
>  ipc/compat.c        |   36 +++++++++++++++++++-----------------
>  ipc/msg.c           |   44 +++++++++++++++++++++++---------------------
>  3 files changed, 45 insertions(+), 40 deletions(-)
> 
> diff --git a/include/linux/msg.h b/include/linux/msg.h
> index 7a4b9e9..f38edba 100644
> --- a/include/linux/msg.h
> +++ b/include/linux/msg.h
> @@ -34,7 +34,8 @@ struct msg_queue {
>  /* Helper routines for sys_msgsnd and sys_msgrcv */
>  extern long do_msgsnd(int msqid, long mtype, void __user *mtext,
>  			size_t msgsz, int msgflg);
> -extern long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
> -			size_t msgsz, long msgtyp, int msgflg);
> +extern long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
> +		      int msgflg,
> +		      long (*msg_fill)(void __user *, struct msg_msg *, size_t ));
>  
>  #endif /* _LINUX_MSG_H */
> diff --git a/ipc/compat.c b/ipc/compat.c
> index 84d8efd..b879d50 100644
> --- a/ipc/compat.c
> +++ b/ipc/compat.c
[...]
> @@ -394,7 +395,8 @@ long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
>  {
>  	long err, mtype;
>  
> -	err =  do_msgrcv(msqid, &mtype, msgp->mtext, (ssize_t)msgsz, msgtyp, msgflg);
> +	err =  do_msgrcv(msqid, &mtype, msgp->mtext, (ssize_t)msgsz, msgtyp,
> +			 msgflg, compat_do_msg_fill);
>  	if (err < 0)
>  		goto out;
>  
[...]

That isn't even the right number of arguments now...

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply

* Re: [RFC PATCH net-next v2 0/1] Add support of ECMPv6
From: Vincent Bernat @ 2012-10-15 19:54 UTC (permalink / raw)
  To: nicolas.dichtel; +Cc: yoshfuji, netdev, davem
In-Reply-To: <c6a5aae8c773f78aaa1c59cfb68a3d52@luffy.cx>

 ❦ 15 octobre 2012 14:36 CEST, Vincent Bernat <bernat@luffy.cx> :

> The problem is the same with BIRD. The difference with IPv4 makes it
> difficult to factor the code between IPv4 and IPv6. What do you think?

I am in the process of creating the appropriate patches for Quagga and
it is less difficult that I thought. It is possible to plug the
difference between IPv4 and IPv6 for multipath routes right into the
difference between IPv4 single hop and IPv4 multi hop routes that are
also handled differently.

I am still thinking that the approach is confusing for the userland but
it is not really cumbersome from the implementor point of view and it
has also some advantages.
-- 
Make it clear before you make it faster.
            - The Elements of Programming Style (Kernighan & Plauger)

^ permalink raw reply

* [PATCH V2 7/7] cpsw: use the time stamping capabilities of the cpts
From: Richard Cochran @ 2012-10-15 19:48 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, David Miller, Cyril Chemparathy, Mugunthan V N,
	Sriramakrishnan A G
In-Reply-To: <cover.1350329726.git.richardcochran@gmail.com>

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
 drivers/net/ethernet/ti/cpsw.c |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index aeaa3bb..06a134f 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -35,6 +35,7 @@
 #include <linux/platform_data/cpsw.h>
 
 #include "cpsw_ale.h"
+#include "cpts.h"
 #include "davinci_cpdma.h"
 
 #define CPSW_DEBUG	(NETIF_MSG_HW		| NETIF_MSG_WOL		| \
@@ -236,6 +237,7 @@ struct cpsw_priv {
 	/* snapshot of IRQ numbers */
 	u32 irqs_table[4];
 	u32 num_irqs;
+	struct cpts cpts;
 };
 
 #define napi_to_priv(napi)	container_of(napi, struct cpsw_priv, napi)
@@ -272,6 +274,7 @@ void cpsw_tx_handler(void *token, int len, int status)
 
 	if (unlikely(netif_queue_stopped(ndev)))
 		netif_start_queue(ndev);
+	cpts_tx_timestamp(&priv->cpts, skb);
 	priv->stats.tx_packets++;
 	priv->stats.tx_bytes += len;
 	dev_kfree_skb_any(skb);
@@ -292,6 +295,7 @@ void cpsw_rx_handler(void *token, int len, int status)
 	}
 	if (likely(status >= 0)) {
 		skb_put(skb, len);
+		cpts_rx_timestamp(&priv->cpts, skb);
 		skb->protocol = eth_type_trans(skb, ndev);
 		netif_receive_skb(skb);
 		priv->stats.rx_bytes += len;
@@ -610,6 +614,11 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
 		return NETDEV_TX_OK;
 	}
 
+	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && priv->cpts.tx_enable)
+		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
+	skb_tx_timestamp(skb);
+
 	ret = cpdma_chan_submit(priv->txch, skb, skb->data,
 				skb->len, GFP_KERNEL);
 	if (unlikely(ret != 0)) {
@@ -647,6 +656,21 @@ static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags)
 		dev_err(&ndev->dev, "multicast traffic cannot be filtered!\n");
 }
 
+static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+	struct cpsw_priv *priv = netdev_priv(dev);
+
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	switch (cmd) {
+	case SIOCSHWTSTAMP:
+		return cpts_hwtstamp_ioctl(&priv->cpts, req);
+	}
+
+	return -ENOTSUPP;
+}
+
 static void cpsw_ndo_tx_timeout(struct net_device *ndev)
 {
 	struct cpsw_priv *priv = netdev_priv(ndev);
@@ -687,6 +711,7 @@ static const struct net_device_ops cpsw_netdev_ops = {
 	.ndo_stop		= cpsw_ndo_stop,
 	.ndo_start_xmit		= cpsw_ndo_start_xmit,
 	.ndo_change_rx_flags	= cpsw_ndo_change_rx_flags,
+	.ndo_do_ioctl		= cpsw_ndo_ioctl,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_change_mtu		= eth_change_mtu,
 	.ndo_tx_timeout		= cpsw_ndo_tx_timeout,
@@ -988,6 +1013,8 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
 	priv->regs = regs;
 	priv->host_port = data->host_port_num;
 	priv->host_port_regs = regs + data->host_port_reg_ofs;
+	priv->cpts.reg = regs + data->cpts_reg_ofs;
+	priv->cpts.tsp = regs + priv->data.slave_data[0].slave_reg_ofs;
 
 	priv->cpsw_ss_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	if (!priv->cpsw_ss_res) {
@@ -1109,6 +1136,11 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
 		goto clean_irq_ret;
 	}
 
+	if (cpts_register(&pdev->dev, &priv->cpts))
+		dev_err(priv->dev, "error registering cpts device\n");
+
+	__raw_writel(ETH_P_1588, &priv->regs->ts_ltype);
+
 	cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n",
 		  priv->cpsw_res->start, ndev->irq);
 
@@ -1148,6 +1180,7 @@ static int __devexit cpsw_remove(struct platform_device *pdev)
 	pr_info("removing device");
 	platform_set_drvdata(pdev, NULL);
 
+	cpts_unregister(&priv->cpts);
 	free_irq(ndev->irq, priv);
 	cpsw_ale_destroy(priv->ale);
 	cpdma_chan_destroy(priv->txch);
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH V2 6/7] cpsw: add a DT field for the cpts offset
From: Richard Cochran @ 2012-10-15 19:48 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, David Miller, Cyril Chemparathy, Mugunthan V N,
	Sriramakrishnan A G
In-Reply-To: <cover.1350329726.git.richardcochran@gmail.com>

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
 Documentation/devicetree/bindings/net/cpsw.txt |    3 +++
 arch/arm/boot/dts/am33xx.dtsi                  |    1 +
 drivers/net/ethernet/ti/cpsw.c                 |    7 +++++++
 include/linux/platform_data/cpsw.h             |    1 +
 4 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 3af47b7..dba014f 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -16,6 +16,7 @@ Required properties:
 - ale_entries		: Specifies No of entries ALE can hold
 - host_port_reg_ofs	: Specifies host port register offset
 - hw_stats_reg_ofs	: Specifies hardware statistics register offset
+- cpts_reg_ofs		: Specifies the offset of the CPTS registers
 - bd_ram_ofs		: Specifies internal desciptor RAM offset
 - bd_ram_size		: Specifies internal descriptor RAM size
 - rx_descs		: Specifies number of Rx descriptors
@@ -52,6 +53,7 @@ Examples:
 		ale_entries = <1024>;
 		host_port_reg_ofs = <0x108>;
 		hw_stats_reg_ofs = <0x900>;
+		cpts_reg_ofs = <0xc00>;
 		bd_ram_ofs = <0x2000>;
 		bd_ram_size = <0x2000>;
 		no_bd_ram = <0>;
@@ -86,6 +88,7 @@ Examples:
 		ale_entries = <1024>;
 		host_port_reg_ofs = <0x108>;
 		hw_stats_reg_ofs = <0x900>;
+		cpts_reg_ofs = <0xc00>;
 		bd_ram_ofs = <0x2000>;
 		bd_ram_size = <0x2000>;
 		no_bd_ram = <0>;
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index cd9b3b4..c981753 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -222,6 +222,7 @@
 			ale_entries = <1024>;
 			host_port_reg_ofs = <0x108>;
 			hw_stats_reg_ofs = <0x900>;
+			cpts_reg_ofs = <0xc00>;
 			bd_ram_ofs = <0x2000>;
 			bd_ram_size = <0x2000>;
 			no_bd_ram = <0>;
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index e29bb8f..aeaa3bb 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -817,6 +817,13 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 	}
 	data->hw_stats_reg_ofs = prop;
 
+	if (of_property_read_u32(node, "cpts_reg_ofs", &prop)) {
+		pr_err("Missing cpts_reg_ofs property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	data->cpts_reg_ofs = prop;
+
 	if (of_property_read_u32(node, "bd_ram_ofs", &prop)) {
 		pr_err("Missing bd_ram_ofs property in the DT.\n");
 		ret = -EINVAL;
diff --git a/include/linux/platform_data/cpsw.h b/include/linux/platform_data/cpsw.h
index c4e23d0..a052b1d 100644
--- a/include/linux/platform_data/cpsw.h
+++ b/include/linux/platform_data/cpsw.h
@@ -41,6 +41,7 @@ struct cpsw_platform_data {
 	u32     host_port_num; /* The port number for the host port */
 
 	u32	hw_stats_reg_ofs;  /* cpsw hardware statistics counters */
+	u32	cpts_reg_ofs;      /* cpts registers */
 
 	u32	bd_ram_ofs;   /* embedded buffer descriptor RAM offset*/
 	u32	bd_ram_size;  /*buffer descriptor ram size */
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH V2 5/7] cpts: introduce time stamping code and a PTP hardware clock.
From: Richard Cochran @ 2012-10-15 19:48 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, David Miller, Cyril Chemparathy, Mugunthan V N,
	Sriramakrishnan A G
In-Reply-To: <cover.1350329726.git.richardcochran@gmail.com>

This patch adds a driver for the CPTS that offers time
stamping and a PTP hardware clock. Even though the
hardware does not support frequency adjustment, still the
unit can be useful for 802.1AS for example.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
 drivers/net/ethernet/ti/Kconfig  |    8 +
 drivers/net/ethernet/ti/Makefile |    2 +-
 drivers/net/ethernet/ti/cpts.c   |  468 ++++++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/ti/cpts.h   |  148 ++++++++++++
 4 files changed, 625 insertions(+), 1 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/cpts.c
 create mode 100644 drivers/net/ethernet/ti/cpts.h

diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index b26cbda..cbc3905 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -60,6 +60,14 @@ config TI_CPSW
 	  To compile this driver as a module, choose M here: the module
 	  will be called cpsw.
 
+config TI_CPTS
+	boolean "TI Common Platform Time Sync (CPTS) Support"
+	depends on TI_CPSW && PTP_1588_CLOCK && !(TI_CPSW=y && PTP_1588_CLOCK=m)
+	---help---
+	  This driver supports the Common Platform Time Sync unit of
+	  the CPSW Ethernet Switch. The unit can time stamp PTP UDP/IPv4
+	  and Layer 2 packets, and the driver offers a PTP Hardware Clock.
+
 config TLAN
 	tristate "TI ThunderLAN support"
 	depends on (PCI || EISA)
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 91bd8bb..c65148e 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -8,4 +8,4 @@ obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o
 obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o
 obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o
 obj-$(CONFIG_TI_CPSW) += ti_cpsw.o
-ti_cpsw-y := cpsw_ale.o cpsw.o
+ti_cpsw-y := cpsw_ale.o cpsw.o cpts.o
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
new file mode 100644
index 0000000..bdb20c4
--- /dev/null
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -0,0 +1,468 @@
+/*
+ * TI Common Platform Time Sync
+ *
+ * Copyright (C) 2012 Richard Cochran <richardcochran@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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/err.h>
+#include <linux/if.h>
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_classify.h>
+#include <linux/time.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+
+#include <plat/clock.h>
+
+#include "cpts.h"
+
+#ifdef CONFIG_TI_CPTS
+
+static struct sock_filter ptp_filter[] = {
+	PTP_FILTER
+};
+
+#define cpts_read32(c, r)	__raw_readl(&c->reg->r)
+#define cpts_write32(c, v, r)	__raw_writel(v, &c->reg->r)
+#define port_read32(c, r)	__raw_readl(&c->tsp->r)
+#define port_write32(c, v, r)	__raw_writel(v, &c->tsp->r)
+
+static int event_expired(struct cpts_event *event)
+{
+	return time_after(jiffies, event->tmo);
+}
+
+static int event_type(struct cpts_event *event)
+{
+	return (event->high >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK;
+}
+
+static int cpts_fifo_pop(struct cpts *cpts, u32 *high, u32 *low)
+{
+	u32 r = cpts_read32(cpts, intstat_raw);
+
+	if (r & TS_PEND_RAW) {
+		*high = cpts_read32(cpts, event_high);
+		*low  = cpts_read32(cpts, event_low);
+		cpts_write32(cpts, EVENT_POP, event_pop);
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * Returns zero if matching event type was found.
+ */
+static int cpts_fifo_read(struct cpts *cpts, int match)
+{
+	int i, type = -1;
+	u32 hi, lo;
+	struct cpts_event *event;
+
+	for (i = 0; i < CPTS_FIFO_DEPTH; i++) {
+		if (cpts_fifo_pop(cpts, &hi, &lo))
+			break;
+		if (list_empty(&cpts->pool)) {
+			pr_err("cpts: event pool is empty\n");
+			return -1;
+		}
+		event = list_first_entry(&cpts->pool, struct cpts_event, list);
+		event->tmo = jiffies + 2;
+		event->high = hi;
+		event->low = lo;
+		type = event_type(event);
+		switch (type) {
+		case CPTS_EV_PUSH:
+		case CPTS_EV_RX:
+		case CPTS_EV_TX:
+			list_del_init(&event->list);
+			list_add_tail(&event->list, &cpts->events);
+			break;
+		case CPTS_EV_ROLL:
+		case CPTS_EV_HALF:
+		case CPTS_EV_HW:
+			break;
+		default:
+			pr_err("cpts: unkown event type\n");
+			break;
+		}
+		if (type == match)
+			break;
+	}
+	return type == match ? 0 : -1;
+}
+
+static cycle_t cpts_systim_read(const struct cyclecounter *cc)
+{
+	u64 val = 0;
+	struct cpts_event *event;
+	struct list_head *this, *next;
+	struct cpts *cpts = container_of(cc, struct cpts, cc);
+
+	cpts_write32(cpts, TS_PUSH, ts_push);
+	if (cpts_fifo_read(cpts, CPTS_EV_PUSH))
+		pr_err("cpts: unable to obtain a time stamp\n");
+
+	list_for_each_safe(this, next, &cpts->events) {
+		event = list_entry(this, struct cpts_event, list);
+		if (event_type(event) == CPTS_EV_PUSH) {
+			list_del_init(&event->list);
+			list_add(&event->list, &cpts->pool);
+			val = event->low;
+			break;
+		}
+	}
+
+	return val;
+}
+
+/* PTP clock operations */
+
+static int cpts_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+	return -EOPNOTSUPP;
+}
+
+static int cpts_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+	s64 now;
+	unsigned long flags;
+	struct cpts *cpts = container_of(ptp, struct cpts, info);
+
+	spin_lock_irqsave(&cpts->lock, flags);
+	now = timecounter_read(&cpts->tc);
+	now += delta;
+	timecounter_init(&cpts->tc, &cpts->cc, now);
+	spin_unlock_irqrestore(&cpts->lock, flags);
+
+	return 0;
+}
+
+static int cpts_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+	u64 ns;
+	u32 remainder;
+	unsigned long flags;
+	struct cpts *cpts = container_of(ptp, struct cpts, info);
+
+	spin_lock_irqsave(&cpts->lock, flags);
+	ns = timecounter_read(&cpts->tc);
+	spin_unlock_irqrestore(&cpts->lock, flags);
+
+	ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+	ts->tv_nsec = remainder;
+
+	return 0;
+}
+
+static int cpts_ptp_settime(struct ptp_clock_info *ptp,
+			    const struct timespec *ts)
+{
+	u64 ns;
+	unsigned long flags;
+	struct cpts *cpts = container_of(ptp, struct cpts, info);
+
+	ns = ts->tv_sec * 1000000000ULL;
+	ns += ts->tv_nsec;
+
+	spin_lock_irqsave(&cpts->lock, flags);
+	timecounter_init(&cpts->tc, &cpts->cc, ns);
+	spin_unlock_irqrestore(&cpts->lock, flags);
+
+	return 0;
+}
+
+static int cpts_ptp_enable(struct ptp_clock_info *ptp,
+			   struct ptp_clock_request *rq, int on)
+{
+	return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info cpts_info = {
+	.owner		= THIS_MODULE,
+	.name		= "CTPS timer",
+	.max_adj	= 0,
+	.n_ext_ts	= 0,
+	.pps		= 0,
+	.adjfreq	= cpts_ptp_adjfreq,
+	.adjtime	= cpts_ptp_adjtime,
+	.gettime	= cpts_ptp_gettime,
+	.settime	= cpts_ptp_settime,
+	.enable		= cpts_ptp_enable,
+};
+
+static void cpts_overflow_check(struct work_struct *work)
+{
+	struct timespec ts;
+	struct cpts *cpts = container_of(work, struct cpts, overflow_work.work);
+
+	cpts_write32(cpts, CPTS_EN, control);
+	cpts_write32(cpts, TS_PEND_EN, int_enable);
+	cpts_ptp_gettime(&cpts->info, &ts);
+	pr_debug("cpts overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec);
+	schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
+}
+
+#define CPTS_REF_CLOCK_NAME "cpsw_cpts_rft_clk"
+
+static void cpts_clk_init(struct cpts *cpts)
+{
+	cpts->refclk = clk_get(NULL, CPTS_REF_CLOCK_NAME);
+	if (IS_ERR(cpts->refclk)) {
+		pr_err("Failed to clk_get %s\n", CPTS_REF_CLOCK_NAME);
+		cpts->refclk = NULL;
+		return;
+	}
+	clk_enable(cpts->refclk);
+	cpts->freq = cpts->refclk->recalc(cpts->refclk);
+}
+
+static void cpts_clk_release(struct cpts *cpts)
+{
+	clk_disable(cpts->refclk);
+	clk_put(cpts->refclk);
+}
+
+static int cpts_match(struct sk_buff *skb, unsigned int ptp_class,
+		      u16 ts_seqid, u8 ts_msgtype)
+{
+	u16 *seqid;
+	unsigned int offset;
+	u8 *msgtype, *data = skb->data;
+
+	switch (ptp_class) {
+	case PTP_CLASS_V1_IPV4:
+	case PTP_CLASS_V2_IPV4:
+		offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+		break;
+	case PTP_CLASS_V1_IPV6:
+	case PTP_CLASS_V2_IPV6:
+		offset = OFF_PTP6;
+		break;
+	case PTP_CLASS_V2_L2:
+		offset = ETH_HLEN;
+		break;
+	case PTP_CLASS_V2_VLAN:
+		offset = ETH_HLEN + VLAN_HLEN;
+		break;
+	default:
+		return 0;
+	}
+
+	if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid))
+		return 0;
+
+	if (unlikely(ptp_class & PTP_CLASS_V1))
+		msgtype = data + offset + OFF_PTP_CONTROL;
+	else
+		msgtype = data + offset;
+
+	seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+
+	return (ts_msgtype == (*msgtype & 0xf) && ts_seqid == ntohs(*seqid));
+}
+
+static u64 cpts_find_ts(struct cpts *cpts, struct sk_buff *skb, int ev_type)
+{
+	u64 ns = 0;
+	struct cpts_event *event;
+	struct list_head *this, *next;
+	unsigned int class = sk_run_filter(skb, ptp_filter);
+	unsigned long flags;
+	u16 seqid;
+	u8 mtype;
+
+	if (class == PTP_CLASS_NONE)
+		return 0;
+
+	spin_lock_irqsave(&cpts->lock, flags);
+	cpts_fifo_read(cpts, CPTS_EV_PUSH);
+	list_for_each_safe(this, next, &cpts->events) {
+		event = list_entry(this, struct cpts_event, list);
+		if (event_expired(event)) {
+			list_del_init(&event->list);
+			list_add(&event->list, &cpts->pool);
+			continue;
+		}
+		mtype = (event->high >> MESSAGE_TYPE_SHIFT) & MESSAGE_TYPE_MASK;
+		seqid = (event->high >> SEQUENCE_ID_SHIFT) & SEQUENCE_ID_MASK;
+		if (ev_type == event_type(event) &&
+		    cpts_match(skb, class, seqid, mtype)) {
+			ns = timecounter_cyc2time(&cpts->tc, event->low);
+			list_del_init(&event->list);
+			list_add(&event->list, &cpts->pool);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&cpts->lock, flags);
+
+	return ns;
+}
+
+void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
+{
+	u64 ns;
+	struct skb_shared_hwtstamps *ssh;
+
+	if (!cpts->rx_enable)
+		return;
+	ns = cpts_find_ts(cpts, skb, CPTS_EV_RX);
+	if (!ns)
+		return;
+	ssh = skb_hwtstamps(skb);
+	memset(ssh, 0, sizeof(*ssh));
+	ssh->hwtstamp = ns_to_ktime(ns);
+}
+
+void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
+{
+	u64 ns;
+	struct skb_shared_hwtstamps ssh;
+
+	if (!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
+		return;
+	ns = cpts_find_ts(cpts, skb, CPTS_EV_TX);
+	if (!ns)
+		return;
+	memset(&ssh, 0, sizeof(ssh));
+	ssh.hwtstamp = ns_to_ktime(ns);
+	skb_tstamp_tx(skb, &ssh);
+}
+
+#endif /*CONFIG_TI_CPTS*/
+
+int cpts_hwtstamp_ioctl(struct cpts *cpts, struct ifreq *ifr)
+{
+#ifdef CONFIG_TI_CPTS
+	struct hwtstamp_config cfg;
+	u32 ctrl, mtype;
+
+	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+		return -EFAULT;
+
+	/* reserved for future extensions */
+	if (cfg.flags)
+		return -EINVAL;
+
+	ctrl = port_read32(cpts, control);
+	ctrl &= ~CTRL_ALL_TS_MASK;
+
+	switch (cfg.tx_type) {
+	case HWTSTAMP_TX_OFF:
+		cpts->tx_enable = 0;
+		break;
+	case HWTSTAMP_TX_ON:
+		cpts->tx_enable = 1;
+		ctrl |= CTRL_TX_TS_BITS;
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	switch (cfg.rx_filter) {
+	case HWTSTAMP_FILTER_NONE:
+		cpts->rx_enable = 0;
+		break;
+	case HWTSTAMP_FILTER_ALL:
+	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+		return -ERANGE;
+	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+		cpts->rx_enable = 1;
+		cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+		ctrl |= CTRL_RX_TS_BITS;
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS;
+	port_write32(cpts, mtype, ts_seq_mtype);
+	port_write32(cpts, ctrl, control);
+
+	return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+#else
+	return -EOPNOTSUPP;
+#endif
+}
+
+int cpts_register(struct device *dev, struct cpts *cpts)
+{
+#ifdef CONFIG_TI_CPTS
+	int err, i;
+	unsigned long flags;
+
+	if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
+		pr_err("cpts: bad ptp filter\n");
+		return -EINVAL;
+	}
+	cpts->info = cpts_info;
+	cpts->clock = ptp_clock_register(&cpts->info, dev);
+	if (IS_ERR(cpts->clock)) {
+		err = PTR_ERR(cpts->clock);
+		cpts->clock = NULL;
+		return err;
+	}
+	spin_lock_init(&cpts->lock);
+
+	cpts->cc.read = cpts_systim_read;
+	cpts->cc.mask = CLOCKSOURCE_MASK(32);
+	cpts->cc.mult = 4;
+	cpts->cc.shift = 0;
+
+	INIT_LIST_HEAD(&cpts->events);
+	INIT_LIST_HEAD(&cpts->pool);
+	for (i = 0; i < CPTS_MAX_EVENTS; i++)
+		list_add(&cpts->pool_data[i].list, &cpts->pool);
+
+	cpts_clk_init(cpts);
+	cpts_write32(cpts, CPTS_EN, control);
+	cpts_write32(cpts, TS_PEND_EN, int_enable);
+
+	spin_lock_irqsave(&cpts->lock, flags);
+	timecounter_init(&cpts->tc, &cpts->cc, ktime_to_ns(ktime_get_real()));
+	spin_unlock_irqrestore(&cpts->lock, flags);
+
+	INIT_DELAYED_WORK(&cpts->overflow_work, cpts_overflow_check);
+	schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
+
+	cpts->phc_index = ptp_clock_index(cpts->clock);
+#endif
+	return 0;
+}
+
+void cpts_unregister(struct cpts *cpts)
+{
+#ifdef CONFIG_TI_CPTS
+	if (cpts->clock) {
+		ptp_clock_unregister(cpts->clock);
+		cancel_delayed_work_sync(&cpts->overflow_work);
+	}
+	if (cpts->refclk)
+		cpts_clk_release(cpts);
+#endif
+}
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
new file mode 100644
index 0000000..86e45ff
--- /dev/null
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -0,0 +1,148 @@
+/*
+ * TI Common Platform Time Sync
+ *
+ * Copyright (C) 2012 Richard Cochran <richardcochran@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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef _TI_CPTS_H_
+#define _TI_CPTS_H_
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clocksource.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/skbuff.h>
+
+#include "cpsw_reg.h"
+
+struct cpsw_cpts {
+	u32 idver;                /* Identification and version */
+	u32 control;              /* Time sync control */
+	u32 res1;
+	u32 ts_push;              /* Time stamp event push */
+	u32 ts_load_val;          /* Time stamp load value */
+	u32 ts_load_en;           /* Time stamp load enable */
+	u32 res2[2];
+	u32 intstat_raw;          /* Time sync interrupt status raw */
+	u32 intstat_masked;       /* Time sync interrupt status masked */
+	u32 int_enable;           /* Time sync interrupt enable */
+	u32 res3;
+	u32 event_pop;            /* Event interrupt pop */
+	u32 event_low;            /* 32 Bit Event Time Stamp */
+	u32 event_high;           /* Event Type Fields */
+};
+
+/* Bit definitions for the IDVER register */
+#define TX_IDENT_SHIFT       (16)    /* TX Identification Value */
+#define TX_IDENT_MASK        (0xffff)
+#define RTL_VER_SHIFT        (11)    /* RTL Version Value */
+#define RTL_VER_MASK         (0x1f)
+#define MAJOR_VER_SHIFT      (8)     /* Major Version Value */
+#define MAJOR_VER_MASK       (0x7)
+#define MINOR_VER_SHIFT      (0)     /* Minor Version Value */
+#define MINOR_VER_MASK       (0xff)
+
+/* Bit definitions for the CONTROL register */
+#define HW4_TS_PUSH_EN       (1<<11) /* Hardware push 4 enable */
+#define HW3_TS_PUSH_EN       (1<<10) /* Hardware push 3 enable */
+#define HW2_TS_PUSH_EN       (1<<9)  /* Hardware push 2 enable */
+#define HW1_TS_PUSH_EN       (1<<8)  /* Hardware push 1 enable */
+#define INT_TEST             (1<<1)  /* Interrupt Test */
+#define CPTS_EN              (1<<0)  /* Time Sync Enable */
+
+/*
+ * Definitions for the single bit resisters:
+ * TS_PUSH TS_LOAD_EN  INTSTAT_RAW INTSTAT_MASKED INT_ENABLE EVENT_POP
+ */
+#define TS_PUSH             (1<<0)  /* Time stamp event push */
+#define TS_LOAD_EN          (1<<0)  /* Time Stamp Load */
+#define TS_PEND_RAW         (1<<0)  /* int read (before enable) */
+#define TS_PEND             (1<<0)  /* masked interrupt read (after enable) */
+#define TS_PEND_EN          (1<<0)  /* masked interrupt enable */
+#define EVENT_POP           (1<<0)  /* writing discards one event */
+
+/* Bit definitions for the EVENT_HIGH register */
+#define PORT_NUMBER_SHIFT    (24)    /* Indicates Ethernet port or HW pin */
+#define PORT_NUMBER_MASK     (0x1f)
+#define EVENT_TYPE_SHIFT     (20)    /* Time sync event type */
+#define EVENT_TYPE_MASK      (0xf)
+#define MESSAGE_TYPE_SHIFT   (16)    /* PTP message type */
+#define MESSAGE_TYPE_MASK    (0xf)
+#define SEQUENCE_ID_SHIFT    (0)     /* PTP message sequence ID */
+#define SEQUENCE_ID_MASK     (0xffff)
+
+enum {
+	CPTS_EV_PUSH, /* Time Stamp Push Event */
+	CPTS_EV_ROLL, /* Time Stamp Rollover Event */
+	CPTS_EV_HALF, /* Time Stamp Half Rollover Event */
+	CPTS_EV_HW,   /* Hardware Time Stamp Push Event */
+	CPTS_EV_RX,   /* Ethernet Receive Event */
+	CPTS_EV_TX,   /* Ethernet Transmit Event */
+};
+
+/* This covers any input clock up to about 500 MHz. */
+#define CPTS_OVERFLOW_PERIOD (HZ * 8)
+
+#define CPTS_FIFO_DEPTH 16
+#define CPTS_MAX_EVENTS 32
+
+struct cpts_event {
+	struct list_head list;
+	unsigned long tmo;
+	u32 high;
+	u32 low;
+};
+
+struct cpts {
+	struct cpsw_cpts __iomem *reg;
+	struct cpsw_port __iomem *tsp;
+	int tx_enable;
+#ifdef CONFIG_TI_CPTS
+	int rx_enable;
+	struct ptp_clock_info info;
+	struct ptp_clock *clock;
+	spinlock_t lock; /* protects time registers */
+	struct cyclecounter cc;
+	struct timecounter tc;
+	struct delayed_work overflow_work;
+	int phc_index;
+	struct clk *refclk;
+	unsigned long freq;
+	struct list_head events;
+	struct list_head pool;
+	struct cpts_event pool_data[CPTS_MAX_EVENTS];
+#endif
+};
+
+#ifdef CONFIG_TI_CPTS
+extern void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb);
+extern void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
+#else
+static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
+{
+}
+static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
+{
+}
+#endif
+
+extern int cpts_hwtstamp_ioctl(struct cpts *cpts, struct ifreq *ifr);
+extern int cpts_register(struct device *dev, struct cpts *cpts);
+extern void cpts_unregister(struct cpts *cpts);
+
+#endif
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH V2 4/7] cpsw: add a common header file for regsiter declarations
From: Richard Cochran @ 2012-10-15 19:48 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, David Miller, Cyril Chemparathy, Mugunthan V N,
	Sriramakrishnan A G
In-Reply-To: <cover.1350329726.git.richardcochran@gmail.com>

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
 drivers/net/ethernet/ti/cpsw_reg.h |   81 ++++++++++++++++++++++++++++++++++++
 1 files changed, 81 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/cpsw_reg.h

diff --git a/drivers/net/ethernet/ti/cpsw_reg.h b/drivers/net/ethernet/ti/cpsw_reg.h
new file mode 100644
index 0000000..88fb15f
--- /dev/null
+++ b/drivers/net/ethernet/ti/cpsw_reg.h
@@ -0,0 +1,81 @@
+/*
+ * Common CPSW register declarations
+ *
+ * Copyright (C) 2012 Richard Cochran <richardcochran@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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef _TI_CPSW_REG_H_
+#define _TI_CPSW_REG_H_
+
+struct cpsw_port {
+	u32 control;                /* Control Register */
+	u32 res1;
+	u32 max_blks;               /* Maximum FIFO Blocks */
+	u32 blk_cnt;                /* FIFO Block Usage Count (Read Only) */
+	u32 tx_in_ctl;              /* Transmit FIFO Control */
+	u32 port_vlan;              /* VLAN Register */
+	u32 tx_pri_map;             /* Tx Header Priority to Switch Pri Map */
+	u32 ts_seq_mtype;           /* Time Sync Seq ID Offset and Msg Type */
+	u32 sa_lo;                  /* CPGMAC_SL Source Address Low */
+	u32 sa_hi;                  /* CPGMAC_SL Source Address High */
+	u32 send_percent;           /* Transmit Queue Send Percentages */
+	u32 res2;
+	u32 rx_dscp_pri_map0;       /* Rx DSCP Priority to Rx Packet Mapping */
+	u32 rx_dscp_pri_map1;       /* Rx DSCP Priority to Rx Packet Mapping */
+	u32 rx_dscp_pri_map2;       /* Rx DSCP Priority to Rx Packet Mapping */
+	u32 rx_dscp_pri_map3;       /* Rx DSCP Priority to Rx Packet Mapping */
+	u32 rx_dscp_pri_map4;       /* Rx DSCP Priority to Rx Packet Mapping */
+	u32 rx_dscp_pri_map5;       /* Rx DSCP Priority to Rx Packet Mapping */
+	u32 rx_dscp_pri_map6;       /* Rx DSCP Priority to Rx Packet Mapping */
+	u32 rx_dscp_pri_map7;       /* Rx DSCP Priority to Rx Packet Mapping */
+};
+
+/* Bit definitions for the CONTROL register */
+#define PASS_PRI_TAGGED        (1<<24) /* Pass Priority Tagged */
+#define VLAN_LTYPE2_EN         (1<<21) /* VLAN LTYPE 2 enable */
+#define VLAN_LTYPE1_EN         (1<<20) /* VLAN LTYPE 1 enable */
+#define DSCP_PRI_EN            (1<<16) /* DSCP Priority Enable */
+#define TS_320                 (1<<14) /* Time Sync Dest Port 320 enable */
+#define TS_319                 (1<<13) /* Time Sync Dest Port 319 enable */
+#define TS_132                 (1<<12) /* Time Sync Dest IP Addr 132 enable */
+#define TS_131                 (1<<11) /* Time Sync Dest IP Addr 131 enable */
+#define TS_130                 (1<<10) /* Time Sync Dest IP Addr 130 enable */
+#define TS_129                 (1<<9)  /* Time Sync Dest IP Addr 129 enable */
+#define TS_BIT8                (1<<8)  /* ts_ttl_nonzero? */
+#define TS_ANNEX_D_EN          (1<<4)  /* Time Sync Annex D enable */
+#define TS_LTYPE2_EN           (1<<3)  /* Time Sync LTYPE 2 enable */
+#define TS_LTYPE1_EN           (1<<2)  /* Time Sync LTYPE 1 enable */
+#define TS_TX_EN               (1<<1)  /* Time Sync Transmit Enable */
+#define TS_RX_EN               (1<<0)  /* Time Sync Receive Enable */
+
+#define CTRL_TS_BITS \
+	(TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 | TS_BIT8 | \
+	 TS_ANNEX_D_EN | TS_LTYPE2_EN | TS_LTYPE1_EN)
+
+#define CTRL_ALL_TS_MASK (CTRL_TS_BITS | TS_TX_EN | TS_RX_EN)
+#define CTRL_TX_TS_BITS  (CTRL_TS_BITS | TS_TX_EN)
+#define CTRL_RX_TS_BITS  (CTRL_TS_BITS | TS_RX_EN)
+
+/* Bit definitions for the TS_SEQ_MTYPE register */
+#define TS_SEQ_ID_OFFSET_SHIFT (16)    /* Time Sync Sequence ID Offset */
+#define TS_SEQ_ID_OFFSET_MASK  (0x3f)
+#define TS_MSG_TYPE_EN_SHIFT   (0)     /* Time Sync Message Type Enable */
+#define TS_MSG_TYPE_EN_MASK    (0xffff)
+
+/* The PTP event messages - Sync, Delay_Req, Pdelay_Req, and Pdelay_Resp. */
+#define EVENT_MSG_BITS ((1<<0) | (1<<1) | (1<<2) | (1<<3))
+
+#endif
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH V2 3/7] cpsw: correct the CPSW_PORT register bank declaration
From: Richard Cochran @ 2012-10-15 19:48 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, David Miller, Cyril Chemparathy, Mugunthan V N,
	Sriramakrishnan A G
In-Reply-To: <cover.1350329726.git.richardcochran@gmail.com>

This commit corrects and expands the slave port register bank
according to TI's Technical Reference Manual.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
 Documentation/devicetree/bindings/net/cpsw.txt |    8 ++++----
 arch/arm/boot/dts/am33xx.dtsi                  |    4 ++--
 drivers/net/ethernet/ti/cpsw.c                 |   18 ++++++++++++++----
 3 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index dcaabe9..3af47b7 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -59,14 +59,14 @@ Examples:
 		mac_control = <0x20>;
 		slaves = <2>;
 		cpsw_emac0: slave@0 {
-			slave_reg_ofs = <0x208>;
+			slave_reg_ofs = <0x200>;
 			sliver_reg_ofs = <0xd80>;
 			phy_id = "davinci_mdio.16:00";
 			/* Filled in by U-Boot */
 			mac-address = [ 00 00 00 00 00 00 ];
 		};
 		cpsw_emac1: slave@1 {
-			slave_reg_ofs = <0x308>;
+			slave_reg_ofs = <0x300>;
 			sliver_reg_ofs = <0xdc0>;
 			phy_id = "davinci_mdio.16:01";
 			/* Filled in by U-Boot */
@@ -93,14 +93,14 @@ Examples:
 		mac_control = <0x20>;
 		slaves = <2>;
 		cpsw_emac0: slave@0 {
-			slave_reg_ofs = <0x208>;
+			slave_reg_ofs = <0x200>;
 			sliver_reg_ofs = <0xd80>;
 			phy_id = "davinci_mdio.16:00";
 			/* Filled in by U-Boot */
 			mac-address = [ 00 00 00 00 00 00 ];
 		};
 		cpsw_emac1: slave@1 {
-			slave_reg_ofs = <0x308>;
+			slave_reg_ofs = <0x300>;
 			sliver_reg_ofs = <0xdc0>;
 			phy_id = "davinci_mdio.16:01";
 			/* Filled in by U-Boot */
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index f6bea04..cd9b3b4 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -238,13 +238,13 @@
 			interrupts = <40 41 42 43>;
 			ranges;
 			cpsw_emac0: slave@0 {
-				slave_reg_ofs = <0x208>;
+				slave_reg_ofs = <0x200>;
 				sliver_reg_ofs = <0xd80>;
 				/* Filled in by U-Boot */
 				mac-address = [ 00 00 00 00 00 00 ];
 			};
 			cpsw_emac1: slave@1 {
-				slave_reg_ofs = <0x308>;
+				slave_reg_ofs = <0x300>;
 				sliver_reg_ofs = <0xdc0>;
 				/* Filled in by U-Boot */
 				mac-address = [ 00 00 00 00 00 00 ];
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 1bdbb36..e29bb8f 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -157,16 +157,26 @@ struct cpsw_ss_regs {
 };
 
 struct cpsw_slave_regs {
+	u32	control;
+	u32	res1;
 	u32	max_blks;
 	u32	blk_cnt;
-	u32	flow_thresh;
+	u32	tx_in_ctl;
 	u32	port_vlan;
 	u32	tx_pri_map;
-	u32	ts_ctl;
-	u32	ts_seq_ltype;
-	u32	ts_vlan;
+	u32	ts_seq_mtype;
 	u32	sa_lo;
 	u32	sa_hi;
+	u32	send_percent;
+	u32	res2;
+	u32	rx_dscp_pri_map0;
+	u32	rx_dscp_pri_map1;
+	u32	rx_dscp_pri_map2;
+	u32	rx_dscp_pri_map3;
+	u32	rx_dscp_pri_map4;
+	u32	rx_dscp_pri_map5;
+	u32	rx_dscp_pri_map6;
+	u32	rx_dscp_pri_map7;
 };
 
 struct cpsw_host_regs {
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH V2 2/7] cpsw: add missing fields to the CPSW_SS register bank.
From: Richard Cochran @ 2012-10-15 19:48 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, David Miller, Cyril Chemparathy, Mugunthan V N,
	Sriramakrishnan A G
In-Reply-To: <cover.1350329726.git.richardcochran@gmail.com>

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
 drivers/net/ethernet/ti/cpsw.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 3568b46..1bdbb36 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -146,6 +146,14 @@ struct cpsw_ss_regs {
 	u32	soft_reset;
 	u32	stat_port_en;
 	u32	ptype;
+	u32	soft_idle;
+	u32	thru_rate;
+	u32	gap_thresh;
+	u32	tx_start_wds;
+	u32	flow_control;
+	u32	vlan_ltype;
+	u32	ts_ltype;
+	u32	dlr_ltype;
 };
 
 struct cpsw_slave_regs {
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH V2 1/7] cpsw: rename register banks to match the reference manual
From: Richard Cochran @ 2012-10-15 19:48 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, David Miller, Cyril Chemparathy, Mugunthan V N,
	Sriramakrishnan A G
In-Reply-To: <cover.1350329726.git.richardcochran@gmail.com>

The code mixes up the CPSW_SS and the CPSW_WR register naming. This patch
changes the names to conform to the published Technical Reference Manual
from TI, in order to make working on the code less confusing.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
 drivers/net/ethernet/ti/cpsw.c |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index fb1a692..3568b46 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -129,7 +129,7 @@ static int rx_packet_max = CPSW_MAX_PACKET_SIZE;
 module_param(rx_packet_max, int, 0);
 MODULE_PARM_DESC(rx_packet_max, "maximum receive packet size (bytes)");
 
-struct cpsw_ss_regs {
+struct cpsw_wr_regs {
 	u32	id_ver;
 	u32	soft_reset;
 	u32	control;
@@ -140,7 +140,7 @@ struct cpsw_ss_regs {
 	u32	misc_en;
 };
 
-struct cpsw_regs {
+struct cpsw_ss_regs {
 	u32	id_ver;
 	u32	control;
 	u32	soft_reset;
@@ -202,8 +202,8 @@ struct cpsw_priv {
 	struct napi_struct		napi;
 	struct device			*dev;
 	struct cpsw_platform_data	data;
-	struct cpsw_regs __iomem	*regs;
-	struct cpsw_ss_regs __iomem	*ss_regs;
+	struct cpsw_ss_regs __iomem	*regs;
+	struct cpsw_wr_regs __iomem	*wr_regs;
 	struct cpsw_host_regs __iomem	*host_port_regs;
 	u32				msg_enable;
 	struct net_device_stats		stats;
@@ -230,8 +230,8 @@ struct cpsw_priv {
 
 static void cpsw_intr_enable(struct cpsw_priv *priv)
 {
-	__raw_writel(0xFF, &priv->ss_regs->tx_en);
-	__raw_writel(0xFF, &priv->ss_regs->rx_en);
+	__raw_writel(0xFF, &priv->wr_regs->tx_en);
+	__raw_writel(0xFF, &priv->wr_regs->rx_en);
 
 	cpdma_ctlr_int_ctrl(priv->dma, true);
 	return;
@@ -239,8 +239,8 @@ static void cpsw_intr_enable(struct cpsw_priv *priv)
 
 static void cpsw_intr_disable(struct cpsw_priv *priv)
 {
-	__raw_writel(0, &priv->ss_regs->tx_en);
-	__raw_writel(0, &priv->ss_regs->rx_en);
+	__raw_writel(0, &priv->wr_regs->tx_en);
+	__raw_writel(0, &priv->wr_regs->rx_en);
 
 	cpdma_ctlr_int_ctrl(priv->dma, false);
 	return;
@@ -984,7 +984,7 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
 		dev_err(priv->dev, "unable to map i/o region\n");
 		goto clean_cpsw_ss_iores_ret;
 	}
-	priv->ss_regs = regs;
+	priv->wr_regs = regs;
 
 	for_each_slave(priv, cpsw_slave_init, priv);
 
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH V2 0/7] support the cpts found on am335x devices
From: Richard Cochran @ 2012-10-15 19:48 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, David Miller, Cyril Chemparathy, Mugunthan V N,
	Sriramakrishnan A G

This patch series, based on linux-3.7-rc1 plus the fixes I posted
today, adds support for the Common Platform Time Sync (CPTS) found on
the popular BeagleBone. The code enables hardware time stamping and a
PTP Hardware Clock.

Changes in V2
   - Now uses device tree
   - Actually works with vanilla kernel

This work has been tested using the linuxptp PTP stack, and it seems
to be working quite well. One limitation of the hardware is that not
possible to adjust the clock frequency. Even without with this
capability, the driver will be still be useful for 802.1AS
applications, since they typically use a free running clock.

There is one open issue with this driver which will hopefully soon be
resolved. Time stamping only works on UDP packets. Although Layer 2 is
supposed to work according to the TRM, I have not yet figured out
how. The UDP only works when setting an undocumented bit, so maybe
someone from TI can fill me in on this.

Thanks,
Richard


Richard Cochran (7):
  cpsw: rename register banks to match the reference manual
  cpsw: add missing fields to the CPSW_SS register bank.
  cpsw: correct the CPSW_PORT register bank declaration
  cpsw: add a common header file for regsiter declarations
  cpts: introduce time stamping code and a PTP hardware clock.
  cpsw: add a DT field for the cpts offset
  cpsw: use the time stamping capabilities of the cpts

 Documentation/devicetree/bindings/net/cpsw.txt |   11 +-
 arch/arm/boot/dts/am33xx.dtsi                  |    5 +-
 drivers/net/ethernet/ti/Kconfig                |    8 +
 drivers/net/ethernet/ti/Makefile               |    2 +-
 drivers/net/ethernet/ti/cpsw.c                 |   84 ++++-
 drivers/net/ethernet/ti/cpsw_reg.h             |   81 ++++
 drivers/net/ethernet/ti/cpts.c                 |  468 ++++++++++++++++++++++++
 drivers/net/ethernet/ti/cpts.h                 |  148 ++++++++
 include/linux/platform_data/cpsw.h             |    1 +
 9 files changed, 788 insertions(+), 20 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/cpsw_reg.h
 create mode 100644 drivers/net/ethernet/ti/cpts.c
 create mode 100644 drivers/net/ethernet/ti/cpts.h

-- 
1.7.2.5

^ permalink raw reply

* Re: [PATCH v6 02/10] ipc: "use key as id" functionality for resource get system call introduced
From: Eric W. Biederman @ 2012-10-15 19:47 UTC (permalink / raw)
  To: Stanislav Kinsbursky
  Cc: akpm, catalin.marinas, will.deacon, dhowells, manfred, hughd,
	jmorris, mtk.manpages, kosaki.motohiro, paulmck, sds, devel,
	a.p.zijlstra, cmetcalf, linux-driver, ron.mercer, viro, eparis,
	tglx, jitendra.kalsaria, netdev, linux-kernel,
	linux-security-module, casey
In-Reply-To: <87lif7frt8.fsf@xmission.com>

ebiederm@xmission.com (Eric W. Biederman) writes:

> Stanislav Kinsbursky <skinsbursky@parallels.com> writes:
>
>> This patch introduces new IPC resource get request flag IPC_PRESET, which
>> should be interpreted as a request to try to allocate IPC slot with number,
>> starting from value resented by key. IOW, kernel will try
>> allocate new segment in specified slot.
>>
>> Note: if desired slot is not emply, then next free slot will be used.
>
> This way of handling things is pretty nasty.
>
> - You don't fail if the requested id is not available.
> - You don't allow assigning the key (which leads to the need to change
>   the key in later patches).  Changing the creator uid and creator
>   gid and key is semantically ugly.
>
> It would be much cleaner if you could instead add IPC_PRESET and then
> extend the definition of the creation functions all by one argument.
>
> aka
> int msgget(key_t key, int msgflg, int id);
> int semget(key_t key, int nsems, int semflg, int id);
> int shmget(key_t key, size_t size, int shmflg, int id);
>
> Where the extra id argument is ignored unless IPC_PRESET is specified.
>
> Also msgget, semget, and shmget should fail if unregconized flags are
> passed in.  That ipcget doesn't do that today is bizarre.

Hmm.  Come to think of it I don't see why you need to set the id at all.
We are using an idr allocator which effectively offers the semantics
that the lowest available id will be allocated.  The same semantics we
have for file descriptors.

So it should be possible at least for the first pass at
checkpoint/restart to implement the restoration of sysv ipc without
IPC_PRESET at all.

So IPC_PRESET should just be an optimization, not a necessary feature.

That makes all of your code go away except the message queue
peeking, which seems much less intrusive for the first pass.

Eric

^ permalink raw reply

* Re: [PATCH v6 02/10] ipc: "use key as id" functionality for resource get system call introduced
From: Eric W. Biederman @ 2012-10-15 19:39 UTC (permalink / raw)
  To: Stanislav Kinsbursky
  Cc: akpm, catalin.marinas, will.deacon, dhowells, manfred, hughd,
	jmorris, mtk.manpages, kosaki.motohiro, paulmck, sds, devel,
	a.p.zijlstra, cmetcalf, linux-driver, ron.mercer, viro, eparis,
	tglx, jitendra.kalsaria, netdev, linux-kernel,
	linux-security-module, casey
In-Reply-To: <20121015155946.28348.47885.stgit@localhost.localdomain>

Stanislav Kinsbursky <skinsbursky@parallels.com> writes:

> This patch introduces new IPC resource get request flag IPC_PRESET, which
> should be interpreted as a request to try to allocate IPC slot with number,
> starting from value resented by key. IOW, kernel will try
> allocate new segment in specified slot.
>
> Note: if desired slot is not emply, then next free slot will be used.

This way of handling things is pretty nasty.

- You don't fail if the requested id is not available.
- You don't allow assigning the key (which leads to the need to change
  the key in later patches).  Changing the creator uid and creator
  gid and key is semantically ugly.

It would be much cleaner if you could instead add IPC_PRESET and then
extend the definition of the creation functions all by one argument.

aka
int msgget(key_t key, int msgflg, int id);
int semget(key_t key, int nsems, int semflg, int id);
int shmget(key_t key, size_t size, int shmflg, int id);

Where the extra id argument is ignored unless IPC_PRESET is specified.

Also msgget, semget, and shmget should fail if unregconized flags are
passed in.  That ipcget doesn't do that today is bizarre.

Eric

^ permalink raw reply

* Re: [PATCH v6 10/10] test: IPC message queue copy feture test
From: David Howells @ 2012-10-15 19:23 UTC (permalink / raw)
  To: Stanislav Kinsbursky
  Cc: dhowells, akpm, catalin.marinas, will.deacon, manfred, hughd,
	jmorris, mtk.manpages, kosaki.motohiro, paulmck, sds, devel,
	a.p.zijlstra, cmetcalf, linux-driver, ron.mercer, viro, eparis,
	tglx, jitendra.kalsaria, netdev, linux-kernel,
	linux-security-module, ebiederm, casey
In-Reply-To: <20121015160027.28348.35065.stgit@localhost.localdomain>

Stanislav Kinsbursky <skinsbursky@parallels.com> wrote:

> +CFLAGS += -I../../../../arch/x86/include/generated/
> +CFLAGS += -I../../../../include/
> +CFLAGS += -I../../../../usr/include/
> +CFLAGS += -I../../../../arch/x86/include/

Do you need to add uapi/ into some of these?

David

^ permalink raw reply

* [PATCH 5/5] arm/dts: am33xx: Add cpsw and mdio module nodes for AM33XX
From: Richard Cochran @ 2012-10-15 19:16 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, Arnd Bergmann, David Miller, Russell King,
	Mugunthan V N, Vaibhav Hiremath
In-Reply-To: <cover.1350327320.git.richardcochran@gmail.com>

From: Mugunthan V N <mugunthanvnm@ti.com>

Add CPSW and MDIO related device tree data for AM33XX.
Also enable them into board/evm dts files by providing
respective phy-id.

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
---
 arch/arm/boot/dts/am335x-bone.dts |    8 ++++++
 arch/arm/boot/dts/am335x-evm.dts  |    8 ++++++
 arch/arm/boot/dts/am33xx.dtsi     |   50 +++++++++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
index c634f87..e233cfa 100644
--- a/arch/arm/boot/dts/am335x-bone.dts
+++ b/arch/arm/boot/dts/am335x-bone.dts
@@ -78,3 +78,11 @@
 		};
 	};
 };
+
+&cpsw_emac0 {
+	phy_id = "4a101000.mdio:00";
+};
+
+&cpsw_emac1 {
+	phy_id = "4a101000.mdio:01";
+};
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 185d632..415c3b3 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -118,3 +118,11 @@
 		};
 	};
 };
+
+&cpsw_emac0 {
+	phy_id = "4a101000.mdio:00";
+};
+
+&cpsw_emac1 {
+	phy_id = "4a101000.mdio:01";
+};
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index bb31bff..f6bea04 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -210,5 +210,55 @@
 			interrupt-parent = <&intc>;
 			interrupts = <91>;
 		};
+
+		mac: ethernet@4A100000 {
+			compatible = "ti,cpsw";
+			ti,hwmods = "cpgmac0";
+			cpdma_channels = <8>;
+			host_port_no = <0>;
+			cpdma_reg_ofs = <0x800>;
+			cpdma_sram_ofs = <0xa00>;
+			ale_reg_ofs = <0xd00>;
+			ale_entries = <1024>;
+			host_port_reg_ofs = <0x108>;
+			hw_stats_reg_ofs = <0x900>;
+			bd_ram_ofs = <0x2000>;
+			bd_ram_size = <0x2000>;
+			no_bd_ram = <0>;
+			rx_descs = <64>;
+			mac_control = <0x20>;
+			slaves = <2>;
+			reg = <0x4a100000 0x800
+				0x4a101200 0x100
+				0x4a101000 0x100>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			interrupt-parent = <&intc>;
+			/* c0_rx_thresh_pend c0_rx_pend c0_tx_pend c0_misc_pend*/
+			interrupts = <40 41 42 43>;
+			ranges;
+			cpsw_emac0: slave@0 {
+				slave_reg_ofs = <0x208>;
+				sliver_reg_ofs = <0xd80>;
+				/* Filled in by U-Boot */
+				mac-address = [ 00 00 00 00 00 00 ];
+			};
+			cpsw_emac1: slave@1 {
+				slave_reg_ofs = <0x308>;
+				sliver_reg_ofs = <0xdc0>;
+				/* Filled in by U-Boot */
+				mac-address = [ 00 00 00 00 00 00 ];
+			};
+
+			davinci_mdio: mdio@4a101000 {
+				compatible = "ti,davinci_mdio";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				ti,hwmods = "davinci_mdio";
+				bus_freq = <1000000>;
+				reg = <0x4a101000 0x100>;
+			};
+
+		};
 	};
 };
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH 4/5] net: cpsw: Add parent<->child relation support between cpsw and mdio
From: Richard Cochran @ 2012-10-15 19:16 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, Arnd Bergmann, David Miller, Russell King,
	Vaibhav Hiremath, Mugunthan V N
In-Reply-To: <cover.1350327320.git.richardcochran@gmail.com>

From: Vaibhav Hiremath <hvaibhav@ti.com>

CPGMAC SubSystem consist of various sub-modules, like, mdio, cpdma,
cpsw, etc... These sub-modules are also used in some of Davinci family
of devices. Now based on requirement, use-case and available technology
nodes the integration of these sub-modules varies across devices.

So coming back to Linux net driver, currently separate and independent
platform devices & drivers for CPSW and MDIO is implemented. In case of
Davinci they both has separate control, from resources perspective,
like clock.

In case of AM33XX, the resources are shared and only one register
bit-field is provided to control module/clock enable/disable, makes it
difficult to handle common resource.

So the solution here implemented in this patch is,

Create parent<->child relationship between both the drivers, making
CPSW as a parent and MDIO as its child and enumerate all the child nodes
under cpsw module.
Both the drivers will function exactly the way it was operating before,
including runtime-pm functionality. No change is required in MDIO driver
(for that matter to any child driver).

As this is only supported during DT boot, the parent<->child relationship
is created and populated in DT execution flow. The only required change
is inside DTS file, making MDIO as a child to CPSW node.

Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
Cc: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/net/ethernet/ti/cpsw.c |   16 ++++++++++++++--
 1 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index df55e24..fb1a692 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -827,7 +827,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 	}
 	data->mac_control = prop;
 
-	for_each_child_of_node(node, slave_node) {
+	for_each_node_by_name(slave_node, "slave") {
 		struct cpsw_slave_data *slave_data = data->slave_data + i;
 		const char *phy_id = NULL;
 		const void *mac_addr = NULL;
@@ -862,6 +862,14 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 		i++;
 	}
 
+	/*
+	 * Populate all the child nodes here...
+	 */
+	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+	/* We do not want to force this, as in some cases may not have child */
+	if (ret)
+		pr_warn("Doesn't have any child node\n");
+
 	return 0;
 
 error_ret:
@@ -895,6 +903,11 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
 	priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
 	priv->rx_packet_max = max(rx_packet_max, 128);
 
+	/*
+	 * This may be required here for child devices.
+	 */
+	pm_runtime_enable(&pdev->dev);
+
 	if (cpsw_probe_dt(&priv->data, pdev)) {
 		pr_err("cpsw: platform data missing\n");
 		ret = -ENODEV;
@@ -921,7 +934,6 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
 	for (i = 0; i < data->slaves; i++)
 		priv->slaves[i].slave_num = i;
 
-	pm_runtime_enable(&pdev->dev);
 	priv->clk = clk_get(&pdev->dev, "fck");
 	if (IS_ERR(priv->clk)) {
 		dev_err(&pdev->dev, "fck is not found\n");
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH 3/5] net: davinci_mdio: Fix type mistake in calling runtime-pm api
From: Richard Cochran @ 2012-10-15 19:16 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, Arnd Bergmann, David Miller, Russell King,
	Vaibhav Hiremath, Mugunthan V N
In-Reply-To: <cover.1350327320.git.richardcochran@gmail.com>

From: Vaibhav Hiremath <hvaibhav@ti.com>

By mistake (most likely a copy-paste), instead of pm_runtime_get_sync()
api, driver is calling pm_runtime_put_sync() api in resume callback
function. The bug was introduced by commit id (ae2c07aaf74:
davinci_mdio: runtime PM support).

Now, the reason why it didn't impact functionality is, the patch has
been tested on AM335x-EVM and BeagleBone platform while submitting;
and in case of AM335x the MDIO driver doesn't control the module
enable/disable part, which is handled by CPSW driver.

Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
Cc: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/net/ethernet/ti/davinci_mdio.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index 51a96db..ae74280 100644
--- a/drivers/net/ethernet/ti/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
@@ -465,7 +465,7 @@ static int davinci_mdio_resume(struct device *dev)
 	u32 ctrl;
 
 	spin_lock(&data->lock);
-	pm_runtime_put_sync(data->dev);
+	pm_runtime_get_sync(data->dev);
 
 	/* restart the scan state machine */
 	ctrl = __raw_readl(&data->regs->control);
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH 2/5] ARM: OMAP3+: hwmod: Add AM33XX HWMOD data for davinci_mdio
From: Richard Cochran @ 2012-10-15 19:16 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, Arnd Bergmann, David Miller, Russell King,
	Mugunthan V N
In-Reply-To: <cover.1350327320.git.richardcochran@gmail.com>

From: Mugunthan V N <mugunthanvnm@ti.com>

This patch adds minimal hwmod support for davinci mdio driver. This patch
requires rework on parent child relation between cpsw and davinci mdio
hwmod data to support runtime PM.

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_33xx_data.c |   34 ++++++++++++++++++++++++++-
 1 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
index 59d5c1c..f96bbc0 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
@@ -650,8 +650,7 @@ static struct omap_hwmod_class_sysconfig am33xx_cpgmac_sysc = {
 	.rev_offs	= 0x0,
 	.sysc_offs	= 0x8,
 	.syss_offs	= 0x4,
-	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE |
-			   SYSS_HAS_RESET_STATUS),
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE),
 	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | MSTANDBY_FORCE |
 			   MSTANDBY_NO),
 	.sysc_fields	= &omap_hwmod_sysc_type3,
@@ -682,6 +681,8 @@ static struct omap_hwmod am33xx_cpgmac0_hwmod = {
 			.modulemode	= MODULEMODE_SWCTRL,
 		},
 	},
+	.flags		= (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
+			   HWMOD_INIT_NO_RESET | HWMOD_INIT_NO_IDLE),
 };
 
 /*
@@ -2510,6 +2511,34 @@ static struct omap_hwmod_addr_space am33xx_elm_addr_space[] = {
 	{ }
 };
 
+/* mdio class */
+static struct omap_hwmod_class am33xx_mdio_hwmod_class = {
+	.name		= "davinci_mdio",
+};
+
+struct omap_hwmod_addr_space am33xx_mdio_addr_space[] = {
+	{
+		.pa_start	= 0x4A101000,
+		.pa_end		= 0x4A101000 + SZ_256 - 1,
+		.flags		= ADDR_MAP_ON_INIT,
+	},
+	{ }
+};
+
+static struct omap_hwmod am33xx_mdio_hwmod = {
+	.name		= "davinci_mdio",
+	.class		= &am33xx_mdio_hwmod_class,
+	.clkdm_name	= "cpsw_125mhz_clkdm",
+	.main_clk	= "cpsw_125mhz_gclk",
+};
+
+struct omap_hwmod_ocp_if am33xx_cpgmac0__mdio = {
+	.master		= &am33xx_cpgmac0_hwmod,
+	.slave		= &am33xx_mdio_hwmod,
+	.addr		= am33xx_mdio_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
 static struct omap_hwmod_ocp_if am33xx_l4_ls__elm = {
 	.master		= &am33xx_l4_ls_hwmod,
 	.slave		= &am33xx_elm_hwmod,
@@ -3371,6 +3400,7 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
 	&am33xx_l3_main__tptc2,
 	&am33xx_l3_s__usbss,
 	&am33xx_l4_hs__cpgmac0,
+	&am33xx_cpgmac0__mdio,
 	NULL,
 };
 
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH 1/5] ARM: OMAP2+: gpmc: Fix kernel BUG for DT boot mode
From: Richard Cochran @ 2012-10-15 19:16 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, Arnd Bergmann, David Miller, Russell King,
	hvaibhav@ti.com, Afzal Mohammed, Tony Lindgren
In-Reply-To: <cover.1350327320.git.richardcochran@gmail.com>

From: hvaibhav@ti.com <hvaibhav@ti.com>

With recent changes in omap gpmc driver code, in case of DT
boot mode, where bootloader does not configure gpmc cs space
will result into kernel BUG() inside gpmc_mem_init() function,
as gpmc cs0 gpmc_config7[0].csvalid bit is set to '1' and
gpmc_config7[0].baseaddress is set to '0' on reset.

This use-case is applicable for any board/EVM which doesn't have
any peripheral connected to gpmc cs0, for example BeagleXM and
BeagleBone, so DT boot mode fails.

This patch adds of_have_populated_dt() check before creating
device, so that for DT boot mode, gpmc probe will not be called
which is expected behavior, as gpmc is not supported yet from DT.

Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
Cc: Afzal Mohammed <afzal@ti.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/gpmc.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5ac5cf3..90b033e 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -981,6 +981,10 @@ static int __init omap_gpmc_init(void)
 	struct platform_device *pdev;
 	char *oh_name = "gpmc";
 
+	/* If dtb is there, the devices will be created dynamically */
+	if (of_have_populated_dt())
+		return -ENODEV;
+
 	oh = omap_hwmod_lookup(oh_name);
 	if (!oh) {
 		pr_err("Could not look up %s\n", oh_name);
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH 0/5] am335x fixes for 3.7-rc2
From: Richard Cochran @ 2012-10-15 19:16 UTC (permalink / raw)
  To: netdev; +Cc: linux-arm-kernel, Arnd Bergmann, David Miller, Russell King

This series contains patches required to let the kernel run on a TI
am335x, like the popular BeagleBone. None of these patches are from
me, yet all of them are essential fixes. For net-next I have prepared
a cpsw driver extension that enables time stamping and a PTP clock,
but in order to be useful, the kernel must boot and the MAC driver
must be working.

The first patch was supposed to have made -rc1, but it seems to have
been forgotten. The other four patches are for the cpsw MAC driver,
which has not worked since the migration to device tree. Actually, I
am not sure if the cpsw ever did work, but in any case these patches
let the driver work (again), rather than being a lifeless derelict.

Thanks,
Richard


Mugunthan V N (2):
  ARM: OMAP3+: hwmod: Add AM33XX HWMOD data for davinci_mdio
  arm/dts: am33xx: Add cpsw and mdio module nodes for AM33XX

Vaibhav Hiremath (2):
  net: davinci_mdio: Fix type mistake in calling runtime-pm api
  net: cpsw: Add parent<->child relation support between cpsw and mdio

hvaibhav@ti.com (1):
  ARM: OMAP2+: gpmc: Fix kernel BUG for DT boot mode

 arch/arm/boot/dts/am335x-bone.dts          |    8 ++++
 arch/arm/boot/dts/am335x-evm.dts           |    8 ++++
 arch/arm/boot/dts/am33xx.dtsi              |   50 ++++++++++++++++++++++++++++
 arch/arm/mach-omap2/gpmc.c                 |    4 ++
 arch/arm/mach-omap2/omap_hwmod_33xx_data.c |   34 ++++++++++++++++++-
 drivers/net/ethernet/ti/cpsw.c             |   16 ++++++++-
 drivers/net/ethernet/ti/davinci_mdio.c     |    2 +-
 7 files changed, 117 insertions(+), 5 deletions(-)

-- 
1.7.2.5

^ permalink raw reply

* Re: [PATCH v6 04/10] ipc: add new SHM_SET command for sys_shmctl() call
From: Ben Hutchings @ 2012-10-15 19:00 UTC (permalink / raw)
  To: Stanislav Kinsbursky
  Cc: akpm, catalin.marinas, will.deacon, dhowells, manfred, hughd,
	jmorris, mtk.manpages, kosaki.motohiro, paulmck, sds, devel,
	a.p.zijlstra, cmetcalf, linux-driver, ron.mercer, viro, eparis,
	tglx, jitendra.kalsaria, netdev, linux-kernel,
	linux-security-module, ebiederm, casey
In-Reply-To: <20121015155956.28348.36765.stgit@localhost.localdomain>

On Mon, 2012-10-15 at 19:59 +0400, Stanislav Kinsbursky wrote:
> New SHM_SET command will be interpreted exactly as IPC_SET, but also will
> update key, cuid and cgid values. IOW, it allows to change existent key value.
> The fact, that key is not used is checked before update. Otherwise -EEXIST is
> returned.
[...]
> --- a/ipc/shm.c
> +++ b/ipc/shm.c
[...]
> @@ -759,6 +763,10 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
>  	case IPC_RMID:
>  		do_shm_rmid(ns, ipcp);
>  		goto out_up;
> +	case SHM_SET:
> +		err = ipc_update_key(&shm_ids(ns), &shmid64.shm_perm, ipcp);
> +		if (err)
> +			break;
[...]

Please add /* fall through */ here, and in the similar cases in patches
5 and 7, to make clear that it's deliberate.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply

* Re: [PATCH v6 06/10] glge driver: rename internal SEM_SET macro to SEM_INIT
From: Ben Hutchings @ 2012-10-15 18:28 UTC (permalink / raw)
  To: Stanislav Kinsbursky
  Cc: akpm, catalin.marinas, will.deacon, dhowells, manfred, hughd,
	jmorris, mtk.manpages, kosaki.motohiro, paulmck, sds, devel,
	a.p.zijlstra, cmetcalf, linux-driver, ron.mercer, viro, eparis,
	tglx, jitendra.kalsaria, netdev, linux-kernel,
	linux-security-module, ebiederm, casey
In-Reply-To: <20121015160006.28348.79520.stgit@localhost.localdomain>

On Mon, 2012-10-15 at 20:00 +0400, Stanislav Kinsbursky wrote:
> The reason for shit patch is that SET_SET is desired to be a part of new part
> of API of IPC sys_semctl() system call.
[...]

Two spelling errors above. :-)

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply

* [PATCH for-3.7] vhost: fix mergeable bufs on BE hosts
From: Michael S. Tsirkin @ 2012-10-15 17:55 UTC (permalink / raw)
  To: Alexander Graf; +Cc: netdev, stable, kvm, virtualization

We copy head count to a 16 bit field,
this works by chance on LE but on BE
guest gets 0. Fix it up.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Tested-by: Alexander Graf <agraf@suse.de>
Cc: stable@kernel.org

---
 drivers/vhost/net.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 9ab6d47..2bb463c 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -448,7 +448,8 @@ static void handle_rx(struct vhost_net *net)
 		.hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
 	};
 	size_t total_len = 0;
-	int err, headcount, mergeable;
+	int err, mergeable;
+	s16 headcount;
 	size_t vhost_hlen, sock_hlen;
 	size_t vhost_len, sock_len;
 	/* TODO: check that we are running from vhost_worker? */
-- 
MST

^ permalink raw reply related

* [PATCH 1/1] dev_change_net_namespace: send a KOBJ_REMOVED/KOBJ_ADD
From: Serge Hallyn @ 2012-10-15 17:47 UTC (permalink / raw)
  To: netdev
  Cc: Eric W. Biederman, Dan Kegel, Stéphane Graber, lxc-users,
	Daniel Lezcano, containers, Stefan Bader

When a new nic is created in namespace ns1, the kernel sends a KOBJ_ADD uevent
to ns1.  When the nic is moved to ns2, we only send a KOBJ_MOVE to ns2, and
nothing to ns1.

This patch changes that behavior so that when moving a nic from ns1 to ns2, we
send a KOBJ_REMOVED to ns1 and KOBJ_ADD to ns2.  (The KOBJ_MOVE is still
sent to ns2).

The effects of this can be seen when starting and stopping containers in
an upstart based host.  Lxc will create a pair of veth nics, the kernel
sends KOBJ_ADD, and upstart starts network-instance jobs for each.  When
one nic is moved to the container, because no KOBJ_REMOVED event is
received, the network-instance job for that veth never goes away.  This
was reported at https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1065589
With this patch the networ-instance jobs properly go away.

The other oddness solved here is that if a nic is passed into a running
upstart-based container, without this patch no network-instance job is
started in the container.  But when the container creates a new nic
itself (ip link add new type veth) then network-interface jobs are
created.  With this patch, behavior comes in line with a regular host.

v2: also send KOBJ_ADD to new netns.  There will then be a
_MOVE event from the device_rename() call, but that should
be innocuous.

Signed-off-by: Serge Hallyn <serge.hallyn@canonical.com>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
 net/core/dev.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/net/core/dev.c b/net/core/dev.c
index e2215ee..2c43aaf 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6172,6 +6172,9 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
 	dev_uc_flush(dev);
 	dev_mc_flush(dev);
 
+	/* Send a netdev-removed uevent to the old namespace */
+	kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE);
+
 	/* Actually switch the network namespace */
 	dev_net_set(dev, net);
 
@@ -6183,6 +6186,9 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
 			dev->iflink = dev->ifindex;
 	}
 
+	/* Send a netdev-add uevent to the new namespace */
+	kobject_uevent(&dev->dev.kobj, KOBJ_ADD);
+
 	/* Fixup kobjects */
 	err = device_rename(&dev->dev, dev->name);
 	WARN_ON(err);
-- 
1.7.9.5

^ permalink raw reply related

* IPSEC maintainership...
From: David Miller @ 2012-10-15 17:38 UTC (permalink / raw)
  To: steffen.klassert; +Cc: netdev, herbert


Steffen, after some discussions with Herbert we'd like to formally
recognize your outstanding contributions to the IPSEC stack over
the past few years by listing you explicitly as a maintainer as
per the patch below.

Let us know if you are OK with this.

Thanks!

--------------------
MAINTAINERS: Add explicit section for IPSEC networking.

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

diff --git a/MAINTAINERS b/MAINTAINERS
index e73060f..6d6632f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5019,6 +5019,20 @@ F:	net/ipv6/
 F:	include/net/ip*
 F:	arch/x86/net/*
 
+NETWORKING [IPSEC]
+M:	Steffen Klassert <steffen.klassert@secunet.com>
+M:	Herbert Xu <herbert@gondor.apana.org.au>
+M:	"David S. Miller" <davem@davemloft.net>
+L:	netdev@vger.kernel.org
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+S:	Maintained
+F:	net/xfrm/
+F:	net/key/
+F:	net/ipv4/xfrm*
+F:	net/ipv6/xfrm*
+F:	include/uapi/linux/xfrm.h
+F:	include/net/xfrm.h
+
 NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK)
 M:	Paul Moore <paul@paul-moore.com>
 L:	netdev@vger.kernel.org

^ permalink raw reply related

* Re: listen(2) backlog changes in or around Linux 3.1?
From: enh @ 2012-10-15 17:26 UTC (permalink / raw)
  To: Venkat Venkatsubra; +Cc: netdev
In-Reply-To: <507C4401.7050500@oracle.com>

On Mon, Oct 15, 2012 at 10:12 AM, Venkat Venkatsubra
<venkat.x.venkatsubra@oracle.com> wrote:
> On 10/12/2012 6:40 PM, enh wrote:
>>
>> i used to use the following hack to unit test connect timeouts: i'd
>> call listen(2) on a socket and then deliberately connect (backlog + 3)
>> sockets without accept(2)ing any of the connections. (why 3? because
>> Stevens told me so, and experiment backed him up. see figure 4.10 in
>> his UNIX Network Programming.)
>>
>> with "old" kernels, 2.6.35-ish to 3.0-ish, this worked great. my next
>> connect(2) to the same loopback port would hang indefinitely. i could
>> even unblock the connect by calling accept(2) in another thread. this
>> was awesome for testing.
>>
>> in 3.1 on ARM, 3.2 on x86 (Ubuntu desktop), and 3.4 on ARM, this no
>> longer works. it doesn't seem to be as simple as "the constant is no
>> longer 3". my tests are now flaky. sometimes they work like they used
>> to, and sometimes an extra connect(2) will succeed. (or, if i'm in
>> non-blocking mode, my poll(2) will return with the non-blocking socket
>> that's trying to connect now ready.)
>>
>> i'm guessing if this changed in 3.1 and is still changed in 3.4,
>> whatever's changed wasn't an accident. but i haven't been able to find
>> the right search terms to RTFM. i also finally got around to grepping
>> the kernel for the "+ 3", but wasn't able to find that. (so i'd be
>> interested to know where the old behavior came from too.)
>>
>> my least worst workaround at the moment is to use one of RFC5737's
>> test networks, but that requires that the device have a network
>> connection, otherwise my connect(2)s fail immediately with
>> ENETUNREACH, which is no use to me. also, unlike my old trick, i've
>> got no way to suddenly "unblock" a slow connect(2) (this is useful for
>> unit testing the code that does the poll(2) part of the usual
>> connect-with-timeout implementation).
>> https://android-review.googlesource.com/#/c/44563/
>>
>> hopefully someone here can shed some light on this? ideally someone
>> will have a workaround as good as my old trick. i realize i was
>> relying on undocumented behavior, and i'm happy to have to check
>> /proc/version and behave appropriately, but i'd really like a way to
>> keep my unit tests!
>>
>> thanks,
>>   elliott
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
> Hi Elliott,
>
> In BSD I think the backlog used to be reset to 3/2 times that passed by the
> user. So, 2 becomes 3.
> Probably the 1/2 times increase was to accommodate the ones in
> partial/incomplete queue.
> In Linux is it possible you were getting the same behavior before the below
> commit ?
> Since the check used to be "backlog+1" a 2 will behave as 3 ?

i don't think so, because with <= 3.0 kernels i used to have a backlog
of 1 and be able to make _4_ connections before my next connect would
hang. but this > to >= change is at least something for me to
investigate...

> commit 8488df894d05d6fa41c2bd298c335f944bb0e401
> Author: Wei Dong <weid@np.css.fujitsu.com>
> Date:   Fri Mar 2 12:37:26 2007 -0800
>
>     [NET]: Fix bugs in "Whether sock accept queue is full" checking
>
>         when I use linux TCP socket, and find there is a bug in function
> sk_acceptq_is_full().
>
>         When a new SYN comes, TCP module first checks its validation. If
> valid,
>     send SYN,ACK to the client and add the sock to the syn hash table. Next
>     time if received the valid ACK for SYN,ACK from the client. server will
>     accept this connection and increase the sk->sk_ack_backlog -- which is
>     done in function tcp_check_req().We check wether acceptq is full in
>     function tcp_v4_syn_recv_sock().
>
>     Consider an example:
>
>      After listen(sockfd, 1) system call, sk->sk_max_ack_backlog is set to
>     1. As we know, sk->sk_ack_backlog is initialized to 0. Assuming accept()
>     system call is not invoked now.
>
>     1. 1st connection comes. invoke sk_acceptq_is_full().
>      sk->sk_ack_backlog=0 sk->sk_max_ack_backlog=1, function return 0 accept
> this connection.
>      Increase the sk->sk_ack_backlog
>     2. 2nd connection comes. invoke sk_acceptq_is_full().
>      sk->sk_ack_backlog=1 sk->sk_max_ack_backlog=1, function return 0 accept
> this connection.
>      Increase the sk->sk_ack_backlog
>     3. 3rd connection comes. invoke sk_acceptq_is_full().
>      sk->sk_ack_backlog=2 sk->sk_max_ack_backlog=1, function return 1.
> Refuse this connection.
>
>     I think it has bugs. after listen system call. sk->sk_max_ack_backlog=1
>     but now it can accept 2 connections.
>
>     Signed-off-by: Wei Dong <weid@np.css.fujitsu.com>
>     Signed-off-by: David S. Miller <davem@davemloft.net>
>
> Venkat

^ permalink raw reply


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