* RE: [PATCH iproute2 v1 1/1] lib/utils: fix get_addr() and get_prefix() error messages
From: Varlese, Marco @ 2016-03-30 7:19 UTC (permalink / raw)
To: Stephen Hemminger
Cc: netdev@vger.kernel.org, davem@davemloft.net, Jiri Pirko,
John Fastabend, jhs@mojatatu.com, Szczerbik, PrzemyslawX
In-Reply-To: <20160327103506.28f3d68e@xeon-e3>
[-- Attachment #1: Type: text/plain, Size: 2806 bytes --]
> -----Original Message-----
> From: netdev-owner@vger.kernel.org [mailto:netdev-owner@vger.kernel.org]
> On Behalf Of Stephen Hemminger
> Sent: Sunday, March 27, 2016 6:35 PM
> To: Varlese, Marco <marco.varlese@intel.com>
> Cc: netdev@vger.kernel.org; davem@davemloft.net; Jiri Pirko
<jiri@resnulli.us>;
> John Fastabend <john.fastabend@gmail.com>; jhs@mojatatu.com; Szczerbik,
> PrzemyslawX <przemyslawx.szczerbik@intel.com>
> Subject: Re: [PATCH iproute2 v1 1/1] lib/utils: fix get_addr() and
get_prefix()
> error messages
>
> On Tue, 22 Mar 2016 13:02:02 +0000
> "Varlese, Marco" <marco.varlese@intel.com> wrote:
>
> > An attempt to add invalid address to interface would print "???" string
> > instead of the address family name.
> >
> > For example:
> > $ ip address add 256.10.166.1/24 dev ens8
> > Error: ??? prefix is expected rather than "256.10.166.1/24".
> >
> > $ ip neighbor add proxy 2001:db8::g dev ens8
> > Error: ??? address is expected rather than "2001:db8::g".
> >
> > With this patch the output will look like:
> > $ ip address add 256.10.166.1/24 dev ens8
> > Error: inet prefix is expected rather than "256.10.166.1/24".
> >
> > $ ip neighbor add proxy 2001:db8::g dev ens8
> > Error: inet6 address is expected rather than "2001:db8::g".
> >
> > Signed-off-by: Przemyslaw Szczerbik <przemyslawx.szczerbik@intel.com>
> > Signed-off-by: Marco Varlese <marco.varlese@intel.com>
> > ---
> > lib/utils.c | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/lib/utils.c b/lib/utils.c
> > index fa35f4d..4820de1 100644
> > --- a/lib/utils.c
> > +++ b/lib/utils.c
> > @@ -567,7 +567,7 @@ int get_addr(inet_prefix *dst, const char *arg, int
> family)
> > {
> > if (get_addr_1(dst, arg, family)) {
> > fprintf(stderr, "Error: %s address is expected rather than
\"%s\".\n",
> > - family_name(family) ,arg);
> > + family_name(dst->family), arg);
> > exit(1);
> > }
> > return 0;
> > @@ -581,7 +581,7 @@ int get_prefix(inet_prefix *dst, char *arg, int family)
> > }
> > if (get_prefix_1(dst, arg, family)) {
> > fprintf(stderr, "Error: %s prefix is expected rather than
\"%s\".\n",
> > - family_name(family) ,arg);
> > + family_name(dst->family), arg);
> > exit(1);
> > }
> > return 0;
>
> Your patch was corrupted by your email client?
Yes, you're right; the patch got corrupted by the email client.
Sorry about that.
Looking into this now.
>
> $ patch -p1
<~/Downloads/iproute2-v1-1-1-lib-utils-fix-get_addr-and-get_prefix-
> error-messages.patch
> patching file lib/utils.c
> patch: **** malformed patch at line 6: {
[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 4414 bytes --]
^ permalink raw reply
* qdisc spin lock
From: Michael Ma @ 2016-03-30 7:20 UTC (permalink / raw)
To: netdev
Hi -
I know this might be an old topic so bare with me – what we are facing
is that applications are sending small packets using hundreds of
threads so the contention on spin lock in __dev_xmit_skb increases the
latency of dev_queue_xmit significantly. We’re building a network QoS
solution to avoid interference of different applications using HTB.
But in this case when some applications send massive small packets in
parallel, the application to be protected will get its throughput
affected (because it’s doing synchronous network communication using
multiple threads and throughput is sensitive to the increased latency)
Here is the profiling from perf:
- 67.57% iperf [kernel.kallsyms] [k] _spin_lock
- 99.94%
dev_queue_xmit
96.91%
_spin_lock
- 2.62%
__qdisc_run
-
98.98% sch_direct_xmit
99.98% _spin_lock
1.01%
_spin_lock
As far as I understand the design of TC is to simplify locking schema
and minimize the work in __qdisc_run so that throughput won’t be
affected, especially with large packets. However if the scenario is
that multiple classes in the queueing discipline only have the shaping
limit, there isn’t really a necessary correlation between different
classes. The only synchronization point should be when the packet is
dequeued from the qdisc queue and enqueued to the transmit queue of
the device. My question is – is it worth investing on avoiding the
locking contention by partitioning the queue/lock so that this
scenario is addressed with relatively smaller latency?
I must have oversimplified a lot of details since I’m not familiar
with the TC implementation at this point – just want to get your input
in terms of whether this is a worthwhile effort or there is something
fundamental that I’m not aware of. If this is just a matter of quite
some additional work, would also appreciate helping to outline the
required work here.
Also would appreciate if there is any information about the latest
status of this work http://www.ijcset.com/docs/IJCSET13-04-04-113.pdf
Thanks,
Ke Ma
^ permalink raw reply
* Re: am335x: no multicast reception over VLAN
From: Yegor Yefremov @ 2016-03-30 8:35 UTC (permalink / raw)
To: Mugunthan V N
Cc: Grygorii Strashko, netdev, linux-omap@vger.kernel.org, drivshin,
ml
In-Reply-To: <56FB6543.9060904@ti.com>
On Wed, Mar 30, 2016 at 7:33 AM, Mugunthan V N <mugunthanvnm@ti.com> wrote:
> On Tuesday 29 March 2016 06:14 PM, Grygorii Strashko wrote:
>> On 03/29/2016 03:35 PM, Yegor Yefremov wrote:
>>> On Tue, Mar 29, 2016 at 1:05 PM, Grygorii Strashko
>>> <grygorii.strashko@ti.com> wrote:
>>>> On 03/29/2016 08:21 AM, Yegor Yefremov wrote:
>>>>> Hi Mugunthan,
>>>>>
>>>>> On Tue, Mar 29, 2016 at 6:00 AM, Mugunthan V N <mugunthanvnm@ti.com> wrote:
>>>>>> Hi Yegor
>>>>>>
>>>>>> On Wednesday 16 March 2016 08:35 PM, Yegor Yefremov wrote:
>>>>>>> I have an am335x based board using CPSW in Dual EMAC mode. Without
>>>>>>> VLAN IDs I can receive and send multicast packets [1]. When I create
>>>>>>> VLAN ID:
>>>>>>>
>>>>>>> ip link add link eth1 name eth1.100 type vlan id 100
>>>>>>> ip addr add 192.168.100.2/24 brd 192.168.100.255 dev eth1.100
>>>>>>> route add -net 224.0.0.0 netmask 224.0.0.0 eth1.100
>>>>>>>
>>>>>>> I can successfully send multicast packets, but not receive them. On
>>>>>>> the other side of the Ethernet cable I've used Pandaboard. Pandaboard
>>>>>>> could both receive and send multicast packets via VLAN.
>>>>>>
>>>>>> Are you trying multicast tx/rx on eth1 or eth1.100?
>>>>>
>>>>> I'm trying multicast tx/rx on eth1.100.
>>>>>
>>>>> eth1 has no problems.
>>>>>
>>>>
>>>> it'd be nice if will be able to post here output fom commands:
>>>> # switch-config -d [git://git.ti.com/switch-config/switch-config.git v4.1]
>>>> # ifconfig -a
>>>> # tcpdump -e -f -Q in -i eth0
>>>> # tcpdump -e -f -Q in -i eth0.100
>>>
>>> Which kernel/branch do you want me to test?
>>>
>>> git://git.ti.com/ti-linux-kernel/ti-linux-kernel.git and ti-rt-linux-4.1.y?
>>>
>>> So far I was using vanilla kernel.
>>
>> Your branch (but better 4.5 kernels (or 4.4)).
>> Just when you've done with configuration run cmds 1&2,
>> and when you run your use-case - run cmds 2&3 on receiver side (grap ~5-10 packets).
>> then stop test and run cmd 1 again.
>>
>> After all could you provide your console output here, pls.
>>
>>
>
> To use command 1, you need TI kernel [1] as it won't build with vanilla
> kernel.
>
> [1]: git://git.ti.com/ti-linux-kernel/ti-linux-kernel.git ti-linux-4.1.y
# uname -a
Linux buildroot 4.1.18 #1 SMP Wed Mar 30 09:48:37 CEST 2016 armv7l GNU/Linux
# switch-config -d
cpsw hw version 1.12 (0)
0 : type: vlan , vid = 1, untag_force = 0x3, reg_mcast = 0x3,
unreg_mcast = 0x1, member_list = 0x3
1 : type: mcast, vid = 1, addr = ff:ff:ff:ff:ff:ff, mcast_state = f,
no super, port_mask = 0x3
2 : type: ucast, vid = 1, addr = 74:6a:8f:00:16:12, ucast_type =
persistant, port_num = 0x0, Secure
3 : type: vlan , vid = 0, untag_force = 0x7, reg_mcast = 0x0,
unreg_mcast = 0x1, member_list = 0x7
4 : type: mcast, vid = 1, addr = 01:00:5e:00:00:01, mcast_state = f,
no super, port_mask = 0x3
5 : type: vlan , vid = 2, untag_force = 0x5, reg_mcast = 0x5,
unreg_mcast = 0x1, member_list = 0x5
6 : type: mcast, vid = 2, addr = ff:ff:ff:ff:ff:ff, mcast_state = f,
no super, port_mask = 0x5
7 : type: ucast, vid = 2, addr = 74:6a:8f:00:16:13, ucast_type =
persistant, port_num = 0x0, Secure
8 : type: mcast, vid = 2, addr = 01:00:5e:00:00:01, mcast_state = f,
no super, port_mask = 0x5
9 : type: vlan , vid = 100, untag_force = 0x0, reg_mcast = 0x5,
unreg_mcast = 0x1, member_list = 0x5
10 : type: ucast, vid = 100, addr = 74:6a:8f:00:16:13, ucast_type =
persistant, port_num = 0x0
11 : type: mcast, vid = 100, addr = ff:ff:ff:ff:ff:ff, mcast_state =
f, no super, port_mask = 0x5
12 : type: mcast, vid = 2, addr = 01:80:c2:00:00:21, mcast_state = f,
no super, port_mask = 0x5
13 : type: mcast, vid = 2, addr = 01:00:5e:03:1d:47, mcast_state = f,
no super, port_mask = 0x5
# ifconfig -a
can0 Link encap:UNSPEC HWaddr
00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:16 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Interrupt:165
eth0 Link encap:Ethernet HWaddr 74:6A:8F:00:16:12
inet addr:192.168.254.254 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Interrupt:175
eth1 Link encap:Ethernet HWaddr 74:6A:8F:00:16:13
inet addr:192.168.1.233 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:245 errors:0 dropped:0 overruns:0 frame:0
TX packets:123 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:40995 (40.0 KiB) TX bytes:14086 (13.7 KiB)
eth1.100 Link encap:Ethernet HWaddr 74:6A:8F:00:16:13
inet addr:192.168.100.2 Bcast:192.168.100.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:65 errors:0 dropped:0 overruns:0 frame:0
TX packets:51 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:8369 (8.1 KiB) TX bytes:6340 (6.1 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:4 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:344 (344.0 B) TX bytes:344 (344.0 B)
# tcpdump -e -f -Q in -i eth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
00:47:40.240731 06:15:4d:85:61:1e (oui Unknown) > 01:00:5e:03:1d:47
(oui Unknown), ethertype 802.1Q (0x8100), length 65: vlan 100, p 0,
ethertype IPv4, 192.168.100.1.59870 > 224.3.29.71.10000: UDP, length
19
00:47:45.259285 06:15:4d:85:61:1e (oui Unknown) > 74:6a:8f:00:16:13
(oui Unknown), ethertype 802.1Q (0x8100), length 60: vlan 100, p 0,
ethertype ARP, Reply 192.168.100.1 is-at 06:15:4d:85:61:1e (oui
Unknown), length 42
# tcpdump -e -f -Q in -i eth1.100
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1.100, link-type EN10MB (Ethernet), capture size 262144 bytes
00:48:52.477500 06:15:4d:85:61:1e (oui Unknown) > 01:00:5e:03:1d:47
(oui Unknown), ethertype IPv4 (0x0800), length 61: 192.168.100.1.54382
> 224.3.29.71.10000: UDP, length 19
00:48:57.486437 06:15:4d:85:61:1e (oui Unknown) > 74:6a:8f:00:16:13
(oui Unknown), ethertype ARP (0x0806), length 56: Reply 192.168.100.1
is-at 06:15:4d:85:61:1e (oui Unknown), length 42
What does "no super" mean and where can I see the "--fwd-state <value
0-3>" value/description?
Yegor
^ permalink raw reply
* [PATCH 1/5] fsl/qe: add rx_sync and tx_sync for TDM mode
From: Zhao Qiang @ 2016-03-30 8:50 UTC (permalink / raw)
To: davem
Cc: akpm, gregkh, oss, xiaobo.xie, linux-kernel, netdev, linuxppc-dev,
Zhao Qiang
Rx_sync and tx_sync are used by QE-TDM mode,
add them to struct ucc_fast_info.
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
---
drivers/soc/fsl/qe/qe.c | 6 ++++++
include/soc/fsl/qe/qe.h | 2 ++
include/soc/fsl/qe/ucc_fast.h | 2 ++
3 files changed, 10 insertions(+)
diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c
index 709fc63..7026507 100644
--- a/drivers/soc/fsl/qe/qe.c
+++ b/drivers/soc/fsl/qe/qe.c
@@ -239,6 +239,12 @@ enum qe_clock qe_clock_source(const char *source)
if (strcasecmp(source, "none") == 0)
return QE_CLK_NONE;
+ if (strcmp(source, "tsync_pin") == 0)
+ return QE_TSYNC_PIN;
+
+ if (strcmp(source, "rsync_pin") == 0)
+ return QE_RSYNC_PIN;
+
if (strncasecmp(source, "brg", 3) == 0) {
i = simple_strtoul(source + 3, NULL, 10);
if ((i >= 1) && (i <= 16))
diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h
index 33b29ea..f918745 100644
--- a/include/soc/fsl/qe/qe.h
+++ b/include/soc/fsl/qe/qe.h
@@ -80,6 +80,8 @@ enum qe_clock {
QE_CLK22, /* Clock 22 */
QE_CLK23, /* Clock 23 */
QE_CLK24, /* Clock 24 */
+ QE_RSYNC_PIN, /* RSYNC from pin */
+ QE_TSYNC_PIN, /* TSYNC from pin */
QE_CLK_DUMMY
};
diff --git a/include/soc/fsl/qe/ucc_fast.h b/include/soc/fsl/qe/ucc_fast.h
index df8ea79..31548b7 100644
--- a/include/soc/fsl/qe/ucc_fast.h
+++ b/include/soc/fsl/qe/ucc_fast.h
@@ -120,6 +120,8 @@ struct ucc_fast_info {
int ucc_num;
enum qe_clock rx_clock;
enum qe_clock tx_clock;
+ enum qe_clock rx_sync;
+ enum qe_clock tx_sync;
u32 regs;
int irq;
u32 uccm_mask;
--
2.1.0.27.g96db324
^ permalink raw reply related
* [PATCH 2/5] fsl/qe: setup clock source for TDM mode
From: Zhao Qiang @ 2016-03-30 8:50 UTC (permalink / raw)
To: davem
Cc: akpm, gregkh, oss, xiaobo.xie, linux-kernel, netdev, linuxppc-dev,
Zhao Qiang
In-Reply-To: <1459327830-19829-1-git-send-email-qiang.zhao@nxp.com>
Add tdm clock configuration in both qe clock system and ucc
fast controller.
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
---
drivers/soc/fsl/qe/ucc.c | 450 ++++++++++++++++++++++++++++++++++++++++++
drivers/soc/fsl/qe/ucc_fast.c | 36 ++++
include/soc/fsl/qe/qe.h | 16 ++
include/soc/fsl/qe/ucc.h | 4 +
include/soc/fsl/qe/ucc_fast.h | 1 +
5 files changed, 507 insertions(+)
diff --git a/drivers/soc/fsl/qe/ucc.c b/drivers/soc/fsl/qe/ucc.c
index b59d335..5e1a850 100644
--- a/drivers/soc/fsl/qe/ucc.c
+++ b/drivers/soc/fsl/qe/ucc.c
@@ -25,6 +25,12 @@
#include <soc/fsl/qe/qe.h>
#include <soc/fsl/qe/ucc.h>
+#define UCC_TDM_NUM 8
+#define RX_SYNC_SHIFT_BASE 30
+#define TX_SYNC_SHIFT_BASE 14
+#define RX_CLK_SHIFT_BASE 28
+#define TX_CLK_SHIFT_BASE 12
+
int ucc_set_qe_mux_mii_mng(unsigned int ucc_num)
{
unsigned long flags;
@@ -210,3 +216,447 @@ int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock,
return 0;
}
+
+static int ucc_get_tdm_common_clk(u32 tdm_num, enum qe_clock clock)
+{
+ int clock_bits = -EINVAL;
+
+ /*
+ * for TDM[0, 1, 2, 3], TX and RX use common
+ * clock source BRG3,4 and CLK1,2
+ * for TDM[4, 5, 6, 7], TX and RX use common
+ * clock source BRG12,13 and CLK23,24
+ */
+ switch (tdm_num) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ switch (clock) {
+ case QE_BRG3:
+ clock_bits = 1;
+ break;
+ case QE_BRG4:
+ clock_bits = 2;
+ break;
+ case QE_CLK1:
+ clock_bits = 4;
+ break;
+ case QE_CLK2:
+ clock_bits = 5;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ switch (clock) {
+ case QE_BRG12:
+ clock_bits = 1;
+ break;
+ case QE_BRG13:
+ clock_bits = 2;
+ break;
+ case QE_CLK23:
+ clock_bits = 4;
+ break;
+ case QE_CLK24:
+ clock_bits = 5;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return clock_bits;
+}
+
+static int ucc_get_tdm_rx_clk(u32 tdm_num, enum qe_clock clock)
+{
+ int clock_bits = -EINVAL;
+
+ switch (tdm_num) {
+ case 0:
+ switch (clock) {
+ case QE_CLK3:
+ clock_bits = 6;
+ break;
+ case QE_CLK8:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (clock) {
+ case QE_CLK5:
+ clock_bits = 6;
+ break;
+ case QE_CLK10:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (clock) {
+ case QE_CLK7:
+ clock_bits = 6;
+ break;
+ case QE_CLK12:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (clock) {
+ case QE_CLK9:
+ clock_bits = 6;
+ break;
+ case QE_CLK14:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ switch (clock) {
+ case QE_CLK11:
+ clock_bits = 6;
+ break;
+ case QE_CLK16:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 5:
+ switch (clock) {
+ case QE_CLK13:
+ clock_bits = 6;
+ break;
+ case QE_CLK18:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 6:
+ switch (clock) {
+ case QE_CLK15:
+ clock_bits = 6;
+ break;
+ case QE_CLK20:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 7:
+ switch (clock) {
+ case QE_CLK17:
+ clock_bits = 6;
+ break;
+ case QE_CLK22:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ return clock_bits;
+}
+
+static int ucc_get_tdm_tx_clk(u32 tdm_num, enum qe_clock clock)
+{
+ int clock_bits = -EINVAL;
+
+ switch (tdm_num) {
+ case 0:
+ switch (clock) {
+ case QE_CLK4:
+ clock_bits = 6;
+ break;
+ case QE_CLK9:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (clock) {
+ case QE_CLK6:
+ clock_bits = 6;
+ break;
+ case QE_CLK11:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (clock) {
+ case QE_CLK8:
+ clock_bits = 6;
+ break;
+ case QE_CLK13:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (clock) {
+ case QE_CLK10:
+ clock_bits = 6;
+ break;
+ case QE_CLK15:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ switch (clock) {
+ case QE_CLK12:
+ clock_bits = 6;
+ break;
+ case QE_CLK17:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 5:
+ switch (clock) {
+ case QE_CLK14:
+ clock_bits = 6;
+ break;
+ case QE_CLK19:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 6:
+ switch (clock) {
+ case QE_CLK16:
+ clock_bits = 6;
+ break;
+ case QE_CLK21:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 7:
+ switch (clock) {
+ case QE_CLK18:
+ clock_bits = 6;
+ break;
+ case QE_CLK3:
+ clock_bits = 7;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ return clock_bits;
+}
+
+/* tdm_num: TDM A-H port num is 0-7 */
+static int ucc_get_tdm_rxtx_clk(enum comm_dir mode, u32 tdm_num,
+ enum qe_clock clock)
+{
+ int clock_bits;
+
+ clock_bits = ucc_get_tdm_common_clk(tdm_num, clock);
+ if (clock_bits > 0)
+ return clock_bits;
+ if (mode == COMM_DIR_RX)
+ clock_bits = ucc_get_tdm_rx_clk(tdm_num, clock);
+ if (mode == COMM_DIR_TX)
+ clock_bits = ucc_get_tdm_tx_clk(tdm_num, clock);
+ return clock_bits;
+}
+
+static u32 ucc_get_tdm_clk_shift(enum comm_dir mode, u32 tdm_num)
+{
+ u32 shift;
+
+ shift = (mode == COMM_DIR_RX) ? RX_CLK_SHIFT_BASE : TX_CLK_SHIFT_BASE;
+ if (tdm_num < 4)
+ shift -= tdm_num * 4;
+ else
+ shift -= (tdm_num - 4) * 4;
+
+ return shift;
+}
+
+int ucc_set_tdm_rxtx_clk(u32 tdm_num, enum qe_clock clock,
+ enum comm_dir mode)
+{
+ int clock_bits;
+ u32 shift;
+ struct qe_mux __iomem *qe_mux_reg;
+ __be32 __iomem *cmxs1cr;
+
+ qe_mux_reg = &qe_immr->qmx;
+
+ if (tdm_num > 7 || tdm_num < 0)
+ return -EINVAL;
+
+ /* The communications direction must be RX or TX */
+ if (mode != COMM_DIR_RX && mode != COMM_DIR_TX)
+ return -EINVAL;
+
+ clock_bits = ucc_get_tdm_rxtx_clk(mode, tdm_num, clock);
+ if (clock_bits < 0)
+ return -EINVAL;
+
+ shift = ucc_get_tdm_clk_shift(mode, tdm_num);
+
+ cmxs1cr = (tdm_num < 4) ? &qe_mux_reg->cmxsi1cr_l :
+ &qe_mux_reg->cmxsi1cr_h;
+
+ qe_clrsetbits32(cmxs1cr, QE_CMXUCR_TX_CLK_SRC_MASK << shift,
+ clock_bits << shift);
+
+ return 0;
+}
+
+static int ucc_get_tdm_sync_source(u32 tdm_num, enum qe_clock clock,
+ enum comm_dir mode)
+{
+ int source = -EINVAL;
+
+ if (mode == COMM_DIR_RX && clock == QE_RSYNC_PIN) {
+ source = 0;
+ return source;
+ }
+ if (mode == COMM_DIR_TX && clock == QE_TSYNC_PIN) {
+ source = 0;
+ return source;
+ }
+
+ switch (tdm_num) {
+ case 0:
+ case 1:
+ switch (clock) {
+ case QE_BRG9:
+ source = 1;
+ break;
+ case QE_BRG10:
+ source = 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ case 3:
+ switch (clock) {
+ case QE_BRG9:
+ source = 1;
+ break;
+ case QE_BRG11:
+ source = 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ case 5:
+ switch (clock) {
+ case QE_BRG13:
+ source = 1;
+ break;
+ case QE_BRG14:
+ source = 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 6:
+ case 7:
+ switch (clock) {
+ case QE_BRG13:
+ source = 1;
+ break;
+ case QE_BRG15:
+ source = 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ return source;
+}
+
+static u32 ucc_get_tdm_sync_shift(enum comm_dir mode, u32 tdm_num)
+{
+ u32 shift;
+
+ shift = (mode == COMM_DIR_RX) ? RX_SYNC_SHIFT_BASE : RX_SYNC_SHIFT_BASE;
+ shift -= tdm_num * 2;
+
+ return shift;
+}
+
+int ucc_set_tdm_rxtx_sync(u32 tdm_num, enum qe_clock clock,
+ enum comm_dir mode)
+{
+ int source;
+ u32 shift;
+ struct qe_mux *qe_mux_reg;
+
+ qe_mux_reg = &qe_immr->qmx;
+
+ if (tdm_num >= UCC_TDM_NUM)
+ return -EINVAL;
+
+ /* The communications direction must be RX or TX */
+ if (mode != COMM_DIR_RX && mode != COMM_DIR_TX)
+ return -EINVAL;
+
+ source = ucc_get_tdm_sync_source(tdm_num, clock, mode);
+ if (source < 0)
+ return -EINVAL;
+
+ shift = ucc_get_tdm_sync_shift(mode, tdm_num);
+
+ qe_clrsetbits32(&qe_mux_reg->cmxsi1syr,
+ QE_CMXUCR_TX_CLK_SRC_MASK << shift,
+ source << shift);
+
+ return 0;
+}
diff --git a/drivers/soc/fsl/qe/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c
index a768931..83d8d16 100644
--- a/drivers/soc/fsl/qe/ucc_fast.c
+++ b/drivers/soc/fsl/qe/ucc_fast.c
@@ -327,6 +327,42 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
ucc_fast_free(uccf);
return -EINVAL;
}
+ } else {
+ /* tdm Rx clock routing */
+ if ((uf_info->rx_clock != QE_CLK_NONE) &&
+ ucc_set_tdm_rxtx_clk(uf_info->tdm_num, uf_info->rx_clock,
+ COMM_DIR_RX)) {
+ pr_err("%s: illegal value for RX clock", __func__);
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+
+ /* tdm Tx clock routing */
+ if ((uf_info->tx_clock != QE_CLK_NONE) &&
+ ucc_set_tdm_rxtx_clk(uf_info->tdm_num, uf_info->tx_clock,
+ COMM_DIR_TX)) {
+ pr_err("%s: illegal value for TX clock", __func__);
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+
+ /* tdm Rx sync clock routing */
+ if ((uf_info->rx_sync != QE_CLK_NONE) &&
+ ucc_set_tdm_rxtx_sync(uf_info->tdm_num, uf_info->rx_sync,
+ COMM_DIR_RX)) {
+ pr_err("%s: illegal value for RX clock", __func__);
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+
+ /* tdm Tx sync clock routing */
+ if ((uf_info->tx_sync != QE_CLK_NONE) &&
+ ucc_set_tdm_rxtx_sync(uf_info->tdm_num, uf_info->tx_sync,
+ COMM_DIR_TX)) {
+ pr_err("%s: illegal value for TX clock", __func__);
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
}
/* Set interrupt mask register at UCC level. */
diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h
index f918745..c3b1dc8 100644
--- a/include/soc/fsl/qe/qe.h
+++ b/include/soc/fsl/qe/qe.h
@@ -244,6 +244,22 @@ static inline int qe_alive_during_sleep(void)
#define qe_muram_addr cpm_muram_addr
#define qe_muram_offset cpm_muram_offset
+#define qe_setbits32(_addr, _v) iowrite32be(ioread32be(_addr) | (_v), (_addr))
+#define qe_clrbits32(_addr, _v) iowrite32be(ioread32be(_addr) & ~(_v), (_addr))
+
+#define qe_setbits16(_addr, _v) iowrite16be(ioread16be(_addr) | (_v), (_addr))
+#define qe_clrbits16(_addr, _v) iowrite16be(ioread16be(_addr) & ~(_v), (_addr))
+
+#define qe_setbits8(_addr, _v) iowrite8(ioread8(_addr) | (_v), (_addr))
+#define qe_clrbits8(_addr, _v) iowrite8(ioread8(_addr) & ~(_v), (_addr))
+
+#define qe_clrsetbits32(addr, clear, set) \
+ iowrite32be((ioread32be(addr) & ~(clear)) | (set), (addr))
+#define qe_clrsetbits16(addr, clear, set) \
+ iowrite16be((ioread16be(addr) & ~(clear)) | (set), (addr))
+#define qe_clrsetbits8(addr, clear, set) \
+ iowrite8((ioread8(addr) & ~(clear)) | (set), (addr))
+
/* Structure that defines QE firmware binary files.
*
* See Documentation/powerpc/qe_firmware.txt for a description of these
diff --git a/include/soc/fsl/qe/ucc.h b/include/soc/fsl/qe/ucc.h
index 894f14c..6bbbb59 100644
--- a/include/soc/fsl/qe/ucc.h
+++ b/include/soc/fsl/qe/ucc.h
@@ -41,6 +41,10 @@ int ucc_set_qe_mux_mii_mng(unsigned int ucc_num);
int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock,
enum comm_dir mode);
+int ucc_set_tdm_rxtx_clk(unsigned int tdm_num, enum qe_clock clock,
+ enum comm_dir mode);
+int ucc_set_tdm_rxtx_sync(unsigned int tdm_num, enum qe_clock clock,
+ enum comm_dir mode);
int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask);
diff --git a/include/soc/fsl/qe/ucc_fast.h b/include/soc/fsl/qe/ucc_fast.h
index 31548b7..b2633b7 100644
--- a/include/soc/fsl/qe/ucc_fast.h
+++ b/include/soc/fsl/qe/ucc_fast.h
@@ -118,6 +118,7 @@ enum ucc_fast_transparent_tcrc {
/* Fast UCC initialization structure */
struct ucc_fast_info {
int ucc_num;
+ int tdm_num;
enum qe_clock rx_clock;
enum qe_clock tx_clock;
enum qe_clock rx_sync;
--
2.1.0.27.g96db324
^ permalink raw reply related
* [PATCH 3/5] fsl/qe: Make regs resouce_size_t
From: Zhao Qiang @ 2016-03-30 8:50 UTC (permalink / raw)
To: davem
Cc: akpm, gregkh, oss, xiaobo.xie, linux-kernel, netdev, linuxppc-dev,
Zhao Qiang
In-Reply-To: <1459327830-19829-1-git-send-email-qiang.zhao@nxp.com>
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
---
include/soc/fsl/qe/ucc_fast.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/soc/fsl/qe/ucc_fast.h b/include/soc/fsl/qe/ucc_fast.h
index b2633b7..e898895 100644
--- a/include/soc/fsl/qe/ucc_fast.h
+++ b/include/soc/fsl/qe/ucc_fast.h
@@ -123,7 +123,7 @@ struct ucc_fast_info {
enum qe_clock tx_clock;
enum qe_clock rx_sync;
enum qe_clock tx_sync;
- u32 regs;
+ resource_size_t regs;
int irq;
u32 uccm_mask;
int bd_mem_part;
--
2.1.0.27.g96db324
^ permalink raw reply related
* [PATCH 4/5] fsl/qe: Add QE TDM lib
From: Zhao Qiang @ 2016-03-30 8:50 UTC (permalink / raw)
To: davem
Cc: akpm, gregkh, oss, xiaobo.xie, linux-kernel, netdev, linuxppc-dev,
Zhao Qiang
In-Reply-To: <1459327830-19829-1-git-send-email-qiang.zhao@nxp.com>
QE has module to support TDM, some other protocols
supported by QE are based on TDM.
add a qe-tdm lib, this lib provides functions to the protocols
using TDM to configurate QE-TDM.
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
---
drivers/soc/fsl/qe/Kconfig | 4 +
drivers/soc/fsl/qe/Makefile | 1 +
drivers/soc/fsl/qe/qe_tdm.c | 271 ++++++++++++++++++++++++++++++++++++++++++
include/soc/fsl/qe/immap_qe.h | 5 +-
include/soc/fsl/qe/qe_tdm.h | 94 +++++++++++++++
5 files changed, 371 insertions(+), 4 deletions(-)
create mode 100644 drivers/soc/fsl/qe/qe_tdm.c
create mode 100644 include/soc/fsl/qe/qe_tdm.h
diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index 20978f2..463cf29 100644
--- a/drivers/soc/fsl/qe/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -31,6 +31,10 @@ config UCC
bool
default y if UCC_FAST || UCC_SLOW
+config QE_TDM
+ bool
+ select UCC_FAST
+
config QE_USB
bool
default y if USB_FSL_QE
diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
index ffac541..2031d38 100644
--- a/drivers/soc/fsl/qe/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_CPM) += qe_common.o
obj-$(CONFIG_UCC) += ucc.o
obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
obj-$(CONFIG_UCC_FAST) += ucc_fast.o
+obj-$(CONFIG_QE_TDM) += qe_tdm.o
obj-$(CONFIG_QE_USB) += usb.o
obj-$(CONFIG_QE_GPIO) += gpio.o
diff --git a/drivers/soc/fsl/qe/qe_tdm.c b/drivers/soc/fsl/qe/qe_tdm.c
new file mode 100644
index 0000000..9a2374d
--- /dev/null
+++ b/drivers/soc/fsl/qe/qe_tdm.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Authors: Zhao Qiang <qiang.zhao@nxp.com>
+ *
+ * Description:
+ * QE TDM API Set - TDM specific routines implementations.
+ *
+ * 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.
+ */
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <soc/fsl/qe/qe_tdm.h>
+
+static enum tdm_framer_t set_tdm_framer(const char *tdm_framer_type)
+{
+ if (strcmp(tdm_framer_type, "e1") == 0)
+ return TDM_FRAMER_E1;
+ else
+ return TDM_FRAMER_T1;
+}
+
+static void set_si_param(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info)
+{
+ struct si_mode_info *si_info = &ut_info->si_info;
+
+ if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) {
+ si_info->simr_crt = 1;
+ si_info->simr_rfsd = 0;
+ }
+}
+
+int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm,
+ struct ucc_tdm_info *ut_info)
+{
+ const char *sprop;
+ int ret = 0;
+ u32 val;
+ struct resource *res;
+ struct device_node *np2;
+ static int siram_init_flag;
+ struct platform_device *pdev;
+
+ sprop = of_get_property(np, "fsl,rx-sync-clock", NULL);
+ if (sprop) {
+ ut_info->uf_info.rx_sync = qe_clock_source(sprop);
+ if ((ut_info->uf_info.rx_sync < QE_CLK_NONE) ||
+ (ut_info->uf_info.rx_sync > QE_RSYNC_PIN)) {
+ pr_err("QE-TDM: Invalid rx-sync-clock property\n");
+ return -EINVAL;
+ }
+ } else {
+ pr_err("QE-TDM: Invalid rx-sync-clock property\n");
+ return -EINVAL;
+ }
+
+ sprop = of_get_property(np, "fsl,tx-sync-clock", NULL);
+ if (sprop) {
+ ut_info->uf_info.tx_sync = qe_clock_source(sprop);
+ if ((ut_info->uf_info.tx_sync < QE_CLK_NONE) ||
+ (ut_info->uf_info.tx_sync > QE_TSYNC_PIN)) {
+ pr_err("QE-TDM: Invalid tx-sync-clock property\n");
+ return -EINVAL;
+ }
+ } else {
+ pr_err("QE-TDM: Invalid tx-sync-clock property\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_index(np, "fsl,tx-timeslot-mask", 0, &val);
+ if (ret) {
+ pr_err("QE-TDM: Invalid tx-timeslot-mask property\n");
+ return -EINVAL;
+ }
+ utdm->tx_ts_mask = val;
+
+ ret = of_property_read_u32_index(np, "fsl,rx-timeslot-mask", 0, &val);
+ if (ret) {
+ ret = -EINVAL;
+ pr_err("QE-TDM: Invalid rx-timeslot-mask property\n");
+ return ret;
+ }
+ utdm->rx_ts_mask = val;
+
+ ret = of_property_read_u32_index(np, "fsl,tdm-id", 0, &val);
+ if (ret) {
+ ret = -EINVAL;
+ pr_err("QE-TDM: No fsl,tdm-id property for this UCC\n");
+ return ret;
+ }
+ utdm->tdm_port = val;
+ ut_info->uf_info.tdm_num = utdm->tdm_port;
+
+ if (of_get_property(np, "fsl,tdm-internal-loopback", NULL))
+ utdm->tdm_mode = TDM_INTERNAL_LOOPBACK;
+ else
+ utdm->tdm_mode = TDM_NORMAL;
+
+ sprop = of_get_property(np, "fsl,tdm-framer-type", NULL);
+ if (!sprop) {
+ ret = -EINVAL;
+ pr_err("QE-TDM: No tdm-framer-type property for UCC\n");
+ return ret;
+ }
+ utdm->tdm_framer_type = set_tdm_framer(sprop);
+
+ ret = of_property_read_u32_index(np, "fsl,siram-entry-id", 0, &val);
+ if (ret) {
+ ret = -EINVAL;
+ pr_err("QE-TDM: No siram entry id for UCC\n");
+ return ret;
+ }
+ utdm->siram_entry_id = val;
+
+ set_si_param(utdm, ut_info);
+
+ np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-si");
+ if (!np2)
+ return -EINVAL;
+
+ pdev = of_find_device_by_node(np2);
+ if (!pdev) {
+ pr_err("%s: failed to lookup pdev\n", np2->name);
+ of_node_put(np2);
+ return -EINVAL;
+ }
+
+ of_node_put(np2);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ utdm->si_regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(utdm->si_regs)) {
+ ret = PTR_ERR(utdm->si_regs);
+ goto err_miss_siram_property;
+ }
+
+ np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-siram");
+ if (!np2) {
+ ret = -EINVAL;
+ goto err_miss_siram_property;
+ }
+
+ pdev = of_find_device_by_node(np2);
+ if (!pdev) {
+ ret = -EINVAL;
+ pr_err("%s: failed to lookup pdev\n", np2->name);
+ of_node_put(np2);
+ goto err_miss_siram_property;
+ }
+
+ of_node_put(np2);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ utdm->siram = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(utdm->siram)) {
+ ret = PTR_ERR(utdm->siram);
+ goto err_miss_siram_property;
+ }
+
+ if (siram_init_flag == 0) {
+ memset_io(utdm->siram, 0, res->end - res->start + 1);
+ siram_init_flag = 1;
+ }
+
+ return ret;
+
+err_miss_siram_property:
+ devm_iounmap(&pdev->dev, utdm->si_regs);
+ return ret;
+}
+
+void ucc_tdm_init(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info)
+{
+ struct si1 __iomem *si_regs;
+ u16 __iomem *siram;
+ u16 siram_entry_valid;
+ u16 siram_entry_closed;
+ u16 ucc_num;
+ u8 csel;
+ u16 sixmr;
+ u16 tdm_port;
+ u32 siram_entry_id;
+ u32 mask;
+ int i;
+
+ si_regs = utdm->si_regs;
+ siram = utdm->siram;
+ ucc_num = ut_info->uf_info.ucc_num;
+ tdm_port = utdm->tdm_port;
+ siram_entry_id = utdm->siram_entry_id;
+
+ if (utdm->tdm_framer_type == TDM_FRAMER_T1)
+ utdm->num_of_ts = 24;
+ if (utdm->tdm_framer_type == TDM_FRAMER_E1)
+ utdm->num_of_ts = 32;
+
+ /* set siram table */
+ csel = (ucc_num < 4) ? ucc_num + 9 : ucc_num - 3;
+
+ siram_entry_valid = SIR_CSEL(csel) | SIR_BYTE | SIR_CNT(0);
+ siram_entry_closed = SIR_IDLE | SIR_BYTE | SIR_CNT(0);
+
+ for (i = 0; i < utdm->num_of_ts; i++) {
+ mask = 0x01 << i;
+
+ if (utdm->tx_ts_mask & mask)
+ iowrite16be(siram_entry_valid,
+ &siram[siram_entry_id * 32 + i]);
+ else
+ iowrite16be(siram_entry_closed,
+ &siram[siram_entry_id * 32 + i]);
+
+ if (utdm->rx_ts_mask & mask)
+ iowrite16be(siram_entry_valid,
+ &siram[siram_entry_id * 32 + 0x200 + i]);
+ else
+ iowrite16be(siram_entry_closed,
+ &siram[siram_entry_id * 32 + 0x200 + i]);
+ }
+
+ setbits16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)],
+ SIR_LAST);
+ setbits16(&siram[(siram_entry_id * 32) + 0x200 + (utdm->num_of_ts - 1)],
+ SIR_LAST);
+
+ /* Set SIxMR register */
+ sixmr = SIMR_SAD(siram_entry_id);
+
+ sixmr &= ~SIMR_SDM_MASK;
+
+ if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK)
+ sixmr |= SIMR_SDM_INTERNAL_LOOPBACK;
+ else
+ sixmr |= SIMR_SDM_NORMAL;
+
+ sixmr |= SIMR_RFSD(ut_info->si_info.simr_rfsd) |
+ SIMR_TFSD(ut_info->si_info.simr_tfsd);
+
+ if (ut_info->si_info.simr_crt)
+ sixmr |= SIMR_CRT;
+ if (ut_info->si_info.simr_sl)
+ sixmr |= SIMR_SL;
+ if (ut_info->si_info.simr_ce)
+ sixmr |= SIMR_CE;
+ if (ut_info->si_info.simr_fe)
+ sixmr |= SIMR_FE;
+ if (ut_info->si_info.simr_gm)
+ sixmr |= SIMR_GM;
+
+ switch (tdm_port) {
+ case 0:
+ iowrite16be(sixmr, &si_regs->sixmr1[0]);
+ break;
+ case 1:
+ iowrite16be(sixmr, &si_regs->sixmr1[1]);
+ break;
+ case 2:
+ iowrite16be(sixmr, &si_regs->sixmr1[2]);
+ break;
+ case 3:
+ iowrite16be(sixmr, &si_regs->sixmr1[3]);
+ break;
+ default:
+ pr_err("QE-TDM: can not find tdm sixmr reg\n");
+ break;
+ }
+}
diff --git a/include/soc/fsl/qe/immap_qe.h b/include/soc/fsl/qe/immap_qe.h
index bedbff8..c76ef30 100644
--- a/include/soc/fsl/qe/immap_qe.h
+++ b/include/soc/fsl/qe/immap_qe.h
@@ -159,10 +159,7 @@ struct spi {
/* SI */
struct si1 {
- __be16 siamr1; /* SI1 TDMA mode register */
- __be16 sibmr1; /* SI1 TDMB mode register */
- __be16 sicmr1; /* SI1 TDMC mode register */
- __be16 sidmr1; /* SI1 TDMD mode register */
+ __be16 sixmr1[4]; /* SI1 TDMx (x = A B C D) mode register */
u8 siglmr1_h; /* SI1 global mode register high */
u8 res0[0x1];
u8 sicmdr1_h; /* SI1 command register high */
diff --git a/include/soc/fsl/qe/qe_tdm.h b/include/soc/fsl/qe/qe_tdm.h
new file mode 100644
index 0000000..e7ae93a
--- /dev/null
+++ b/include/soc/fsl/qe/qe_tdm.h
@@ -0,0 +1,94 @@
+/*
+ * Internal header file for QE TDM mode routines.
+ *
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Authors: Zhao Qiang <qiang.zhao@nxp.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
+ */
+
+#ifndef CONFIG_QE_TDM_H
+#define CONFIG_QE_TDM_H
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
+
+#include <soc/fsl/qe/ucc.h>
+#include <soc/fsl/qe/ucc_fast.h>
+
+/* SI RAM entries */
+#define SIR_LAST 0x0001
+#define SIR_BYTE 0x0002
+#define SIR_CNT(x) ((x) << 2)
+#define SIR_CSEL(x) ((x) << 5)
+#define SIR_SGS 0x0200
+#define SIR_SWTR 0x4000
+#define SIR_MCC 0x8000
+#define SIR_IDLE 0
+
+/* SIxMR fields */
+#define SIMR_SAD(x) ((x) << 12)
+#define SIMR_SDM_NORMAL 0x0000
+#define SIMR_SDM_INTERNAL_LOOPBACK 0x0800
+#define SIMR_SDM_MASK 0x0c00
+#define SIMR_CRT 0x0040
+#define SIMR_SL 0x0020
+#define SIMR_CE 0x0010
+#define SIMR_FE 0x0008
+#define SIMR_GM 0x0004
+#define SIMR_TFSD(n) (n)
+#define SIMR_RFSD(n) ((n) << 8)
+
+enum tdm_ts_t {
+ TDM_TX_TS,
+ TDM_RX_TS
+};
+
+enum tdm_framer_t {
+ TDM_FRAMER_T1,
+ TDM_FRAMER_E1
+};
+
+enum tdm_mode_t {
+ TDM_INTERNAL_LOOPBACK,
+ TDM_NORMAL
+};
+
+struct si_mode_info {
+ u8 simr_rfsd;
+ u8 simr_tfsd;
+ u8 simr_crt;
+ u8 simr_sl;
+ u8 simr_ce;
+ u8 simr_fe;
+ u8 simr_gm;
+};
+
+struct ucc_tdm_info {
+ struct ucc_fast_info uf_info;
+ struct si_mode_info si_info;
+};
+
+struct ucc_tdm {
+ u16 tdm_port; /* port for this tdm:TDMA,TDMB */
+ u32 siram_entry_id;
+ u16 __iomem *siram;
+ struct si1 __iomem *si_regs;
+ enum tdm_framer_t tdm_framer_type;
+ enum tdm_mode_t tdm_mode;
+ u8 num_of_ts; /* the number of timeslots in this tdm frame */
+ u32 tx_ts_mask; /* tx time slot mask */
+ u32 rx_ts_mask; /* rx time slot mask */
+};
+
+int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm,
+ struct ucc_tdm_info *ut_info);
+void ucc_tdm_init(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info);
+#endif
--
2.1.0.27.g96db324
^ permalink raw reply related
* [PATCH 5/5] drivers/net: support hdlc function for QE-UCC
From: Zhao Qiang @ 2016-03-30 8:50 UTC (permalink / raw)
To: davem
Cc: akpm, gregkh, oss, xiaobo.xie, linux-kernel, netdev, linuxppc-dev,
Zhao Qiang
In-Reply-To: <1459327830-19829-1-git-send-email-qiang.zhao@nxp.com>
The driver add hdlc support for Freescale QUICC Engine.
It support NMSI and TSA mode.
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
---
MAINTAINERS | 6 +
drivers/net/wan/Kconfig | 12 +
drivers/net/wan/Makefile | 1 +
drivers/net/wan/fsl_ucc_hdlc.c | 1339 ++++++++++++++++++++++++++++++++++++++++
drivers/net/wan/fsl_ucc_hdlc.h | 140 +++++
include/soc/fsl/qe/ucc_fast.h | 4 +
6 files changed, 1502 insertions(+)
create mode 100644 drivers/net/wan/fsl_ucc_hdlc.c
create mode 100644 drivers/net/wan/fsl_ucc_hdlc.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 74bbff3..428d6ed 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4572,6 +4572,12 @@ F: drivers/net/ethernet/freescale/gianfar*
X: drivers/net/ethernet/freescale/gianfar_ptp.c
F: Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
+FREESCALE QUICC ENGINE UCC HDLC DRIVER
+M: Zhao Qiang <qiang.zhao@nxp.com>
+L: linuxppc-dev@lists.ozlabs.org
+S: Maintained
+F: drivers/net/wan/fsl_ucc_hdlc*
+
FREESCALE QUICC ENGINE UCC UART DRIVER
M: Timur Tabi <timur@tabi.org>
L: linuxppc-dev@lists.ozlabs.org
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index a2fdd15..cc424b2 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -280,6 +280,18 @@ config DSCC4
To compile this driver as a module, choose M here: the
module will be called dscc4.
+config FSL_UCC_HDLC
+ tristate "Freescale QUICC Engine HDLC support"
+ depends on HDLC
+ select QE_TDM
+ select QUICC_ENGINE
+ help
+ Driver for Freescale QUICC Engine HDLC controller. The driver
+ support HDLC run on NMSI and TDM mode.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fsl_ucc_hdlc.
+
config DSCC4_PCISYNC
bool "Etinc PCISYNC features"
depends on DSCC4
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index c135ef4..25fec40 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_WANXL) += wanxl.o
obj-$(CONFIG_PCI200SYN) += pci200syn.o
obj-$(CONFIG_PC300TOO) += pc300too.o
obj-$(CONFIG_IXP4XX_HSS) += ixp4xx_hss.o
+obj-$(CONFIG_FSL_UCC_HDLC) += fsl_ucc_hdlc.o
clean-files := wanxlfw.inc
$(obj)/wanxl.o: $(obj)/wanxlfw.inc
diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c
new file mode 100644
index 0000000..9958ec1
--- /dev/null
+++ b/drivers/net/wan/fsl_ucc_hdlc.c
@@ -0,0 +1,1339 @@
+/* Freescale QUICC Engine HDLC Device Driver
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/hdlc.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+#include <soc/fsl/qe/qe_tdm.h>
+#include <uapi/linux/if_arp.h>
+
+#include "fsl_ucc_hdlc.h"
+
+#define DRV_DESC "Freescale QE UCC HDLC Driver"
+#define DRV_NAME "ucc_hdlc"
+
+#define TDM_PPPOHT_SLIC_MAXIN
+/* #define DEBUG */
+/* #define QE_HDLC_TEST */
+#define BROKEN_FRAME_INFO
+
+static struct ucc_tdm_info utdm_primary_info = {
+ .uf_info = {
+ .tsa = 0,
+ .cdp = 0,
+ .cds = 1,
+ .ctsp = 1,
+ .ctss = 1,
+ .revd = 0,
+ .urfs = 256,
+ .utfs = 256,
+ .urfet = 128,
+ .urfset = 192,
+ .utfet = 128,
+ .utftt = 0x40,
+ .ufpt = 256,
+ .mode = UCC_FAST_PROTOCOL_MODE_HDLC,
+ .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
+ .tenc = UCC_FAST_TX_ENCODING_NRZ,
+ .renc = UCC_FAST_RX_ENCODING_NRZ,
+ .tcrc = UCC_FAST_16_BIT_CRC,
+ .synl = UCC_FAST_SYNC_LEN_NOT_USED,
+ },
+
+ .si_info = {
+#ifdef CONFIG_FSL_PQ_MDS_T1
+ .simr_rfsd = 1, /* TDM card need 1 bit delay */
+ .simr_tfsd = 0,
+#else
+#ifdef TDM_PPPOHT_SLIC_MAXIN
+ .simr_rfsd = 1,
+ .simr_tfsd = 2,
+#else
+ .simr_rfsd = 0,
+ .simr_tfsd = 0,
+#endif
+#endif
+ .simr_crt = 0,
+ .simr_sl = 0,
+ .simr_ce = 1,
+ .simr_fe = 1,
+ .simr_gm = 0,
+ },
+};
+
+static struct ucc_tdm_info utdm_info[MAX_HDLC_NUM];
+
+#ifdef DEBUG
+static void mem_disp(u8 *addr, int size)
+{
+ void *i;
+ int size16_aling = (size >> 4) << 4;
+ int size4_aling = (size >> 2) << 2;
+ int not_align = 0;
+
+ if (size % 16)
+ not_align = 1;
+
+ for (i = addr; i < addr + size16_aling; i += 16) {
+ u32 *i32 = i;
+
+ pr_info("0x%08p: %08x %08x %08x %08x\r\n",
+ i32, be32_to_cpu(i32[0]), be32_to_cpu(i32[1]),
+ be32_to_cpu(i32[2]), be32_to_cpu(i32[3]));
+ }
+
+ if (not_align == 1)
+ pr_info("0x%08p: ", i);
+ for (; i < addr + size4_aling; i += 4)
+ pr_info("%08x ", be32_to_cpu(*((u32 *)(i))));
+ for (; i < addr + size; i++)
+ pr_info("%02x", *((u8 *)(i)));
+ if (not_align == 1)
+ pr_info("\r\n");
+}
+
+static void dump_ucc(struct ucc_hdlc_private *priv)
+{
+ struct ucc_hdlc_param *ucc_pram;
+
+ ucc_pram = priv->ucc_pram;
+
+ dev_info(priv->dev, "DumpiniCC %d Registers\n",
+ priv->ut_info->uf_info.ucc_num);
+ ucc_fast_dump_regs(priv->uccf);
+ dev_info(priv->dev, "Dumping UCC %d Parameter RAM\n",
+ priv->ut_info->uf_info.ucc_num);
+ dev_info(priv->dev, "rbase = 0x%x\n", ioread32be(&ucc_pram->rbase));
+ dev_info(priv->dev, "rbptr = 0x%x\n", ioread32be(&ucc_pram->rbptr));
+ dev_info(priv->dev, "mrblr = 0x%x\n", ioread16be(&ucc_pram->mrblr));
+ dev_info(priv->dev, "rbdlen = 0x%x\n", ioread16be(&ucc_pram->rbdlen));
+ dev_info(priv->dev, "rbdstat = 0x%x\n", ioread16be(&ucc_pram->rbdstat));
+ dev_info(priv->dev, "rstate = 0x%x\n", ioread32be(&ucc_pram->rstate));
+ dev_info(priv->dev, "rdptr = 0x%x\n", ioread32be(&ucc_pram->rdptr));
+ dev_info(priv->dev, "riptr = 0x%x\n", ioread16be(&ucc_pram->riptr));
+ dev_info(priv->dev, "tbase = 0x%x\n", ioread32be(&ucc_pram->tbase));
+ dev_info(priv->dev, "tbptr = 0x%x\n", ioread32be(&ucc_pram->tbptr));
+ dev_info(priv->dev, "tbdlen = 0x%x\n", ioread16be(&ucc_pram->tbdlen));
+ dev_info(priv->dev, "tbdstat = 0x%x\n", ioread16be(&ucc_pram->tbdstat));
+ dev_info(priv->dev, "tstate = 0x%x\n", ioread32be(&ucc_pram->tstate));
+ dev_info(priv->dev, "tdptr = 0x%x\n", ioread32be(&ucc_pram->tdptr));
+ dev_info(priv->dev, "tiptr = 0x%x\n", ioread16be(&ucc_pram->tiptr));
+ dev_info(priv->dev, "rcrc = 0x%x\n", ioread32be(&ucc_pram->rcrc));
+ dev_info(priv->dev, "tcrc = 0x%x\n", ioread32be(&ucc_pram->tcrc));
+ dev_info(priv->dev, "c_mask = 0x%x\n", ioread32be(&ucc_pram->c_mask));
+ dev_info(priv->dev, "c_pers = 0x%x\n", ioread32be(&ucc_pram->c_pres));
+ dev_info(priv->dev, "disfc = 0x%x\n", ioread16be(&ucc_pram->disfc));
+ dev_info(priv->dev, "crcec = 0x%x\n", ioread16be(&ucc_pram->crcec));
+}
+
+static void dump_bds(struct ucc_hdlc_private *priv)
+{
+ int length;
+
+ if (priv->tx_bd_base) {
+ length = sizeof(struct qe_bd) * TX_BD_RING_LEN;
+ dev_info(priv->dev, " Dump tx BDs\n");
+ mem_disp((u8 *)priv->tx_bd_base, length);
+ }
+
+ if (priv->rx_bd_base) {
+ length = sizeof(struct qe_bd) * RX_BD_RING_LEN;
+ dev_info(priv->dev, " Dump rx BDs\n");
+ mem_disp((u8 *)priv->rx_bd_base, length);
+ }
+}
+
+static void dump_priv(struct ucc_hdlc_private *priv)
+{
+ dev_info(priv->dev, "ut_info = 0x%x\n", (u32)priv->ut_info);
+ dev_info(priv->dev, "uccf = 0x%x\n", (u32)priv->uccf);
+ dev_info(priv->dev, "uf_regs = 0x%x\n", (u32)priv->uf_regs);
+ dev_info(priv->dev, "si_regs = 0x%x\n", (u32)priv->utdm->si_regs);
+ dev_info(priv->dev, "ucc_pram = 0x%x\n", (u32)priv->ucc_pram);
+ dev_info(priv->dev, "tdm_port = 0x%x\n", (u32)priv->utdm->tdm_port);
+ dev_info(priv->dev, "siram_entry_id = 0x%x\n",
+ priv->utdm->siram_entry_id);
+ dev_info(priv->dev, "siram = 0x%x\n", (u32)priv->utdm->siram);
+ dev_info(priv->dev, "tdm_mode = 0x%x\n", (u32)priv->utdm->tdm_mode);
+ dev_info(priv->dev, "tdm_framer_type; = 0x%x\n",
+ (u32)priv->utdm->tdm_framer_type);
+ dev_info(priv->dev, "rx_buffer; = 0x%x\n", (u32)priv->rx_buffer);
+ dev_info(priv->dev, "tx_buffer; = 0x%x\n", (u32)priv->tx_buffer);
+ dev_info(priv->dev, "dma_rx_addr; = 0x%x\n", (u32)priv->dma_rx_addr);
+ dev_info(priv->dev, "tx_bd; = 0x%x\n", (u32)priv->tx_bd_base);
+ dev_info(priv->dev, "rx_bd; = 0x%x\n", (u32)priv->rx_bd_base);
+ dev_info(priv->dev, "curtx_bd = 0x%x\n", (u32)priv->curtx_bd);
+ dev_info(priv->dev, "currx_bd = 0x%x\n", (u32)priv->currx_bd);
+ dev_info(priv->dev, "ucc_pram_offset = 0x%x\n", priv->ucc_pram_offset);
+}
+
+#endif /* DEBUG */
+
+static int uhdlc_init(struct ucc_hdlc_private *priv)
+{
+ struct ucc_tdm_info *ut_info;
+ struct ucc_fast_info *uf_info;
+ u32 cecr_subblock;
+ u32 bd_status;
+ int ret, i;
+ void *bd_buffer;
+ dma_addr_t bd_dma_addr;
+ u32 riptr;
+ u32 tiptr;
+ u32 gumr;
+
+ ut_info = priv->ut_info;
+ uf_info = &ut_info->uf_info;
+
+ if (priv->tsa) {
+ uf_info->tsa = 1;
+ uf_info->ctsp = 1;
+ }
+ uf_info->uccm_mask = (u32)((UCC_HDLC_UCCE_RXB | UCC_HDLC_UCCE_RXF |
+ UCC_HDLC_UCCE_TXB) << 16);
+
+ if (ucc_fast_init(uf_info, &priv->uccf)) {
+ dev_err(priv->dev, "Failed to init uccf.");
+ return -ENOMEM;
+ }
+
+ priv->uf_regs = priv->uccf->uf_regs;
+ ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
+
+ /* Loopback mode */
+ if (priv->loopback) {
+ pr_info("TDM Mode: Loopback Mode\n");
+ gumr = ioread32be(&priv->uf_regs->gumr);
+ gumr |= (0x40000000 | UCC_FAST_GUMR_CDS | UCC_FAST_GUMR_TCI);
+ gumr &= ~(UCC_FAST_GUMR_CTSP | UCC_FAST_GUMR_RSYN);
+ iowrite32be(gumr, &priv->uf_regs->gumr);
+ }
+
+ /* Initialize SI */
+ if (priv->tsa)
+ ucc_tdm_init(priv->utdm, priv->ut_info);
+
+ /* Write to QE CECR, UCCx channel to Stop Transmission */
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
+ ret = qe_issue_cmd(QE_STOP_TX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ /* Set UPSMR normal mode (need fixed)*/
+ iowrite32be(0, &priv->uf_regs->upsmr);
+
+ priv->rx_ring_size = RX_BD_RING_LEN;
+ priv->tx_ring_size = TX_BD_RING_LEN;
+ /* Alloc Rx BD */
+ priv->rx_bd_base = dma_alloc_coherent(priv->dev,
+ RX_BD_RING_LEN * sizeof(struct qe_bd *),
+ &priv->dma_rx_bd, GFP_KERNEL);
+
+ if (IS_ERR_VALUE((unsigned long)priv->rx_bd_base)) {
+ dev_err(priv->dev, "Cannot allocate MURAM memory for RxBDs\n");
+ ret = -ENOMEM;
+ goto rxbd_alloc_error;
+ }
+
+ /* Alloc Tx BD */
+ priv->tx_bd_base = dma_alloc_coherent(priv->dev,
+ TX_BD_RING_LEN * sizeof(struct qe_bd *),
+ &priv->dma_tx_bd, GFP_KERNEL);
+
+ if (IS_ERR_VALUE((unsigned long)priv->tx_bd_base)) {
+ dev_err(priv->dev, "Cannot allocate MURAM memory for TxBDs\n");
+ ret = -ENOMEM;
+ goto txbd_alloc_error;
+ }
+
+ /* Alloc parameter ram for ucc hdlc */
+ priv->ucc_pram_offset = qe_muram_alloc(sizeof(priv->ucc_pram),
+ ALIGNMENT_OF_UCC_HDLC_PRAM);
+
+ if (IS_ERR_VALUE(priv->ucc_pram_offset)) {
+ dev_err(priv->dev, "Can not allocate MURAM for hdlc prameter.\n");
+ ret = -ENOMEM;
+ goto pram_alloc_error;
+ }
+
+ priv->rx_skbuff = kmalloc_array(priv->rx_ring_size,
+ sizeof(*priv->rx_skbuff), GFP_KERNEL);
+ if (!priv->rx_skbuff)
+ goto rx_skb_alloc_error;
+ for (i = 0; i < priv->rx_ring_size; i++)
+ priv->rx_skbuff[i] = NULL;
+
+ priv->tx_skbuff = kmalloc_array(priv->tx_ring_size,
+ sizeof(*priv->tx_skbuff), GFP_KERNEL);
+ if (!priv->tx_skbuff)
+ goto tx_skb_alloc_error;
+ for (i = 0; i < priv->tx_ring_size; i++)
+ priv->tx_skbuff[i] = NULL;
+
+ priv->skb_curtx = 0;
+ priv->skb_dirtytx = 0;
+ priv->curtx_bd = priv->tx_bd_base;
+ priv->dirty_tx = priv->tx_bd_base;
+ priv->currx_bd = priv->rx_bd_base;
+ priv->currx_bdnum = 0;
+
+ /* init parameter base */
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
+ ret = qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, cecr_subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, priv->ucc_pram_offset);
+
+ priv->ucc_pram = (struct ucc_hdlc_param __iomem *)
+ qe_muram_addr(priv->ucc_pram_offset);
+
+ /* Zero out parameter ram */
+ memset_io(priv->ucc_pram, 0, sizeof(struct ucc_hdlc_param));
+
+ /* Alloc riptr, tiptr */
+ riptr = qe_muram_alloc(32, 32);
+ if (IS_ERR_VALUE(riptr)) {
+ dev_err(priv->dev, "Cannot allocate MURAM mem for Receive internal temp data pointer\n");
+ ret = -ENOMEM;
+ goto riptr_alloc_error;
+ }
+
+ tiptr = qe_muram_alloc(32, 32);
+ if (IS_ERR_VALUE(tiptr)) {
+ dev_err(priv->dev, "Cannot allocate MURAM mem for Transmit internal temp data pointer\n");
+ ret = -ENOMEM;
+ goto tiptr_alloc_error;
+ }
+
+ /* Set RIPTR, TIPTR */
+ iowrite16be((u16)riptr, &priv->ucc_pram->riptr);
+ iowrite16be((u16)tiptr, &priv->ucc_pram->tiptr);
+
+ /* Set MRBLR */
+ iowrite16be((u16)MAX_RX_BUF_LENGTH, &priv->ucc_pram->mrblr);
+
+ /* Set RBASE, TBASE */
+ iowrite32be((u32)priv->dma_rx_bd, &priv->ucc_pram->rbase);
+ iowrite32be((u32)priv->dma_tx_bd, &priv->ucc_pram->tbase);
+
+ /* Set RSTATE, TSTATE */
+ iowrite32be(0x30000000, &priv->ucc_pram->rstate);
+ iowrite32be(0x30000000, &priv->ucc_pram->tstate);
+
+ /* Set C_MASK, C_PRES for 16bit CRC */
+ iowrite32be(0x0000F0B8, &priv->ucc_pram->c_mask);
+ iowrite32be(0x0000FFFF, &priv->ucc_pram->c_pres);
+
+ iowrite16be(MAX_RX_BUF_LENGTH + 8, &priv->ucc_pram->mflr);
+ iowrite16be(1, &priv->ucc_pram->rfthr);
+ iowrite16be(1, &priv->ucc_pram->rfcnt);
+ iowrite16be(DEFAULT_ADDR_MASK, &priv->ucc_pram->hmask);
+ iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr1);
+ iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr2);
+ iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr3);
+ iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr4);
+
+ /* Get BD buffer */
+ bd_buffer = dma_alloc_coherent(priv->dev,
+ (RX_BD_RING_LEN + TX_BD_RING_LEN) *
+ MAX_RX_BUF_LENGTH,
+ &bd_dma_addr, GFP_KERNEL);
+
+ if (!bd_buffer) {
+ dev_err(priv->dev, "Could not allocate buffer descriptors\n");
+ return -ENOMEM;
+ }
+
+ memset(bd_buffer, 0, (RX_BD_RING_LEN + TX_BD_RING_LEN)
+ * MAX_RX_BUF_LENGTH);
+
+ priv->rx_buffer = bd_buffer;
+ priv->tx_buffer = bd_buffer + RX_BD_RING_LEN * MAX_RX_BUF_LENGTH;
+
+ priv->dma_rx_addr = bd_dma_addr;
+ priv->dma_tx_addr = bd_dma_addr + RX_BD_RING_LEN * MAX_RX_BUF_LENGTH;
+
+ for (i = 0; i < RX_BD_RING_LEN; i++) {
+ if (i < (RX_BD_RING_LEN - 1))
+ bd_status = R_E | R_I;
+ else
+ bd_status = R_E | R_I | R_W;
+
+ iowrite32be(bd_status, (u32 *)(priv->rx_bd_base + i));
+ iowrite32be(priv->dma_rx_addr + i * MAX_RX_BUF_LENGTH,
+ &priv->rx_bd_base[i].buf);
+ }
+
+ for (i = 0; i < TX_BD_RING_LEN; i++) {
+ if (i < (TX_BD_RING_LEN - 1))
+ bd_status = T_I | T_TC;
+ else
+ bd_status = T_I | T_TC | T_W;
+
+ iowrite32be(bd_status, (u32 *)(priv->tx_bd_base + i));
+ iowrite32be(priv->dma_tx_addr + i * MAX_RX_BUF_LENGTH,
+ &priv->tx_bd_base[i].buf);
+ }
+
+ return 0;
+
+tiptr_alloc_error:
+ qe_muram_free(riptr);
+riptr_alloc_error:
+ kfree(priv->tx_skbuff);
+tx_skb_alloc_error:
+ kfree(priv->rx_skbuff);
+rx_skb_alloc_error:
+ qe_muram_free(priv->ucc_pram_offset);
+pram_alloc_error:
+ dma_free_coherent(priv->dev,
+ TX_BD_RING_LEN * sizeof(struct qe_bd),
+ priv->tx_bd_base, priv->dma_tx_bd);
+txbd_alloc_error:
+ dma_free_coherent(priv->dev,
+ RX_BD_RING_LEN * sizeof(struct qe_bd),
+ priv->rx_bd_base, priv->dma_rx_bd);
+rxbd_alloc_error:
+ ucc_fast_free(priv->uccf);
+
+ return ret;
+}
+
+static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct ucc_hdlc_private *priv = (struct ucc_hdlc_private *)hdlc->priv;
+ struct qe_bd __iomem *bd;
+ u32 bd_status;
+ unsigned long flags;
+#ifdef QE_HDLC_TEST
+ u8 *send_buf;
+ int i;
+#endif
+ u16 *proto_head, tmp_head;
+
+ switch (dev->type) {
+ case ARPHRD_RAWHDLC:
+ if (skb_headroom(skb) < HDLC_HEAD_LEN) {
+ dev->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ netdev_err(dev, "No enough space for hdlc head\n");
+ return -ENOMEM;
+ }
+
+ skb_push(skb, HDLC_HEAD_LEN);
+
+ proto_head = (u16 *)skb->data;
+ tmp_head = *proto_head;
+ tmp_head = (tmp_head & HDLC_HEAD_MASK) |
+ htons(DEFAULT_HDLC_HEAD);
+ *proto_head = tmp_head;
+
+ dev->stats.tx_bytes += skb->len;
+ break;
+
+ case ARPHRD_PPP:
+ proto_head = (u16 *)skb->data;
+ if (*proto_head != ntohs(DEFAULT_PPP_HEAD)) {
+ dev->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ netdev_err(dev, "Wrong ppp header\n");
+ return -ENOMEM;
+ }
+
+ dev->stats.tx_bytes += skb->len;
+ break;
+
+ default:
+ dev->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ netdev_err(dev, "Protocol not supported!\n");
+ return -ENOMEM;
+
+ } /*switch right bracket*/
+
+#ifdef QE_HDLC_TEST
+ pr_info("Tx data skb->len:%d ", skb->len);
+ send_buf = (u8 *)skb->data;
+ pr_info("\nTransmitted data:\n");
+ for (i = 0; (i < 16); i++) {
+ if (i == skb->len)
+ pr_info("++++");
+ else
+ pr_info("%02x\n", send_buf[i]);
+ }
+#endif
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Start from the next BD that should be filled */
+ bd = priv->curtx_bd;
+ bd_status = ioread32be((u32 __iomem *)bd);
+ /* Save the skb pointer so we can free it later */
+ priv->tx_skbuff[priv->skb_curtx] = skb;
+
+ /* Update the current skb pointer (wrapping if this was the last) */
+ priv->skb_curtx =
+ (priv->skb_curtx + 1) & TX_RING_MOD_MASK(TX_BD_RING_LEN);
+
+ /* copy skb data to tx buffer for sdma processing */
+ memcpy(priv->tx_buffer + (be32_to_cpu(bd->buf) - priv->dma_tx_addr),
+ skb->data, skb->len);
+
+ /* set bd status and length */
+ bd_status = (bd_status & T_W) | T_R | T_I | T_L | T_TC | skb->len;
+
+ iowrite32be(bd_status, (u32 __iomem *)bd);
+
+ /* Move to next BD in the ring */
+ if (!(bd_status & T_W))
+ bd += 1;
+ else
+ bd = priv->tx_bd_base;
+
+ if (bd == priv->dirty_tx) {
+ if (!netif_queue_stopped(dev))
+ netif_stop_queue(dev);
+ }
+
+ priv->curtx_bd = bd;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return NETDEV_TX_OK;
+}
+
+static int hdlc_tx_done(struct ucc_hdlc_private *priv)
+{
+ /* Start from the next BD that should be filled */
+ struct net_device *dev = priv->ndev;
+ struct qe_bd *bd; /* BD pointer */
+ u32 bd_status;
+
+ bd = priv->dirty_tx;
+ bd_status = ioread32be((u32 __iomem *)bd);
+
+ /* Normal processing. */
+ while ((bd_status & T_R) == 0) {
+ struct sk_buff *skb;
+
+ /* BD contains already transmitted buffer. */
+ /* Handle the transmitted buffer and release */
+ /* the BD to be used with the current frame */
+
+ skb = priv->tx_skbuff[priv->skb_dirtytx];
+ if (!skb)
+ break;
+#ifdef QE_HDLC_TEST
+ pr_info("TxBD: %x\n", bd_status);
+#endif
+ dev->stats.tx_packets++;
+ memset(priv->tx_buffer +
+ (be32_to_cpu(bd->buf) - priv->dma_tx_addr),
+ 0, skb->len);
+ dev_kfree_skb_irq(skb);
+
+ priv->tx_skbuff[priv->skb_dirtytx] = NULL;
+ priv->skb_dirtytx =
+ (priv->skb_dirtytx +
+ 1) & TX_RING_MOD_MASK(TX_BD_RING_LEN);
+
+ /* We freed a buffer, so now we can restart transmission */
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+
+ /* Advance the confirmation BD pointer */
+ if (!(bd_status & T_W))
+ bd += 1;
+ else
+ bd = priv->tx_bd_base;
+ bd_status = ioread32be((u32 __iomem *)bd);
+ }
+ priv->dirty_tx = bd;
+
+ return 0;
+}
+
+static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit)
+{
+ struct net_device *dev = priv->ndev;
+ struct sk_buff *skb;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct qe_bd *bd;
+ u32 bd_status;
+ u16 length, howmany = 0;
+ u8 *bdbuffer;
+#ifdef QE_HDLC_TEST
+ int i;
+ static int entry;
+#endif
+
+ bd = priv->currx_bd;
+ bd_status = ioread32be((u32 __iomem *)bd);
+
+ /* while there are received buffers and BD is full (~R_E) */
+ while (!((bd_status & (R_E)) || (--rx_work_limit < 0))) {
+ if (bd_status & R_CR) {
+#ifdef BROKEN_FRAME_INFO
+ pr_info("Broken Frame with RxBD: %x\n", bd_status);
+#endif
+ dev->stats.rx_dropped++;
+ goto recycle;
+ }
+ bdbuffer = priv->rx_buffer +
+ (priv->currx_bdnum * MAX_RX_BUF_LENGTH);
+ length = (u16)(bd_status & BD_LENGTH_MASK);
+
+#ifdef QE_HDLC_TEST
+ pr_info("Received data length:%d", length);
+ pr_info("while entry times:%d", entry++);
+
+ pr_info("\nReceived data:\n");
+ for (i = 0; (i < 16); i++) {
+ if (i == length)
+ pr_info("++++");
+ else
+ pr_info("%02x\n", bdbuffer[i]);
+ }
+#endif
+
+ switch (dev->type) {
+ case ARPHRD_RAWHDLC:
+ bdbuffer += HDLC_HEAD_LEN;
+ length -= (HDLC_HEAD_LEN + HDLC_CRC_SIZE);
+
+ skb = dev_alloc_skb(length);
+ if (!skb) {
+ dev->stats.rx_dropped++;
+ return -ENOMEM;
+ }
+
+ skb_put(skb, length);
+ skb->len = length;
+ skb->dev = dev;
+ memcpy(skb->data, bdbuffer, length);
+ break;
+
+ case ARPHRD_PPP:
+ length -= HDLC_CRC_SIZE;
+
+ skb = dev_alloc_skb(length);
+ if (!skb) {
+ dev->stats.rx_dropped++;
+ return -ENOMEM;
+ }
+
+ skb_put(skb, length);
+ skb->len = length;
+ skb->dev = dev;
+ memcpy(skb->data, bdbuffer, length);
+ break;
+ }
+
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+ howmany++;
+ if (hdlc->proto)
+ skb->protocol = hdlc_type_trans(skb, dev);
+#ifdef QE_HDLC_TEST
+ pr_info("skb->protocol:%x\n", skb->protocol);
+#endif
+ netif_receive_skb(skb);
+
+recycle:
+ iowrite32be((bd_status & ~BD_LENGTH_MASK) | R_E | R_I,
+ (u32 *)bd);
+
+ /* update to point at the next bd */
+ if (bd_status & R_W) {
+ priv->currx_bdnum = 0;
+ bd = priv->rx_bd_base;
+ } else {
+ if (priv->currx_bdnum < (RX_BD_RING_LEN - 1))
+ priv->currx_bdnum += 1;
+ else
+ priv->currx_bdnum = RX_BD_RING_LEN - 1;
+
+ bd += 1;
+ }
+
+ bd_status = ioread32be((u32 __iomem *)bd);
+ }
+
+ priv->currx_bd = bd;
+ return howmany;
+}
+
+static int ucc_hdlc_poll(struct napi_struct *napi, int budget)
+{
+ struct ucc_hdlc_private *priv = container_of(napi,
+ struct ucc_hdlc_private,
+ napi);
+ int howmany;
+
+ /* Tx event processing */
+ spin_lock(&priv->lock);
+ hdlc_tx_done(priv);
+ spin_unlock(&priv->lock);
+
+ howmany = 0;
+ howmany += hdlc_rx_done(priv, budget - howmany);
+
+ if (howmany < budget) {
+ napi_complete(napi);
+ qe_setbits32(priv->uccf->p_uccm,
+ (UCCE_HDLC_RX_EVENTS | UCCE_HDLC_TX_EVENTS) << 16);
+ }
+
+ return howmany;
+}
+
+static irqreturn_t ucc_hdlc_irq_handler(int irq, void *dev_id)
+{
+ struct ucc_hdlc_private *priv = (struct ucc_hdlc_private *)dev_id;
+ struct net_device *dev = priv->ndev;
+ struct ucc_fast_private *uccf;
+ struct ucc_tdm_info *ut_info;
+ u32 ucce;
+ u32 uccm;
+
+ ut_info = priv->ut_info;
+ uccf = priv->uccf;
+
+ ucce = ioread32be(uccf->p_ucce);
+ uccm = ioread32be(uccf->p_uccm);
+ ucce &= uccm;
+ iowrite32be(ucce, uccf->p_ucce);
+#ifdef QE_HDLC_TEST
+ pr_info("irq ucce:%x\n", ucce);
+#endif
+
+ if ((ucce >> 16) & (UCCE_HDLC_RX_EVENTS | UCCE_HDLC_TX_EVENTS)) {
+ if (napi_schedule_prep(&priv->napi)) {
+ uccm &= ~((UCCE_HDLC_RX_EVENTS | UCCE_HDLC_TX_EVENTS)
+ << 16);
+ iowrite32be(uccm, uccf->p_uccm);
+ __napi_schedule(&priv->napi);
+ }
+ }
+
+ /* Errors and other events */
+ if (ucce >> 16 & UCC_HDLC_UCCE_BSY)
+ dev->stats.rx_errors++;
+ if (ucce >> 16 & UCC_HDLC_UCCE_TXE)
+ dev->stats.tx_errors++;
+
+ return IRQ_HANDLED;
+}
+
+static int uhdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ const size_t size = sizeof(te1_settings);
+ te1_settings line;
+ struct ucc_hdlc_private *priv = netdev_priv(dev);
+
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_IFACE:
+ ifr->ifr_settings.type = IF_IFACE_E1;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+ line.clock_type = priv->clocking;
+ line.clock_rate = 0;
+ line.loopback = 0;
+
+ if (copy_to_user(ifr->ifr_settings.ifs_ifsu.sync, &line, size))
+ return -EFAULT;
+ return 0;
+
+ default:
+ return hdlc_ioctl(dev, ifr, cmd);
+ }
+}
+
+static int uhdlc_open(struct net_device *dev)
+{
+ u32 cecr_subblock;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct ucc_hdlc_private *priv = hdlc->priv;
+ struct ucc_tdm *utdm = priv->utdm;
+
+ if (priv->hdlc_busy != 1) {
+ if (request_irq(priv->ut_info->uf_info.irq,
+ ucc_hdlc_irq_handler, 0,
+ "hdlc", (void *)priv)) {
+ dev_err(priv->dev, "request_irq for ucc hdlc failed\n");
+ return -ENODEV;
+ }
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(
+ priv->ut_info->uf_info.ucc_num);
+
+ qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ ucc_fast_enable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
+
+ /* Enable the TDM port */
+ if (priv->tsa)
+ utdm->si_regs->siglmr1_h |= (0x1 << utdm->tdm_port);
+
+ priv->hdlc_busy = 1;
+ netif_device_attach(priv->ndev);
+ napi_enable(&priv->napi);
+ netif_start_queue(dev);
+ hdlc_open(dev);
+ } else {
+ dev_err(priv->dev, "HDLC IS RUNNING!\n");
+ }
+
+#ifdef DEBUG
+ dump_priv(priv);
+ dump_ucc(priv);
+ dump_bds(priv);
+#endif
+ return 0;
+}
+
+static void uhdlc_memclean(struct ucc_hdlc_private *priv)
+{
+ qe_muram_free(priv->ucc_pram->riptr);
+ qe_muram_free(priv->ucc_pram->tiptr);
+
+ if (priv->rx_bd_base) {
+ dma_free_coherent(priv->dev,
+ RX_BD_RING_LEN * sizeof(struct qe_bd),
+ priv->rx_bd_base, priv->dma_rx_bd);
+
+ priv->rx_bd_base = NULL;
+ priv->dma_rx_bd = 0;
+ }
+
+ if (priv->tx_bd_base) {
+ dma_free_coherent(priv->dev,
+ TX_BD_RING_LEN * sizeof(struct qe_bd),
+ priv->tx_bd_base, priv->dma_tx_bd);
+
+ priv->tx_bd_base = NULL;
+ priv->dma_tx_bd = 0;
+ }
+
+ if (priv->ucc_pram) {
+ qe_muram_free(priv->ucc_pram_offset);
+ priv->ucc_pram = NULL;
+ priv->ucc_pram_offset = 0;
+ }
+
+ kfree(priv->rx_skbuff);
+ priv->rx_skbuff = NULL;
+
+ kfree(priv->tx_skbuff);
+ priv->tx_skbuff = NULL;
+
+ if (priv->uf_regs) {
+ iounmap(priv->uf_regs);
+ priv->uf_regs = NULL;
+ }
+
+ if (priv->uccf) {
+ ucc_fast_free(priv->uccf);
+ priv->uccf = NULL;
+ }
+
+ if (priv->rx_buffer) {
+ dma_free_coherent(priv->dev,
+ RX_BD_RING_LEN * MAX_RX_BUF_LENGTH,
+ priv->rx_buffer, priv->dma_rx_addr);
+ priv->rx_buffer = NULL;
+ priv->dma_rx_addr = 0;
+ }
+
+ if (priv->tx_buffer) {
+ dma_free_coherent(priv->dev,
+ TX_BD_RING_LEN * MAX_RX_BUF_LENGTH,
+ priv->tx_buffer, priv->dma_tx_addr);
+ priv->tx_buffer = NULL;
+ priv->dma_tx_addr = 0;
+ }
+}
+
+static int uhdlc_close(struct net_device *dev)
+{
+ struct ucc_hdlc_private *priv = dev_to_hdlc(dev)->priv;
+ struct ucc_tdm *utdm = priv->utdm;
+ u32 cecr_subblock;
+
+ napi_disable(&priv->napi);
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(
+ priv->ut_info->uf_info.ucc_num);
+
+ qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
+ qe_issue_cmd(QE_CLOSE_RX_BD, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ if (priv->tsa)
+ utdm->si_regs->siglmr1_h &= ~(0x1 << utdm->tdm_port);
+
+ ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
+
+ free_irq(priv->ut_info->uf_info.irq, priv);
+ netif_stop_queue(dev);
+ priv->hdlc_busy = 0;
+
+ return 0;
+}
+
+static int ucc_hdlc_attach(struct net_device *dev, unsigned short encoding,
+ unsigned short parity)
+{
+ struct ucc_hdlc_private *priv = dev_to_hdlc(dev)->priv;
+
+ if (encoding != ENCODING_NRZ &&
+ encoding != ENCODING_NRZI)
+ return -EINVAL;
+
+ if (parity != PARITY_NONE &&
+ parity != PARITY_CRC32_PR1_CCITT &&
+ parity != PARITY_CRC16_PR1_CCITT)
+ return -EINVAL;
+
+ priv->encoding = encoding;
+ priv->parity = parity;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static void store_clk_config(struct ucc_hdlc_private *priv)
+{
+ struct qe_mux *qe_mux_reg = &qe_immr->qmx;
+
+ /* store si clk */
+ priv->cmxsi1cr_h = ioread32be(&qe_mux_reg->cmxsi1cr_h);
+ priv->cmxsi1cr_l = ioread32be(&qe_mux_reg->cmxsi1cr_l);
+
+ /* store si sync */
+ priv->cmxsi1syr = ioread32be(&qe_mux_reg->cmxsi1syr);
+
+ /* store ucc clk */
+ memcpy_fromio(priv->cmxucr, qe_mux_reg->cmxucr, 4 * sizeof(u32));
+}
+
+static void resume_clk_config(struct ucc_hdlc_private *priv)
+{
+ struct qe_mux *qe_mux_reg = &qe_immr->qmx;
+
+ memcpy_toio(qe_mux_reg->cmxucr, priv->cmxucr, 4 * sizeof(u32));
+
+ iowrite32be(priv->cmxsi1cr_h, &qe_mux_reg->cmxsi1cr_h);
+ iowrite32be(priv->cmxsi1cr_l, &qe_mux_reg->cmxsi1cr_l);
+
+ iowrite32be(priv->cmxsi1syr, &qe_mux_reg->cmxsi1syr);
+}
+
+static int uhdlc_suspend(struct device *dev)
+{
+ struct ucc_hdlc_private *priv = dev_get_drvdata(dev);
+ struct ucc_tdm_info *ut_info;
+ struct ucc_fast __iomem *uf_regs;
+
+ if (!priv)
+ return -EINVAL;
+
+ if (!netif_running(priv->ndev))
+ return 0;
+
+ netif_device_detach(priv->ndev);
+ napi_disable(&priv->napi);
+
+ ut_info = priv->ut_info;
+ uf_regs = priv->uf_regs;
+
+ /* backup gumr guemr*/
+ priv->gumr = ioread32be(&uf_regs->gumr);
+ priv->guemr = ioread8(&uf_regs->guemr);
+
+ priv->ucc_pram_bak = kmalloc(sizeof(*priv->ucc_pram_bak),
+ GFP_KERNEL);
+ if (!priv->ucc_pram_bak)
+ return -ENOMEM;
+
+ /* backup HDLC parameter */
+ memcpy_fromio(priv->ucc_pram_bak, priv->ucc_pram,
+ sizeof(struct ucc_hdlc_param));
+
+ /* store the clk configuration */
+ store_clk_config(priv);
+
+ /* save power */
+ ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
+
+ dev_dbg(dev, "ucc hdlc suspend\n");
+ return 0;
+}
+
+static int uhdlc_resume(struct device *dev)
+{
+ struct ucc_hdlc_private *priv = dev_get_drvdata(dev);
+ struct ucc_tdm *utdm = priv->utdm;
+ struct ucc_tdm_info *ut_info;
+ struct ucc_fast __iomem *uf_regs;
+ struct ucc_fast_private *uccf;
+ struct ucc_fast_info *uf_info;
+ int ret, i;
+ u32 cecr_subblock, bd_status;
+
+ if (!priv)
+ return -EINVAL;
+
+ if (!netif_running(priv->ndev))
+ return 0;
+
+ ut_info = priv->ut_info;
+ uf_info = &ut_info->uf_info;
+ uf_regs = priv->uf_regs;
+ uccf = priv->uccf;
+
+ /* restore gumr guemr */
+ iowrite8(priv->guemr, &uf_regs->guemr);
+ iowrite32be(priv->gumr, &uf_regs->gumr);
+
+ /* Set Virtual Fifo registers */
+ iowrite16be(uf_info->urfs, &uf_regs->urfs);
+ iowrite16be(uf_info->urfet, &uf_regs->urfet);
+ iowrite16be(uf_info->urfset, &uf_regs->urfset);
+ iowrite16be(uf_info->utfs, &uf_regs->utfs);
+ iowrite16be(uf_info->utfet, &uf_regs->utfet);
+ iowrite16be(uf_info->utftt, &uf_regs->utftt);
+ /* utfb, urfb are offsets from MURAM base */
+ iowrite32be(uccf->ucc_fast_tx_virtual_fifo_base_offset, &uf_regs->utfb);
+ iowrite32be(uccf->ucc_fast_rx_virtual_fifo_base_offset, &uf_regs->urfb);
+
+ /* Rx Tx and sync clock routing */
+ resume_clk_config(priv);
+
+ iowrite32be(uf_info->uccm_mask, &uf_regs->uccm);
+ iowrite32be(0xffffffff, &uf_regs->ucce);
+
+ ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
+
+ /* rebuild SIRAM */
+ if (priv->tsa)
+ ucc_tdm_init(priv->utdm, priv->ut_info);
+
+ /* Write to QE CECR, UCCx channel to Stop Transmission */
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
+ ret = qe_issue_cmd(QE_STOP_TX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ /* Set UPSMR normal mode */
+ iowrite32be(0, &uf_regs->upsmr);
+
+ /* init parameter base */
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
+ ret = qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, cecr_subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, priv->ucc_pram_offset);
+
+ priv->ucc_pram = (struct ucc_hdlc_param __iomem *)
+ qe_muram_addr(priv->ucc_pram_offset);
+
+ /* restore ucc parameter */
+ memcpy_toio(priv->ucc_pram, priv->ucc_pram_bak,
+ sizeof(struct ucc_hdlc_param));
+ kfree(priv->ucc_pram_bak);
+
+ /* rebuild BD entry */
+ for (i = 0; i < RX_BD_RING_LEN; i++) {
+ if (i < (RX_BD_RING_LEN - 1))
+ bd_status = R_E | R_I;
+ else
+ bd_status = R_E | R_I | R_W;
+
+ iowrite32be(bd_status, (u32 *)(priv->rx_bd_base + i));
+ iowrite32be(priv->dma_rx_addr + i * MAX_RX_BUF_LENGTH,
+ &priv->rx_bd_base[i].buf);
+ }
+
+ for (i = 0; i < TX_BD_RING_LEN; i++) {
+ if (i < (TX_BD_RING_LEN - 1))
+ bd_status = T_I | T_TC;
+ else
+ bd_status = T_I | T_TC | T_W;
+
+ iowrite32be(bd_status, (u32 *)(priv->tx_bd_base + i));
+ iowrite32be(priv->dma_tx_addr + i * MAX_RX_BUF_LENGTH,
+ &priv->tx_bd_base[i].buf);
+ }
+
+ /* if hdlc is busy enable TX and RX */
+ if (priv->hdlc_busy == 1) {
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(
+ priv->ut_info->uf_info.ucc_num);
+
+ qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ ucc_fast_enable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
+
+ /* Enable the TDM port */
+ if (priv->tsa)
+ utdm->si_regs->siglmr1_h |= (0x1 << utdm->tdm_port);
+ }
+
+ napi_enable(&priv->napi);
+ netif_device_attach(priv->ndev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops uhdlc_pm_ops = {
+ .suspend = uhdlc_suspend,
+ .resume = uhdlc_resume,
+ .freeze = uhdlc_suspend,
+ .thaw = uhdlc_resume,
+};
+
+#define HDLC_PM_OPS (&uhdlc_pm_ops)
+
+#else
+
+#define HDLC_PM_OPS NULL
+
+#endif
+static const struct net_device_ops uhdlc_ops = {
+ .ndo_open = uhdlc_open,
+ .ndo_stop = uhdlc_close,
+ .ndo_change_mtu = hdlc_change_mtu,
+ .ndo_start_xmit = hdlc_start_xmit,
+ .ndo_do_ioctl = uhdlc_ioctl,
+};
+
+static int ucc_hdlc_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct ucc_hdlc_private *uhdlc_priv = NULL;
+ struct ucc_tdm_info *ut_info;
+ struct ucc_tdm *utdm;
+ struct resource res;
+ struct net_device *dev;
+ hdlc_device *hdlc;
+ int ucc_num;
+ const char *sprop;
+ int ret;
+ u32 val;
+
+ ret = of_property_read_u32_index(np, "cell-index", 0, &val);
+ if (ret) {
+ dev_err(&pdev->dev, "Invalid ucc property\n");
+ return -ENODEV;
+ }
+
+ ucc_num = val - 1;
+ if ((ucc_num > 3) || (ucc_num < 0)) {
+ dev_err(&pdev->dev, ": Invalid UCC num\n");
+ return -EINVAL;
+ }
+
+ memcpy(&utdm_info[ucc_num], &utdm_primary_info,
+ sizeof(utdm_primary_info));
+
+ ut_info = &utdm_info[ucc_num];
+ ut_info->uf_info.ucc_num = ucc_num;
+
+ sprop = of_get_property(np, "rx-clock-name", NULL);
+ if (sprop) {
+ ut_info->uf_info.rx_clock = qe_clock_source(sprop);
+ if ((ut_info->uf_info.rx_clock < QE_CLK_NONE) ||
+ (ut_info->uf_info.rx_clock > QE_CLK24)) {
+ dev_err(&pdev->dev, "Invalid rx-clock-name property\n");
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&pdev->dev, "Invalid rx-clock-name property\n");
+ return -EINVAL;
+ }
+
+ sprop = of_get_property(np, "tx-clock-name", NULL);
+ if (sprop) {
+ ut_info->uf_info.tx_clock = qe_clock_source(sprop);
+ if ((ut_info->uf_info.tx_clock < QE_CLK_NONE) ||
+ (ut_info->uf_info.tx_clock > QE_CLK24)) {
+ dev_err(&pdev->dev, "Invalid tx-clock-name property\n");
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&pdev->dev, "Invalid tx-clock-name property\n");
+ return -EINVAL;
+ }
+
+ /* use the same clock when work in loopback */
+ if (ut_info->uf_info.rx_clock == ut_info->uf_info.tx_clock)
+ qe_setbrg(ut_info->uf_info.rx_clock, 20000000, 1);
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ return -EINVAL;
+
+ ut_info->uf_info.regs = res.start;
+ ut_info->uf_info.irq = irq_of_parse_and_map(np, 0);
+
+ uhdlc_priv = kzalloc(sizeof(*uhdlc_priv), GFP_KERNEL);
+ if (!uhdlc_priv) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev, "No mem to alloc hdlc private data\n");
+ goto err_alloc_priv;
+ }
+
+ dev_set_drvdata(&pdev->dev, uhdlc_priv);
+ uhdlc_priv->dev = &pdev->dev;
+ uhdlc_priv->ut_info = ut_info;
+
+ if (of_get_property(np, "fsl,tdm-interface", NULL))
+ uhdlc_priv->tsa = 1;
+
+ if (of_get_property(np, "fsl,ucc-internal-loopback", NULL))
+ uhdlc_priv->loopback = 1;
+
+ if (uhdlc_priv->tsa == 1) {
+ utdm = kzalloc(sizeof(*utdm), GFP_KERNEL);
+ if (!utdm) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev, "No mem to alloc ucc tdm data\n");
+ goto err_alloc_utdm;
+ }
+ uhdlc_priv->utdm = utdm;
+ ret = ucc_of_parse_tdm(np, utdm, ut_info);
+ if (ret)
+ goto err_miss_tsa_property;
+ }
+
+ ret = uhdlc_init(uhdlc_priv);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to init uhdlc\n");
+ goto err_hdlc_init;
+ }
+
+ dev = alloc_hdlcdev(uhdlc_priv);
+ if (!dev) {
+ ret = -ENOMEM;
+ pr_err("ucc_hdlc: unable to allocate memory\n");
+ goto err_hdlc_init;
+ }
+
+ uhdlc_priv->ndev = dev;
+ hdlc = dev_to_hdlc(dev);
+ dev->tx_queue_len = 16;
+ dev->netdev_ops = &uhdlc_ops;
+ hdlc->attach = ucc_hdlc_attach;
+ hdlc->xmit = ucc_hdlc_tx;
+ netif_napi_add(dev, &uhdlc_priv->napi, ucc_hdlc_poll, 32);
+ if (register_hdlc_device(dev)) {
+ ret = -ENOBUFS;
+ pr_err("ucc_hdlc: unable to register hdlc device\n");
+ free_netdev(dev);
+ goto err_hdlc_init;
+ }
+
+#ifdef DEBUG
+ dump_priv(uhdlc_priv);
+ dump_ucc(uhdlc_priv);
+ dump_bds(uhdlc_priv);
+ if (uhdlc_priv->tsa)
+ mem_disp((u8 *)uhdlc_priv->utdm->si_regs, 0x20);
+#endif
+
+ return 0;
+
+err_hdlc_init:
+err_miss_tsa_property:
+ kfree(uhdlc_priv);
+ if (uhdlc_priv->tsa)
+ kfree(utdm);
+err_alloc_utdm:
+ kfree(uhdlc_priv);
+err_alloc_priv:
+ return ret;
+}
+
+static int ucc_hdlc_remove(struct platform_device *pdev)
+{
+ struct ucc_hdlc_private *priv = dev_get_drvdata(&pdev->dev);
+
+ uhdlc_memclean(priv);
+
+ if (priv->utdm->si_regs) {
+ iounmap(priv->utdm->si_regs);
+ priv->utdm->si_regs = NULL;
+ }
+
+ if (priv->utdm->siram) {
+ iounmap(priv->utdm->siram);
+ priv->utdm->siram = NULL;
+ }
+ kfree(priv);
+
+ dev_info(&pdev->dev, "UCC based hdlc module removed\n");
+
+ return 0;
+}
+
+static const struct of_device_id fsl_ucc_hdlc_of_match[] = {
+ {
+ .compatible = "fsl,ucc-hdlc",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, fsl_ucc_hdlc_of_match);
+
+static struct platform_driver ucc_hdlc_driver = {
+ .probe = ucc_hdlc_probe,
+ .remove = ucc_hdlc_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .pm = HDLC_PM_OPS,
+ .of_match_table = fsl_ucc_hdlc_of_match,
+ },
+};
+
+static int __init ucc_hdlc_init(void)
+{
+ return platform_driver_register(&ucc_hdlc_driver);
+}
+
+static void __exit ucc_hdlc_exit(void)
+{
+ platform_driver_unregister(&ucc_hdlc_driver);
+}
+
+module_init(ucc_hdlc_init);
+module_exit(ucc_hdlc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale Semiconductor Inc.");
+MODULE_DESCRIPTION("Driver For Freescale QE UCC HDLC controller");
+MODULE_VERSION("1.0");
diff --git a/drivers/net/wan/fsl_ucc_hdlc.h b/drivers/net/wan/fsl_ucc_hdlc.h
new file mode 100644
index 0000000..ded03d6
--- /dev/null
+++ b/drivers/net/wan/fsl_ucc_hdlc.h
@@ -0,0 +1,140 @@
+/* Freescale QUICC Engine HDLC Device Driver
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#ifndef CONFIG_UCC_HDLC_H
+#define CONFIG_UCC_HDLC_H
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
+
+#include <soc/fsl/qe/ucc.h>
+#include <soc/fsl/qe/ucc_fast.h>
+
+/* UCC HDLC event register */
+#define UCCE_HDLC_RX_EVENTS \
+(UCC_HDLC_UCCE_RXF | UCC_HDLC_UCCE_RXB | UCC_HDLC_UCCE_BSY)
+#define UCCE_HDLC_TX_EVENTS (UCC_HDLC_UCCE_TXB | UCC_HDLC_UCCE_TXE)
+
+struct ucc_hdlc_param {
+ __be16 riptr;
+ __be16 tiptr;
+ __be16 res0;
+ __be16 mrblr;
+ __be32 rstate;
+ __be32 rbase;
+ __be16 rbdstat;
+ __be16 rbdlen;
+ __be32 rdptr;
+ __be32 tstate;
+ __be32 tbase;
+ __be16 tbdstat;
+ __be16 tbdlen;
+ __be32 tdptr;
+ __be32 rbptr;
+ __be32 tbptr;
+ __be32 rcrc;
+ __be32 res1;
+ __be32 tcrc;
+ __be32 res2;
+ __be32 res3;
+ __be32 c_mask;
+ __be32 c_pres;
+ __be16 disfc;
+ __be16 crcec;
+ __be16 abtsc;
+ __be16 nmarc;
+ __be32 max_cnt;
+ __be16 mflr;
+ __be16 rfthr;
+ __be16 rfcnt;
+ __be16 hmask;
+ __be16 haddr1;
+ __be16 haddr2;
+ __be16 haddr3;
+ __be16 haddr4;
+ __be16 ts_tmp;
+ __be16 tmp_mb;
+} __attribute__ ((__packed__));
+
+struct ucc_hdlc_private {
+ struct ucc_tdm *utdm;
+ struct ucc_tdm_info *ut_info;
+ struct ucc_fast_private *uccf;
+ struct device *dev;
+ struct net_device *ndev;
+ struct napi_struct napi;
+ struct ucc_fast __iomem *uf_regs; /* UCC Fast registers */
+ struct ucc_hdlc_param __iomem *ucc_pram;
+ u16 tsa;
+ bool hdlc_busy;
+ u8 loopback;
+
+ u8 *tx_buffer; /* buffer used for Tx by the HDLC */
+ u8 *rx_buffer; /* buffer used for Rx by the HDLC */
+ dma_addr_t dma_tx_addr; /* dma mapped buffer for HDLC Tx */
+ dma_addr_t dma_rx_addr; /* dma mapped buffer for HDLC Rx */
+
+ struct qe_bd *tx_bd_base;
+ struct qe_bd *rx_bd_base;
+ dma_addr_t dma_tx_bd;
+ dma_addr_t dma_rx_bd;
+ struct qe_bd *curtx_bd;
+ struct qe_bd *currx_bd;
+ struct qe_bd *dirty_tx;
+ u16 currx_bdnum;
+
+ struct sk_buff **tx_skbuff;
+ struct sk_buff **rx_skbuff;
+ u16 skb_curtx;
+ u16 skb_currx;
+ unsigned short skb_dirtytx;
+
+ unsigned short tx_ring_size;
+ unsigned short rx_ring_size;
+ u32 ucc_pram_offset;
+
+ unsigned short encoding;
+ unsigned short parity;
+ u32 clocking;
+ spinlock_t lock; /* lock for Tx BD and Tx buffer */
+#ifdef CONFIG_PM
+ struct ucc_hdlc_param *ucc_pram_bak;
+ u32 gumr;
+ u8 guemr;
+ u32 cmxsi1cr_l, cmxsi1cr_h;
+ u32 cmxsi1syr;
+ u32 cmxucr[4];
+#endif
+};
+
+#define TX_BD_RING_LEN 0x10
+#define RX_BD_RING_LEN 0x20
+#define RX_CLEAN_MAX 0x10
+#define NUM_OF_BUF 4
+#define MAX_RX_BUF_LENGTH (48 * 0x20)
+#define ALIGNMENT_OF_UCC_HDLC_PRAM 64
+#define SI_BANK_SIZE 128
+#define MAX_HDLC_NUM 4
+#define HDLC_HEAD_LEN 2
+#define HDLC_CRC_SIZE 2
+#define TX_RING_MOD_MASK(size) (size - 1)
+#define RX_RING_MOD_MASK(size) (size - 1)
+
+#define HDLC_HEAD_MASK 0x0000
+#define DEFAULT_HDLC_HEAD 0xff44
+#define DEFAULT_ADDR_MASK 0x00ff
+#define DEFAULT_HDLC_ADDR 0x00ff
+
+#define DEFAULT_PPP_HEAD 0xff03
+
+#endif
diff --git a/include/soc/fsl/qe/ucc_fast.h b/include/soc/fsl/qe/ucc_fast.h
index e898895..d775550 100644
--- a/include/soc/fsl/qe/ucc_fast.h
+++ b/include/soc/fsl/qe/ucc_fast.h
@@ -27,12 +27,16 @@
#define R_I 0x10000000 /* interrupt on reception */
#define R_L 0x08000000 /* last */
#define R_F 0x04000000 /* first */
+#define R_CM 0x02000000 /* first */
+#define R_CR 0x00040000 /* first */
/* transmit BD's status */
#define T_R 0x80000000 /* ready bit */
#define T_W 0x20000000 /* wrap bit */
#define T_I 0x10000000 /* interrupt on completion */
#define T_L 0x08000000 /* last */
+#define T_TC 0x04000000 /* crc */
+#define T_TM 0x02000000 /* crc */
/* Rx Data buffer must be 4 bytes aligned in most cases */
#define UCC_FAST_RX_ALIGN 4
--
2.1.0.27.g96db324
^ permalink raw reply related
* Re: Question on rhashtable in worst-case scenario.
From: Johannes Berg @ 2016-03-30 9:14 UTC (permalink / raw)
To: Ben Greear, Linux Kernel Mailing List, Herbert Xu,
linux-wireless@vger.kernel.org, netdev
Cc: Thomas Graf
In-Reply-To: <56FAAA6D.3070806@candelatech.com>
On Tue, 2016-03-29 at 09:16 -0700, Ben Greear wrote:
> Looks like rhashtable has too much policy in it to properly deal with
> cases where there are too many hash collisions, so I am going to work
> on reverting it's use in mac80211.
I'm not really all that happy with that approach - can't we fix the
rhashtable? It's a pretty rare corner case that many keys really are
identical and no kind of hash algorithm, but it seems much better to
still deal with it than to remove the rhashtable usage and go back to
hand-rolling something.
johannes
^ permalink raw reply
* Re: [PATCH] bus: mvebu-mbus: use %pad to print phys_addr_t
From: Gregory CLEMENT @ 2016-03-30 9:37 UTC (permalink / raw)
To: Arnd Bergmann
Cc: David S . Miller, Marcin Wojtas, Evan Wang, netdev,
Thomas Petazzoni, Nicolas Schichan, linux-kernel
In-Reply-To: <3820422.5Ogyd0Xvfq@wuerfel>
Hi Arnd,
On mar., mars 29 2016, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 29 March 2016 18:04:47 Gregory CLEMENT wrote:
>>
>> What is the status of this patch?
>>
>> Do you plan to send a second version with the title fixed as suggested
>> by Joe Perches?
>>
>> Also do you expect that I collect this patch in the mvebu subsystem?
>
> Right now, it's on my long-term todo list along with some 70 other patches
> I need to revisit. If you want to fix up the title and apply it now,
> that would be great, otherwise I'll get to it in a few weeks after coming
> back from ELC/vacation.
So I fixed the title and applied it on mvebu/fixes
Thanks,
Gregory
>
> ARnd
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply
* RE: [PATCH] sctp: avoid refreshing heartbeat timer too often
From: David Laight @ 2016-03-30 9:37 UTC (permalink / raw)
To: 'Marcelo Ricardo Leitner', netdev@vger.kernel.org
Cc: Neil Horman, Vlad Yasevich, linux-sctp@vger.kernel.org
In-Reply-To: <1459258897-21607-1-git-send-email-marcelo.leitner@gmail.com>
From: Marcelo Ricardo Leitner
> Sent: 29 March 2016 14:42
>
> Currently on high rate SCTP streams the heartbeat timer refresh can
> consume quite a lot of resources as timer updates are costly and it
> contains a random factor, which a) is also costly and b) invalidates
> mod_timer() optimization for not editing a timer to the same value.
> It may even cause the timer to be slightly advanced, for no good reason.
Interesting thoughts:
1) Is it necessary to use a different 'random factor' until the timer actually
expires?
2) It might be better to allow the heartbeat timer to expire, on expiry work
out the new interval based on when the last 'refresh' was done.
David
^ permalink raw reply
* Re: bpf: net/core/filter.c:2115 suspicious rcu_dereference_protected() usage!
From: Michal Kubecek @ 2016-03-30 9:42 UTC (permalink / raw)
To: Daniel Borkmann
Cc: Sasha Levin, Jiri Slaby, David S. Miller, ast,
netdev@vger.kernel.org, LKML
In-Reply-To: <56FA93AF.8060001@iogearbox.net>
On Tue, Mar 29, 2016 at 04:39:43PM +0200, Daniel Borkmann wrote:
> >
> >>diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> >>index afdf950617c3..7417d7c20bab 100644
> >>--- a/drivers/net/tun.c
> >>+++ b/drivers/net/tun.c
> >>@@ -1818,11 +1818,13 @@ static int set_offload(struct tun_struct *tun, unsigned long arg)
> >> static void tun_detach_filter(struct tun_struct *tun, int n)
> >> {
> >> int i;
> >>- struct tun_file *tfile;
> >>
> >> for (i = 0; i < n; i++) {
> >>- tfile = rtnl_dereference(tun->tfiles[i]);
> >>- sk_detach_filter(tfile->socket.sk);
> >>+ struct sock *sk = rtnl_dereference(tun->tfiles[i])->socket.sk;
> >>+
> >>+ lock_sock(sk);
> >>+ sk_detach_filter(sk);
> >>+ release_sock(sk);
> >> }
> >>
> >> tun->filter_attached = false;
> >>
> >
> >In tun case, the control path for tun_attach_filter() and tun_detach_filter()
> >is under RTNL lock (held in __tun_chr_ioctl()).
> >
> >So in the BPF core the rcu_dereference_protected(<sk_filter>, sock_owned_by_user(sk))
> >looks like a false positive in this specific use case to me, that we should probably
> >just silence.
> >
> >Running the filter via sk_filter() in tun device happens under rcu_read_lock(),
> >so the dereference and assignment pair seems okay to me.
> >
> >Was wondering whether we should convert this to unattached BPF filter, but this
> >would break with existing expectations from sk_filter() (e.g. security modules).
>
> If we want to silence it, could be something like the below (only compile-tested):
>
> drivers/net/tun.c | 8 +++++---
> include/linux/filter.h | 4 ++++
> net/core/filter.c | 33 +++++++++++++++++++++------------
> 3 files changed, 30 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index afdf950..510e90a 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -622,7 +622,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filte
>
> /* Re-attach the filter to persist device */
> if (!skip_filter && (tun->filter_attached == true)) {
> - err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
> + err = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
> + lockdep_rtnl_is_held());
> if (!err)
> goto out;
> }
> @@ -1822,7 +1823,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n)
>
> for (i = 0; i < n; i++) {
> tfile = rtnl_dereference(tun->tfiles[i]);
> - sk_detach_filter(tfile->socket.sk);
> + __sk_detach_filter(tfile->socket.sk, lockdep_rtnl_is_held());
> }
>
> tun->filter_attached = false;
> @@ -1835,7 +1836,8 @@ static int tun_attach_filter(struct tun_struct *tun)
>
> for (i = 0; i < tun->numqueues; i++) {
> tfile = rtnl_dereference(tun->tfiles[i]);
> - ret = sk_attach_filter(&tun->fprog, tfile->socket.sk);
> + ret = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
> + lockdep_rtnl_is_held());
> if (ret) {
> tun_detach_filter(tun, i);
> return ret;
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index 43aa1f8..a51a536 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -465,10 +465,14 @@ int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog,
> void bpf_prog_destroy(struct bpf_prog *fp);
>
> int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
> +int __sk_attach_filter(struct sock_fprog *fprog, struct sock *sk,
> + bool locked);
> int sk_attach_bpf(u32 ufd, struct sock *sk);
> int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk);
> int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk);
> int sk_detach_filter(struct sock *sk);
> +int __sk_detach_filter(struct sock *sk, bool locked);
> +
> int sk_get_filter(struct sock *sk, struct sock_filter __user *filter,
> unsigned int len);
>
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 2429918..02f2f6c 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -1149,7 +1149,8 @@ void bpf_prog_destroy(struct bpf_prog *fp)
> }
> EXPORT_SYMBOL_GPL(bpf_prog_destroy);
>
> -static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk)
> +static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk,
> + bool locked)
> {
> struct sk_filter *fp, *old_fp;
>
> @@ -1165,10 +1166,8 @@ static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk)
> return -ENOMEM;
> }
>
> - old_fp = rcu_dereference_protected(sk->sk_filter,
> - sock_owned_by_user(sk));
> + old_fp = rcu_dereference_protected(sk->sk_filter, locked);
> rcu_assign_pointer(sk->sk_filter, fp);
> -
> if (old_fp)
> sk_filter_uncharge(sk, old_fp);
>
> @@ -1247,7 +1246,8 @@ struct bpf_prog *__get_filter(struct sock_fprog *fprog, struct sock *sk)
> * occurs or there is insufficient memory for the filter a negative
> * errno code is returned. On success the return is zero.
> */
> -int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
> +int __sk_attach_filter(struct sock_fprog *fprog, struct sock *sk,
> + bool locked)
> {
> struct bpf_prog *prog = __get_filter(fprog, sk);
> int err;
> @@ -1255,7 +1255,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
> if (IS_ERR(prog))
> return PTR_ERR(prog);
>
> - err = __sk_attach_prog(prog, sk);
> + err = __sk_attach_prog(prog, sk, locked);
> if (err < 0) {
> __bpf_prog_release(prog);
> return err;
> @@ -1263,7 +1263,12 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
>
> return 0;
> }
> -EXPORT_SYMBOL_GPL(sk_attach_filter);
> +EXPORT_SYMBOL_GPL(__sk_attach_filter);
> +
> +int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
> +{
> + return __sk_attach_filter(fprog, sk, sock_owned_by_user(sk));
> +}
>
> int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk)
> {
> @@ -1309,7 +1314,7 @@ int sk_attach_bpf(u32 ufd, struct sock *sk)
> if (IS_ERR(prog))
> return PTR_ERR(prog);
>
> - err = __sk_attach_prog(prog, sk);
> + err = __sk_attach_prog(prog, sk, sock_owned_by_user(sk));
> if (err < 0) {
> bpf_prog_put(prog);
> return err;
> @@ -2445,7 +2450,7 @@ static int __init register_sk_filter_ops(void)
> }
> late_initcall(register_sk_filter_ops);
>
> -int sk_detach_filter(struct sock *sk)
> +int __sk_detach_filter(struct sock *sk, bool locked)
> {
> int ret = -ENOENT;
> struct sk_filter *filter;
> @@ -2453,8 +2458,7 @@ int sk_detach_filter(struct sock *sk)
> if (sock_flag(sk, SOCK_FILTER_LOCKED))
> return -EPERM;
>
> - filter = rcu_dereference_protected(sk->sk_filter,
> - sock_owned_by_user(sk));
> + filter = rcu_dereference_protected(sk->sk_filter, locked);
> if (filter) {
> RCU_INIT_POINTER(sk->sk_filter, NULL);
> sk_filter_uncharge(sk, filter);
> @@ -2463,7 +2467,12 @@ int sk_detach_filter(struct sock *sk)
>
> return ret;
> }
> -EXPORT_SYMBOL_GPL(sk_detach_filter);
> +EXPORT_SYMBOL_GPL(__sk_detach_filter);
> +
> +int sk_detach_filter(struct sock *sk)
> +{
> + return __sk_detach_filter(sk, sock_owned_by_user(sk));
> +}
>
> int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf,
> unsigned int len)
> --
> 1.9.3
Looks good to me.
I'm just not sure checking if we hold the right lock depending on caller
is worth the extra complexity. After all, what is really needed is to
hold _some_ lock guaranteeing sk_attach_prog() and sk_detach_filter()
are safe so that just changing the condition in both to
sock_owned_by_user(sk) || lockdep_rtnl_is_held()
could suffice.
Michal Kubecek
^ permalink raw reply
* Re: [PATCH 5/5] drivers/net: support hdlc function for QE-UCC
From: kbuild test robot @ 2016-03-30 9:53 UTC (permalink / raw)
To: Zhao Qiang
Cc: kbuild-all, davem, akpm, gregkh, oss, xiaobo.xie, linux-kernel,
netdev, linuxppc-dev, Zhao Qiang
In-Reply-To: <1459327830-19829-5-git-send-email-qiang.zhao@nxp.com>
[-- Attachment #1: Type: text/plain, Size: 928 bytes --]
Hi Zhao,
[auto build test WARNING on net/master]
[also build test WARNING on v4.6-rc1 next-20160330]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Zhao-Qiang/fsl-qe-add-rx_sync-and-tx_sync-for-TDM-mode/20160330-170411
config: xtensa-allyesconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=xtensa
All warnings (new ones prefixed by >>):
warning: (FSL_UCC_HDLC) selects QUICC_ENGINE which has unmet direct dependencies (FSL_SOC && PPC32)
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 44940 bytes --]
^ permalink raw reply
* Re: [PATCH net-next] net: hns: add support of pause frame ctrl for HNS V2
From: Andy Shevchenko @ 2016-03-30 10:51 UTC (permalink / raw)
To: Yisen Zhuang, davem, salil.mehta, liguozhu, huangdaode, arnd,
andrew, geliangtang, ivecera, lisheng011, fengguang.wu
Cc: charles.chenxin, haifeng.wei, netdev, linux-kernel,
linux-arm-kernel, linuxarm
In-Reply-To: <1459235041-91766-1-git-send-email-Yisen.Zhuang@huawei.com>
On Tue, 2016-03-29 at 15:04 +0800, Yisen Zhuang wrote:
> From: Lisheng <lisheng011@huawei.com>
>
> The patch adds support of pause ctrl for HNS V2, and this feature is
> lost
> by HNS V1:
> 1) service ports can disable rx pause frame,
> 2) debug ports can open tx/rx pause frame.
>
> And this patch updates the REGs about the pause ctrl when updated
> status function called by upper layer routine.
> --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
> +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
>
> +void hns_dsaf_get_rx_mac_pause_en(struct dsaf_device *dsaf_dev, int
> mac_id,
> + u32 *en)
> +{
> + if (AE_IS_VER1(dsaf_dev->dsaf_ver))
> + *en = 1;
> else
> dsaf_write_dev(dsaf_dev, DSAF_PFC_EN_0_REG + mac_id
> * 4, 0xff);
> + *en = dsaf_get_dev_bit(dsaf_dev,
> + DSAF_PAUSE_CFG_REG + mac_id *
> 4,
> + DSAF_MAC_PAUSE_RX_EN_B);
And what the point of if branch then? I think it's an obvious misfix,
you must replace else to } else { and add }.
How did you test this part?
> }
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* Re: bpf: net/core/filter.c:2115 suspicious rcu_dereference_protected() usage!
From: Daniel Borkmann @ 2016-03-30 11:33 UTC (permalink / raw)
To: Michal Kubecek
Cc: Sasha Levin, Jiri Slaby, David S. Miller, ast,
netdev@vger.kernel.org, LKML
In-Reply-To: <20160330094224.GC15048@unicorn.suse.cz>
On 03/30/2016 11:42 AM, Michal Kubecek wrote:
> On Tue, Mar 29, 2016 at 04:39:43PM +0200, Daniel Borkmann wrote:
>>>
>>>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>>>> index afdf950617c3..7417d7c20bab 100644
>>>> --- a/drivers/net/tun.c
>>>> +++ b/drivers/net/tun.c
>>>> @@ -1818,11 +1818,13 @@ static int set_offload(struct tun_struct *tun, unsigned long arg)
>>>> static void tun_detach_filter(struct tun_struct *tun, int n)
>>>> {
>>>> int i;
>>>> - struct tun_file *tfile;
>>>>
>>>> for (i = 0; i < n; i++) {
>>>> - tfile = rtnl_dereference(tun->tfiles[i]);
>>>> - sk_detach_filter(tfile->socket.sk);
>>>> + struct sock *sk = rtnl_dereference(tun->tfiles[i])->socket.sk;
>>>> +
>>>> + lock_sock(sk);
>>>> + sk_detach_filter(sk);
>>>> + release_sock(sk);
>>>> }
>>>>
>>>> tun->filter_attached = false;
>>>>
>>>
>>> In tun case, the control path for tun_attach_filter() and tun_detach_filter()
>>> is under RTNL lock (held in __tun_chr_ioctl()).
>>>
>>> So in the BPF core the rcu_dereference_protected(<sk_filter>, sock_owned_by_user(sk))
>>> looks like a false positive in this specific use case to me, that we should probably
>>> just silence.
>>>
>>> Running the filter via sk_filter() in tun device happens under rcu_read_lock(),
>>> so the dereference and assignment pair seems okay to me.
>>>
>>> Was wondering whether we should convert this to unattached BPF filter, but this
>>> would break with existing expectations from sk_filter() (e.g. security modules).
>>
>> If we want to silence it, could be something like the below (only compile-tested):
>>
>> drivers/net/tun.c | 8 +++++---
>> include/linux/filter.h | 4 ++++
>> net/core/filter.c | 33 +++++++++++++++++++++------------
>> 3 files changed, 30 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>> index afdf950..510e90a 100644
>> --- a/drivers/net/tun.c
>> +++ b/drivers/net/tun.c
>> @@ -622,7 +622,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filte
>>
>> /* Re-attach the filter to persist device */
>> if (!skip_filter && (tun->filter_attached == true)) {
>> - err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
>> + err = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
>> + lockdep_rtnl_is_held());
>> if (!err)
>> goto out;
>> }
>> @@ -1822,7 +1823,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n)
>>
>> for (i = 0; i < n; i++) {
>> tfile = rtnl_dereference(tun->tfiles[i]);
>> - sk_detach_filter(tfile->socket.sk);
>> + __sk_detach_filter(tfile->socket.sk, lockdep_rtnl_is_held());
>> }
>>
>> tun->filter_attached = false;
>> @@ -1835,7 +1836,8 @@ static int tun_attach_filter(struct tun_struct *tun)
>>
>> for (i = 0; i < tun->numqueues; i++) {
>> tfile = rtnl_dereference(tun->tfiles[i]);
>> - ret = sk_attach_filter(&tun->fprog, tfile->socket.sk);
>> + ret = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
>> + lockdep_rtnl_is_held());
>> if (ret) {
>> tun_detach_filter(tun, i);
>> return ret;
>> diff --git a/include/linux/filter.h b/include/linux/filter.h
>> index 43aa1f8..a51a536 100644
>> --- a/include/linux/filter.h
>> +++ b/include/linux/filter.h
>> @@ -465,10 +465,14 @@ int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog,
>> void bpf_prog_destroy(struct bpf_prog *fp);
>>
>> int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
>> +int __sk_attach_filter(struct sock_fprog *fprog, struct sock *sk,
>> + bool locked);
>> int sk_attach_bpf(u32 ufd, struct sock *sk);
>> int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk);
>> int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk);
>> int sk_detach_filter(struct sock *sk);
>> +int __sk_detach_filter(struct sock *sk, bool locked);
>> +
>> int sk_get_filter(struct sock *sk, struct sock_filter __user *filter,
>> unsigned int len);
>>
>> diff --git a/net/core/filter.c b/net/core/filter.c
>> index 2429918..02f2f6c 100644
>> --- a/net/core/filter.c
>> +++ b/net/core/filter.c
>> @@ -1149,7 +1149,8 @@ void bpf_prog_destroy(struct bpf_prog *fp)
>> }
>> EXPORT_SYMBOL_GPL(bpf_prog_destroy);
>>
>> -static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk)
>> +static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk,
>> + bool locked)
>> {
>> struct sk_filter *fp, *old_fp;
>>
>> @@ -1165,10 +1166,8 @@ static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk)
>> return -ENOMEM;
>> }
>>
>> - old_fp = rcu_dereference_protected(sk->sk_filter,
>> - sock_owned_by_user(sk));
>> + old_fp = rcu_dereference_protected(sk->sk_filter, locked);
>> rcu_assign_pointer(sk->sk_filter, fp);
>> -
>> if (old_fp)
>> sk_filter_uncharge(sk, old_fp);
>>
>> @@ -1247,7 +1246,8 @@ struct bpf_prog *__get_filter(struct sock_fprog *fprog, struct sock *sk)
>> * occurs or there is insufficient memory for the filter a negative
>> * errno code is returned. On success the return is zero.
>> */
>> -int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
>> +int __sk_attach_filter(struct sock_fprog *fprog, struct sock *sk,
>> + bool locked)
>> {
>> struct bpf_prog *prog = __get_filter(fprog, sk);
>> int err;
>> @@ -1255,7 +1255,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
>> if (IS_ERR(prog))
>> return PTR_ERR(prog);
>>
>> - err = __sk_attach_prog(prog, sk);
>> + err = __sk_attach_prog(prog, sk, locked);
>> if (err < 0) {
>> __bpf_prog_release(prog);
>> return err;
>> @@ -1263,7 +1263,12 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
>>
>> return 0;
>> }
>> -EXPORT_SYMBOL_GPL(sk_attach_filter);
>> +EXPORT_SYMBOL_GPL(__sk_attach_filter);
>> +
>> +int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
>> +{
>> + return __sk_attach_filter(fprog, sk, sock_owned_by_user(sk));
>> +}
>>
>> int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk)
>> {
>> @@ -1309,7 +1314,7 @@ int sk_attach_bpf(u32 ufd, struct sock *sk)
>> if (IS_ERR(prog))
>> return PTR_ERR(prog);
>>
>> - err = __sk_attach_prog(prog, sk);
>> + err = __sk_attach_prog(prog, sk, sock_owned_by_user(sk));
>> if (err < 0) {
>> bpf_prog_put(prog);
>> return err;
>> @@ -2445,7 +2450,7 @@ static int __init register_sk_filter_ops(void)
>> }
>> late_initcall(register_sk_filter_ops);
>>
>> -int sk_detach_filter(struct sock *sk)
>> +int __sk_detach_filter(struct sock *sk, bool locked)
>> {
>> int ret = -ENOENT;
>> struct sk_filter *filter;
>> @@ -2453,8 +2458,7 @@ int sk_detach_filter(struct sock *sk)
>> if (sock_flag(sk, SOCK_FILTER_LOCKED))
>> return -EPERM;
>>
>> - filter = rcu_dereference_protected(sk->sk_filter,
>> - sock_owned_by_user(sk));
>> + filter = rcu_dereference_protected(sk->sk_filter, locked);
>> if (filter) {
>> RCU_INIT_POINTER(sk->sk_filter, NULL);
>> sk_filter_uncharge(sk, filter);
>> @@ -2463,7 +2467,12 @@ int sk_detach_filter(struct sock *sk)
>>
>> return ret;
>> }
>> -EXPORT_SYMBOL_GPL(sk_detach_filter);
>> +EXPORT_SYMBOL_GPL(__sk_detach_filter);
>> +
>> +int sk_detach_filter(struct sock *sk)
>> +{
>> + return __sk_detach_filter(sk, sock_owned_by_user(sk));
>> +}
>>
>> int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf,
>> unsigned int len)
>> --
>> 1.9.3
>
> Looks good to me.
>
> I'm just not sure checking if we hold the right lock depending on caller
> is worth the extra complexity. After all, what is really needed is to
> hold _some_ lock guaranteeing sk_attach_prog() and sk_detach_filter()
> are safe so that just changing the condition in both to
>
> sock_owned_by_user(sk) || lockdep_rtnl_is_held()
It would certainly silence it, but would be less accurate in terms of lock
proving as opposed to the diff above. E.g. rntl could be held elsewhere,
while someone attaches a socket filter w/o having locked the socket (currently
not the case, but it would kind of defeat the purpose of rcu_dereference_protected()
here). Was thinking about using a extra socket flag to indicate it's
externally managed, but it's not really worth wasting sk's flags bit
space just for this corner case.
> could suffice.
>
> Michal Kubecek
>
^ permalink raw reply
* Re: [PATCH] sctp: really allow using GFP_KERNEL on sctp_packet_transmit
From: Neil Horman @ 2016-03-30 11:45 UTC (permalink / raw)
To: Marcelo Ricardo Leitner; +Cc: netdev, Vlad Yasevich, linux-sctp
In-Reply-To: <1459258863-21351-1-git-send-email-marcelo.leitner@gmail.com>
On Tue, Mar 29, 2016 at 10:41:03AM -0300, Marcelo Ricardo Leitner wrote:
> Somehow my patch for commit cea8768f333e ("sctp: allow
> sctp_transmit_packet and others to use gfp") missed two important
> chunks, which are now added.
>
> Fixes: cea8768f333e ("sctp: allow sctp_transmit_packet and others to use gfp")
> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> ---
> net/sctp/output.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/net/sctp/output.c b/net/sctp/output.c
> index 736c004abfbc2787a3c50fa85168ebdf3b112787..97745351d58c2fb32b9f9b57d61831d7724d83b2 100644
> --- a/net/sctp/output.c
> +++ b/net/sctp/output.c
> @@ -401,7 +401,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
> sk = chunk->skb->sk;
>
> /* Allocate the new skb. */
> - nskb = alloc_skb(packet->size + MAX_HEADER, GFP_ATOMIC);
> + nskb = alloc_skb(packet->size + MAX_HEADER, gfp);
> if (!nskb)
> goto nomem;
>
> @@ -523,8 +523,8 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
> */
> if (auth)
> sctp_auth_calculate_hmac(asoc, nskb,
> - (struct sctp_auth_chunk *)auth,
> - GFP_ATOMIC);
> + (struct sctp_auth_chunk *)auth,
> + gfp);
>
> /* 2) Calculate the Adler-32 checksum of the whole packet,
> * including the SCTP common header and all the
> --
> 2.5.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Acked-By: Neil Horman <nhorman@tuxdriver.com>
^ permalink raw reply
* Re: [PATCH 4/5] fsl/qe: Add QE TDM lib
From: Joakim Tjernlund @ 2016-03-30 11:50 UTC (permalink / raw)
To: davem@davemloft.net, qiang.zhao@nxp.com
Cc: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
xiaobo.xie@nxp.com, oss@buserror.net, gregkh@linuxfoundation.org,
akpm@linux-foundation.org, netdev@vger.kernel.org
In-Reply-To: <1459327830-19829-4-git-send-email-qiang.zhao@nxp.com>
On Wed, 2016-03-30 at 16:50 +0800, Zhao Qiang wrote:
> QE has module to support TDM, some other protocols
> supported by QE are based on TDM.
> add a qe-tdm lib, this lib provides functions to the protocols
> using TDM to configurate QE-TDM.
>
> Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
> ---
> drivers/soc/fsl/qe/Kconfig | 4 +
> drivers/soc/fsl/qe/Makefile | 1 +
> drivers/soc/fsl/qe/qe_tdm.c | 271 ++++++++++++++++++++++++++++++++++++++++++
> include/soc/fsl/qe/immap_qe.h | 5 +-
> include/soc/fsl/qe/qe_tdm.h | 94 +++++++++++++++
> 5 files changed, 371 insertions(+), 4 deletions(-)
> create mode 100644 drivers/soc/fsl/qe/qe_tdm.c
> create mode 100644 include/soc/fsl/qe/qe_tdm.h
>
> diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
> index 20978f2..463cf29 100644
> --- a/drivers/soc/fsl/qe/Kconfig
> +++ b/drivers/soc/fsl/qe/Kconfig
> @@ -31,6 +31,10 @@ config UCC
> bool
> default y if UCC_FAST || UCC_SLOW
>
> +config QE_TDM
> + bool
> + select UCC_FAST
> +
> config QE_USB
> bool
> default y if USB_FSL_QE
> diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
> index ffac541..2031d38 100644
> --- a/drivers/soc/fsl/qe/Makefile
> +++ b/drivers/soc/fsl/qe/Makefile
> @@ -6,5 +6,6 @@ obj-$(CONFIG_CPM) += qe_common.o
> obj-$(CONFIG_UCC) += ucc.o
> obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
> obj-$(CONFIG_UCC_FAST) += ucc_fast.o
> +obj-$(CONFIG_QE_TDM) += qe_tdm.o
> obj-$(CONFIG_QE_USB) += usb.o
> obj-$(CONFIG_QE_GPIO) += gpio.o
> diff --git a/drivers/soc/fsl/qe/qe_tdm.c b/drivers/soc/fsl/qe/qe_tdm.c
> new file mode 100644
> index 0000000..9a2374d
> --- /dev/null
> +++ b/drivers/soc/fsl/qe/qe_tdm.c
> @@ -0,0 +1,271 @@
> +/*
> + * Copyright (C) 2015 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * Authors: Zhao Qiang <qiang.zhao@nxp.com>
> + *
> + * Description:
> + * QE TDM API Set - TDM specific routines implementations.
> + *
> + * 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.
> + */
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <soc/fsl/qe/qe_tdm.h>
> +
> +static enum tdm_framer_t set_tdm_framer(const char *tdm_framer_type)
> +{
> + if (strcmp(tdm_framer_type, "e1") == 0)
> + return TDM_FRAMER_E1;
> + else
> + return TDM_FRAMER_T1;
> +}
> +
> +static void set_si_param(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info)
> +{
> + struct si_mode_info *si_info = &ut_info->si_info;
> +
> + if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) {
> + si_info->simr_crt = 1;
> + si_info->simr_rfsd = 0;
> + }
> +}
> +
> +int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm,
> + struct ucc_tdm_info *ut_info)
> +{
> + const char *sprop;
> + int ret = 0;
> + u32 val;
> + struct resource *res;
> + struct device_node *np2;
> + static int siram_init_flag;
> + struct platform_device *pdev;
> +
> + sprop = of_get_property(np, "fsl,rx-sync-clock", NULL);
> + if (sprop) {
> + ut_info->uf_info.rx_sync = qe_clock_source(sprop);
> + if ((ut_info->uf_info.rx_sync < QE_CLK_NONE) ||
> + (ut_info->uf_info.rx_sync > QE_RSYNC_PIN)) {
> + pr_err("QE-TDM: Invalid rx-sync-clock property\n");
> + return -EINVAL;
> + }
> + } else {
> + pr_err("QE-TDM: Invalid rx-sync-clock property\n");
> + return -EINVAL;
> + }
> +
> + sprop = of_get_property(np, "fsl,tx-sync-clock", NULL);
> + if (sprop) {
> + ut_info->uf_info.tx_sync = qe_clock_source(sprop);
> + if ((ut_info->uf_info.tx_sync < QE_CLK_NONE) ||
> + (ut_info->uf_info.tx_sync > QE_TSYNC_PIN)) {
> + pr_err("QE-TDM: Invalid tx-sync-clock property\n");
> + return -EINVAL;
> + }
> + } else {
> + pr_err("QE-TDM: Invalid tx-sync-clock property\n");
> + return -EINVAL;
> + }
> +
> + ret = of_property_read_u32_index(np, "fsl,tx-timeslot-mask", 0, &val);
> + if (ret) {
> + pr_err("QE-TDM: Invalid tx-timeslot-mask property\n");
> + return -EINVAL;
> + }
> + utdm->tx_ts_mask = val;
> +
> + ret = of_property_read_u32_index(np, "fsl,rx-timeslot-mask", 0, &val);
> + if (ret) {
> + ret = -EINVAL;
> + pr_err("QE-TDM: Invalid rx-timeslot-mask property\n");
> + return ret;
> + }
> + utdm->rx_ts_mask = val;
> +
> + ret = of_property_read_u32_index(np, "fsl,tdm-id", 0, &val);
> + if (ret) {
> + ret = -EINVAL;
> + pr_err("QE-TDM: No fsl,tdm-id property for this UCC\n");
> + return ret;
> + }
> + utdm->tdm_port = val;
> + ut_info->uf_info.tdm_num = utdm->tdm_port;
> +
> + if (of_get_property(np, "fsl,tdm-internal-loopback", NULL))
> + utdm->tdm_mode = TDM_INTERNAL_LOOPBACK;
> + else
> + utdm->tdm_mode = TDM_NORMAL;
> +
> + sprop = of_get_property(np, "fsl,tdm-framer-type", NULL);
> + if (!sprop) {
> + ret = -EINVAL;
> + pr_err("QE-TDM: No tdm-framer-type property for UCC\n");
> + return ret;
> + }
> + utdm->tdm_framer_type = set_tdm_framer(sprop);
> +
> + ret = of_property_read_u32_index(np, "fsl,siram-entry-id", 0, &val);
> + if (ret) {
> + ret = -EINVAL;
> + pr_err("QE-TDM: No siram entry id for UCC\n");
> + return ret;
> + }
> + utdm->siram_entry_id = val;
> +
> + set_si_param(utdm, ut_info);
> +
> + np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-si");
fsl,t1040-qe-si only? What about mpc83xx?
I recall QE is a little bit different compared to T1040 or will this work(including the hdlc driver)
on 83xx as well?
Jocke
^ permalink raw reply
* Re: [PATCH 0/5] wireless: ti: Convert specialized logging macros to kernel style
From: Kalle Valo @ 2016-03-30 11:51 UTC (permalink / raw)
To: Joe Perches; +Cc: linux-kernel, linux-wireless, netdev
In-Reply-To: <cover.1457395071.git.joe@perches.com>
Joe Perches <joe@perches.com> writes:
> Using the normal kernel logging mechanisms makes this code
> a bit more like other wireless drivers.
Personally I don't see the point but I don't have any strong opinions. A
bigger problem is that TI drivers are not really in active development
and that's I'm not thrilled to take big patches like this for dormant
drivers.
--
Kalle Valo
^ permalink raw reply
* [PATCH] net: mvneta: replace MVNETA_CPU_D_CACHE_LINE_SIZE with L1_CACHE_BYTES
From: Jisheng Zhang @ 2016-03-30 11:55 UTC (permalink / raw)
To: thomas.petazzoni, davem
Cc: netdev, linux-kernel, linux-arm-kernel, Jisheng Zhang
The mvneta is also used in some Marvell berlin family SoCs which may
have 64bytes cacheline size. Replace the MVNETA_CPU_D_CACHE_LINE_SIZE
usage with L1_CACHE_BYTES.
And since dma_alloc_coherent() is always cacheline size aligned, so
remove the align checks.
Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
---
drivers/net/ethernet/marvell/mvneta.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 577f7ca..5880871 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -260,7 +260,6 @@
#define MVNETA_VLAN_TAG_LEN 4
-#define MVNETA_CPU_D_CACHE_LINE_SIZE 32
#define MVNETA_TX_CSUM_DEF_SIZE 1600
#define MVNETA_TX_CSUM_MAX_SIZE 9800
#define MVNETA_ACC_MODE_EXT1 1
@@ -300,7 +299,7 @@
#define MVNETA_RX_PKT_SIZE(mtu) \
ALIGN((mtu) + MVNETA_MH_SIZE + MVNETA_VLAN_TAG_LEN + \
ETH_HLEN + ETH_FCS_LEN, \
- MVNETA_CPU_D_CACHE_LINE_SIZE)
+ L1_CACHE_BYTES)
#define IS_TSO_HEADER(txq, addr) \
((addr >= txq->tso_hdrs_phys) && \
@@ -2764,9 +2763,6 @@ static int mvneta_rxq_init(struct mvneta_port *pp,
if (rxq->descs == NULL)
return -ENOMEM;
- BUG_ON(rxq->descs !=
- PTR_ALIGN(rxq->descs, MVNETA_CPU_D_CACHE_LINE_SIZE));
-
rxq->last_desc = rxq->size - 1;
/* Set Rx descriptors queue starting address */
@@ -2837,10 +2833,6 @@ static int mvneta_txq_init(struct mvneta_port *pp,
if (txq->descs == NULL)
return -ENOMEM;
- /* Make sure descriptor address is cache line size aligned */
- BUG_ON(txq->descs !=
- PTR_ALIGN(txq->descs, MVNETA_CPU_D_CACHE_LINE_SIZE));
-
txq->last_desc = txq->size - 1;
/* Set maximum bandwidth for enabled TXQs */
--
2.8.0.rc3
^ permalink raw reply related
* [PATCH] net: mvpp2: replace MVPP2_CPU_D_CACHE_LINE_SIZE with L1_CACHE_BYTES
From: Jisheng Zhang @ 2016-03-30 11:53 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-kernel, linux-arm-kernel, Jisheng Zhang
The mvpp2 ip maybe used in SoCs which may have have 64bytes cacheline
size. Replace the MVPP2_CPU_D_CACHE_LINE_SIZE with L1_CACHE_BYTES.
And since dma_alloc_coherent() is always cacheline size aligned, so
remove the align checks.
Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index c797971a..05f358b 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -321,7 +321,6 @@
/* Lbtd 802.3 type */
#define MVPP2_IP_LBDT_TYPE 0xfffa
-#define MVPP2_CPU_D_CACHE_LINE_SIZE 32
#define MVPP2_TX_CSUM_MAX_SIZE 9800
/* Timeout constants */
@@ -377,7 +376,7 @@
#define MVPP2_RX_PKT_SIZE(mtu) \
ALIGN((mtu) + MVPP2_MH_SIZE + MVPP2_VLAN_TAG_LEN + \
- ETH_HLEN + ETH_FCS_LEN, MVPP2_CPU_D_CACHE_LINE_SIZE)
+ ETH_HLEN + ETH_FCS_LEN, L1_CACHE_BYTES)
#define MVPP2_RX_BUF_SIZE(pkt_size) ((pkt_size) + NET_SKB_PAD)
#define MVPP2_RX_TOTAL_SIZE(buf_size) ((buf_size) + MVPP2_SKB_SHINFO_SIZE)
@@ -4493,10 +4492,6 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev,
if (!aggr_txq->descs)
return -ENOMEM;
- /* Make sure descriptor address is cache line size aligned */
- BUG_ON(aggr_txq->descs !=
- PTR_ALIGN(aggr_txq->descs, MVPP2_CPU_D_CACHE_LINE_SIZE));
-
aggr_txq->last_desc = aggr_txq->size - 1;
/* Aggr TXQ no reset WA */
@@ -4526,9 +4521,6 @@ static int mvpp2_rxq_init(struct mvpp2_port *port,
if (!rxq->descs)
return -ENOMEM;
- BUG_ON(rxq->descs !=
- PTR_ALIGN(rxq->descs, MVPP2_CPU_D_CACHE_LINE_SIZE));
-
rxq->last_desc = rxq->size - 1;
/* Zero occupied and non-occupied counters - direct access */
@@ -4616,10 +4608,6 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
if (!txq->descs)
return -ENOMEM;
- /* Make sure descriptor address is cache line size aligned */
- BUG_ON(txq->descs !=
- PTR_ALIGN(txq->descs, MVPP2_CPU_D_CACHE_LINE_SIZE));
-
txq->last_desc = txq->size - 1;
/* Set Tx descriptors queue starting address - indirect access */
--
2.8.0.rc3
^ permalink raw reply related
* Re: [PATCH] sctp: flush if we can't fit another DATA chunk
From: Neil Horman @ 2016-03-30 12:03 UTC (permalink / raw)
To: Marcelo Ricardo Leitner; +Cc: netdev, Vlad Yasevich, linux-sctp
In-Reply-To: <1459258885-21502-1-git-send-email-marcelo.leitner@gmail.com>
On Tue, Mar 29, 2016 at 10:41:25AM -0300, Marcelo Ricardo Leitner wrote:
> There is no point in delaying the packet if we can't fit a single byte
> of data on it anymore. So lets just reduce the threshold by the amount
> that a data chunk with 4 bytes (rounding) would use.
>
> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> ---
> net/sctp/output.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/net/sctp/output.c b/net/sctp/output.c
> index 97745351d58c2fb32b9f9b57d61831d7724d83b2..c518569123ce42a8f21f80754756306c39875013 100644
> --- a/net/sctp/output.c
> +++ b/net/sctp/output.c
> @@ -705,7 +705,8 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
> /* Check whether this chunk and all the rest of pending data will fit
> * or delay in hopes of bundling a full sized packet.
> */
> - if (chunk->skb->len + q->out_qlen >= transport->pathmtu - packet->overhead)
> + if (chunk->skb->len + q->out_qlen >
> + maxsize - packet->overhead - sizeof(sctp_data_chunk_t) - 4)
> /* Enough data queued to fill a packet */
> return SCTP_XMIT_OK;
>
> --
> 2.5.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Acked-By: Neil Horman <nhorman@tuxdriver.com>
^ permalink raw reply
* Re: [PATCH] sctp: avoid refreshing heartbeat timer too often
From: Marcelo Ricardo Leitner @ 2016-03-30 12:13 UTC (permalink / raw)
To: David Laight, netdev@vger.kernel.org
Cc: Neil Horman, Vlad Yasevich, linux-sctp@vger.kernel.org
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6D54DBFFCD@AcuExch.aculab.com>
Em 30-03-2016 06:37, David Laight escreveu:
> From: Marcelo Ricardo Leitner
>> Sent: 29 March 2016 14:42
>>
>> Currently on high rate SCTP streams the heartbeat timer refresh can
>> consume quite a lot of resources as timer updates are costly and it
>> contains a random factor, which a) is also costly and b) invalidates
>> mod_timer() optimization for not editing a timer to the same value.
>> It may even cause the timer to be slightly advanced, for no good reason.
>
> Interesting thoughts:
> 1) Is it necessary to use a different 'random factor' until the timer actually
> expires?
I don't understand you fully here, but we have to have a random factor
on timer expire. As noted by Daniel Borkmann on his commit 8f61059a96c2
("net: sctp: improve timer slack calculation for transport HBs"):
RFC4960, section 8.3 says:
On an idle destination address that is allowed to heartbeat,
it is recommended that a HEARTBEAT chunk is sent once per RTO
of that destination address plus the protocol parameter
'HB.interval', with jittering of +/- 50% of the RTO value,
and exponential backoff of the RTO if the previous HEARTBEAT
is unanswered.
Previous to his commit, it was using a random factor based on jiffies.
This patch then assumes that random_A+2 is just as random as random_B as
long as it is within the allowed range, avoiding the unnecessary updates.
> 2) It might be better to allow the heartbeat timer to expire, on expiry work
> out the new interval based on when the last 'refresh' was done.
Cool, I thought about this too. It would introduce some extra complexity
that is not really worth I think, specially because now we may be doing
more timer updates even with this patch but it's not triggering any wake
ups and we would need at least 2 wake ups then: one for the first
timeout event, and then re-schedule the timer for the next updated one,
and maybe again, and again.. less timer updates but more wake ups, one
at every heartbeat interval even on a busy transport. Seems it's cheaper
to just update the timer then.
Thanks,
Marcelo
^ permalink raw reply
* Re: bpf: net/core/filter.c:2115 suspicious rcu_dereference_protected() usage!
From: Michal Kubecek @ 2016-03-30 12:24 UTC (permalink / raw)
To: Daniel Borkmann
Cc: Sasha Levin, Jiri Slaby, David S. Miller, ast,
netdev@vger.kernel.org, LKML
In-Reply-To: <56FBB998.5090504@iogearbox.net>
On Wed, Mar 30, 2016 at 01:33:44PM +0200, Daniel Borkmann wrote:
> On 03/30/2016 11:42 AM, Michal Kubecek wrote:
> >
> >I'm just not sure checking if we hold the right lock depending on caller
> >is worth the extra complexity. After all, what is really needed is to
> >hold _some_ lock guaranteeing sk_attach_prog() and sk_detach_filter()
> >are safe so that just changing the condition in both to
> >
> > sock_owned_by_user(sk) || lockdep_rtnl_is_held()
>
> It would certainly silence it, but would be less accurate in terms of lock
> proving as opposed to the diff above. E.g. rntl could be held elsewhere,
> while someone attaches a socket filter w/o having locked the socket (currently
> not the case, but it would kind of defeat the purpose of rcu_dereference_protected()
> here). Was thinking about using a extra socket flag to indicate it's
> externally managed, but it's not really worth wasting sk's flags bit
> space just for this corner case.
Originally my reasoning was that to actually hide a locking issue from
lockdep, this would have to happen every time we get down into the
function which is unlikely. But thinking about it again, this code path
is not so frequent and the fuzzers tend to do strange things so that it
could really happen.
Sasha/Jiri, could you test the patch with your testcases? I received it
corrupted (strange leading whitespaces) so I better add cleaned up
version below.
Michal Kubecek
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index afdf950617c3..510e90a6bb26 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -622,7 +622,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filte
/* Re-attach the filter to persist device */
if (!skip_filter && (tun->filter_attached == true)) {
- err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
+ err = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
+ lockdep_rtnl_is_held());
if (!err)
goto out;
}
@@ -1822,7 +1823,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n)
for (i = 0; i < n; i++) {
tfile = rtnl_dereference(tun->tfiles[i]);
- sk_detach_filter(tfile->socket.sk);
+ __sk_detach_filter(tfile->socket.sk, lockdep_rtnl_is_held());
}
tun->filter_attached = false;
@@ -1835,7 +1836,8 @@ static int tun_attach_filter(struct tun_struct *tun)
for (i = 0; i < tun->numqueues; i++) {
tfile = rtnl_dereference(tun->tfiles[i]);
- ret = sk_attach_filter(&tun->fprog, tfile->socket.sk);
+ ret = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
+ lockdep_rtnl_is_held());
if (ret) {
tun_detach_filter(tun, i);
return ret;
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 43aa1f8855c7..a51a5361695f 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -465,10 +465,14 @@ int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog,
void bpf_prog_destroy(struct bpf_prog *fp);
int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
+int __sk_attach_filter(struct sock_fprog *fprog, struct sock *sk,
+ bool locked);
int sk_attach_bpf(u32 ufd, struct sock *sk);
int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk);
int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk);
int sk_detach_filter(struct sock *sk);
+int __sk_detach_filter(struct sock *sk, bool locked);
+
int sk_get_filter(struct sock *sk, struct sock_filter __user *filter,
unsigned int len);
diff --git a/net/core/filter.c b/net/core/filter.c
index b7177d01ecb0..dfb4561a2247 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1149,7 +1149,8 @@ void bpf_prog_destroy(struct bpf_prog *fp)
}
EXPORT_SYMBOL_GPL(bpf_prog_destroy);
-static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk)
+static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk,
+ bool locked)
{
struct sk_filter *fp, *old_fp;
@@ -1165,10 +1166,8 @@ static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk)
return -ENOMEM;
}
- old_fp = rcu_dereference_protected(sk->sk_filter,
- sock_owned_by_user(sk));
+ old_fp = rcu_dereference_protected(sk->sk_filter, locked);
rcu_assign_pointer(sk->sk_filter, fp);
-
if (old_fp)
sk_filter_uncharge(sk, old_fp);
@@ -1247,7 +1246,8 @@ struct bpf_prog *__get_filter(struct sock_fprog *fprog, struct sock *sk)
* occurs or there is insufficient memory for the filter a negative
* errno code is returned. On success the return is zero.
*/
-int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
+int __sk_attach_filter(struct sock_fprog *fprog, struct sock *sk,
+ bool locked)
{
struct bpf_prog *prog = __get_filter(fprog, sk);
int err;
@@ -1255,7 +1255,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
if (IS_ERR(prog))
return PTR_ERR(prog);
- err = __sk_attach_prog(prog, sk);
+ err = __sk_attach_prog(prog, sk, locked);
if (err < 0) {
__bpf_prog_release(prog);
return err;
@@ -1263,7 +1263,12 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
return 0;
}
-EXPORT_SYMBOL_GPL(sk_attach_filter);
+EXPORT_SYMBOL_GPL(__sk_attach_filter);
+
+int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
+{
+ return __sk_attach_filter(fprog, sk, sock_owned_by_user(sk));
+}
int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk)
{
@@ -1309,7 +1314,7 @@ int sk_attach_bpf(u32 ufd, struct sock *sk)
if (IS_ERR(prog))
return PTR_ERR(prog);
- err = __sk_attach_prog(prog, sk);
+ err = __sk_attach_prog(prog, sk, sock_owned_by_user(sk));
if (err < 0) {
bpf_prog_put(prog);
return err;
@@ -2247,7 +2252,7 @@ static int __init register_sk_filter_ops(void)
}
late_initcall(register_sk_filter_ops);
-int sk_detach_filter(struct sock *sk)
+int __sk_detach_filter(struct sock *sk, bool locked)
{
int ret = -ENOENT;
struct sk_filter *filter;
@@ -2255,8 +2260,7 @@ int sk_detach_filter(struct sock *sk)
if (sock_flag(sk, SOCK_FILTER_LOCKED))
return -EPERM;
- filter = rcu_dereference_protected(sk->sk_filter,
- sock_owned_by_user(sk));
+ filter = rcu_dereference_protected(sk->sk_filter, locked);
if (filter) {
RCU_INIT_POINTER(sk->sk_filter, NULL);
sk_filter_uncharge(sk, filter);
@@ -2265,7 +2269,12 @@ int sk_detach_filter(struct sock *sk)
return ret;
}
-EXPORT_SYMBOL_GPL(sk_detach_filter);
+EXPORT_SYMBOL_GPL(__sk_detach_filter);
+
+int sk_detach_filter(struct sock *sk)
+{
+ return __sk_detach_filter(sk, sock_owned_by_user(sk));
+}
int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf,
unsigned int len)
^ permalink raw reply related
* Re: [PATCH 5/5] drivers/net: support hdlc function for QE-UCC
From: kbuild test robot @ 2016-03-30 12:27 UTC (permalink / raw)
To: Zhao Qiang
Cc: kbuild-all, davem, akpm, gregkh, oss, xiaobo.xie, linux-kernel,
netdev, linuxppc-dev, Zhao Qiang
In-Reply-To: <1459327830-19829-5-git-send-email-qiang.zhao@nxp.com>
[-- Attachment #1: Type: text/plain, Size: 941 bytes --]
Hi Zhao,
[auto build test WARNING on net/master]
[also build test WARNING on v4.6-rc1 next-20160330]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Zhao-Qiang/fsl-qe-add-rx_sync-and-tx_sync-for-TDM-mode/20160330-170411
config: powerpc-allyesconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=powerpc
All warnings (new ones prefixed by >>):
warning: (KMETER1 && FSL_UCC_HDLC) selects QUICC_ENGINE which has unmet direct dependencies (FSL_SOC && PPC32)
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 48751 bytes --]
^ permalink raw reply
* Re: bpf: net/core/filter.c:2115 suspicious rcu_dereference_protected() usage!
From: Daniel Borkmann @ 2016-03-30 12:38 UTC (permalink / raw)
To: Michal Kubecek
Cc: Sasha Levin, Jiri Slaby, David S. Miller, ast,
netdev@vger.kernel.org, LKML
In-Reply-To: <20160330122418.GD15048@unicorn.suse.cz>
On 03/30/2016 02:24 PM, Michal Kubecek wrote:
> On Wed, Mar 30, 2016 at 01:33:44PM +0200, Daniel Borkmann wrote:
>> On 03/30/2016 11:42 AM, Michal Kubecek wrote:
>>>
>>> I'm just not sure checking if we hold the right lock depending on caller
>>> is worth the extra complexity. After all, what is really needed is to
>>> hold _some_ lock guaranteeing sk_attach_prog() and sk_detach_filter()
>>> are safe so that just changing the condition in both to
>>>
>>> sock_owned_by_user(sk) || lockdep_rtnl_is_held()
>>
>> It would certainly silence it, but would be less accurate in terms of lock
>> proving as opposed to the diff above. E.g. rntl could be held elsewhere,
>> while someone attaches a socket filter w/o having locked the socket (currently
>> not the case, but it would kind of defeat the purpose of rcu_dereference_protected()
>> here). Was thinking about using a extra socket flag to indicate it's
>> externally managed, but it's not really worth wasting sk's flags bit
>> space just for this corner case.
>
> Originally my reasoning was that to actually hide a locking issue from
> lockdep, this would have to happen every time we get down into the
> function which is unlikely. But thinking about it again, this code path
> is not so frequent and the fuzzers tend to do strange things so that it
> could really happen.
In this case actually nothing too fancy, just seems that filters on tap devices
might not be really used by anyone (issue is already couple of years old).
> Sasha/Jiri, could you test the patch with your testcases? I received it
> corrupted (strange leading whitespaces) so I better add cleaned up
> version below.
Tested this yesterday night on my machine with PROVE_RCU + PROVE_RCU_REPEATEDLY
enabled, and it can easily be triggered with a simple ioctl(tun_fd,
TUN{ATTACH,DETACH}FILTER, ...) on a tap device, and the patch now silences
it. Sorry for the white space damage (should have just attached it), I'd send
it later today.
Thanks,
Daniel
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox