Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next] sk-filter: Add ability to get socket filter program (v2)
From: Pavel Emelyanov @ 2012-11-01 12:01 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

The SO_ATTACH_FILTER option is set only. I propose to add the get
ability by using SO_ATTACH_FILTER in getsockopt. To be less
irritating to eyes the SO_GET_FILTER alias to it is declared. This
ability is required by checkpoint-restore project to be able to 
save full state of a socket. 


There are two issues with getting filter back.

First, kernel modifies the sock_filter->code on filter load, thus in
order to return the filter element back to user we have to decode it
into user-visible constants. Fortunately the modification in question
is interconvertible.

Second, the BPF_S_ALU_DIV_K code modifies the command argument k to
speed up the run-time division by doing kernel_k = reciprocal(user_k).
Bad news is that different user_k may result in same kernel_k, so we 
can't get the original user_k back. Good news is that we don't have 
to do it. What we need to is calculate a user2_k so, that

  reciprocal(user2_k) == reciprocal(user_k) == kernel_k

i.e. if it's re-loaded back the compiled again value will be exactly
the same as it was. That said, the user2_k can be calculated like this

  user2_k = reciprocal(kernel_k)

with an exception, that if kernel_k == 0, then user2_k == 1.


The optlen argument is treated like this -- when zero, kernel returns
the amount of sock_fprog elements in filter, otherwise it should be
large enough for the sock_fprog array.

changes since v1:
* Declared SO_GET_FILTER in all arch headers
* Added decode of vlan-tag codes

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---

diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h
index 7d2f75b..0087d05 100644
--- a/arch/alpha/include/asm/socket.h
+++ b/arch/alpha/include/asm/socket.h
@@ -47,6 +47,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h
index a473f8c..486df68 100644
--- a/arch/avr32/include/uapi/asm/socket.h
+++ b/arch/avr32/include/uapi/asm/socket.h
@@ -40,6 +40,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h
index ae52825..b681b04 100644
--- a/arch/cris/include/asm/socket.h
+++ b/arch/cris/include/asm/socket.h
@@ -42,6 +42,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP           29
diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h
index a5b1d7d..871f89b 100644
--- a/arch/frv/include/uapi/asm/socket.h
+++ b/arch/frv/include/uapi/asm/socket.h
@@ -40,6 +40,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME             28
 #define SO_TIMESTAMP		29
diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h
index ec4554e..90a2e57 100644
--- a/arch/h8300/include/asm/socket.h
+++ b/arch/h8300/include/asm/socket.h
@@ -40,6 +40,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME             28
 #define SO_TIMESTAMP		29
diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h
index 41fc28a..23d6759 100644
--- a/arch/ia64/include/uapi/asm/socket.h
+++ b/arch/ia64/include/uapi/asm/socket.h
@@ -49,6 +49,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER	26
 #define SO_DETACH_FILTER	27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h
index a15f40b..5e7088a 100644
--- a/arch/m32r/include/asm/socket.h
+++ b/arch/m32r/include/asm/socket.h
@@ -40,6 +40,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h
index d1be684..285da3b 100644
--- a/arch/m68k/include/asm/socket.h
+++ b/arch/m68k/include/asm/socket.h
@@ -40,6 +40,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME             28
 #define SO_TIMESTAMP		29
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index c5ed595..17307ab 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -63,6 +63,7 @@ To add: #define SO_REUSEPORT 0x0200	/* Allow local address and port reuse.  */
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME             28
 #define SO_TIMESTAMP		29
diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h
index 820463a..af5366b 100644
--- a/arch/mn10300/include/uapi/asm/socket.h
+++ b/arch/mn10300/include/uapi/asm/socket.h
@@ -40,6 +40,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h
index 1b52c2c..d9ff473 100644
--- a/arch/parisc/include/asm/socket.h
+++ b/arch/parisc/include/asm/socket.h
@@ -48,6 +48,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        0x401a
 #define SO_DETACH_FILTER        0x401b
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_ACCEPTCONN		0x401c
 
diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h
index 3d5179b..eb0b186 100644
--- a/arch/powerpc/include/uapi/asm/socket.h
+++ b/arch/powerpc/include/uapi/asm/socket.h
@@ -47,6 +47,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER	26
 #define SO_DETACH_FILTER	27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index 69718cd..436d07c 100644
--- a/arch/s390/include/uapi/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
@@ -46,6 +46,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index bea1568..c83a937 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -41,6 +41,7 @@
 
 #define SO_ATTACH_FILTER	0x001a
 #define SO_DETACH_FILTER        0x001b
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		0x001c
 #define SO_TIMESTAMP		0x001d
diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h
index e36c681..38079be 100644
--- a/arch/xtensa/include/asm/socket.h
+++ b/arch/xtensa/include/asm/socket.h
@@ -52,6 +52,7 @@
 
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
diff --git a/include/linux/filter.h b/include/linux/filter.h
index c9f0005..c45eabc 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -45,6 +45,7 @@ extern void sk_unattached_filter_destroy(struct sk_filter *fp);
 extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
 extern int sk_detach_filter(struct sock *sk);
 extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
+extern int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned len);
 
 #ifdef CONFIG_BPF_JIT
 extern void bpf_jit_compile(struct sk_filter *fp);
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index b1bea03..2d32d07 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -43,6 +43,7 @@
 /* Socket filtering */
 #define SO_ATTACH_FILTER	26
 #define SO_DETACH_FILTER	27
+#define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
diff --git a/net/core/filter.c b/net/core/filter.c
index 5a114d4..c23543c 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -760,3 +760,133 @@ int sk_detach_filter(struct sock *sk)
 	return ret;
 }
 EXPORT_SYMBOL_GPL(sk_detach_filter);
+
+static void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to)
+{
+	static const u16 decodes[] = {
+		[BPF_S_ALU_ADD_K]	= BPF_ALU|BPF_ADD|BPF_K,
+		[BPF_S_ALU_ADD_X]	= BPF_ALU|BPF_ADD|BPF_X,
+		[BPF_S_ALU_SUB_K]	= BPF_ALU|BPF_SUB|BPF_K,
+		[BPF_S_ALU_SUB_X]	= BPF_ALU|BPF_SUB|BPF_X,
+		[BPF_S_ALU_MUL_K]	= BPF_ALU|BPF_MUL|BPF_K,
+		[BPF_S_ALU_MUL_X]	= BPF_ALU|BPF_MUL|BPF_X,
+		[BPF_S_ALU_DIV_X]	= BPF_ALU|BPF_DIV|BPF_X,
+		[BPF_S_ALU_MOD_K]	= BPF_ALU|BPF_MOD|BPF_K,
+		[BPF_S_ALU_MOD_X]	= BPF_ALU|BPF_MOD|BPF_X,
+		[BPF_S_ALU_AND_K]	= BPF_ALU|BPF_AND|BPF_K,
+		[BPF_S_ALU_AND_X]	= BPF_ALU|BPF_AND|BPF_X,
+		[BPF_S_ALU_OR_K]	= BPF_ALU|BPF_OR|BPF_K,
+		[BPF_S_ALU_OR_X]	= BPF_ALU|BPF_OR|BPF_X,
+		[BPF_S_ALU_XOR_K]	= BPF_ALU|BPF_XOR|BPF_K,
+		[BPF_S_ALU_XOR_X]	= BPF_ALU|BPF_XOR|BPF_X,
+		[BPF_S_ALU_LSH_K]	= BPF_ALU|BPF_LSH|BPF_K,
+		[BPF_S_ALU_LSH_X]	= BPF_ALU|BPF_LSH|BPF_X,
+		[BPF_S_ALU_RSH_K]	= BPF_ALU|BPF_RSH|BPF_K,
+		[BPF_S_ALU_RSH_X]	= BPF_ALU|BPF_RSH|BPF_X,
+		[BPF_S_ALU_NEG]		= BPF_ALU|BPF_NEG,
+		[BPF_S_LD_W_ABS]	= BPF_LD|BPF_W|BPF_ABS,
+		[BPF_S_LD_H_ABS]	= BPF_LD|BPF_H|BPF_ABS,
+		[BPF_S_LD_B_ABS]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_PROTOCOL]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_PKTTYPE]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_IFINDEX]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_NLATTR]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_NLATTR_NEST]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_MARK]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_QUEUE]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_HATYPE]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_RXHASH]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_CPU]		= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_ALU_XOR_X]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_SECCOMP_LD_W] = BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_VLAN_TAG]	= BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_ANC_VLAN_TAG_PRESENT] = BPF_LD|BPF_B|BPF_ABS,
+		[BPF_S_LD_W_LEN]	= BPF_LD|BPF_W|BPF_LEN,
+		[BPF_S_LD_W_IND]	= BPF_LD|BPF_W|BPF_IND,
+		[BPF_S_LD_H_IND]	= BPF_LD|BPF_H|BPF_IND,
+		[BPF_S_LD_B_IND]	= BPF_LD|BPF_B|BPF_IND,
+		[BPF_S_LD_IMM]		= BPF_LD|BPF_IMM,
+		[BPF_S_LDX_W_LEN]	= BPF_LDX|BPF_W|BPF_LEN,
+		[BPF_S_LDX_B_MSH]	= BPF_LDX|BPF_B|BPF_MSH,
+		[BPF_S_LDX_IMM]		= BPF_LDX|BPF_IMM,
+		[BPF_S_MISC_TAX]	= BPF_MISC|BPF_TAX,
+		[BPF_S_MISC_TXA]	= BPF_MISC|BPF_TXA,
+		[BPF_S_RET_K]		= BPF_RET|BPF_K,
+		[BPF_S_RET_A]		= BPF_RET|BPF_A,
+		[BPF_S_ALU_DIV_K]	= BPF_ALU|BPF_DIV|BPF_K,
+		[BPF_S_LD_MEM]		= BPF_LD|BPF_MEM,
+		[BPF_S_LDX_MEM]		= BPF_LDX|BPF_MEM,
+		[BPF_S_ST]		= BPF_ST,
+		[BPF_S_STX]		= BPF_STX,
+		[BPF_S_JMP_JA]		= BPF_JMP|BPF_JA,
+		[BPF_S_JMP_JEQ_K]	= BPF_JMP|BPF_JEQ|BPF_K,
+		[BPF_S_JMP_JEQ_X]	= BPF_JMP|BPF_JEQ|BPF_X,
+		[BPF_S_JMP_JGE_K]	= BPF_JMP|BPF_JGE|BPF_K,
+		[BPF_S_JMP_JGE_X]	= BPF_JMP|BPF_JGE|BPF_X,
+		[BPF_S_JMP_JGT_K]	= BPF_JMP|BPF_JGT|BPF_K,
+		[BPF_S_JMP_JGT_X]	= BPF_JMP|BPF_JGT|BPF_X,
+		[BPF_S_JMP_JSET_K]	= BPF_JMP|BPF_JSET|BPF_K,
+		[BPF_S_JMP_JSET_X]	= BPF_JMP|BPF_JSET|BPF_X,
+	};
+	u16 code;
+
+	code = filt->code;
+
+	to->code = decodes[code];
+	to->jt = filt->jt;
+	to->jf = filt->jf;
+
+	if (code == BPF_S_ALU_DIV_K) {
+		/*
+		 * When loaded this rule user gave us X, which was
+		 * translated into R = r(X). Now we calculate the
+		 * RR = r(R) and report it back. If next time this
+		 * value is loaded and RRR = r(RR) is calculated
+		 * then the R == RRR will be true.
+		 *
+		 * One exception. X == 1 translates into R == 0 and
+		 * we can't calculate RR out of it with r().
+		 */
+
+		if (filt->k == 0)
+			to->k = 1;
+		else
+			to->k = reciprocal_value(filt->k);
+
+		BUG_ON(reciprocal_value(to->k) != filt->k);
+	} else
+		to->k = filt->k;
+}
+
+int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, unsigned int len)
+{
+	struct sk_filter *filter;
+	int i, ret;
+
+	lock_sock(sk);
+	filter = rcu_dereference_protected(sk->sk_filter,
+			sock_owned_by_user(sk));
+	ret = 0;
+	if (!filter)
+		goto out;
+	ret = filter->len;
+	if (!len)
+		goto out;
+	ret = -EINVAL;
+	if (len < filter->len)
+		goto out;
+
+	ret = -EFAULT;
+	for (i = 0; i < filter->len; i++) {
+		struct sock_filter fb;
+
+		sk_decode_filter(&filter->insns[i], &fb);
+		if (copy_to_user(&ubuf[i], &fb, sizeof(fb)))
+			goto out;
+	}
+
+	ret = filter->len;
+out:
+	release_sock(sk);
+	return ret;
+}
diff --git a/net/core/sock.c b/net/core/sock.c
index 0a023b8..0628600 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1077,6 +1077,12 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 	case SO_BINDTODEVICE:
 		v.val = sk->sk_bound_dev_if;
 		break;
+	case SO_GET_FILTER:
+		len = sk_get_filter(sk, (struct sock_filter __user *)optval, len);
+		if (len < 0)
+			return len;
+
+		goto lenout;
 	default:
 		return -ENOPROTOOPT;
 	}

^ permalink raw reply related

* [net-next 6/6] e1000: fix concurrent accesses to PHY from watchdog and ethtool
From: Jeff Kirsher @ 2012-11-01 10:44 UTC (permalink / raw)
  To: davem; +Cc: Maxime Bizon, netdev, gospo, sassmann, Florian Fainelli,
	Jeff Kirsher
In-Reply-To: <1351766667-28489-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Maxime Bizon <mbizon@freebox.fr>

The e1000 driver currently does not protect concurrent accesses to the PHY
from both the ethtool callbacks, and from the e1000_watchdog function. This
patchs adds a new spinlock which is used by e1000_{read,write}_phy_reg in
order to serialize concurrent accesses to the PHY.

Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Signed-off-by: Florian Fainelli <ffainelli@freebox.fr>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000/e1000_hw.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c
index 3d68395..8fedd24 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -107,6 +107,7 @@ u16 e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = {
 };
 
 static DEFINE_SPINLOCK(e1000_eeprom_lock);
+static DEFINE_SPINLOCK(e1000_phy_lock);
 
 /**
  * e1000_set_phy_type - Set the phy type member in the hw struct.
@@ -2830,19 +2831,25 @@ static u16 e1000_shift_in_mdi_bits(struct e1000_hw *hw)
 s32 e1000_read_phy_reg(struct e1000_hw *hw, u32 reg_addr, u16 *phy_data)
 {
 	u32 ret_val;
+	unsigned long flags;
 
 	e_dbg("e1000_read_phy_reg");
 
+	spin_lock_irqsave(&e1000_phy_lock, flags);
+
 	if ((hw->phy_type == e1000_phy_igp) &&
 	    (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
 		ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
 						 (u16) reg_addr);
-		if (ret_val)
+		if (ret_val) {
+			spin_unlock_irqrestore(&e1000_phy_lock, flags);
 			return ret_val;
+		}
 	}
 
 	ret_val = e1000_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
 					phy_data);
+	spin_unlock_irqrestore(&e1000_phy_lock, flags);
 
 	return ret_val;
 }
@@ -2965,19 +2972,25 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
 s32 e1000_write_phy_reg(struct e1000_hw *hw, u32 reg_addr, u16 phy_data)
 {
 	u32 ret_val;
+	unsigned long flags;
 
 	e_dbg("e1000_write_phy_reg");
 
+	spin_lock_irqsave(&e1000_phy_lock, flags);
+
 	if ((hw->phy_type == e1000_phy_igp) &&
 	    (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
 		ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
 						 (u16) reg_addr);
-		if (ret_val)
+		if (ret_val) {
+			spin_unlock_irqrestore(&e1000_phy_lock, flags);
 			return ret_val;
+		}
 	}
 
 	ret_val = e1000_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
 					 phy_data);
+	spin_unlock_irqrestore(&e1000_phy_lock, flags);
 
 	return ret_val;
 }
-- 
1.7.11.7

^ permalink raw reply related

* [net-next 5/6] igb: Fix EEPROM writes via ethtool on i210
From: Jeff Kirsher @ 2012-11-01 10:44 UTC (permalink / raw)
  To: davem; +Cc: Carolyn Wyborny, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1351766667-28489-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Carolyn Wyborny <carolyn.wyborny@intel.com>

This patch fixes a problem where the driver would crash when trying to
write a word to the EEPROM on i210 devices.

Reported-by: Ekman Tsang <Ekman.Tsang@riverbed.com>
Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/igb/e1000_82575.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index 4313bcc..deb0597 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -319,6 +319,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
 		nvm->ops.acquire = igb_acquire_nvm_i210;
 		nvm->ops.release = igb_release_nvm_i210;
 		nvm->ops.read    = igb_read_nvm_srrd_i210;
+		nvm->ops.write   = igb_write_nvm_srwr_i210;
 		nvm->ops.valid_led_default = igb_valid_led_default_i210;
 		break;
 	case e1000_i211:
-- 
1.7.11.7

^ permalink raw reply related

* [net-next 4/6] igb: Add function to read i211's invm version
From: Jeff Kirsher @ 2012-11-01 10:44 UTC (permalink / raw)
  To: davem; +Cc: Carolyn Wyborny, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1351766667-28489-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Carolyn Wyborny <carolyn.wyborny@intel.com>

The i211's one-time programmable (invm) version field is different than the
other fields contained in it.  This patch adds a function to get the invm version
of it and store it for output from ethtool.

Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/igb/e1000_i210.c | 94 +++++++++++++++++++++++++++++
 drivers/net/ethernet/intel/igb/e1000_i210.h | 11 ++++
 drivers/net/ethernet/intel/igb/e1000_mac.h  |  1 +
 drivers/net/ethernet/intel/igb/e1000_nvm.c  |  1 +
 4 files changed, 107 insertions(+)

diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c
index 77a5f93..4147429 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.c
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.c
@@ -423,6 +423,100 @@ s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data)
 }
 
 /**
+ *  igb_read_invm_version - Reads iNVM version and image type
+ *  @hw: pointer to the HW structure
+ *  @invm_ver: version structure for the version read
+ *
+ *  Reads iNVM version and image type.
+ **/
+s32 igb_read_invm_version(struct e1000_hw *hw,
+			  struct e1000_fw_version *invm_ver) {
+	u32 *record = NULL;
+	u32 *next_record = NULL;
+	u32 i = 0;
+	u32 invm_dword = 0;
+	u32 invm_blocks = E1000_INVM_SIZE - (E1000_INVM_ULT_BYTES_SIZE /
+					     E1000_INVM_RECORD_SIZE_IN_BYTES);
+	u32 buffer[E1000_INVM_SIZE];
+	s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
+	u16 version = 0;
+
+	/* Read iNVM memory */
+	for (i = 0; i < E1000_INVM_SIZE; i++) {
+		invm_dword = rd32(E1000_INVM_DATA_REG(i));
+		buffer[i] = invm_dword;
+	}
+
+	/* Read version number */
+	for (i = 1; i < invm_blocks; i++) {
+		record = &buffer[invm_blocks - i];
+		next_record = &buffer[invm_blocks - i + 1];
+
+		/* Check if we have first version location used */
+		if ((i == 1) && ((*record & E1000_INVM_VER_FIELD_ONE) == 0)) {
+			version = 0;
+			status = E1000_SUCCESS;
+			break;
+		}
+		/* Check if we have second version location used */
+		else if ((i == 1) &&
+			 ((*record & E1000_INVM_VER_FIELD_TWO) == 0)) {
+			version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
+			status = E1000_SUCCESS;
+			break;
+		}
+		/* Check if we have odd version location
+		 * used and it is the last one used
+		 */
+		else if ((((*record & E1000_INVM_VER_FIELD_ONE) == 0) &&
+			 ((*record & 0x3) == 0)) || (((*record & 0x3) != 0) &&
+			 (i != 1))) {
+			version = (*next_record & E1000_INVM_VER_FIELD_TWO)
+				  >> 13;
+			status = E1000_SUCCESS;
+			break;
+		}
+		/* Check if we have even version location
+		 * used and it is the last one used
+		 */
+		else if (((*record & E1000_INVM_VER_FIELD_TWO) == 0) &&
+			 ((*record & 0x3) == 0)) {
+			version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
+			status = E1000_SUCCESS;
+			break;
+		}
+	}
+
+	if (status == E1000_SUCCESS) {
+		invm_ver->invm_major = (version & E1000_INVM_MAJOR_MASK)
+					>> E1000_INVM_MAJOR_SHIFT;
+		invm_ver->invm_minor = version & E1000_INVM_MINOR_MASK;
+	}
+	/* Read Image Type */
+	for (i = 1; i < invm_blocks; i++) {
+		record = &buffer[invm_blocks - i];
+		next_record = &buffer[invm_blocks - i + 1];
+
+		/* Check if we have image type in first location used */
+		if ((i == 1) && ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) {
+			invm_ver->invm_img_type = 0;
+			status = E1000_SUCCESS;
+			break;
+		}
+		/* Check if we have image type in first location used */
+		else if ((((*record & 0x3) == 0) &&
+			 ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) ||
+			 ((((*record & 0x3) != 0) && (i != 1)))) {
+			invm_ver->invm_img_type =
+				(*next_record & E1000_INVM_IMGTYPE_FIELD) >> 23;
+			status = E1000_SUCCESS;
+			break;
+		}
+	}
+	return status;
+}
+
+/**
  *  igb_validate_nvm_checksum_i210 - Validate EEPROM checksum
  *  @hw: pointer to the HW structure
  *
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h
index 5dc2bd3..974d235 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.h
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.h
@@ -43,6 +43,8 @@ extern void igb_release_nvm_i210(struct e1000_hw *hw);
 extern s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data);
 extern s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words,
 			       u16 *data);
+extern s32 igb_read_invm_version(struct e1000_hw *hw,
+				 struct e1000_fw_version *invm_ver);
 
 #define E1000_STM_OPCODE		0xDB00
 #define E1000_EEPROM_FLASH_SIZE_WORD	0x11
@@ -65,6 +67,15 @@ enum E1000_INVM_STRUCTURE_TYPE {
 
 #define E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS	8
 #define E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS	1
+#define E1000_INVM_ULT_BYTES_SIZE			8
+#define E1000_INVM_RECORD_SIZE_IN_BYTES			4
+#define E1000_INVM_VER_FIELD_ONE			0x1FF8
+#define E1000_INVM_VER_FIELD_TWO			0x7FE000
+#define E1000_INVM_IMGTYPE_FIELD			0x1F800000
+
+#define E1000_INVM_MAJOR_MASK		0x3F0
+#define E1000_INVM_MINOR_MASK		0xF
+#define E1000_INVM_MAJOR_SHIFT		4
 
 #define ID_LED_DEFAULT_I210		((ID_LED_OFF1_ON2  << 8) | \
 					 (ID_LED_OFF1_OFF2 <<  4) | \
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h
index cbddc4e..e2b2c4b 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.h
@@ -33,6 +33,7 @@
 #include "e1000_phy.h"
 #include "e1000_nvm.h"
 #include "e1000_defines.h"
+#include "e1000_i210.h"
 
 /*
  * Functions that should not be called directly from drivers but can be used
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index 54ff539..7db3f80 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
@@ -727,6 +727,7 @@ void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
 
 	switch (hw->mac.type) {
 	case e1000_i211:
+		igb_read_invm_version(hw, fw_vers);
 		return;
 	case e1000_82575:
 	case e1000_82576:
-- 
1.7.11.7

^ permalink raw reply related

* [net-next 3/6] igb: Remove workaround for EEE configuration on i210/I211
From: Jeff Kirsher @ 2012-11-01 10:44 UTC (permalink / raw)
  To: davem; +Cc: Carolyn Wyborny, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1351766667-28489-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Carolyn Wyborny <carolyn.wyborny@intel.com>

This patch removes a workaround that was needed on pre-release hardware.
Released hardware should not have this setting, but any devices that do
will get a warning message instead.

Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/igb/e1000_82575.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index ca4641e..4313bcc 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -2233,19 +2233,16 @@ s32 igb_set_eee_i350(struct e1000_hw *hw)
 
 	/* enable or disable per user setting */
 	if (!(hw->dev_spec._82575.eee_disable)) {
-		ipcnfg |= (E1000_IPCNFG_EEE_1G_AN |
-			E1000_IPCNFG_EEE_100M_AN);
-		eeer |= (E1000_EEER_TX_LPI_EN |
-			E1000_EEER_RX_LPI_EN |
+		u32 eee_su = rd32(E1000_EEE_SU);
+
+		ipcnfg |= (E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
+		eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
 			E1000_EEER_LPI_FC);
 
-		/* keep the LPI clock running before EEE is enabled */
-		if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) {
-			u32 eee_su;
-			eee_su = rd32(E1000_EEE_SU);
-			eee_su &= ~E1000_EEE_SU_LPI_CLK_STP;
-			wr32(E1000_EEE_SU, eee_su);
-		}
+		/* This bit should not be set in normal operation. */
+		if (eee_su & E1000_EEE_SU_LPI_CLK_STP)
+			hw_dbg("LPI Clock Stop Bit should not be set!\n");
+
 
 	} else {
 		ipcnfg &= ~(E1000_IPCNFG_EEE_1G_AN |
-- 
1.7.11.7

^ permalink raw reply related

* [net-next 2/6] ixgbe: fix default setting of TXDCTL.WTHRESH
From: Jeff Kirsher @ 2012-11-01 10:44 UTC (permalink / raw)
  To: davem; +Cc: Emil Tantilov, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1351766667-28489-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Emil Tantilov <emil.s.tantilov@intel.com>

The q_vector->itr check in ixgbe_configure_tx_ring() was done prior to it
being set, which resulted in TXDCTL.WTHRESH always being set to 1 on driver
load, while consequent resets would set it to 8.

This patch moves the setting of q_vector->itr in ixgbe_alloc_q_vector() to
make sure that TXDCTL.WTHRESH is set to 8 by default.

Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c  | 15 +++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 20 --------------------
 2 files changed, 15 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index 5e508b6..8c74f73 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -824,6 +824,21 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
 	/* initialize pointer to rings */
 	ring = q_vector->ring;
 
+	/* intialize ITR */
+	if (txr_count && !rxr_count) {
+		/* tx only vector */
+		if (adapter->tx_itr_setting == 1)
+			q_vector->itr = IXGBE_10K_ITR;
+		else
+			q_vector->itr = adapter->tx_itr_setting;
+	} else {
+		/* rx or rx/tx vector */
+		if (adapter->rx_itr_setting == 1)
+			q_vector->itr = IXGBE_20K_ITR;
+		else
+			q_vector->itr = adapter->rx_itr_setting;
+	}
+
 	while (txr_count) {
 		/* assign generic ring traits */
 		ring->dev = &adapter->pdev->dev;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 26bfaae..8b1a38b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1976,20 +1976,6 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
 		ixgbe_for_each_ring(ring, q_vector->tx)
 			ixgbe_set_ivar(adapter, 1, ring->reg_idx, v_idx);
 
-		if (q_vector->tx.ring && !q_vector->rx.ring) {
-			/* tx only vector */
-			if (adapter->tx_itr_setting == 1)
-				q_vector->itr = IXGBE_10K_ITR;
-			else
-				q_vector->itr = adapter->tx_itr_setting;
-		} else {
-			/* rx or rx/tx vector */
-			if (adapter->rx_itr_setting == 1)
-				q_vector->itr = IXGBE_20K_ITR;
-			else
-				q_vector->itr = adapter->rx_itr_setting;
-		}
-
 		ixgbe_write_eitr(q_vector);
 	}
 
@@ -2761,12 +2747,6 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_q_vector *q_vector = adapter->q_vector[0];
 
-	/* rx/tx vector */
-	if (adapter->rx_itr_setting == 1)
-		q_vector->itr = IXGBE_20K_ITR;
-	else
-		q_vector->itr = adapter->rx_itr_setting;
-
 	ixgbe_write_eitr(q_vector);
 
 	ixgbe_set_ivar(adapter, 0, 0, 0);
-- 
1.7.11.7

^ permalink raw reply related

* [net-next 0/6][pull request] Intel Wired LAN Driver Updates
From: Jeff Kirsher @ 2012-11-01 10:44 UTC (permalink / raw)
  To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann

This series contains updates to igb, ixgbe and e1000.

The following are changes since commit 810b6d7638a288216f99bd190470d67061c8bd88:
  Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next
and are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next master

Carolyn Wyborny (3):
  igb: Remove workaround for EEE configuration on i210/I211
  igb: Add function to read i211's invm version
  igb: Fix EEPROM writes via ethtool on i210

Emil Tantilov (1):
  ixgbe: fix default setting of TXDCTL.WTHRESH

Jacob Keller (1):
  ixgbe: fix uninitialized event.type in ixgbe_ptp_check_pps_event

Maxime Bizon (1):
  e1000: fix concurrent accesses to PHY from watchdog and ethtool

 drivers/net/ethernet/intel/e1000/e1000_hw.c   | 17 ++++-
 drivers/net/ethernet/intel/igb/e1000_82575.c  | 20 +++---
 drivers/net/ethernet/intel/igb/e1000_i210.c   | 94 +++++++++++++++++++++++++++
 drivers/net/ethernet/intel/igb/e1000_i210.h   | 11 ++++
 drivers/net/ethernet/intel/igb/e1000_mac.h    |  1 +
 drivers/net/ethernet/intel/igb/e1000_nvm.c    |  1 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c  | 15 +++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 20 ------
 drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c  |  9 +++
 9 files changed, 155 insertions(+), 33 deletions(-)

-- 
1.7.11.7

^ permalink raw reply

* [net-next 1/6] ixgbe: fix uninitialized event.type in ixgbe_ptp_check_pps_event
From: Jeff Kirsher @ 2012-11-01 10:44 UTC (permalink / raw)
  To: davem; +Cc: Jacob Keller, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1351766667-28489-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Jacob Keller <jacob.e.keller@intel.com>

This patch fixes a bug in ixgbe_ptp_check_pps_event where the type was
uninitialized and could cause unknown event outcomes.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index 842ba15..01d99af 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -387,6 +387,15 @@ void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr)
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct ptp_clock_event event;
 
+	event.type = PTP_CLOCK_PPS;
+
+	/* this check is necessary in case the interrupt was enabled via some
+	 * alternative means (ex. debug_fs). Better to check here than
+	 * everywhere that calls this function.
+	 */
+	if (!adapter->ptp_clock)
+		return;
+
 	switch (hw->mac.type) {
 	case ixgbe_mac_X540:
 		ptp_clock_event(adapter->ptp_clock, &event);
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH v2 RESEND 6/6] net: calxedaxgmac: ip align receive buffers
From: Rob Herring @ 2012-11-01 10:41 UTC (permalink / raw)
  To: netdev, davem; +Cc: eric.dumazet, Rob Herring
In-Reply-To: <1351766464-27354-1-git-send-email-robherring2@gmail.com>

From: Rob Herring <rob.herring@calxeda.com>

On gcc 4.7, we will get alignment traps in the ip stack if we don't align
the ip headers on receive. The h/w can support this, so use ip aligned
allocations.

Cut down the unnecessary padding on the allocation. The buffer can start on
any byte alignment, but the size including the begining offset must be 8
byte aligned. So the h/w buffer size must include the NET_IP_ALIGN offset.

Thanks to Eric Dumazet for the initial patch highlighting the padding issues.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
---
 drivers/net/ethernet/calxeda/xgmac.c |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 38eb1b2..855bf2b 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -665,6 +665,7 @@ static void xgmac_rx_refill(struct xgmac_priv *priv)
 {
 	struct xgmac_dma_desc *p;
 	dma_addr_t paddr;
+	int bufsz = priv->dev->mtu + ETH_HLEN + ETH_FCS_LEN;
 
 	while (dma_ring_space(priv->rx_head, priv->rx_tail, DMA_RX_RING_SZ) > 1) {
 		int entry = priv->rx_head;
@@ -673,13 +674,13 @@ static void xgmac_rx_refill(struct xgmac_priv *priv)
 		p = priv->dma_rx + entry;
 
 		if (priv->rx_skbuff[entry] == NULL) {
-			skb = netdev_alloc_skb(priv->dev, priv->dma_buf_sz);
+			skb = netdev_alloc_skb_ip_align(priv->dev, bufsz);
 			if (unlikely(skb == NULL))
 				break;
 
 			priv->rx_skbuff[entry] = skb;
 			paddr = dma_map_single(priv->device, skb->data,
-					       priv->dma_buf_sz, DMA_FROM_DEVICE);
+					       bufsz, DMA_FROM_DEVICE);
 			desc_set_buf_addr(p, paddr, priv->dma_buf_sz);
 		}
 
@@ -703,10 +704,10 @@ static int xgmac_dma_desc_rings_init(struct net_device *dev)
 	unsigned int bfsize;
 
 	/* Set the Buffer size according to the MTU;
-	 * indeed, in case of jumbo we need to bump-up the buffer sizes.
+	 * The total buffer size including any IP offset must be a multiple
+	 * of 8 bytes.
 	 */
-	bfsize = ALIGN(dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN + 64,
-		       64);
+	bfsize = ALIGN(dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN, 8);
 
 	netdev_dbg(priv->dev, "mtu [%d] bfsize [%d]\n", dev->mtu, bfsize);
 
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v2 RESEND 5/6] net: calxedaxgmac: rework transmit ring handling
From: Rob Herring @ 2012-11-01 10:41 UTC (permalink / raw)
  To: netdev, davem; +Cc: eric.dumazet, Rob Herring
In-Reply-To: <1351766464-27354-1-git-send-email-robherring2@gmail.com>

From: Rob Herring <rob.herring@calxeda.com>

Only generate tx interrupts on every ring size / 4 descriptors. Move the
netif_stop_queue call to the end of the xmit function rather than
checking at the beginning.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
---
 drivers/net/ethernet/calxeda/xgmac.c |   24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 4a1a06a..38eb1b2 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -211,7 +211,7 @@
 #define DMA_INTR_ENA_TIE	0x00000001	/* Transmit Interrupt */
 
 #define DMA_INTR_NORMAL		(DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
-				 DMA_INTR_ENA_TUE)
+				 DMA_INTR_ENA_TUE | DMA_INTR_ENA_TIE)
 
 #define DMA_INTR_ABNORMAL	(DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
 				 DMA_INTR_ENA_RWE | DMA_INTR_ENA_RSE | \
@@ -374,6 +374,7 @@ struct xgmac_priv {
 	struct sk_buff **tx_skbuff;
 	unsigned int tx_head;
 	unsigned int tx_tail;
+	int tx_irq_cnt;
 
 	void __iomem *base;
 	unsigned int dma_buf_sz;
@@ -886,7 +887,7 @@ static void xgmac_tx_complete(struct xgmac_priv *priv)
 	}
 
 	if (dma_ring_space(priv->tx_head, priv->tx_tail, DMA_TX_RING_SZ) >
-	    TX_THRESH)
+	    MAX_SKB_FRAGS)
 		netif_wake_queue(priv->dev);
 }
 
@@ -1057,19 +1058,15 @@ static netdev_tx_t xgmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	struct xgmac_priv *priv = netdev_priv(dev);
 	unsigned int entry;
 	int i;
+	u32 irq_flag;
 	int nfrags = skb_shinfo(skb)->nr_frags;
 	struct xgmac_dma_desc *desc, *first;
 	unsigned int desc_flags;
 	unsigned int len;
 	dma_addr_t paddr;
 
-	if (dma_ring_space(priv->tx_head, priv->tx_tail, DMA_TX_RING_SZ) <
-	    (nfrags + 1)) {
-		writel(DMA_INTR_DEFAULT_MASK | DMA_INTR_ENA_TIE,
-			priv->base + XGMAC_DMA_INTR_ENA);
-		netif_stop_queue(dev);
-		return NETDEV_TX_BUSY;
-	}
+	priv->tx_irq_cnt = (priv->tx_irq_cnt + 1) & (DMA_TX_RING_SZ/4 - 1);
+	irq_flag = priv->tx_irq_cnt ? 0 : TXDESC_INTERRUPT;
 
 	desc_flags = (skb->ip_summed == CHECKSUM_PARTIAL) ?
 		TXDESC_CSUM_ALL : 0;
@@ -1110,9 +1107,9 @@ static netdev_tx_t xgmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* Interrupt on completition only for the latest segment */
 	if (desc != first)
 		desc_set_tx_owner(desc, desc_flags |
-			TXDESC_LAST_SEG | TXDESC_INTERRUPT);
+			TXDESC_LAST_SEG | irq_flag);
 	else
-		desc_flags |= TXDESC_LAST_SEG | TXDESC_INTERRUPT;
+		desc_flags |= TXDESC_LAST_SEG | irq_flag;
 
 	/* Set owner on first desc last to avoid race condition */
 	wmb();
@@ -1121,6 +1118,9 @@ static netdev_tx_t xgmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	priv->tx_head = dma_ring_incr(entry, DMA_TX_RING_SZ);
 
 	writel(1, priv->base + XGMAC_DMA_TX_POLL);
+	if (dma_ring_space(priv->tx_head, priv->tx_tail, DMA_TX_RING_SZ) <
+	    MAX_SKB_FRAGS)
+		netif_stop_queue(dev);
 
 	return NETDEV_TX_OK;
 }
@@ -1397,7 +1397,7 @@ static irqreturn_t xgmac_interrupt(int irq, void *dev_id)
 	}
 
 	/* TX/RX NORMAL interrupts */
-	if (intr_status & (DMA_STATUS_RI | DMA_STATUS_TU)) {
+	if (intr_status & (DMA_STATUS_RI | DMA_STATUS_TU | DMA_STATUS_TI)) {
 		writel_relaxed(DMA_INTR_ABNORMAL, priv->base + XGMAC_DMA_INTR_ENA);
 		napi_schedule(&priv->napi);
 	}
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v2 RESEND 4/6] net: calxedaxgmac: drop some unnecessary register writes
From: Rob Herring @ 2012-11-01 10:41 UTC (permalink / raw)
  To: netdev, davem; +Cc: eric.dumazet, Rob Herring
In-Reply-To: <1351766464-27354-1-git-send-email-robherring2@gmail.com>

From: Rob Herring <rob.herring@calxeda.com>

The interrupts have already been cleared, so we don't need to clear them
again. Also, we could miss interrupts if they are cleared, but we don't
process the packet.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
---
 drivers/net/ethernet/calxeda/xgmac.c |    6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 117839e..4a1a06a 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -846,9 +846,6 @@ static void xgmac_free_dma_desc_rings(struct xgmac_priv *priv)
 static void xgmac_tx_complete(struct xgmac_priv *priv)
 {
 	int i;
-	void __iomem *ioaddr = priv->base;
-
-	writel(DMA_STATUS_TU | DMA_STATUS_NIS, ioaddr + XGMAC_DMA_STATUS);
 
 	while (dma_ring_cnt(priv->tx_head, priv->tx_tail, DMA_TX_RING_SZ)) {
 		unsigned int entry = priv->tx_tail;
@@ -1139,9 +1136,6 @@ static int xgmac_rx(struct xgmac_priv *priv, int limit)
 		struct sk_buff *skb;
 		int frame_len;
 
-		writel(DMA_STATUS_RI | DMA_STATUS_NIS,
-		       priv->base + XGMAC_DMA_STATUS);
-
 		entry = priv->rx_tail;
 		p = priv->dma_rx + entry;
 		if (desc_get_owner(p))
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v2 RESEND 3/6] net: calxedaxgmac: use relaxed i/o accessors in rx and tx paths
From: Rob Herring @ 2012-11-01 10:41 UTC (permalink / raw)
  To: netdev, davem; +Cc: eric.dumazet, Rob Herring
In-Reply-To: <1351766464-27354-1-git-send-email-robherring2@gmail.com>

From: Rob Herring <rob.herring@calxeda.com>

The standard readl/writel accessors involve a spinlock and cache sync
operation on ARM platforms with an outer cache. Only DMA triggering
accesses need this, so use the relaxed variants instead.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
---
 drivers/net/ethernet/calxeda/Kconfig |    2 +-
 drivers/net/ethernet/calxeda/xgmac.c |   12 ++++++------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/calxeda/Kconfig b/drivers/net/ethernet/calxeda/Kconfig
index aba435c..6a4ddf6 100644
--- a/drivers/net/ethernet/calxeda/Kconfig
+++ b/drivers/net/ethernet/calxeda/Kconfig
@@ -1,6 +1,6 @@
 config NET_CALXEDA_XGMAC
 	tristate "Calxeda 1G/10G XGMAC Ethernet driver"
-	depends on HAS_IOMEM
+	depends on HAS_IOMEM && ARM
 	select CRC32
 	help
 	  This is the driver for the XGMAC Ethernet IP block found on Calxeda
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 728fcef..117839e 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -1203,7 +1203,7 @@ static int xgmac_poll(struct napi_struct *napi, int budget)
 
 	if (work_done < budget) {
 		napi_complete(napi);
-		writel(DMA_INTR_DEFAULT_MASK, priv->base + XGMAC_DMA_INTR_ENA);
+		writel_relaxed(DMA_INTR_DEFAULT_MASK, priv->base + XGMAC_DMA_INTR_ENA);
 	}
 	return work_done;
 }
@@ -1348,7 +1348,7 @@ static irqreturn_t xgmac_pmt_interrupt(int irq, void *dev_id)
 	struct xgmac_priv *priv = netdev_priv(dev);
 	void __iomem *ioaddr = priv->base;
 
-	intr_status = readl(ioaddr + XGMAC_INT_STAT);
+	intr_status = readl_relaxed(ioaddr + XGMAC_INT_STAT);
 	if (intr_status & XGMAC_INT_STAT_PMT) {
 		netdev_dbg(priv->dev, "received Magic frame\n");
 		/* clear the PMT bits 5 and 6 by reading the PMT */
@@ -1366,9 +1366,9 @@ static irqreturn_t xgmac_interrupt(int irq, void *dev_id)
 	struct xgmac_extra_stats *x = &priv->xstats;
 
 	/* read the status register (CSR5) */
-	intr_status = readl(priv->base + XGMAC_DMA_STATUS);
-	intr_status &= readl(priv->base + XGMAC_DMA_INTR_ENA);
-	writel(intr_status, priv->base + XGMAC_DMA_STATUS);
+	intr_status = readl_relaxed(priv->base + XGMAC_DMA_STATUS);
+	intr_status &= readl_relaxed(priv->base + XGMAC_DMA_INTR_ENA);
+	writel_relaxed(intr_status, priv->base + XGMAC_DMA_STATUS);
 
 	/* It displays the DMA process states (CSR5 register) */
 	/* ABNORMAL interrupts */
@@ -1404,7 +1404,7 @@ static irqreturn_t xgmac_interrupt(int irq, void *dev_id)
 
 	/* TX/RX NORMAL interrupts */
 	if (intr_status & (DMA_STATUS_RI | DMA_STATUS_TU)) {
-		writel(DMA_INTR_ABNORMAL, priv->base + XGMAC_DMA_INTR_ENA);
+		writel_relaxed(DMA_INTR_ABNORMAL, priv->base + XGMAC_DMA_INTR_ENA);
 		napi_schedule(&priv->napi);
 	}
 
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v2 RESEND 2/6] net: calxedaxgmac: remove explicit rx dma buffer polling
From: Rob Herring @ 2012-11-01 10:41 UTC (permalink / raw)
  To: netdev, davem; +Cc: eric.dumazet, Rob Herring
In-Reply-To: <1351766464-27354-1-git-send-email-robherring2@gmail.com>

From: Rob Herring <rob.herring@calxeda.com>

New received frames will trigger the rx DMA to poll the DMA descriptors,
so there is no need to tell the h/w to poll. We also want to enable
dropping frames from the fifo when there is no buffer.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
---
 drivers/net/ethernet/calxeda/xgmac.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 7f5fd17..728fcef 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -966,7 +966,7 @@ static int xgmac_hw_init(struct net_device *dev)
 		ctrl |= XGMAC_CONTROL_IPC;
 	writel(ctrl, ioaddr + XGMAC_CONTROL);
 
-	writel(DMA_CONTROL_DFF | DMA_CONTROL_OSF, ioaddr + XGMAC_DMA_CONTROL);
+	writel(DMA_CONTROL_OSF, ioaddr + XGMAC_DMA_CONTROL);
 
 	/* Set the HW DMA mode and the COE */
 	writel(XGMAC_OMR_TSF | XGMAC_OMR_RFD | XGMAC_OMR_RFA |
@@ -1180,8 +1180,6 @@ static int xgmac_rx(struct xgmac_priv *priv, int limit)
 
 	xgmac_rx_refill(priv);
 
-	writel(1, priv->base + XGMAC_DMA_RX_POLL);
-
 	return count;
 }
 
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v2 RESEND 1/6] net: calxedaxgmac: enable operate on 2nd frame mode
From: Rob Herring @ 2012-11-01 10:40 UTC (permalink / raw)
  To: netdev, davem; +Cc: eric.dumazet, Rob Herring
In-Reply-To: <1351766464-27354-1-git-send-email-robherring2@gmail.com>

From: Rob Herring <rob.herring@calxeda.com>

Enable the tx dma to start reading the next frame while sending the current
frame.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
---
 drivers/net/ethernet/calxeda/xgmac.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 16814b3..7f5fd17 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -191,6 +191,7 @@
 #define DMA_CONTROL_ST		0x00002000	/* Start/Stop Transmission */
 #define DMA_CONTROL_SR		0x00000002	/* Start/Stop Receive */
 #define DMA_CONTROL_DFF		0x01000000	/* Disable flush of rx frames */
+#define DMA_CONTROL_OSF		0x00000004	/* Operate on 2nd tx frame */
 
 /* DMA Normal interrupt */
 #define DMA_INTR_ENA_NIE	0x00010000	/* Normal Summary */
@@ -965,8 +966,7 @@ static int xgmac_hw_init(struct net_device *dev)
 		ctrl |= XGMAC_CONTROL_IPC;
 	writel(ctrl, ioaddr + XGMAC_CONTROL);
 
-	value = DMA_CONTROL_DFF;
-	writel(value, ioaddr + XGMAC_DMA_CONTROL);
+	writel(DMA_CONTROL_DFF | DMA_CONTROL_OSF, ioaddr + XGMAC_DMA_CONTROL);
 
 	/* Set the HW DMA mode and the COE */
 	writel(XGMAC_OMR_TSF | XGMAC_OMR_RFD | XGMAC_OMR_RFA |
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v2 RESEND 0/6] Calxeda xgmac performance fixes
From: Rob Herring @ 2012-11-01 10:40 UTC (permalink / raw)
  To: netdev, davem; +Cc: eric.dumazet, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

This is a repost for 3.8 inclusion. Only patch 5 has changed from v1
and was previously posted.

This is a series of performance improvements to the xgmac driver. The
most significant changes are the alignment fixes to avoid alignment
traps on received frames and using relaxed i/o accessors.

Rob

Rob Herring (6):
  net: calxedaxgmac: enable operate on 2nd frame mode
  net: calxedaxgmac: remove explicit rx dma buffer polling
  net: calxedaxgmac: use relaxed i/o accessors in rx and tx paths
  net: calxedaxgmac: drop some unnecessary register writes
  net: calxedaxgmac: rework transmit ring handling
  net: calxedaxgmac: ip align receive buffers

 drivers/net/ethernet/calxeda/Kconfig |    2 +-
 drivers/net/ethernet/calxeda/xgmac.c |   59 +++++++++++++++-------------------
 2 files changed, 27 insertions(+), 34 deletions(-)

-- 
1.7.10.4

^ permalink raw reply

* Re: [Suggestion] net-ipv6: format %8s change to %16s in rt6_info_route function of route.c
From: Chen Gang @ 2012-11-01 10:23 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: linux-kernel@vger.kernel.org, netdev
In-Reply-To: <1351760482.32673.913.camel@edumazet-glaptop>

于 2012年11月01日 17:01, Eric Dumazet 写道:
> Hi Chen
> 
> Thats a good suggestion indeed.
> 

  thank you very much for your confirmation.

> Networking patches should be sent to netdev@vger.kernel.org (added in
> CC)

  I will do it.

> 
> This list only cares about recent generic kernels, not RedHat ones.
> 

  it seems "it is not suitable to send any issues which only relative
with Red Hat to linux-*@vger.kernel.org".



> If you want to provide a patch, please base it on David Miller net-next
> [1] tree, and make it official (read Documentation/SubmittingPatches for
> general advices)
> 

  ok, I will follow, thank you for your information.


> By the way, the %8s should be replaced by %s, there is no need to make
> /proc/net/ipv6_route 'beautiful'. In the past, it was *needed* because
> each line had to be of a given length, but its not anymore the case.
> 
> Thanks
> 

1) I agree with your result.

2) But for the "reason", I have my opinions:
   A) %.8s :  for limitation of output string length.
   B) %8s  :  for width of output string length (but not limit 8).
   C) %8.8s:  both limitation and width.

3) for rt->rt6i_dev->name:
   A) original %8s is not a bug for name len is more than 8 (can still
be outputted correctly)
   B) it is only effect with name len is less than 8 (it will fill some
' ' before the name)
   C) this is the reason why I call it "beautiful", not a bug.


> [1] :
> http://git.kernel.org/?p=linux/kernel/git/davem/net-next.git;a=summary
> 

  I will reference it, thanks.


-- 
Chen Gang

Asianux Corporation

^ permalink raw reply

* Re: [PATCH 4/9] net: openvswitch: use this_cpu_ptr per-cpu helper
From: Shan Wei @ 2012-11-01 10:07 UTC (permalink / raw)
  To: Christoph Lameter
  Cc: dev-yBygre7rU0TnMu66kgdUjQ, NetDev, Kernel-Maillist, David Miller
In-Reply-To: <0000013ab7e86f8a-4adb8b81-19be-4264-96f1-924aaf3819f2-000000-p/GC64/jrecnJqMo6gzdpkEOCMrvLtNR@public.gmane.org>

Christoph Lameter said, at 2012/11/1 1:39:
> On Wed, 31 Oct 2012, Shan Wei wrote:
> 
>> --- a/net/openvswitch/datapath.c
>> +++ b/net/openvswitch/datapath.c
>> @@ -208,7 +208,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
>>  	int error;
>>  	int key_len;
>>
>> -	stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id());
>> +	stats = this_cpu_ptr(dp->stats_percpu);
> 
> Well this is an improvement and may be ok if the preemption is disabled at
> this point. There is another possibility here to use this_cpu_read/add/inc
> instead of determining the pointer to the local cpu first and then
> performing operations on the fields. The pointer relocation with
> this_cpu_xxx ops is implicit in the instructions and safe against changing
> of processors. It would also save us the determination of a pointer to the
> current cpus stats structure.

yes, this_cpu_ptr just locate the point to current cpu per-cpu data domain.
and then operating [read/write/inc/sub] fields of this per-cpu variable
maybe on other cpu because task is rescheduled for preemption, interrupt.

But for different field in same per-cpu variable, how to guarantee n_missed
and n_hit are from same cpu? 
this_cpu_read(dp->stats_percpu->n_missed);
[processor changed]
this_cpu_read(dp->stats_percpu->n_hit);


In addition, following usage of per_cpu_ptr can be replaced by this_cpu_read.

cpu=get_cpu()
....
*per_cpu_ptr(p,cpu)
....
....
put_cpu()

^ permalink raw reply

* Re: [uclinux-dist-devel] [PATCH RFC net-next 2/4] bfin_mac: replace sys time stamps with raw ones instead.
From: Richard Cochran @ 2012-11-01  9:42 UTC (permalink / raw)
  To: Bob Liu
  Cc: netdev, Miroslav Lichvar, John Ronciak, John Stultz, Jeff Kirsher,
	device-drivers-devel, Jacob Keller, uclinux-dist-devel,
	Patrick Ohly, David Miller
In-Reply-To: <CAA_GA1e_NkFq49abibVtcyOcGp+AnP=yLbNPxmD3SdaAbWp+Jw@mail.gmail.com>

On Thu, Nov 01, 2012 at 05:39:01PM +0800, Bob Liu wrote:
> 
> Thank you very much.
> It works.

Thanks, Bob.

Can you add your Acked- or Tested-by to the V2 series that I posted?

Richard

^ permalink raw reply

* Re: [PATCH V2 net-next 2/4] bfin_mac: replace sys time stamps with raw ones instead.
From: Bob Liu @ 2012-11-01  9:41 UTC (permalink / raw)
  To: Richard Cochran
  Cc: netdev, device-drivers-devel, uclinux-dist-devel, David Miller,
	Jacob Keller, Jeff Kirsher, John Ronciak, John Stultz,
	Mike Frysinger, Sonic Zhang
In-Reply-To: <b3bfe20bd4477e751d2e2b543b513d781eb0dd44.1351696541.git.richardcochran@gmail.com>

On Thu, Nov 1, 2012 at 12:27 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> This patch replaces the sys time stamps and timecompare code with simple
> raw hardware time stamps in nanosecond resolution. The only tricky bit is
> to find a PTP Hardware Clock period slower than the input clock period
> and a power of two.
>
> Compile tested only.
>
> Signed-off-by: Richard Cochran <richardcochran@gmail.com>

Tested-by: Bob Liu <lliubbo@gmail.com>

> ---
>  drivers/net/ethernet/adi/bfin_mac.c |   91 ++++++++++-------------------------
>  drivers/net/ethernet/adi/bfin_mac.h |    7 +--
>  2 files changed, 28 insertions(+), 70 deletions(-)
>
> diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
> index 2349abb..885fa80 100644
> --- a/drivers/net/ethernet/adi/bfin_mac.c
> +++ b/drivers/net/ethernet/adi/bfin_mac.c
> @@ -555,7 +555,7 @@ static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
>         info->so_timestamping =
>                 SOF_TIMESTAMPING_TX_HARDWARE |
>                 SOF_TIMESTAMPING_RX_HARDWARE |
> -               SOF_TIMESTAMPING_SYS_HARDWARE;
> +               SOF_TIMESTAMPING_RAW_HARDWARE;
>         info->phc_index = -1;
>         info->tx_types =
>                 (1 << HWTSTAMP_TX_OFF) |
> @@ -653,6 +653,20 @@ static int bfin_mac_set_mac_address(struct net_device *dev, void *p)
>  #ifdef CONFIG_BFIN_MAC_USE_HWSTAMP
>  #define bfin_mac_hwtstamp_is_none(cfg) ((cfg) == HWTSTAMP_FILTER_NONE)
>
> +static u32 bfin_select_phc_clock(u32 input_clk, unsigned int *shift_result)
> +{
> +       u32 ipn = 1000000000UL / input_clk;
> +       u32 ppn = 1;
> +       unsigned int shift = 0;
> +
> +       while (ppn <= ipn) {
> +               ppn <<= 1;
> +               shift++;
> +       }
> +       *shift_result = shift;
> +       return 1000000000UL / ppn;
> +}
> +
>  static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
>                 struct ifreq *ifr, int cmd)
>  {
> @@ -802,19 +816,7 @@ static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
>                 bfin_read_EMAC_PTP_TXSNAPLO();
>                 bfin_read_EMAC_PTP_TXSNAPHI();
>
> -               /*
> -                * Set registers so that rollover occurs soon to test this.
> -                */
> -               bfin_write_EMAC_PTP_TIMELO(0x00000000);
> -               bfin_write_EMAC_PTP_TIMEHI(0xFF800000);
> -
>                 SSYNC();
> -
> -               lp->compare.last_update = 0;
> -               timecounter_init(&lp->clock,
> -                               &lp->cycles,
> -                               ktime_to_ns(ktime_get_real()));
> -               timecompare_update(&lp->compare, 0);
>         }
>
>         lp->stamp_cfg = config;
> @@ -822,15 +824,6 @@ static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
>                 -EFAULT : 0;
>  }
>
> -static void bfin_dump_hwtamp(char *s, ktime_t *hw, ktime_t *ts, struct timecompare *cmp)
> -{
> -       ktime_t sys = ktime_get_real();
> -
> -       pr_debug("%s %s hardware:%d,%d transform system:%d,%d system:%d,%d, cmp:%lld, %lld\n",
> -                       __func__, s, hw->tv.sec, hw->tv.nsec, ts->tv.sec, ts->tv.nsec, sys.tv.sec,
> -                       sys.tv.nsec, cmp->offset, cmp->skew);
> -}
> -
>  static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
>  {
>         struct bfin_mac_local *lp = netdev_priv(netdev);
> @@ -861,15 +854,9 @@ static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
>                         regval = bfin_read_EMAC_PTP_TXSNAPLO();
>                         regval |= (u64)bfin_read_EMAC_PTP_TXSNAPHI() << 32;
>                         memset(&shhwtstamps, 0, sizeof(shhwtstamps));
> -                       ns = timecounter_cyc2time(&lp->clock,
> -                                       regval);
> -                       timecompare_update(&lp->compare, ns);
> +                       ns = regval << lp->shift;
>                         shhwtstamps.hwtstamp = ns_to_ktime(ns);
> -                       shhwtstamps.syststamp =
> -                               timecompare_transform(&lp->compare, ns);
>                         skb_tstamp_tx(skb, &shhwtstamps);
> -
> -                       bfin_dump_hwtamp("TX", &shhwtstamps.hwtstamp, &shhwtstamps.syststamp, &lp->compare);
>                 }
>         }
>  }
> @@ -892,51 +879,25 @@ static void bfin_rx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
>
>         regval = bfin_read_EMAC_PTP_RXSNAPLO();
>         regval |= (u64)bfin_read_EMAC_PTP_RXSNAPHI() << 32;
> -       ns = timecounter_cyc2time(&lp->clock, regval);
> -       timecompare_update(&lp->compare, ns);
> +       ns = regval << lp->shift;
>         memset(shhwtstamps, 0, sizeof(*shhwtstamps));
>         shhwtstamps->hwtstamp = ns_to_ktime(ns);
> -       shhwtstamps->syststamp = timecompare_transform(&lp->compare, ns);
> -
> -       bfin_dump_hwtamp("RX", &shhwtstamps->hwtstamp, &shhwtstamps->syststamp, &lp->compare);
> -}
> -
> -/*
> - * bfin_read_clock - read raw cycle counter (to be used by time counter)
> - */
> -static cycle_t bfin_read_clock(const struct cyclecounter *tc)
> -{
> -       u64 stamp;
> -
> -       stamp =  bfin_read_EMAC_PTP_TIMELO();
> -       stamp |= (u64)bfin_read_EMAC_PTP_TIMEHI() << 32ULL;
> -
> -       return stamp;
>  }
>
> -#define PTP_CLK 25000000
> -
>  static void bfin_mac_hwtstamp_init(struct net_device *netdev)
>  {
>         struct bfin_mac_local *lp = netdev_priv(netdev);
> -       u64 append;
> +       u64 addend;
> +       u32 input_clk, phc_clk;
>
>         /* Initialize hardware timer */
> -       append = PTP_CLK * (1ULL << 32);
> -       do_div(append, get_sclk());
> -       bfin_write_EMAC_PTP_ADDEND((u32)append);
> -
> -       memset(&lp->cycles, 0, sizeof(lp->cycles));
> -       lp->cycles.read = bfin_read_clock;
> -       lp->cycles.mask = CLOCKSOURCE_MASK(64);
> -       lp->cycles.mult = 1000000000 / PTP_CLK;
> -       lp->cycles.shift = 0;
> -
> -       /* Synchronize our NIC clock against system wall clock */
> -       memset(&lp->compare, 0, sizeof(lp->compare));
> -       lp->compare.source = &lp->clock;
> -       lp->compare.target = ktime_get_real;
> -       lp->compare.num_samples = 10;
> +       input_clk = get_sclk();
> +       phc_clk = bfin_select_phc_clock(input_clk, &lp->shift);
> +       addend = phc_clk * (1ULL << 32);
> +       do_div(addend, input_clk);
> +       bfin_write_EMAC_PTP_ADDEND((u32)addend);
> +
> +       lp->addend = addend;
>
>         /* Initialize hwstamp config */
>         lp->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
> diff --git a/drivers/net/ethernet/adi/bfin_mac.h b/drivers/net/ethernet/adi/bfin_mac.h
> index 960905c..57f042c 100644
> --- a/drivers/net/ethernet/adi/bfin_mac.h
> +++ b/drivers/net/ethernet/adi/bfin_mac.h
> @@ -11,8 +11,6 @@
>  #define _BFIN_MAC_H_
>
>  #include <linux/net_tstamp.h>
> -#include <linux/clocksource.h>
> -#include <linux/timecompare.h>
>  #include <linux/timer.h>
>  #include <linux/etherdevice.h>
>  #include <linux/bfin_mac.h>
> @@ -94,9 +92,8 @@ struct bfin_mac_local {
>         struct mii_bus *mii_bus;
>
>  #if defined(CONFIG_BFIN_MAC_USE_HWSTAMP)
> -       struct cyclecounter cycles;
> -       struct timecounter clock;
> -       struct timecompare compare;
> +       u32 addend;
> +       unsigned int shift;
>         struct hwtstamp_config stamp_cfg;
>  #endif
>  };
> --
> 1.7.2.5
>



-- 
Regards,
--Bob

^ permalink raw reply

* Re: [PATCH V2 net-next 4/4] time: remove the timecompare code.
From: Bob Liu @ 2012-11-01  9:41 UTC (permalink / raw)
  To: Richard Cochran
  Cc: netdev, device-drivers-devel, uclinux-dist-devel, David Miller,
	Jacob Keller, Jeff Kirsher, John Ronciak, John Stultz,
	Mike Frysinger, Sonic Zhang
In-Reply-To: <962c27259144108f7f7033bb30ad9fa49630a9ce.1351696541.git.richardcochran@gmail.com>

On Thu, Nov 1, 2012 at 12:27 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> This patch removes the timecompare code from the kernel. The top five
> reasons to do this are:
>
> 1. There are no more users of this code.
> 2. The original idea was a bit weak.
> 3. The original author has disappeared.
> 4. The code was not general purpose but tuned to a particular hardware,
> 5. There are better ways to accomplish clock synchronization.
>
> Signed-off-by: Richard Cochran <richardcochran@gmail.com>

Tested-by: Bob Liu <lliubbo@gmail.com>

> Acked-by: John Stultz <john.stultz@linaro.org>
> ---
>  include/linux/timecompare.h |  125 ----------------------------
>  kernel/time/Makefile        |    2 +-
>  kernel/time/timecompare.c   |  193 -------------------------------------------
>  3 files changed, 1 insertions(+), 319 deletions(-)
>  delete mode 100644 include/linux/timecompare.h
>  delete mode 100644 kernel/time/timecompare.c
>
> diff --git a/include/linux/timecompare.h b/include/linux/timecompare.h
> deleted file mode 100644
> index 546e223..0000000
> --- a/include/linux/timecompare.h
> +++ /dev/null
> @@ -1,125 +0,0 @@
> -/*
> - * Utility code which helps transforming between two different time
> - * bases, called "source" and "target" time in this code.
> - *
> - * Source time has to be provided via the timecounter API while target
> - * time is accessed via a function callback whose prototype
> - * intentionally matches ktime_get() and ktime_get_real(). These
> - * interfaces where chosen like this so that the code serves its
> - * initial purpose without additional glue code.
> - *
> - * This purpose is synchronizing a hardware clock in a NIC with system
> - * time, in order to implement the Precision Time Protocol (PTP,
> - * IEEE1588) with more accurate hardware assisted time stamping.  In
> - * that context only synchronization against system time (=
> - * ktime_get_real()) is currently needed. But this utility code might
> - * become useful in other situations, which is why it was written as
> - * general purpose utility code.
> - *
> - * The source timecounter is assumed to return monotonically
> - * increasing time (but this code does its best to compensate if that
> - * is not the case) whereas target time may jump.
> - *
> - * The target time corresponding to a source time is determined by
> - * reading target time, reading source time, reading target time
> - * again, then assuming that average target time corresponds to source
> - * time. In other words, the assumption is that reading the source
> - * time is slow and involves equal time for sending the request and
> - * receiving the reply, whereas reading target time is assumed to be
> - * fast.
> - *
> - * Copyright (C) 2009 Intel Corporation.
> - * Author: Patrick Ohly <patrick.ohly@intel.com>
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms and conditions of the GNU General Public License,
> - * version 2, as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope 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 _LINUX_TIMECOMPARE_H
> -#define _LINUX_TIMECOMPARE_H
> -
> -#include <linux/clocksource.h>
> -#include <linux/ktime.h>
> -
> -/**
> - * struct timecompare - stores state and configuration for the two clocks
> - *
> - * Initialize to zero, then set source/target/num_samples.
> - *
> - * Transformation between source time and target time is done with:
> - * target_time = source_time + offset +
> - *               (source_time - last_update) * skew /
> - *               TIMECOMPARE_SKEW_RESOLUTION
> - *
> - * @source:          used to get source time stamps via timecounter_read()
> - * @target:          function returning target time (for example, ktime_get
> - *                   for monotonic time, or ktime_get_real for wall clock)
> - * @num_samples:     number of times that source time and target time are to
> - *                   be compared when determining their offset
> - * @offset:          (target time - source time) at the time of the last update
> - * @skew:            average (target time - source time) / delta source time *
> - *                   TIMECOMPARE_SKEW_RESOLUTION
> - * @last_update:     last source time stamp when time offset was measured
> - */
> -struct timecompare {
> -       struct timecounter *source;
> -       ktime_t (*target)(void);
> -       int num_samples;
> -
> -       s64 offset;
> -       s64 skew;
> -       u64 last_update;
> -};
> -
> -/**
> - * timecompare_transform - transform source time stamp into target time base
> - * @sync:            context for time sync
> - * @source_tstamp:   the result of timecounter_read() or
> - *                   timecounter_cyc2time()
> - */
> -extern ktime_t timecompare_transform(struct timecompare *sync,
> -                                    u64 source_tstamp);
> -
> -/**
> - * timecompare_offset - measure current (target time - source time) offset
> - * @sync:            context for time sync
> - * @offset:          average offset during sample period returned here
> - * @source_tstamp:   average source time during sample period returned here
> - *
> - * Returns number of samples used. Might be zero (= no result) in the
> - * unlikely case that target time was monotonically decreasing for all
> - * samples (= broken).
> - */
> -extern int timecompare_offset(struct timecompare *sync,
> -                             s64 *offset,
> -                             u64 *source_tstamp);
> -
> -extern void __timecompare_update(struct timecompare *sync,
> -                                u64 source_tstamp);
> -
> -/**
> - * timecompare_update - update offset and skew by measuring current offset
> - * @sync:            context for time sync
> - * @source_tstamp:   the result of timecounter_read() or
> - *                   timecounter_cyc2time(), pass zero to force update
> - *
> - * Updates are only done at most once per second.
> - */
> -static inline void timecompare_update(struct timecompare *sync,
> -                                     u64 source_tstamp)
> -{
> -       if (!source_tstamp ||
> -           (s64)(source_tstamp - sync->last_update) >= NSEC_PER_SEC)
> -               __timecompare_update(sync, source_tstamp);
> -}
> -
> -#endif /* _LINUX_TIMECOMPARE_H */
> diff --git a/kernel/time/Makefile b/kernel/time/Makefile
> index e2fd74b..ff7d9d2 100644
> --- a/kernel/time/Makefile
> +++ b/kernel/time/Makefile
> @@ -1,4 +1,4 @@
> -obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o
> +obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
>  obj-y += timeconv.o posix-clock.o alarmtimer.o
>
>  obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)                += clockevents.o
> diff --git a/kernel/time/timecompare.c b/kernel/time/timecompare.c
> deleted file mode 100644
> index a9ae369..0000000
> --- a/kernel/time/timecompare.c
> +++ /dev/null
> @@ -1,193 +0,0 @@
> -/*
> - * Copyright (C) 2009 Intel Corporation.
> - * Author: Patrick Ohly <patrick.ohly@intel.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., 675 Mass Ave, Cambridge, MA 02139, USA.
> - */
> -
> -#include <linux/timecompare.h>
> -#include <linux/module.h>
> -#include <linux/slab.h>
> -#include <linux/math64.h>
> -#include <linux/kernel.h>
> -
> -/*
> - * fixed point arithmetic scale factor for skew
> - *
> - * Usually one would measure skew in ppb (parts per billion, 1e9), but
> - * using a factor of 2 simplifies the math.
> - */
> -#define TIMECOMPARE_SKEW_RESOLUTION (((s64)1)<<30)
> -
> -ktime_t timecompare_transform(struct timecompare *sync,
> -                             u64 source_tstamp)
> -{
> -       u64 nsec;
> -
> -       nsec = source_tstamp + sync->offset;
> -       nsec += (s64)(source_tstamp - sync->last_update) * sync->skew /
> -               TIMECOMPARE_SKEW_RESOLUTION;
> -
> -       return ns_to_ktime(nsec);
> -}
> -EXPORT_SYMBOL_GPL(timecompare_transform);
> -
> -int timecompare_offset(struct timecompare *sync,
> -                      s64 *offset,
> -                      u64 *source_tstamp)
> -{
> -       u64 start_source = 0, end_source = 0;
> -       struct {
> -               s64 offset;
> -               s64 duration_target;
> -       } buffer[10], sample, *samples;
> -       int counter = 0, i;
> -       int used;
> -       int index;
> -       int num_samples = sync->num_samples;
> -
> -       if (num_samples > ARRAY_SIZE(buffer)) {
> -               samples = kmalloc(sizeof(*samples) * num_samples, GFP_ATOMIC);
> -               if (!samples) {
> -                       samples = buffer;
> -                       num_samples = ARRAY_SIZE(buffer);
> -               }
> -       } else {
> -               samples = buffer;
> -       }
> -
> -       /* run until we have enough valid samples, but do not try forever */
> -       i = 0;
> -       counter = 0;
> -       while (1) {
> -               u64 ts;
> -               ktime_t start, end;
> -
> -               start = sync->target();
> -               ts = timecounter_read(sync->source);
> -               end = sync->target();
> -
> -               if (!i)
> -                       start_source = ts;
> -
> -               /* ignore negative durations */
> -               sample.duration_target = ktime_to_ns(ktime_sub(end, start));
> -               if (sample.duration_target >= 0) {
> -                       /*
> -                        * assume symetric delay to and from source:
> -                        * average target time corresponds to measured
> -                        * source time
> -                        */
> -                       sample.offset =
> -                               (ktime_to_ns(end) + ktime_to_ns(start)) / 2 -
> -                               ts;
> -
> -                       /* simple insertion sort based on duration */
> -                       index = counter - 1;
> -                       while (index >= 0) {
> -                               if (samples[index].duration_target <
> -                                   sample.duration_target)
> -                                       break;
> -                               samples[index + 1] = samples[index];
> -                               index--;
> -                       }
> -                       samples[index + 1] = sample;
> -                       counter++;
> -               }
> -
> -               i++;
> -               if (counter >= num_samples || i >= 100000) {
> -                       end_source = ts;
> -                       break;
> -               }
> -       }
> -
> -       *source_tstamp = (end_source + start_source) / 2;
> -
> -       /* remove outliers by only using 75% of the samples */
> -       used = counter * 3 / 4;
> -       if (!used)
> -               used = counter;
> -       if (used) {
> -               /* calculate average */
> -               s64 off = 0;
> -               for (index = 0; index < used; index++)
> -                       off += samples[index].offset;
> -               *offset = div_s64(off, used);
> -       }
> -
> -       if (samples && samples != buffer)
> -               kfree(samples);
> -
> -       return used;
> -}
> -EXPORT_SYMBOL_GPL(timecompare_offset);
> -
> -void __timecompare_update(struct timecompare *sync,
> -                         u64 source_tstamp)
> -{
> -       s64 offset;
> -       u64 average_time;
> -
> -       if (!timecompare_offset(sync, &offset, &average_time))
> -               return;
> -
> -       if (!sync->last_update) {
> -               sync->last_update = average_time;
> -               sync->offset = offset;
> -               sync->skew = 0;
> -       } else {
> -               s64 delta_nsec = average_time - sync->last_update;
> -
> -               /* avoid division by negative or small deltas */
> -               if (delta_nsec >= 10000) {
> -                       s64 delta_offset_nsec = offset - sync->offset;
> -                       s64 skew; /* delta_offset_nsec *
> -                                    TIMECOMPARE_SKEW_RESOLUTION /
> -                                    delta_nsec */
> -                       u64 divisor;
> -
> -                       /* div_s64() is limited to 32 bit divisor */
> -                       skew = delta_offset_nsec * TIMECOMPARE_SKEW_RESOLUTION;
> -                       divisor = delta_nsec;
> -                       while (unlikely(divisor >= ((s64)1) << 32)) {
> -                               /* divide both by 2; beware, right shift
> -                                  of negative value has undefined
> -                                  behavior and can only be used for
> -                                  the positive divisor */
> -                               skew = div_s64(skew, 2);
> -                               divisor >>= 1;
> -                       }
> -                       skew = div_s64(skew, divisor);
> -
> -                       /*
> -                        * Calculate new overall skew as 4/16 the
> -                        * old value and 12/16 the new one. This is
> -                        * a rather arbitrary tradeoff between
> -                        * only using the latest measurement (0/16 and
> -                        * 16/16) and even more weight on past measurements.
> -                        */
> -#define TIMECOMPARE_NEW_SKEW_PER_16 12
> -                       sync->skew =
> -                               div_s64((16 - TIMECOMPARE_NEW_SKEW_PER_16) *
> -                                       sync->skew +
> -                                       TIMECOMPARE_NEW_SKEW_PER_16 * skew,
> -                                       16);
> -                       sync->last_update = average_time;
> -                       sync->offset = offset;
> -               }
> -       }
> -}
> -EXPORT_SYMBOL_GPL(__timecompare_update);
> --
> 1.7.2.5
>



-- 
Regards,
--Bob

^ permalink raw reply

* Re: [PATCH V2 net-next 3/4] bfin_mac: offer a PTP Hardware Clock.
From: Bob Liu @ 2012-11-01  9:40 UTC (permalink / raw)
  To: Richard Cochran
  Cc: netdev, device-drivers-devel, uclinux-dist-devel, David Miller,
	Jacob Keller, Jeff Kirsher, John Ronciak, John Stultz,
	Mike Frysinger, Sonic Zhang
In-Reply-To: <6525f9eba3712d3c11744f061b022cc4038d260f.1351696541.git.richardcochran@gmail.com>

On Thu, Nov 1, 2012 at 12:27 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> The BF518 has a PTP time unit that works in a similar way to other MAC
> based clocks, like gianfar, ixp46x, and igb. This patch adds support for
> using the blackfin as a PHC. Although the blackfin hardware does offer a
> few ancillary features, this patch implements only the basic operations.
>
> Compile tested only.
>
> Signed-off-by: Richard Cochran <richardcochran@gmail.com>

Tested-by: Bob Liu <lliubbo@gmail.com>

> ---
>  drivers/net/ethernet/adi/Kconfig    |    2 +-
>  drivers/net/ethernet/adi/bfin_mac.c |  170 ++++++++++++++++++++++++++++++++++-
>  drivers/net/ethernet/adi/bfin_mac.h |    6 ++
>  3 files changed, 175 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig
> index 49a30d3..175c38c 100644
> --- a/drivers/net/ethernet/adi/Kconfig
> +++ b/drivers/net/ethernet/adi/Kconfig
> @@ -61,7 +61,7 @@ config BFIN_RX_DESC_NUM
>
>  config BFIN_MAC_USE_HWSTAMP
>         bool "Use IEEE 1588 hwstamp"
> -       depends on BFIN_MAC && BF518
> +       depends on BFIN_MAC && BF518 && PTP_1588_CLOCK && !(BFIN_MAC=y && PTP_1588_CLOCK=m)
>         default y
>         ---help---
>           To support the IEEE 1588 Precision Time Protocol (PTP), select y here
> diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
> index 885fa80..f1c458d 100644
> --- a/drivers/net/ethernet/adi/bfin_mac.c
> +++ b/drivers/net/ethernet/adi/bfin_mac.c
> @@ -552,11 +552,13 @@ static int bfin_mac_ethtool_setwol(struct net_device *dev,
>  static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
>         struct ethtool_ts_info *info)
>  {
> +       struct bfin_mac_local *lp = netdev_priv(dev);
> +
>         info->so_timestamping =
>                 SOF_TIMESTAMPING_TX_HARDWARE |
>                 SOF_TIMESTAMPING_RX_HARDWARE |
>                 SOF_TIMESTAMPING_RAW_HARDWARE;
> -       info->phc_index = -1;
> +       info->phc_index = lp->phc_index;
>         info->tx_types =
>                 (1 << HWTSTAMP_TX_OFF) |
>                 (1 << HWTSTAMP_TX_ON);
> @@ -887,7 +889,7 @@ static void bfin_rx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
>  static void bfin_mac_hwtstamp_init(struct net_device *netdev)
>  {
>         struct bfin_mac_local *lp = netdev_priv(netdev);
> -       u64 addend;
> +       u64 addend, ppb;
>         u32 input_clk, phc_clk;
>
>         /* Initialize hardware timer */
> @@ -898,18 +900,175 @@ static void bfin_mac_hwtstamp_init(struct net_device *netdev)
>         bfin_write_EMAC_PTP_ADDEND((u32)addend);
>
>         lp->addend = addend;
> +       ppb = 1000000000ULL * input_clk;
> +       do_div(ppb, phc_clk);
> +       lp->max_ppb = ppb - 1000000000ULL - 1ULL;
>
>         /* Initialize hwstamp config */
>         lp->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
>         lp->stamp_cfg.tx_type = HWTSTAMP_TX_OFF;
>  }
>
> +static u64 bfin_ptp_time_read(struct bfin_mac_local *lp)
> +{
> +       u64 ns;
> +       u32 lo, hi;
> +
> +       lo = bfin_read_EMAC_PTP_TIMELO();
> +       hi = bfin_read_EMAC_PTP_TIMEHI();
> +
> +       ns = ((u64) hi) << 32;
> +       ns |= lo;
> +       ns <<= lp->shift;
> +
> +       return ns;
> +}
> +
> +static void bfin_ptp_time_write(struct bfin_mac_local *lp, u64 ns)
> +{
> +       u32 hi, lo;
> +
> +       ns >>= lp->shift;
> +       hi = ns >> 32;
> +       lo = ns & 0xffffffff;
> +
> +       bfin_write_EMAC_PTP_TIMELO(lo);
> +       bfin_write_EMAC_PTP_TIMEHI(hi);
> +}
> +
> +/* PTP Hardware Clock operations */
> +
> +static int bfin_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
> +{
> +       u64 adj;
> +       u32 diff, addend;
> +       int neg_adj = 0;
> +       struct bfin_mac_local *lp =
> +               container_of(ptp, struct bfin_mac_local, caps);
> +
> +       if (ppb < 0) {
> +               neg_adj = 1;
> +               ppb = -ppb;
> +       }
> +       addend = lp->addend;
> +       adj = addend;
> +       adj *= ppb;
> +       diff = div_u64(adj, 1000000000ULL);
> +
> +       addend = neg_adj ? addend - diff : addend + diff;
> +
> +       bfin_write_EMAC_PTP_ADDEND(addend);
> +
> +       return 0;
> +}
> +
> +static int bfin_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
> +{
> +       s64 now;
> +       unsigned long flags;
> +       struct bfin_mac_local *lp =
> +               container_of(ptp, struct bfin_mac_local, caps);
> +
> +       spin_lock_irqsave(&lp->phc_lock, flags);
> +
> +       now = bfin_ptp_time_read(lp);
> +       now += delta;
> +       bfin_ptp_time_write(lp, now);
> +
> +       spin_unlock_irqrestore(&lp->phc_lock, flags);
> +
> +       return 0;
> +}
> +
> +static int bfin_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
> +{
> +       u64 ns;
> +       u32 remainder;
> +       unsigned long flags;
> +       struct bfin_mac_local *lp =
> +               container_of(ptp, struct bfin_mac_local, caps);
> +
> +       spin_lock_irqsave(&lp->phc_lock, flags);
> +
> +       ns = bfin_ptp_time_read(lp);
> +
> +       spin_unlock_irqrestore(&lp->phc_lock, flags);
> +
> +       ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
> +       ts->tv_nsec = remainder;
> +       return 0;
> +}
> +
> +static int bfin_ptp_settime(struct ptp_clock_info *ptp,
> +                          const struct timespec *ts)
> +{
> +       u64 ns;
> +       unsigned long flags;
> +       struct bfin_mac_local *lp =
> +               container_of(ptp, struct bfin_mac_local, caps);
> +
> +       ns = ts->tv_sec * 1000000000ULL;
> +       ns += ts->tv_nsec;
> +
> +       spin_lock_irqsave(&lp->phc_lock, flags);
> +
> +       bfin_ptp_time_write(lp, ns);
> +
> +       spin_unlock_irqrestore(&lp->phc_lock, flags);
> +
> +       return 0;
> +}
> +
> +static int bfin_ptp_enable(struct ptp_clock_info *ptp,
> +                         struct ptp_clock_request *rq, int on)
> +{
> +       return -EOPNOTSUPP;
> +}
> +
> +static struct ptp_clock_info bfin_ptp_caps = {
> +       .owner          = THIS_MODULE,
> +       .name           = "BF518 clock",
> +       .max_adj        = 0,
> +       .n_alarm        = 0,
> +       .n_ext_ts       = 0,
> +       .n_per_out      = 0,
> +       .pps            = 0,
> +       .adjfreq        = bfin_ptp_adjfreq,
> +       .adjtime        = bfin_ptp_adjtime,
> +       .gettime        = bfin_ptp_gettime,
> +       .settime        = bfin_ptp_settime,
> +       .enable         = bfin_ptp_enable,
> +};
> +
> +static int bfin_phc_init(struct net_device *netdev, struct device *dev)
> +{
> +       struct bfin_mac_local *lp = netdev_priv(netdev);
> +
> +       lp->caps = bfin_ptp_caps;
> +       lp->caps.max_adj = lp->max_ppb;
> +       lp->clock = ptp_clock_register(&lp->caps, dev);
> +       if (IS_ERR(lp->clock))
> +               return PTR_ERR(lp->clock);
> +
> +       lp->phc_index = ptp_clock_index(lp->clock);
> +       spin_lock_init(&lp->phc_lock);
> +
> +       return 0;
> +}
> +
> +static void bfin_phc_release(struct bfin_mac_local *lp)
> +{
> +       ptp_clock_unregister(lp->clock);
> +}
> +
>  #else
>  # define bfin_mac_hwtstamp_is_none(cfg) 0
>  # define bfin_mac_hwtstamp_init(dev)
>  # define bfin_mac_hwtstamp_ioctl(dev, ifr, cmd) (-EOPNOTSUPP)
>  # define bfin_rx_hwtstamp(dev, skb)
>  # define bfin_tx_hwtstamp(dev, skb)
> +# define bfin_phc_init(netdev, dev) 0
> +# define bfin_phc_release(lp)
>  #endif
>
>  static inline void _tx_reclaim_skb(void)
> @@ -1544,12 +1703,17 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
>         }
>
>         bfin_mac_hwtstamp_init(ndev);
> +       if (bfin_phc_init(ndev, &pdev->dev)) {
> +               dev_err(&pdev->dev, "Cannot register PHC device!\n");
> +               goto out_err_phc;
> +       }
>
>         /* now, print out the card info, in a short format.. */
>         netdev_info(ndev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
>
>         return 0;
>
> +out_err_phc:
>  out_err_reg_ndev:
>         free_irq(IRQ_MAC_RX, ndev);
>  out_err_request_irq:
> @@ -1568,6 +1732,8 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev)
>         struct net_device *ndev = platform_get_drvdata(pdev);
>         struct bfin_mac_local *lp = netdev_priv(ndev);
>
> +       bfin_phc_release(lp);
> +
>         platform_set_drvdata(pdev, NULL);
>
>         lp->mii_bus->priv = NULL;
> diff --git a/drivers/net/ethernet/adi/bfin_mac.h b/drivers/net/ethernet/adi/bfin_mac.h
> index 57f042c..7a07ee0 100644
> --- a/drivers/net/ethernet/adi/bfin_mac.h
> +++ b/drivers/net/ethernet/adi/bfin_mac.h
> @@ -11,6 +11,7 @@
>  #define _BFIN_MAC_H_
>
>  #include <linux/net_tstamp.h>
> +#include <linux/ptp_clock_kernel.h>
>  #include <linux/timer.h>
>  #include <linux/etherdevice.h>
>  #include <linux/bfin_mac.h>
> @@ -94,7 +95,12 @@ struct bfin_mac_local {
>  #if defined(CONFIG_BFIN_MAC_USE_HWSTAMP)
>         u32 addend;
>         unsigned int shift;
> +       s32 max_ppb;
>         struct hwtstamp_config stamp_cfg;
> +       struct ptp_clock_info caps;
> +       struct ptp_clock *clock;
> +       int phc_index;
> +       spinlock_t phc_lock; /* protects time lo/hi registers */
>  #endif
>  };
>
> --
> 1.7.2.5
>



-- 
Regards,
--Bob

^ permalink raw reply

* Re: [PATCH V2 net-next 1/4] bfin_mac: only advertise hardware time stamped when enabled.
From: Bob Liu @ 2012-11-01  9:40 UTC (permalink / raw)
  To: Richard Cochran
  Cc: netdev, device-drivers-devel, uclinux-dist-devel, David Miller,
	Jacob Keller, Jeff Kirsher, John Ronciak, John Stultz,
	Mike Frysinger, Sonic Zhang
In-Reply-To: <e9f363ffac9c59b5174b4bf89a157e0dfeb151bb.1351696541.git.richardcochran@gmail.com>

On Thu, Nov 1, 2012 at 12:27 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> The hardware time stamping code is a compile time option for the blackfin.
> When it is not enabled, the driver should fall back to the standard
> ethtool reply to the get_ts_info query.
>
> Compile tested only.
>
> Signed-off-by: Richard Cochran <richardcochran@gmail.com>

Tested-by: Bob Liu <lliubbo@gmail.com>

> ---
>  drivers/net/ethernet/adi/bfin_mac.c |    4 ++++
>  1 files changed, 4 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
> index f816426..2349abb 100644
> --- a/drivers/net/ethernet/adi/bfin_mac.c
> +++ b/drivers/net/ethernet/adi/bfin_mac.c
> @@ -548,6 +548,7 @@ static int bfin_mac_ethtool_setwol(struct net_device *dev,
>         return 0;
>  }
>
> +#ifdef CONFIG_BFIN_MAC_USE_HWSTAMP
>  static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
>         struct ethtool_ts_info *info)
>  {
> @@ -566,6 +567,7 @@ static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
>                 (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
>         return 0;
>  }
> +#endif
>
>  static const struct ethtool_ops bfin_mac_ethtool_ops = {
>         .get_settings = bfin_mac_ethtool_getsettings,
> @@ -574,7 +576,9 @@ static const struct ethtool_ops bfin_mac_ethtool_ops = {
>         .get_drvinfo = bfin_mac_ethtool_getdrvinfo,
>         .get_wol = bfin_mac_ethtool_getwol,
>         .set_wol = bfin_mac_ethtool_setwol,
> +#ifdef CONFIG_BFIN_MAC_USE_HWSTAMP
>         .get_ts_info = bfin_mac_ethtool_get_ts_info,
> +#endif
>  };
>
>  /**************************************************************************/
> --
> 1.7.2.5
>

-- 
Regards,
--Bob

^ permalink raw reply

* Re: [PATCH RFC net-next 2/4] bfin_mac: replace sys time stamps with raw ones instead.
From: Bob Liu @ 2012-11-01  9:39 UTC (permalink / raw)
  To: Richard Cochran
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, Miroslav Lichvar, John Ronciak,
	John Stultz, Jeff Kirsher,
	device-drivers-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b,
	Jacob Keller, uclinux-dist-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b,
	Patrick Ohly, David Miller
In-Reply-To: <20121101093540.GB5949-TJb37gCd1q6chkuNt9O67llkmcu1nq/N@public.gmane.org>

On Thu, Nov 1, 2012 at 5:35 PM, Richard Cochran
<richardcochran-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Thu, Nov 01, 2012 at 04:54:30PM +0800, Bob Liu wrote:
>>
>> date in master side is:
>> root:/> date
>> Thu Dec 21 01:34:26 UTC 2006
>> root:/>
>
> What is the time on the master from the 'testptp -g' command?
>
>> So the system time didn't sync.
>
> I guess that you need to set the PHC time on the master, using 'testptp -s'.
>
> [ There are always two clocks on each host, the Linux system time and
>   the PHC time in the hardware clock. ]
>

Thank you very much.
It works.

-- 
Regards,
--Bob

^ permalink raw reply

* Re: [uclinux-dist-devel] [PATCH RFC net-next 2/4] bfin_mac: replace sys time stamps with raw ones instead.
From: Richard Cochran @ 2012-11-01  9:35 UTC (permalink / raw)
  To: Bob Liu
  Cc: netdev, Miroslav Lichvar, John Ronciak, John Stultz, Jeff Kirsher,
	device-drivers-devel, Jacob Keller, uclinux-dist-devel,
	Patrick Ohly, David Miller
In-Reply-To: <CAA_GA1f=2ubb1z6rr1L8TR54cwh1NQcKiiaZqqv2r3mjX1wL7g@mail.gmail.com>

On Thu, Nov 01, 2012 at 04:54:30PM +0800, Bob Liu wrote:
> 
> date in master side is:
> root:/> date
> Thu Dec 21 01:34:26 UTC 2006
> root:/>

What is the time on the master from the 'testptp -g' command?
 
> So the system time didn't sync.

I guess that you need to set the PHC time on the master, using 'testptp -s'.

[ There are always two clocks on each host, the Linux system time and
  the PHC time in the hardware clock. ]

Thanks,
Richard

^ permalink raw reply

* Re: [PATCH 4/4] arm/dts: am33xx: Add CPSW and MDIO module nodes for AM33XX
From: Cousson, Benoit @ 2012-11-01  9:28 UTC (permalink / raw)
  To: Richard Cochran
  Cc: Vaibhav Hiremath, netdev, paul, linux-arm-kernel, linux-omap,
	Mugunthan V N
In-Reply-To: <20121101074508.GA2637@netboy.at.omicron.at>

On 11/1/2012 8:45 AM, Richard Cochran wrote:
> On Wed, Oct 31, 2012 at 04:17:27PM +0100, Benoit Cousson wrote:
>>> +			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>;
>>
>> Do you have to store all these data in the DTS? Cannot it be in the driver?
>>
>> Do you expect to have several instance of the same IP with different
>> parameters here?
>
> As I understand it, there are only two different layouts for the CPSW,
> the one in the dm814x and the one in the am335x. So I think it would
> work to put only the version register offet in the DT, and the let the
> driver figure out the rest from there.

Yes, that's indeed better. We did that for other IPs already (GPIO, I2C...)

> But if TI is planning on reordering the registers with each new
> silicon revision, again and again, then it might make sense to keep
> the offsets in the DT.

Yeah, let's assume they will do a better job in the future.

All these offset registers information does belong to the driver, and 
even if the HW change a lot, I still rather hide that in the driver.
It will always be cleaner, most efficient, and will reduce the size if 
the blob.

> [ I really wonder why the hardware people think that reshuffling the
>    register layout constitutes an improvement. ]

I've been wondering that for ten years :-(
I'm always hoping it will be better some day.

Regards,
Benoit

^ 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