* Re: [PATCH v4] net: ip, diag -- Add diag interface for raw sockets
From: Eric Dumazet @ 2016-09-27 15:39 UTC (permalink / raw)
To: Cyrill Gorcunov
Cc: David Ahern, netdev, linux-kernel, David Miller, kuznet, jmorris,
yoshfuji, kaber, avagin, stephen
In-Reply-To: <20160927150831.GN1876@uranus.lan>
On Tue, 2016-09-27 at 18:08 +0300, Cyrill Gorcunov wrote:
> +static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r)
> +{
> + struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
> + struct sock *sk = NULL, *s;
> + int slot;
> +
> + if (IS_ERR(hashinfo))
> + return ERR_CAST(hashinfo);
> +
> + read_lock(&hashinfo->lock);
> + for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) {
> + sk_for_each(s, &hashinfo->ht[slot]) {
> + sk = raw_lookup(net, s, r);
> + if (sk)
> + break;
> + }
> + }
> + if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
> + sk = NULL;
Minor detail, but note that raw sockets do not use rcu (yet)
Since you have read_lock(&hashinfo->lock), no writer can suddenly change
sk->sk_refcnt to a zero value.
Therefore, a mere "sock_hold(sk)" should be enough to get a reference on
the socket.
Using atomic_inc_not_zero() also works, but might distract/confuse the
next guy trying to understand this code ;)
> + read_unlock(&hashinfo->lock);
> +
> + return sk ? sk : ERR_PTR(-ENOENT);
> +}
> +
^ permalink raw reply
* Re: [PATCH 4/5] ISDN-Gigaset: Release memory in gigaset_initcs() after an allocation failure
From: SF Markus Elfring @ 2016-09-27 15:10 UTC (permalink / raw)
To: Paul Bolle
Cc: gigaset307x-common, netdev, Karsten Keil, LKML, kernel-janitors,
Julia Lawall, Tilman Schmidt
In-Reply-To: <1474924434.8546.29.camel@tiscali.nl>
>> @@ -772,8 +775,9 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
>>
>> gig_dbg(DEBUG_INIT, "cs initialized");
>> return cs;
>> -
>> -error:
>> +free_bcs:
>> + kfree(cs->bcs);
>> +report_failure:
>> gig_dbg(DEBUG_INIT, "failed");
>> gigaset_freecs(cs);
>
> gigaset_freecs() is not a function I look at for the fun of it. But
> still, in it we find:
>
> case 0: /* error in basic setup */
> [...]
> kfree(cs->inbuf);
> kfree(cs->bcs);
>
> As far as I can tell we will call those two kfree()'s if we jump to
> "error". So, contrary to your analysis, I don't think we leak cs->bcs.
You are right.
Thanks that you pointed this source code place out again.
I imagined that the exception handling implementation could be more direct
somehow for a while. But this function takes extra care for data synchronisation
by a mutex.
Now I recognise also that this proposed update step "4" was inappropriate.
I'm sorry for the confusion I introduced here.
Regards,
Markus
^ permalink raw reply
* [PATCH v4] net: ip, diag -- Add diag interface for raw sockets
From: Cyrill Gorcunov @ 2016-09-27 15:08 UTC (permalink / raw)
To: David Ahern
Cc: Eric Dumazet, netdev, linux-kernel, David Miller, kuznet, jmorris,
yoshfuji, kaber, avagin, stephen
In criu we are actively using diag interface to collect sockets
present in the system when dumping applications. And while for
unix, tcp, udp[lite], packet, netlink it works as expected,
the raw sockets do not have. Thus add it.
v2:
- add missing sock_put calls in raw_diag_dump_one (by eric.dumazet@)
- implement @destroy for diag requests (by dsa@)
v3:
- add export of raw_abort for IPv6 (by dsa@)
- pass net-admin flag into inet_sk_diag_fill due to
changes in net-next branch (by dsa@)
v4:
- use @pad in struct inet_diag_req_v2 for raw socket
protocol specification: raw module carries sockets
which may have custom protocol passed from socket()
syscall and sole @sdiag_protocol is not enough to
match underlied ones
- start reporting protocol specifed in socket() call
when sockets are raw ones for the same reason: user
space tools like ss may parse this attribute and use
it for socket matching
CC: David S. Miller <davem@davemloft.net>
CC: Eric Dumazet <eric.dumazet@gmail.com>
CC: David Ahern <dsa@cumulusnetworks.com>
CC: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
CC: James Morris <jmorris@namei.org>
CC: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
CC: Patrick McHardy <kaber@trash.net>
CC: Andrey Vagin <avagin@openvz.org>
CC: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
---
Guys, take a look please once time permit. I mostly worried
about start reporint protocol in inet_sk_diag_fill, I think
it should be safe but still.
include/net/raw.h | 6 +
include/net/rawv6.h | 7 +
include/uapi/linux/inet_diag.h | 5
net/ipv4/Kconfig | 8 +
net/ipv4/Makefile | 1
net/ipv4/inet_diag.c | 9 +
net/ipv4/raw.c | 21 +++
net/ipv4/raw_diag.c | 226 +++++++++++++++++++++++++++++++++++++++++
net/ipv6/raw.c | 7 -
9 files changed, 285 insertions(+), 5 deletions(-)
Index: linux-ml.git/include/net/raw.h
===================================================================
--- linux-ml.git.orig/include/net/raw.h
+++ linux-ml.git/include/net/raw.h
@@ -23,6 +23,12 @@
extern struct proto raw_prot;
+extern struct raw_hashinfo raw_v4_hashinfo;
+struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
+ unsigned short num, __be32 raddr,
+ __be32 laddr, int dif);
+
+int raw_abort(struct sock *sk, int err);
void raw_icmp_error(struct sk_buff *, int, u32);
int raw_local_deliver(struct sk_buff *, int);
Index: linux-ml.git/include/net/rawv6.h
===================================================================
--- linux-ml.git.orig/include/net/rawv6.h
+++ linux-ml.git/include/net/rawv6.h
@@ -3,6 +3,13 @@
#include <net/protocol.h>
+extern struct raw_hashinfo raw_v6_hashinfo;
+struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
+ unsigned short num, const struct in6_addr *loc_addr,
+ const struct in6_addr *rmt_addr, int dif);
+
+int raw_abort(struct sock *sk, int err);
+
void raw6_icmp_error(struct sk_buff *, int nexthdr,
u8 type, u8 code, int inner_offset, __be32);
bool raw6_local_deliver(struct sk_buff *, int);
Index: linux-ml.git/include/uapi/linux/inet_diag.h
===================================================================
--- linux-ml.git.orig/include/uapi/linux/inet_diag.h
+++ linux-ml.git/include/uapi/linux/inet_diag.h
@@ -38,7 +38,10 @@ struct inet_diag_req_v2 {
__u8 sdiag_family;
__u8 sdiag_protocol;
__u8 idiag_ext;
- __u8 pad;
+ union {
+ __u8 pad;
+ __u8 sdiag_raw_protocol; /* SOCK_RAW only, @pad for others */
+ };
__u32 idiag_states;
struct inet_diag_sockid id;
};
Index: linux-ml.git/net/ipv4/Kconfig
===================================================================
--- linux-ml.git.orig/net/ipv4/Kconfig
+++ linux-ml.git/net/ipv4/Kconfig
@@ -430,6 +430,14 @@ config INET_UDP_DIAG
Support for UDP socket monitoring interface used by the ss tool.
If unsure, say Y.
+config INET_RAW_DIAG
+ tristate "RAW: socket monitoring interface"
+ depends on INET_DIAG && (IPV6 || IPV6=n)
+ default n
+ ---help---
+ Support for RAW socket monitoring interface used by the ss tool.
+ If unsure, say Y.
+
config INET_DIAG_DESTROY
bool "INET: allow privileged process to administratively close sockets"
depends on INET_DIAG
Index: linux-ml.git/net/ipv4/Makefile
===================================================================
--- linux-ml.git.orig/net/ipv4/Makefile
+++ linux-ml.git/net/ipv4/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_NETFILTER) += netfilter.o n
obj-$(CONFIG_INET_DIAG) += inet_diag.o
obj-$(CONFIG_INET_TCP_DIAG) += tcp_diag.o
obj-$(CONFIG_INET_UDP_DIAG) += udp_diag.o
+obj-$(CONFIG_INET_RAW_DIAG) += raw_diag.o
obj-$(CONFIG_NET_TCPPROBE) += tcp_probe.o
obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o
obj-$(CONFIG_TCP_CONG_CDG) += tcp_cdg.o
Index: linux-ml.git/net/ipv4/inet_diag.c
===================================================================
--- linux-ml.git.orig/net/ipv4/inet_diag.c
+++ linux-ml.git/net/ipv4/inet_diag.c
@@ -200,6 +200,15 @@ int inet_sk_diag_fill(struct sock *sk, s
if (sock_diag_put_meminfo(sk, skb, INET_DIAG_SKMEMINFO))
goto errout;
+ /*
+ * RAW sockets might have user-defined protocols assigned,
+ * so report the one supplied on socket creation.
+ */
+ if (sk->sk_type == SOCK_RAW) {
+ if (nla_put_u8(skb, INET_DIAG_PROTOCOL, sk->sk_protocol))
+ goto errout;
+ }
+
if (!icsk) {
handler->idiag_get_info(sk, r, NULL);
goto out;
Index: linux-ml.git/net/ipv4/raw.c
===================================================================
--- linux-ml.git.orig/net/ipv4/raw.c
+++ linux-ml.git/net/ipv4/raw.c
@@ -89,9 +89,10 @@ struct raw_frag_vec {
int hlen;
};
-static struct raw_hashinfo raw_v4_hashinfo = {
+struct raw_hashinfo raw_v4_hashinfo = {
.lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
};
+EXPORT_SYMBOL_GPL(raw_v4_hashinfo);
int raw_hash_sk(struct sock *sk)
{
@@ -120,7 +121,7 @@ void raw_unhash_sk(struct sock *sk)
}
EXPORT_SYMBOL_GPL(raw_unhash_sk);
-static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
+struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
unsigned short num, __be32 raddr, __be32 laddr, int dif)
{
sk_for_each_from(sk) {
@@ -136,6 +137,7 @@ static struct sock *__raw_v4_lookup(stru
found:
return sk;
}
+EXPORT_SYMBOL_GPL(__raw_v4_lookup);
/*
* 0 - deliver
@@ -918,6 +920,20 @@ static int compat_raw_ioctl(struct sock
}
#endif
+int raw_abort(struct sock *sk, int err)
+{
+ lock_sock(sk);
+
+ sk->sk_err = err;
+ sk->sk_error_report(sk);
+ udp_disconnect(sk, 0);
+
+ release_sock(sk);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(raw_abort);
+
struct proto raw_prot = {
.name = "RAW",
.owner = THIS_MODULE,
@@ -943,6 +959,7 @@ struct proto raw_prot = {
.compat_getsockopt = compat_raw_getsockopt,
.compat_ioctl = compat_raw_ioctl,
#endif
+ .diag_destroy = raw_abort,
};
#ifdef CONFIG_PROC_FS
Index: linux-ml.git/net/ipv4/raw_diag.c
===================================================================
--- /dev/null
+++ linux-ml.git/net/ipv4/raw_diag.c
@@ -0,0 +1,226 @@
+#include <linux/module.h>
+
+#include <linux/inet_diag.h>
+#include <linux/sock_diag.h>
+
+#include <net/raw.h>
+#include <net/rawv6.h>
+
+#ifdef pr_fmt
+# undef pr_fmt
+#endif
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+static struct raw_hashinfo *
+raw_get_hashinfo(const struct inet_diag_req_v2 *r)
+{
+ if (r->sdiag_family == AF_INET) {
+ return &raw_v4_hashinfo;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (r->sdiag_family == AF_INET6) {
+ return &raw_v6_hashinfo;
+#endif
+ } else {
+ pr_warn_once("Unexpected inet family %d\n",
+ r->sdiag_family);
+ WARN_ON_ONCE(1);
+ return ERR_PTR(-EINVAL);
+ }
+}
+
+static struct sock *raw_lookup(struct net *net, struct sock *from,
+ const struct inet_diag_req_v2 *r)
+{
+ struct sock *sk = NULL;
+
+ if (r->sdiag_family == AF_INET)
+ sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol,
+ r->id.idiag_dst[0],
+ r->id.idiag_src[0],
+ r->id.idiag_if);
+#if IS_ENABLED(CONFIG_IPV6)
+ else
+ sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol,
+ (const struct in6_addr *)r->id.idiag_src,
+ (const struct in6_addr *)r->id.idiag_dst,
+ r->id.idiag_if);
+#endif
+ return sk;
+}
+
+static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r)
+{
+ struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
+ struct sock *sk = NULL, *s;
+ int slot;
+
+ if (IS_ERR(hashinfo))
+ return ERR_CAST(hashinfo);
+
+ read_lock(&hashinfo->lock);
+ for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) {
+ sk_for_each(s, &hashinfo->ht[slot]) {
+ sk = raw_lookup(net, s, r);
+ if (sk)
+ break;
+ }
+ }
+ if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+ sk = NULL;
+ read_unlock(&hashinfo->lock);
+
+ return sk ? sk : ERR_PTR(-ENOENT);
+}
+
+static int raw_diag_dump_one(struct sk_buff *in_skb,
+ const struct nlmsghdr *nlh,
+ const struct inet_diag_req_v2 *r)
+{
+ struct net *net = sock_net(in_skb->sk);
+ struct sk_buff *rep;
+ struct sock *sk;
+ int err;
+
+ sk = raw_sock_get(net, r);
+ if (IS_ERR(sk))
+ return PTR_ERR(sk);
+
+ rep = nlmsg_new(sizeof(struct inet_diag_msg) +
+ sizeof(struct inet_diag_meminfo) + 64,
+ GFP_KERNEL);
+ if (!rep) {
+ sock_put(sk);
+ return -ENOMEM;
+ }
+
+ err = inet_sk_diag_fill(sk, NULL, rep, r,
+ sk_user_ns(NETLINK_CB(in_skb).sk),
+ NETLINK_CB(in_skb).portid,
+ nlh->nlmsg_seq, 0, nlh,
+ netlink_net_capable(in_skb, CAP_NET_ADMIN));
+ sock_put(sk);
+
+ if (err < 0) {
+ kfree_skb(rep);
+ return err;
+ }
+
+ err = netlink_unicast(net->diag_nlsk, rep,
+ NETLINK_CB(in_skb).portid,
+ MSG_DONTWAIT);
+ if (err > 0)
+ err = 0;
+ return err;
+}
+
+static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
+ struct netlink_callback *cb,
+ const struct inet_diag_req_v2 *r,
+ struct nlattr *bc, bool net_admin)
+{
+ if (!inet_diag_bc_sk(bc, sk))
+ return 0;
+
+ return inet_sk_diag_fill(sk, NULL, skb, r,
+ sk_user_ns(NETLINK_CB(cb->skb).sk),
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ cb->nlh, net_admin);
+}
+
+static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
+ const struct inet_diag_req_v2 *r, struct nlattr *bc)
+{
+ bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
+ struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
+ struct net *net = sock_net(skb->sk);
+ int num, s_num, slot, s_slot;
+ struct sock *sk = NULL;
+
+ if (IS_ERR(hashinfo))
+ return;
+
+ s_slot = cb->args[0];
+ num = s_num = cb->args[1];
+
+ read_lock(&hashinfo->lock);
+ for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) {
+ num = 0;
+
+ sk_for_each(sk, &hashinfo->ht[slot]) {
+ struct inet_sock *inet = inet_sk(sk);
+
+ if (!net_eq(sock_net(sk), net))
+ continue;
+ if (num < s_num)
+ goto next;
+ if (sk->sk_family != r->sdiag_family)
+ goto next;
+ if (r->id.idiag_sport != inet->inet_sport &&
+ r->id.idiag_sport)
+ goto next;
+ if (r->id.idiag_dport != inet->inet_dport &&
+ r->id.idiag_dport)
+ goto next;
+ if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0)
+ goto out_unlock;
+next:
+ num++;
+ }
+ }
+
+out_unlock:
+ read_unlock(&hashinfo->lock);
+
+ cb->args[0] = slot;
+ cb->args[1] = num;
+}
+
+static void raw_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
+ void *info)
+{
+ r->idiag_rqueue = sk_rmem_alloc_get(sk);
+ r->idiag_wqueue = sk_wmem_alloc_get(sk);
+}
+
+#ifdef CONFIG_INET_DIAG_DESTROY
+static int raw_diag_destroy(struct sk_buff *in_skb,
+ const struct inet_diag_req_v2 *r)
+{
+ struct net *net = sock_net(in_skb->sk);
+ struct sock *sk;
+
+ sk = raw_sock_get(net, r);
+ if (IS_ERR(sk))
+ return PTR_ERR(sk);
+ return sock_diag_destroy(sk, ECONNABORTED);
+}
+#endif
+
+static const struct inet_diag_handler raw_diag_handler = {
+ .dump = raw_diag_dump,
+ .dump_one = raw_diag_dump_one,
+ .idiag_get_info = raw_diag_get_info,
+ .idiag_type = IPPROTO_RAW,
+ .idiag_info_size = 0,
+#ifdef CONFIG_INET_DIAG_DESTROY
+ .destroy = raw_diag_destroy,
+#endif
+};
+
+static int __init raw_diag_init(void)
+{
+ return inet_diag_register(&raw_diag_handler);
+}
+
+static void __exit raw_diag_exit(void)
+{
+ inet_diag_unregister(&raw_diag_handler);
+}
+
+module_init(raw_diag_init);
+module_exit(raw_diag_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-255 /* AF_INET - IPPROTO_RAW */);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10-255 /* AF_INET6 - IPPROTO_RAW */);
Index: linux-ml.git/net/ipv6/raw.c
===================================================================
--- linux-ml.git.orig/net/ipv6/raw.c
+++ linux-ml.git/net/ipv6/raw.c
@@ -65,11 +65,12 @@
#define ICMPV6_HDRLEN 4 /* ICMPv6 header, RFC 4443 Section 2.1 */
-static struct raw_hashinfo raw_v6_hashinfo = {
+struct raw_hashinfo raw_v6_hashinfo = {
.lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock),
};
+EXPORT_SYMBOL_GPL(raw_v6_hashinfo);
-static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
+struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
unsigned short num, const struct in6_addr *loc_addr,
const struct in6_addr *rmt_addr, int dif)
{
@@ -102,6 +103,7 @@ static struct sock *__raw_v6_lookup(stru
found:
return sk;
}
+EXPORT_SYMBOL_GPL(__raw_v6_lookup);
/*
* 0 - deliver
@@ -1252,6 +1254,7 @@ struct proto rawv6_prot = {
.compat_getsockopt = compat_rawv6_getsockopt,
.compat_ioctl = compat_rawv6_ioctl,
#endif
+ .diag_destroy = raw_abort,
};
#ifdef CONFIG_PROC_FS
^ permalink raw reply
* Re: [PATCH v3 net-next] net: phy: Add Edge-rate driver for Microsemi PHYs.
From: Andrew Lunn @ 2016-09-27 14:58 UTC (permalink / raw)
To: Allan W. Nielsen
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA,
f.fainelli-Re5JQEeQqe8AvxtiuMwx3w, Raju Lakkaraju
In-Reply-To: <20160927142659.GC10776-dzo6w/eZyo2tG0bUXCXiUA@public.gmane.org>
On Tue, Sep 27, 2016 at 04:26:59PM +0200, Allan W. Nielsen wrote:
> Hi Andrew,
>
> > > +Optional properties:
> > > +- vsc8531,edge-rate : Edge rate sets the drive strength of the MAC
> > > + interface output signals. Changing the drive
> > > + strength will affect the edge rate of the output
> > > + signal.
> >
> > Are we specifying a rate or a strength? It is called edge-rate, so it
> > expect it to be a rate, mV/pS or something similar.
> I do not know - sorry.
The text needs to be consistent with the property name. The text
suggests this setting affects the drive strength. As a result of the
drive strength, the edge rate will differ. Cause and effect.
So maybe the correct units here is mA?
Andrew
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH net-next 4/4] net/sched: act_mirred: Implement ingress actions
From: Daniel Borkmann @ 2016-09-27 14:47 UTC (permalink / raw)
To: Shmulik Ladkani, David Miller
Cc: jhs, xiyou.wangcong, edumazet, netdev, shmulik.ladkani
In-Reply-To: <20160927171804.5288347d@pixies>
On 09/27/2016 04:18 PM, Shmulik Ladkani wrote:
> On Tue, 27 Sep 2016 09:44:41 -0400 (EDT), davem@davemloft.net wrote:
>> From: Daniel Borkmann <daniel@iogearbox.net>
>> Date: Tue, 27 Sep 2016 12:39:34 +0200
>>
>>> Any reason why dev_forward_skb() is not preferred over direct
>>> netif_receive_skb() you're using? It would, for example, implicitly
>>> assure that pkt_type is always PACKET_HOST, etc.
>>
>> dev_forward_skb() will pull the ethernet header.
>>
>> And since a direct call to netif_receive_skb() will not, one of these
>> two choices won't work properly.
>
> In the patch, I'm issuing a skb_pull_rcsum() prior the netif_receive_skb,
> snip:
>
[...]
>
> Existing *egress* mir/red already supported pairing two non-eth devices.
> Therefore I allow it for the new *ingress* mir/red as well.
[...]
Yeah, makes sense then. Should skb->pkt_type become an issue, you might
probably just use act_skbedit for such cases.
^ permalink raw reply
* Re: kernel BUG at net/unix/garbage.c:149!"
From: Hannes Frederic Sowa @ 2016-09-27 14:43 UTC (permalink / raw)
To: Nikolay Borisov, David Miller
Cc: Miklos Szeredi, Linux-Kernel@Vger. Kernel. Org, netdev
In-Reply-To: <57EA7F3B.3030801@kyup.com>
On Tue, Sep 27, 2016, at 16:16, Nikolay Borisov wrote:
> Dave,
>
> What's the status of https://patchwork.ozlabs.org/patch/664062/ , is
> this going to be picked up ?
Not sure if we actually fix a bug with this. Miklos could you maybe
enhance the changelog then?
Thanks,
Hannes
^ permalink raw reply
* Re: [PATCH v3 net-next] net: phy: Add Edge-rate driver for Microsemi PHYs.
From: Allan W. Nielsen @ 2016-09-27 14:26 UTC (permalink / raw)
To: Andrew Lunn; +Cc: netdev, devicetree, f.fainelli, Raju Lakkaraju
In-Reply-To: <20160927141633.GJ28432@lunn.ch>
Hi Andrew,
> > +Optional properties:
> > +- vsc8531,edge-rate : Edge rate sets the drive strength of the MAC
> > + interface output signals. Changing the drive
> > + strength will affect the edge rate of the output
> > + signal.
>
> Are we specifying a rate or a strength? It is called edge-rate, so it
> expect it to be a rate, mV/pS or something similar.
I do not know - sorry.
If it is a hard requirement to document these settings using physical units then
we need to requist some help from the HW team.
I will forward this to the HW team - but it will properly take a few days to get
a decent answer.
Best regards
Allan W. Nielsen
^ permalink raw reply
* RE: [PATCH RFC 1/3] net: Add dev_set_env_hdr_len to accept envelope frames
From: Mintz, Yuval @ 2016-09-27 14:23 UTC (permalink / raw)
To: Toshiaki Makita, netdev@vger.kernel.org, Patrick McHardy,
Stephen Hemminger, Vlad Yasevich, Jeff Kirsher
In-Reply-To: <1474966541-4420-2-git-send-email-makita.toshiaki@lab.ntt.co.jp>
> +/* return envelope header length */
> +static inline int netif_get_env_hdr_len(struct net_device *dev) {
> + if (dev->netdev_ops->ndo_set_env_hdr_len)
> + return dev->env_hdr_len;
> +
> + if (netif_reduces_vlan_mtu(dev))
> + return 0;
> +
> + return 4; /* VLAN_HLEN */
> +}
Why claim that `4' is the default?
What's the benefit of propagating this value to userspace if
driver doesn't actually support it?
Assuming this *is* a good default [meaning your analysis indicated
basically every driver has at least so many octets reserved]
perhaps we should consider initializing the env_hdr_len in some
common function [e.g., in setup_ether() next to the mtu] to this value?
^ permalink raw reply
* Re: [Gigaset307x-common] ISDN-Gigaset: Release memory in gigaset_initcs() after an allocation failure
From: Tilman Schmidt @ 2016-09-27 14:35 UTC (permalink / raw)
To: SF Markus Elfring
Cc: Karsten Keil, Paul Bolle, gigaset307x-common, netdev,
kernel-janitors, LKML, Julia Lawall
In-Reply-To: <02ad1fea-33f6-a38a-fd91-16bc0c351bdd@users.sourceforge.net>
On Tue, Sep 27, 2016, at 14:52, SF Markus Elfring wrote:
> >> * Is it still correct nowadays that the function "gigaset_initcs" did not
> >> call the function "kfree" after a later function call failed?
> >
> > Yes, if it is handled in another place, Paul already did show you the place.
>
> To which source code place do you refer here?
Obviously the one Paul pointed out to you in detail in his mail dated
Mon, 26 Sep 2016 23:13:54 +0200.
HTH,
Tilman
--
Tilman Schmidt
tilman@imap.cc
^ permalink raw reply
* Re: [PATCH net-next 4/4] net/sched: act_mirred: Implement ingress actions
From: Shmulik Ladkani @ 2016-09-27 14:18 UTC (permalink / raw)
To: David Miller, daniel
Cc: jhs, xiyou.wangcong, edumazet, netdev, shmulik.ladkani
In-Reply-To: <20160927.094441.1957543068015677016.davem@davemloft.net>
On Tue, 27 Sep 2016 09:44:41 -0400 (EDT), davem@davemloft.net wrote:
> From: Daniel Borkmann <daniel@iogearbox.net>
> Date: Tue, 27 Sep 2016 12:39:34 +0200
>
> > Any reason why dev_forward_skb() is not preferred over direct
> > netif_receive_skb() you're using? It would, for example, implicitly
> > assure that pkt_type is always PACKET_HOST, etc.
>
> dev_forward_skb() will pull the ethernet header.
>
> And since a direct call to netif_receive_skb() will not, one of these
> two choices won't work properly.
In the patch, I'm issuing a skb_pull_rcsum() prior the netif_receive_skb,
snip:
+ /* If action's target direction differs than filter's direction,
+ * and devices expect a mac header on xmit, then mac push/pull is
+ * needed.
+ */
+ if (at != tcf_mirred_act_direction(m->tcfm_eaction) &&
+ m->tcfm_mac_header_xmit) {
+ if (at & AT_EGRESS) {
+ /* caught at egress, act ingress: pull mac */
+ mac_len = skb_network_header(skb) - skb_mac_header(skb);
+ skb_pull_rcsum(skb2, mac_len);
Existing *egress* mir/red already supported pairing two non-eth devices.
Therefore I allow it for the new *ingress* mir/red as well.
Now, following this premise, the skb_pull_rcsum() shown above is executed
for devices whose xmit is mac_header based.
I've tested both ARPHRD_ETHER devices and some non ARPHRD_ETHER devices.
(an *existing* symmetric skb_push_rcsum() is invoked if packet is caught at
ingress and redirected for egress on a mac_header xmit device)
This was the reason for picking netif_receive_skb() over dev_forward_skb().
Regards,
Shmulik
^ permalink raw reply
* Re: [PATCH v3 net-next] net: phy: Add Edge-rate driver for Microsemi PHYs.
From: Andrew Lunn @ 2016-09-27 14:16 UTC (permalink / raw)
To: Raju Lakkaraju; +Cc: netdev, devicetree, f.fainelli, Allan.Nielsen
In-Reply-To: <1474984075-12312-1-git-send-email-Raju.Lakkaraju@microsemi.com>
> index 0000000..7ba3855
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
> @@ -0,0 +1,61 @@
> +* Microsemi - vsc8531 Giga bit ethernet phy
> +
> +Required properties:
> +- compatible : Should contain phy id as "ethernet-phy-idAAAA.BBBB"
> + If the phy's identifier is known then the list may contain an entry
> + of the form: "ethernet-phy-idAAAA.BBBB" where
> + AAAA - The value of the 16 bit Phy Identifier 1 register as
> + 4 hex digits. This is the chip vendor OUI bits 3:18
> + BBBB - The value of the 16 bit Phy Identifier 2 register as
> + 4 hex digits. This is the chip vendor OUI bits 19:24,
> + followed by 10 bits of a vendor specific ID.
> +- reg : The ID number for the phy, usually a small integer
Please don't copy phy.txt. Just refer to it. Use text like:
The PHY device uses the binding described in
Documentation/devicetree/bindings/net/phy.txt
It may additionally have the following properties
> +Optional properties:
> +- vsc8531,edge-rate : Edge rate sets the drive strength of the MAC
> + interface output signals. Changing the drive
> + strength will affect the edge rate of the output
> + signal.
Are we specifying a rate or a strength? It is called edge-rate, so it
expect it to be a rate, mV/pS or something similar.
Andrew
^ permalink raw reply
* Re: kernel BUG at net/unix/garbage.c:149!"
From: Nikolay Borisov @ 2016-09-27 14:16 UTC (permalink / raw)
To: David Miller
Cc: Miklos Szeredi, Hannes Frederic Sowa,
Linux-Kernel@Vger. Kernel. Org, netdev
In-Reply-To: <CAOssrKcfncAYsQWkfLGFgoOxAQJVT2hYVWdBA6Cw7hhO8RJ_wQ@mail.gmail.com>
[Added Dave Miller to see what's the status of this patch]
On 08/30/2016 12:18 PM, Miklos Szeredi wrote:
> On Tue, Aug 30, 2016 at 12:37 AM, Miklos Szeredi <mszeredi@redhat.com> wrote:
>> On Sat, Aug 27, 2016 at 11:55 AM, Miklos Szeredi <mszeredi@redhat.com> wrote:
>
>> crash> list -H gc_inflight_list unix_sock.link -s unix_sock.inflight |
>> grep counter | cut -d= -f2 | awk '{s+=$1} END {print s}'
>> 130
>> crash> p unix_tot_inflight
>> unix_tot_inflight = $2 = 135
>>
>> We've lost track of a total of five inflight sockets, so it's not a
>> one-off thing. Really weird... Now off to sleep, maybe I'll dream of
>> the solution.
>
> Okay, found one bug: gc assumes that in-flight sockets that don't have
> an external ref can't gain one while unix_gc_lock is held. That is
> true because unix_notinflight() will be called before detaching fds,
> which takes unix_gc_lock. Only MSG_PEEK was somehow overlooked. That
> one also clones the fds, also keeping them in the skb. But through
> MSG_PEEK an external reference can definitely be gained without ever
> touching unix_gc_lock.
>
> Not sure whether the reported bug can be explained by this. Can you
> confirm the MSG_PEEK was used in the setup?
>
> Does someone want to write a stress test for SCM_RIGHTS + MSG_PEEK?
>
> Anyway, attaching a fix that works by acquiring unix_gc_lock in case
> of MSG_PEEK also. It is trivially correct, but I haven't tested it.
>
> Thanks,
> Miklos
>
Dave,
What's the status of https://patchwork.ozlabs.org/patch/664062/ , is
this going to be picked up ?
Regards,
Nikolay
^ permalink raw reply
* Re: [PATCH v7 5/8] thunderbolt: Networking state machine
From: Greg KH @ 2016-09-27 14:15 UTC (permalink / raw)
To: Amir Levy
Cc: andreas.noever, bhelgaas, corbet, linux-kernel, linux-pci, netdev,
linux-doc, mario_limonciello, thunderbolt-linux, mika.westerberg,
tomas.winkler, xiong.y.zhang
In-Reply-To: <1474983821-2313-6-git-send-email-amir.jer.levy@intel.com>
On Tue, Sep 27, 2016 at 04:43:38PM +0300, Amir Levy wrote:
> This patch builds the peer to peer communication path.
> Communication is established by a negotiation process whereby messages are
> sent back and forth between the peers until a connection is established.
> This includes the Thunderbolt Network driver communication with the second
> peer via Intel Connection Manager(ICM) firmware.
> +--------------------+ +--------------------+
> |Host 1 | |Host 2 |
> | | | |
> | +-----------+ | | +-----------+ |
> | |Thunderbolt| | | |Thunderbolt| |
> | |Networking | | | |Networking | |
> | |Driver | | | |Driver | |
> | +-----------+ | | +-----------+ |
> | ^ | | ^ |
> | | | | | |
> | +------------+---+ | | +------------+---+ |
> | |Thunderbolt | | | | |Thunderbolt | | |
> | |Controller v | | | |Controller v | |
> | | +---+ | | | | +---+ | |
> | | |ICM|<-+-+------------+-+-------->|ICM| | |
> | | +---+ | | | | +---+ | |
> | +----------------+ | | +----------------+ |
> +--------------------+ +--------------------+
> Note that this patch only establishes the link between the two hosts and
> not Network Packet handling - this is dealt with in the next patch.
>
> Signed-off-by: Amir Levy <amir.jer.levy@intel.com>
> ---
> drivers/thunderbolt/icm/Makefile | 2 +-
> drivers/thunderbolt/icm/icm_nhi.c | 303 ++++++++++++++-
> drivers/thunderbolt/icm/net.c | 793 ++++++++++++++++++++++++++++++++++++++
> drivers/thunderbolt/icm/net.h | 70 ++++
> 4 files changed, 1157 insertions(+), 11 deletions(-)
> create mode 100644 drivers/thunderbolt/icm/net.c
>
> diff --git a/drivers/thunderbolt/icm/Makefile b/drivers/thunderbolt/icm/Makefile
> index f0d0fbb..94a2797 100644
> --- a/drivers/thunderbolt/icm/Makefile
> +++ b/drivers/thunderbolt/icm/Makefile
> @@ -1,2 +1,2 @@
> obj-${CONFIG_THUNDERBOLT_ICM} += thunderbolt-icm.o
> -thunderbolt-icm-objs := icm_nhi.o
> +thunderbolt-icm-objs := icm_nhi.o net.o
> diff --git a/drivers/thunderbolt/icm/icm_nhi.c b/drivers/thunderbolt/icm/icm_nhi.c
> index 984aa7c..578eb14 100644
> --- a/drivers/thunderbolt/icm/icm_nhi.c
> +++ b/drivers/thunderbolt/icm/icm_nhi.c
> @@ -74,6 +74,12 @@ static const struct nla_policy nhi_genl_policy[NHI_ATTR_MAX + 1] = {
> .len = TBT_ICM_RING_MAX_FRAME_SIZE },
> [NHI_ATTR_MSG_FROM_ICM] = { .type = NLA_BINARY,
> .len = TBT_ICM_RING_MAX_FRAME_SIZE },
> + [NHI_ATTR_LOCAL_ROUTE_STRING] = {.len = sizeof(struct route_string)},
> + [NHI_ATTR_LOCAL_UUID] = { .len = sizeof(uuid_be) },
> + [NHI_ATTR_REMOTE_UUID] = { .len = sizeof(uuid_be) },
> + [NHI_ATTR_LOCAL_DEPTH] = { .type = NLA_U8, },
> + [NHI_ATTR_ENABLE_FULL_E2E] = { .type = NLA_FLAG, },
> + [NHI_ATTR_MATCH_FRAME_ID] = { .type = NLA_FLAG, },
> };
>
> /* NHI genetlink family */
> @@ -522,6 +528,29 @@ int nhi_mailbox(struct tbt_nhi_ctxt *nhi_ctxt, u32 cmd, u32 data, bool deinit)
> return 0;
> }
>
> +static inline bool nhi_is_path_disconnected(u32 cmd, u8 num_ports)
> +{
> + return (cmd >= DISCONNECT_PORT_A_INTER_DOMAIN_PATH &&
> + cmd < (DISCONNECT_PORT_A_INTER_DOMAIN_PATH + num_ports));
> +}
> +
> +static int nhi_mailbox_disconn_path(struct tbt_nhi_ctxt *nhi_ctxt, u32 cmd)
> + __releases(&controllers_list_mutex)
> +{
> + struct port_net_dev *port;
> + u32 port_num = cmd - DISCONNECT_PORT_A_INTER_DOMAIN_PATH;
> +
> + port = &(nhi_ctxt->net_devices[port_num]);
> + mutex_lock(&port->state_mutex);
> +
> + mutex_unlock(&controllers_list_mutex);
> + port->medium_sts = MEDIUM_READY_FOR_APPROVAL;
> + if (port->net_dev)
> + negotiation_events(port->net_dev, MEDIUM_DISCONNECTED);
> + mutex_unlock(&port->state_mutex);
> + return 0;
> +}
> +
> static int nhi_mailbox_generic(struct tbt_nhi_ctxt *nhi_ctxt, u32 mb_cmd)
> __releases(&controllers_list_mutex)
> {
> @@ -571,13 +600,94 @@ static int nhi_genl_mailbox(__always_unused struct sk_buff *u_skb,
> return -ERESTART;
>
> nhi_ctxt = nhi_search_ctxt(*(u32 *)info->userhdr);
> - if (nhi_ctxt && !nhi_ctxt->d0_exit)
> - return nhi_mailbox_generic(nhi_ctxt, mb_cmd);
> + if (nhi_ctxt && !nhi_ctxt->d0_exit) {
> +
> + /* rwsem is released later by the below functions */
> + if (nhi_is_path_disconnected(cmd, nhi_ctxt->num_ports))
> + return nhi_mailbox_disconn_path(nhi_ctxt, cmd);
> + else
> + return nhi_mailbox_generic(nhi_ctxt, mb_cmd);
> +
> + }
>
> mutex_unlock(&controllers_list_mutex);
> return -ENODEV;
> }
>
> +static int nhi_genl_approve_networking(__always_unused struct sk_buff *u_skb,
> + struct genl_info *info)
> +{
> + struct tbt_nhi_ctxt *nhi_ctxt;
> + struct route_string *route_str;
> + int res = -ENODEV;
> + u8 port_num;
> +
> + if (!info || !info->userhdr || !info->attrs ||
> + !info->attrs[NHI_ATTR_LOCAL_ROUTE_STRING] ||
> + !info->attrs[NHI_ATTR_LOCAL_UUID] ||
> + !info->attrs[NHI_ATTR_REMOTE_UUID] ||
> + !info->attrs[NHI_ATTR_LOCAL_DEPTH])
> + return -EINVAL;
> +
> + /*
> + * route_str is an unique topological address
> + * used for approving remote controller
> + */
> + route_str = nla_data(info->attrs[NHI_ATTR_LOCAL_ROUTE_STRING]);
> + /* extracts the port we're connected to */
> + port_num = PORT_NUM_FROM_LINK(L0_PORT_NUM(route_str->lo));
> +
> + if (mutex_lock_interruptible(&controllers_list_mutex))
> + return -ERESTART;
> +
> + nhi_ctxt = nhi_search_ctxt(*(u32 *)info->userhdr);
> + if (nhi_ctxt && !nhi_ctxt->d0_exit) {
> + struct port_net_dev *port;
> +
> + if (port_num >= nhi_ctxt->num_ports) {
> + res = -EINVAL;
> + goto free_ctl_list;
> + }
> +
> + port = &(nhi_ctxt->net_devices[port_num]);
> +
> + mutex_lock(&port->state_mutex);
> + mutex_unlock(&controllers_list_mutex);
> +
> + if (port->medium_sts != MEDIUM_READY_FOR_APPROVAL) {
> + dev_info(&nhi_ctxt->pdev->dev,
> + "%s: controller id %#x in state %u <> MEDIUM_READY_FOR_APPROVAL\n",
> + __func__, nhi_ctxt->id, port->medium_sts);
Why is this needed? Don't spam the kernel log for a normal device
operation please, only report serious errors when something goes wrong.
And if this is an error, why is it dev_info()?
^ permalink raw reply
* Re: [PATCH v7 5/8] thunderbolt: Networking state machine
From: Greg KH @ 2016-09-27 14:13 UTC (permalink / raw)
To: Amir Levy
Cc: andreas.noever, bhelgaas, corbet, linux-kernel, linux-pci, netdev,
linux-doc, mario_limonciello, thunderbolt-linux, mika.westerberg,
tomas.winkler, xiong.y.zhang
In-Reply-To: <1474983821-2313-6-git-send-email-amir.jer.levy@intel.com>
On Tue, Sep 27, 2016 at 04:43:38PM +0300, Amir Levy wrote:
> This patch builds the peer to peer communication path.
> Communication is established by a negotiation process whereby messages are
> sent back and forth between the peers until a connection is established.
> This includes the Thunderbolt Network driver communication with the second
> peer via Intel Connection Manager(ICM) firmware.
> +--------------------+ +--------------------+
> |Host 1 | |Host 2 |
> | | | |
> | +-----------+ | | +-----------+ |
> | |Thunderbolt| | | |Thunderbolt| |
> | |Networking | | | |Networking | |
> | |Driver | | | |Driver | |
> | +-----------+ | | +-----------+ |
> | ^ | | ^ |
> | | | | | |
> | +------------+---+ | | +------------+---+ |
> | |Thunderbolt | | | | |Thunderbolt | | |
> | |Controller v | | | |Controller v | |
> | | +---+ | | | | +---+ | |
> | | |ICM|<-+-+------------+-+-------->|ICM| | |
> | | +---+ | | | | +---+ | |
> | +----------------+ | | +----------------+ |
> +--------------------+ +--------------------+
> Note that this patch only establishes the link between the two hosts and
> not Network Packet handling - this is dealt with in the next patch.
>
> Signed-off-by: Amir Levy <amir.jer.levy@intel.com>
> ---
> drivers/thunderbolt/icm/Makefile | 2 +-
> drivers/thunderbolt/icm/icm_nhi.c | 303 ++++++++++++++-
> drivers/thunderbolt/icm/net.c | 793 ++++++++++++++++++++++++++++++++++++++
> drivers/thunderbolt/icm/net.h | 70 ++++
> 4 files changed, 1157 insertions(+), 11 deletions(-)
> create mode 100644 drivers/thunderbolt/icm/net.c
>
> diff --git a/drivers/thunderbolt/icm/Makefile b/drivers/thunderbolt/icm/Makefile
> index f0d0fbb..94a2797 100644
> --- a/drivers/thunderbolt/icm/Makefile
> +++ b/drivers/thunderbolt/icm/Makefile
> @@ -1,2 +1,2 @@
> obj-${CONFIG_THUNDERBOLT_ICM} += thunderbolt-icm.o
> -thunderbolt-icm-objs := icm_nhi.o
> +thunderbolt-icm-objs := icm_nhi.o net.o
> diff --git a/drivers/thunderbolt/icm/icm_nhi.c b/drivers/thunderbolt/icm/icm_nhi.c
> index 984aa7c..578eb14 100644
> --- a/drivers/thunderbolt/icm/icm_nhi.c
> +++ b/drivers/thunderbolt/icm/icm_nhi.c
> @@ -74,6 +74,12 @@ static const struct nla_policy nhi_genl_policy[NHI_ATTR_MAX + 1] = {
> .len = TBT_ICM_RING_MAX_FRAME_SIZE },
> [NHI_ATTR_MSG_FROM_ICM] = { .type = NLA_BINARY,
> .len = TBT_ICM_RING_MAX_FRAME_SIZE },
> + [NHI_ATTR_LOCAL_ROUTE_STRING] = {.len = sizeof(struct route_string)},
> + [NHI_ATTR_LOCAL_UUID] = { .len = sizeof(uuid_be) },
> + [NHI_ATTR_REMOTE_UUID] = { .len = sizeof(uuid_be) },
Be consistent in your choice of whitespace please.
^ permalink raw reply
* Re: [PATCH v7 4/8] thunderbolt: Communication with the ICM (firmware)
From: Greg KH @ 2016-09-27 14:11 UTC (permalink / raw)
To: Amir Levy
Cc: andreas.noever, bhelgaas, corbet, linux-kernel, linux-pci, netdev,
linux-doc, mario_limonciello, thunderbolt-linux, mika.westerberg,
tomas.winkler, xiong.y.zhang
In-Reply-To: <1474983821-2313-5-git-send-email-amir.jer.levy@intel.com>
On Tue, Sep 27, 2016 at 04:43:37PM +0300, Amir Levy wrote:
> This patch provides the communication protocol between the
> Intel Connection Manager(ICM) firmware that is operational in the
> Thunderbolt controller in non-Apple hardware.
> The ICM firmware-based controller is used for establishing and maintaining
> the Thunderbolt Networking connection - we need to be able to communicate
> with it.
>
> Signed-off-by: Amir Levy <amir.jer.levy@intel.com>
> ---
> drivers/thunderbolt/Makefile | 1 +
> drivers/thunderbolt/icm/Makefile | 2 +
> drivers/thunderbolt/icm/icm_nhi.c | 1324 +++++++++++++++++++++++++++++++++++++
> drivers/thunderbolt/icm/icm_nhi.h | 92 +++
> drivers/thunderbolt/icm/net.h | 227 +++++++
> 5 files changed, 1646 insertions(+)
> create mode 100644 drivers/thunderbolt/icm/Makefile
> create mode 100644 drivers/thunderbolt/icm/icm_nhi.c
> create mode 100644 drivers/thunderbolt/icm/icm_nhi.h
> create mode 100644 drivers/thunderbolt/icm/net.h
>
> diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile
> index 7a85bd1..b6aa6a3 100644
> --- a/drivers/thunderbolt/Makefile
> +++ b/drivers/thunderbolt/Makefile
> @@ -1,3 +1,4 @@
> obj-${CONFIG_THUNDERBOLT_APPLE} := thunderbolt.o
> thunderbolt-objs := nhi.o ctl.o tb.o switch.o cap.o path.o tunnel_pci.o eeprom.o
>
> +obj-${CONFIG_THUNDERBOLT_ICM} += icm/
> diff --git a/drivers/thunderbolt/icm/Makefile b/drivers/thunderbolt/icm/Makefile
> new file mode 100644
> index 0000000..f0d0fbb
> --- /dev/null
> +++ b/drivers/thunderbolt/icm/Makefile
> @@ -0,0 +1,2 @@
> +obj-${CONFIG_THUNDERBOLT_ICM} += thunderbolt-icm.o
> +thunderbolt-icm-objs := icm_nhi.o
> diff --git a/drivers/thunderbolt/icm/icm_nhi.c b/drivers/thunderbolt/icm/icm_nhi.c
> new file mode 100644
> index 0000000..984aa7c
> --- /dev/null
> +++ b/drivers/thunderbolt/icm/icm_nhi.c
> @@ -0,0 +1,1324 @@
> +/*******************************************************************************
> + *
> + * Intel Thunderbolt(TM) driver
> + * Copyright(c) 2014 - 2016 Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program. If not, see <http://www.gnu.org/licenses/>.
Why is this sentence needed?
> + *
> + * The full GNU General Public License is included in this distribution in
> + * the file called "COPYING".
Why is this sentence needed?
> + *
> + * Contact Information:
> + * Intel Thunderbolt Mailing List <thunderbolt-software@lists.01.org>
Shouldn't this just be in the MAINTAINERS file?
> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
Unless you are going to track the address of Intel for the next 40+
years, don't put it in a source comment. Please just drop it.
> + *
> + ******************************************************************************/
> +
> +#include <linux/printk.h>
> +#include <linux/crc32.h>
> +#include <linux/delay.h>
> +#include <linux/dmi.h>
> +#include "icm_nhi.h"
> +#include "net.h"
> +
> +#define NHI_GENL_VERSION 1
> +#define NHI_GENL_NAME "thunderbolt"
> +
> +#define DEVICE_DATA(num_ports, dma_port, nvm_ver_offset, nvm_auth_on_boot,\
> + support_full_e2e) \
> + ((num_ports) | ((dma_port) << 4) | ((nvm_ver_offset) << 10) | \
> + ((nvm_auth_on_boot) << 22) | ((support_full_e2e) << 23))
> +#define DEVICE_DATA_NUM_PORTS(device_data) ((device_data) & 0xf)
> +#define DEVICE_DATA_DMA_PORT(device_data) (((device_data) >> 4) & 0x3f)
> +#define DEVICE_DATA_NVM_VER_OFFSET(device_data) (((device_data) >> 10) & 0xfff)
> +#define DEVICE_DATA_NVM_AUTH_ON_BOOT(device_data) (((device_data) >> 22) & 0x1)
> +#define DEVICE_DATA_SUPPORT_FULL_E2E(device_data) (((device_data) >> 23) & 0x1)
> +
> +#define USEC_TO_256_NSECS(usec) DIV_ROUND_UP((usec) * NSEC_PER_USEC, 256)
> +
> +/* NHI genetlink commands */
> +enum {
> + NHI_CMD_UNSPEC,
> + NHI_CMD_SUBSCRIBE,
> + NHI_CMD_UNSUBSCRIBE,
> + NHI_CMD_QUERY_INFORMATION,
> + NHI_CMD_MSG_TO_ICM,
> + NHI_CMD_MSG_FROM_ICM,
> + NHI_CMD_MAILBOX,
> + NHI_CMD_APPROVE_TBT_NETWORKING,
> + NHI_CMD_ICM_IN_SAFE_MODE,
> + __NHI_CMD_MAX,
> +};
> +#define NHI_CMD_MAX (__NHI_CMD_MAX - 1)
> +
> +/* NHI genetlink policy */
> +static const struct nla_policy nhi_genl_policy[NHI_ATTR_MAX + 1] = {
> + [NHI_ATTR_DRV_VERSION] = { .type = NLA_NUL_STRING, },
> + [NHI_ATTR_NVM_VER_OFFSET] = { .type = NLA_U16, },
> + [NHI_ATTR_NUM_PORTS] = { .type = NLA_U8, },
> + [NHI_ATTR_DMA_PORT] = { .type = NLA_U8, },
> + [NHI_ATTR_SUPPORT_FULL_E2E] = { .type = NLA_FLAG, },
> + [NHI_ATTR_MAILBOX_CMD] = { .type = NLA_U32, },
> + [NHI_ATTR_PDF] = { .type = NLA_U32, },
> + [NHI_ATTR_MSG_TO_ICM] = { .type = NLA_BINARY,
> + .len = TBT_ICM_RING_MAX_FRAME_SIZE },
> + [NHI_ATTR_MSG_FROM_ICM] = { .type = NLA_BINARY,
> + .len = TBT_ICM_RING_MAX_FRAME_SIZE },
> +};
> +
> +/* NHI genetlink family */
> +static struct genl_family nhi_genl_family = {
> + .id = GENL_ID_GENERATE,
> + .hdrsize = FIELD_SIZEOF(struct tbt_nhi_ctxt, id),
> + .name = NHI_GENL_NAME,
> + .version = NHI_GENL_VERSION,
> + .maxattr = NHI_ATTR_MAX,
> +};
> +
> +static LIST_HEAD(controllers_list);
> +static DEFINE_MUTEX(controllers_list_mutex);
> +static atomic_t subscribers = ATOMIC_INIT(0);
> +static u32 portid;
This is really odd, why have a global single portid?
> +
> +static bool nhi_nvm_authenticated(struct tbt_nhi_ctxt *nhi_ctxt)
> +{
> + enum icm_operation_mode op_mode;
> + u32 *msg_head, port_id, reg;
> + struct sk_buff *skb;
> + int i;
> +
> + if (!nhi_ctxt->nvm_auth_on_boot)
> + return true;
> +
> + /*
> + * The check for NVM authentication can take time for iCM,
> + * especially in low power configuration.
> + */
> + for (i = 0; i < 5; i++) {
> + u32 status = ioread32(nhi_ctxt->iobase + REG_FW_STS);
> +
> + if (status & REG_FW_STS_NVM_AUTH_DONE)
> + break;
> +
> + msleep(30);
> + }
> + /*
> + * The check for authentication is done after checking if iCM
> + * is present so it shouldn't reach the max tries (=5).
> + * Anyway, the check for full functionality below covers the error case.
> + */
> + reg = ioread32(nhi_ctxt->iobase + REG_OUTMAIL_CMD);
> + op_mode = (reg & REG_OUTMAIL_CMD_OP_MODE_MASK) >>
> + REG_OUTMAIL_CMD_OP_MODE_SHIFT;
> + if (op_mode == FULL_FUNCTIONALITY)
> + return true;
> +
> + dev_warn(&nhi_ctxt->pdev->dev, "controller id %#x is in operation mode %#x status %#lx\n",
> + nhi_ctxt->id, op_mode,
> + (reg & REG_OUTMAIL_CMD_STS_MASK)>>REG_OUTMAIL_CMD_STS_SHIFT);
> +
> + skb = genlmsg_new(NLMSG_ALIGN(nhi_genl_family.hdrsize), GFP_KERNEL);
> + if (!skb) {
> + dev_err(&nhi_ctxt->pdev->dev, "genlmsg_new failed: not enough memory to send controller operational mode\n");
> + return false;
> + }
> +
> + /* keeping port_id into a local variable for next use */
> + port_id = portid;
> + msg_head = genlmsg_put(skb, port_id, 0, &nhi_genl_family, 0,
> + NHI_CMD_ICM_IN_SAFE_MODE);
> + if (!msg_head) {
> + nlmsg_free(skb);
> + dev_err(&nhi_ctxt->pdev->dev, "genlmsg_put failed: not enough memory to send controller operational mode\n");
> + return false;
> + }
> +
> + *msg_head = nhi_ctxt->id;
> +
> + genlmsg_end(skb, msg_head);
> +
> + genlmsg_unicast(&init_net, skb, port_id);
> +
> + return false;
> +}
> +
> +int nhi_send_message(struct tbt_nhi_ctxt *nhi_ctxt, enum pdf_value pdf,
> + u32 msg_len, const void *msg, bool ignore_icm_resp)
> +{
> + u32 prod_cons, prod, cons, attr;
> + struct tbt_icm_ring_shared_memory *shared_mem;
> + void __iomem *reg = TBT_RING_CONS_PROD_REG(nhi_ctxt->iobase,
> + REG_TX_RING_BASE,
> + TBT_ICM_RING_NUM);
> +
> + dev_dbg(&nhi_ctxt->pdev->dev,
> + "send msg: controller id %#x pdf %u cmd %hhu msg len %u\n",
> + nhi_ctxt->id, pdf, ((u8 *)msg)[3], msg_len);
Don't put trace debug calls in your code, either use a real tracepoint,
or just use ftrace. Delete these, they aren't needed once you want to
submit the code for merging as it should not be needed.
You do this in a lot of other places as well, please fix all of them.
> +
> + if (nhi_ctxt->d0_exit) {
> + dev_notice(&nhi_ctxt->pdev->dev,
> + "controller id %#x is exiting D0\n",
> + nhi_ctxt->id);
What can a user do about this?
> + return -ENODEV;
> + }
> +
> + prod_cons = ioread32(reg);
> + prod = TBT_REG_RING_PROD_EXTRACT(prod_cons);
> + cons = TBT_REG_RING_CONS_EXTRACT(prod_cons);
> + if (prod >= TBT_ICM_RING_NUM_TX_BUFS) {
> + dev_warn(&nhi_ctxt->pdev->dev,
> + "controller id %#x producer %u out of range\n",
> + nhi_ctxt->id, prod);
What can a user do about this?
> + return -ENODEV;
> + }
> + if (TBT_TX_RING_FULL(prod, cons, TBT_ICM_RING_NUM_TX_BUFS)) {
> + dev_err(&nhi_ctxt->pdev->dev,
> + "controller id %#x TX ring full\n",
> + nhi_ctxt->id);
What can a user do about this?
> + return -ENOSPC;
> + }
> +
> + attr = (msg_len << DESC_ATTR_LEN_SHIFT) & DESC_ATTR_LEN_MASK;
> + attr |= (pdf << DESC_ATTR_EOF_SHIFT) & DESC_ATTR_EOF_MASK;
> +
> + shared_mem = nhi_ctxt->icm_ring_shared_mem;
> + shared_mem->tx_buf_desc[prod].attributes = cpu_to_le32(attr);
> +
> + memcpy(shared_mem->tx_buf[prod], msg, msg_len);
No zero-copy, sad :(
> +
> + prod_cons &= ~REG_RING_PROD_MASK;
> + prod_cons |= (((prod + 1) % TBT_ICM_RING_NUM_TX_BUFS) <<
> + REG_RING_PROD_SHIFT) & REG_RING_PROD_MASK;
> +
> + if (likely(!nhi_ctxt->wait_for_icm_resp))
> + nhi_ctxt->wait_for_icm_resp = true;
Can you measure the speed difference with likely() here? If so, great,
if not, drop it as the cpu can guess this better than you or I can.
> + else
> + dev_dbg(&nhi_ctxt->pdev->dev,
> + "controller id %#x wait_for_icm_resp should have been cleared\n",
> + nhi_ctxt->id);
Huh? So this isn't a real issue?
> +
> + nhi_ctxt->ignore_icm_resp = ignore_icm_resp;
> +
> + iowrite32(prod_cons, reg);
> +
> + return 0;
> +}
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH net-next 4/4] net/sched: act_mirred: Implement ingress actions
From: Jamal Hadi Salim @ 2016-09-27 14:06 UTC (permalink / raw)
To: Shmulik Ladkani, David Miller
Cc: xiyou.wangcong, edumazet, netdev, shmulik.ladkani
In-Reply-To: <20160927110711.12555f4e@pixies>
On 16-09-27 04:07 AM, Shmulik Ladkani wrote:
> Hi David,
>
> On Tue, 27 Sep 2016 01:56:06 -0400 (EDT), davem@davemloft.net wrote:
>> The discussion on this patch has ventured off into what to do about
>> recursion.
>>
>> But it unclear to me where this specific patch, and this series,
>> stands right now. Someone please clear this up for me.
>
> Status:
> - Series adds "ingress redirect/mirror" support
> - Positive feedback for the feature
> - So far no comments regarding code itself
> - Questions raised regarding "recursion handling"
>
> Expressed that existing mirred code (i.e egress redirect) is *already*
> loop-unsafe (and also, some non-tc netdev constructs, as exampled by
> others).
> Discussion then wandered to "recursion handling".
not totaly bike-shed discussion; legit issues are being raised
(and the egress issue you point out is fixable now that we are paying
attention to it).
We need to take care of loops. I pointed to how the original thought
process was. I _dont_ see this as resolvable via recursion handling
since this is per-skb and not per entry point.
You can add my Acked-by if you promise to take care of this issue next.
cheers,
jamal
PS:- the code looks straight forward
^ permalink raw reply
* Re: [PATCH v7 3/8] thunderbolt: Kconfig for Thunderbolt Networking
From: Greg KH @ 2016-09-27 14:00 UTC (permalink / raw)
To: Amir Levy
Cc: andreas.noever, bhelgaas, corbet, linux-kernel, linux-pci, netdev,
linux-doc, mario_limonciello, thunderbolt-linux, mika.westerberg,
tomas.winkler, xiong.y.zhang
In-Reply-To: <1474983821-2313-4-git-send-email-amir.jer.levy@intel.com>
On Tue, Sep 27, 2016 at 04:43:36PM +0300, Amir Levy wrote:
> Update to the Kconfig Thunderbolt description to add
> Thunderbolt networking as an option.
> The menu item "Thunderbolt support" now offers:
> "Apple Hardware Support" (existing)
> and/or
> "Thunderbolt Networking" (new)
>
> You can choose the driver for your platform or build both drivers -
> each driver will detect if it can run on the specific platform.
> If the Thunderbolt Networking option is chosen, Thunderbolt Networking
> will be enabled between Linux non-Apple systems, macOS and
> Windows based systems.
> Thunderbolt Networking will not affect any other Thunderbolt feature that
> was previous available to Linux users on either Apple or
> non-Apple platforms.
>
> Signed-off-by: Amir Levy <amir.jer.levy@intel.com>
> ---
> drivers/thunderbolt/Kconfig | 27 +++++++++++++++++++++++----
> drivers/thunderbolt/Makefile | 2 +-
> 2 files changed, 24 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig
> index c121acc..376e5bb 100644
> --- a/drivers/thunderbolt/Kconfig
> +++ b/drivers/thunderbolt/Kconfig
> @@ -1,13 +1,32 @@
> -menuconfig THUNDERBOLT
> - tristate "Thunderbolt support for Apple devices"
> +config THUNDERBOLT
> + tristate "Thunderbolt support"
> depends on PCI
> select CRC32
> help
> - Cactus Ridge Thunderbolt Controller driver
> + Thunderbolt Controller driver
> +
> +if THUNDERBOLT
> +
> +config THUNDERBOLT_APPLE
> + tristate "Apple hardware support"
> + help
> This driver is required if you want to hotplug Thunderbolt devices on
> Apple hardware.
>
> Device chaining is currently not supported.
>
> - To compile this driver a module, choose M here. The module will be
> + To compile this driver as a module, choose M here. The module will be
> called thunderbolt.
> +
> +config THUNDERBOLT_ICM
You are adding a config option here that is not used in the tree yet.
Please wait until you need the option to actually add it :)
You might just want to do the APPLE stuff here, that way you can drop in
the networking stuff in a simple patch at the end of this series.
thanks,
greg k-h
^ permalink raw reply
* [PATCH v2] netfilter: xt_hashlimit: Fix link error in 32bit arch because of 64bit division
From: Vishwanath Pai @ 2016-09-27 13:57 UTC (permalink / raw)
To: pablo
Cc: johunt, netfilter-devel, coreteam, netdev, pai.vishwain, kaber,
kadlec, zlpnobody, hannes, maze, eric.dumazet
v2:
Remove unnecessary div64_u64 around constants
--
Fix link error in 32bit arch because of 64bit division
Division of 64bit integers will cause linker error undefined reference
to `__udivdi3'. Fix this by replacing divisions with div64_64
Signed-off-by: Vishwanath Pai <vpai@akamai.com>
---
net/netfilter/xt_hashlimit.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 44a095e..200a9d8 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -467,17 +467,18 @@ static u64 user2credits(u64 user, int revision)
/* If multiplying would overflow... */
if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY_v1))
/* Divide first. */
- return (user / XT_HASHLIMIT_SCALE) *\
+ return div64_u64(user, XT_HASHLIMIT_SCALE) *\
HZ * CREDITS_PER_JIFFY_v1;
- return (user * HZ * CREDITS_PER_JIFFY_v1) \
- / XT_HASHLIMIT_SCALE;
+ return div64_u64((user * HZ * CREDITS_PER_JIFFY_v1),
+ XT_HASHLIMIT_SCALE);
} else {
if (user > 0xFFFFFFFFFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
- return (user / XT_HASHLIMIT_SCALE_v2) *\
+ return div64_u64(user, XT_HASHLIMIT_SCALE_v2) *\
HZ * CREDITS_PER_JIFFY;
- return (user * HZ * CREDITS_PER_JIFFY) / XT_HASHLIMIT_SCALE_v2;
+ return div64_u64((user * HZ * CREDITS_PER_JIFFY),
+ XT_HASHLIMIT_SCALE_v2);
}
}
--
1.9.1
^ permalink raw reply related
* Re: [PATCH net-next] bnx2x: free the mac filter group list before freeing the cmd
From: David Miller @ 2016-09-27 13:55 UTC (permalink / raw)
To: jbaron; +Cc: Yuval.Mintz, Ariel.Elior, netdev
In-Reply-To: <1474902044-16742-1-git-send-email-jbaron@akamai.com>
From: Jason Baron <jbaron@akamai.com>
Date: Mon, 26 Sep 2016 11:00:44 -0400
> The group list must be freed prior to freeing the command otherwise
> we have a use-after-free.
>
> Signed-off-by: Jason Baron <jbaron@akamai.com>
Applied, thanks for the quick fixup Jason.
^ permalink raw reply
* Re: [PATCH net v3 0/2] Fix tc-ife bugs
From: David Miller @ 2016-09-27 13:54 UTC (permalink / raw)
To: yotam.gi; +Cc: jhs, netdev, mlxsw, yotamg
In-Reply-To: <1474886726-56363-1-git-send-email-yotamg@mellanox.com>
From: Yotam Gigi <yotam.gi@gmail.com>
Date: Mon, 26 Sep 2016 13:45:24 +0300
> This patch-set contains two bugfixes in the tc-ife action, one fixing some
> random behaviour in encode side, and one fixing the decode side packet
> parsing logic.
>
> v2->v3
> - Fix the encode side instead of the decode side
Series applied, thanks.
^ permalink raw reply
* [PATCH v3 net-next] net: phy: Add Edge-rate driver for Microsemi PHYs.
From: Raju Lakkaraju @ 2016-09-27 13:47 UTC (permalink / raw)
To: netdev, devicetree; +Cc: f.fainelli, Allan.Nielsen, andrew, Raju Lakkaraju
From: Raju Lakkaraju <Raju.Lakkaraju@microsemi.com>
All the review comments updated and resending for review.
Edge-rate:
As system and networking speeds increase, a signal's output transition,
also know as the edge rate or slew rate (V/ns), takes on greater importance
because high-speed signals come with a price. That price is an assortment of
interference problems like ringing on the line, signal overshoot and
undershoot, extended signal settling times, crosstalk noise, transmission
line reflections, false signal detection by the receiving device and
electromagnetic interference (EMI) -- all of which can negate the potential
gains designers are seeking when they try to increase system speeds through
the use of higher performance logic devices. The fact is, faster signaling
edge rates can cause a higher level of electrical noise or other type of
interference that can actually lead to slower line speeds and lower maximum
system frequencies. This parameter allow the board designers to change the
driving strange, and thereby change the EMI behavioral.
Edge-rate value get from Device Tree.
Tested on Beaglebone Black with VSC 8531 PHY.
Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microsemi.com>
---
Change set:
v1:
- Initial version of Edge-rate driver add by using IOCTL.
v2:
- Changed edge-rate parameter to Device Tree with magic number.
v3:
- Added Device Tree documentati0n and edge-rate parameter table.
Added probe function initialize the vsc8531 private data structure.
---
.../devicetree/bindings/net/mscc-phy-vsc8531.txt | 61 ++++++++++++++++
drivers/net/phy/mscc.c | 85 ++++++++++++++++++++++
include/dt-bindings/net/mscc-phy-vsc8531.h | 23 ++++++
3 files changed, 169 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
create mode 100644 include/dt-bindings/net/mscc-phy-vsc8531.h
diff --git a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
new file mode 100644
index 0000000..7ba3855
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
@@ -0,0 +1,61 @@
+* Microsemi - vsc8531 Giga bit ethernet phy
+
+Required properties:
+- compatible : Should contain phy id as "ethernet-phy-idAAAA.BBBB"
+ If the phy's identifier is known then the list may contain an entry
+ of the form: "ethernet-phy-idAAAA.BBBB" where
+ AAAA - The value of the 16 bit Phy Identifier 1 register as
+ 4 hex digits. This is the chip vendor OUI bits 3:18
+ BBBB - The value of the 16 bit Phy Identifier 2 register as
+ 4 hex digits. This is the chip vendor OUI bits 19:24,
+ followed by 10 bits of a vendor specific ID.
+- reg : The ID number for the phy, usually a small integer
+
+Optional properties:
+- vsc8531,edge-rate : Edge rate sets the drive strength of the MAC
+ interface output signals. Changing the drive
+ strength will affect the edge rate of the output
+ signal. The goal of this setting is to help
+ reduce electrical emission (EMI) by being able
+ to reprogram drive strength and in effect slow
+ down the edge rate if desired. Table 5 shows the
+ impact to the edge rate per VDDMAC supply for each
+ drive strength setting. Default edge rate is set as
+ Fastest edge rate (i.e. 7).
+ Ref: Table:1 - Edge rate change below.
+
+Note: see dt-bindings/net/mscc-vsc8531.h for applicable values
+
+Table: 1 - Edge rate change
+-----------------------------------------------------------------------------|
+| Edge Rate Change (VDDMAC) |
+| |
+| Reg Setting 3.3V 2.5V 1.8V 1.5V |
+|----------------------------------------------------------------------------|
+| 111 Default Deafult Default Default |
+| (Fastest) (recommended) (recommended)|
+|----------------------------------------------------------------------------|
+| 110 -2% -3% -5% -6% |
+|----------------------------------------------------------------------------|
+| 101 -4% -6% -9% -14% |
+|----------------------------------------------------------------------------|
+| 100 -7% -10% -16% -21% |
+| (recommended) (recommended) |
+|----------------------------------------------------------------------------|
+| 011 -10% -14% -23% -29% |
+|----------------------------------------------------------------------------|
+| 010 -17% -23% -35% -42% |
+|----------------------------------------------------------------------------|
+| 001 -29% -37% -52% -58% |
+|----------------------------------------------------------------------------|
+| 000 -53% -63% -76% -77% |
+| (slowest) |
+|----------------------------------------------------------------------------|
+
+Example:
+
+ vsc8531_0: ethernet-phy@0 {
+ compatible = "ethernet-phy-id0007.0570";
+ reg = <0>;
+ vsc8531,edge-rate = /bits/ 8 <MSCC_EDGE_RATE_CNTL_FASTEST>;
+ };
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index d350deb..de29354 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -11,6 +11,8 @@
#include <linux/mdio.h>
#include <linux/mii.h>
#include <linux/phy.h>
+#include <linux/of.h>
+#include <dt-bindings/net/mscc-phy-vsc8531.h>
enum rgmii_rx_clock_delay {
RGMII_RX_CLK_DELAY_0_2_NS = 0,
@@ -37,6 +39,10 @@ enum rgmii_rx_clock_delay {
#define MII_VSC85XX_INT_MASK_MASK 0xa000
#define MII_VSC85XX_INT_STATUS 26
+#define MSCC_PHY_WOL_MAC_CONTROL 27
+#define EDGE_RATE_CNTL_POS 5
+#define EDGE_RATE_CNTL_MASK 0x00E0
+
#define MSCC_EXT_PAGE_ACCESS 31
#define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
#define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
@@ -50,6 +56,10 @@ enum rgmii_rx_clock_delay {
#define PHY_ID_VSC8531 0x00070570
#define PHY_ID_VSC8541 0x00070770
+struct vsc8531_private {
+ u8 edge_rate;
+};
+
static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
{
int rc;
@@ -58,6 +68,30 @@ static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
return rc;
}
+static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev,
+ u8 edge_rate)
+{
+ int rc;
+ u16 reg_val;
+
+ mutex_lock(&phydev->lock);
+ rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
+ if (rc != 0)
+ goto out_unlock;
+ reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
+ reg_val &= ~(EDGE_RATE_CNTL_MASK);
+ reg_val |= (edge_rate << EDGE_RATE_CNTL_POS);
+ rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
+ if (rc != 0)
+ goto out_unlock;
+ rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
+
+out_unlock:
+ mutex_unlock(&phydev->lock);
+
+ return rc;
+}
+
static int vsc85xx_mac_if_set(struct phy_device *phydev,
phy_interface_t interface)
{
@@ -116,9 +150,41 @@ out_unlock:
return rc;
}
+#ifdef CONFIG_OF_MDIO
+static int vsc8531_of_init(struct phy_device *phydev)
+{
+ int rc;
+ struct vsc8531_private *vsc8531 = phydev->priv;
+ struct device *dev = &phydev->mdio.dev;
+ struct device_node *of_node = dev->of_node;
+
+ if (!of_node)
+ return -ENODEV;
+
+ rc = of_property_read_u8(of_node, "vsc8531,edge-rate",
+ &vsc8531->edge_rate);
+ if (rc == -EINVAL) {
+ vsc8531->edge_rate = MSCC_EDGE_RATE_CNTL_FASTEST;
+ rc = 0;
+ }
+
+ return rc;
+}
+#else
+static int vsc8531_of_init(struct phy_device *phydev)
+{
+ return 0;
+}
+#endif /* CONFIG_OF_MDIO */
+
static int vsc85xx_config_init(struct phy_device *phydev)
{
int rc;
+ struct vsc8531_private *vsc8531 = phydev->priv;
+
+ rc = vsc8531_of_init(phydev);
+ if (rc)
+ return rc;
rc = vsc85xx_default_config(phydev);
if (rc)
@@ -128,6 +194,10 @@ static int vsc85xx_config_init(struct phy_device *phydev)
if (rc)
return rc;
+ rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->edge_rate);
+ if (rc)
+ return rc;
+
rc = genphy_config_init(phydev);
return rc;
@@ -160,6 +230,19 @@ static int vsc85xx_config_intr(struct phy_device *phydev)
return rc;
}
+static int vsc85xx_probe(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531;
+
+ vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
+ if (!vsc8531)
+ return -ENOMEM;
+
+ phydev->priv = vsc8531;
+
+ return 0;
+}
+
/* Microsemi VSC85xx PHYs */
static struct phy_driver vsc85xx_driver[] = {
{
@@ -177,6 +260,7 @@ static struct phy_driver vsc85xx_driver[] = {
.config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend,
.resume = &genphy_resume,
+ .probe = &vsc85xx_probe,
},
{
.phy_id = PHY_ID_VSC8541,
@@ -193,6 +277,7 @@ static struct phy_driver vsc85xx_driver[] = {
.config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend,
.resume = &genphy_resume,
+ .probe = &vsc85xx_probe,
}
};
diff --git a/include/dt-bindings/net/mscc-phy-vsc8531.h b/include/dt-bindings/net/mscc-phy-vsc8531.h
new file mode 100644
index 0000000..e245f40
--- /dev/null
+++ b/include/dt-bindings/net/mscc-phy-vsc8531.h
@@ -0,0 +1,23 @@
+/*
+ * Device Tree constants for Microsemi VSC8531 PHY
+ *
+ * Author: Nagaraju Lakkaraju
+ *
+ * License: Dual MIT/GPL
+ * Copyright (c) 2016 Microsemi Corporation
+ */
+
+#ifndef _DT_BINDINGS_MSCC_VSC8531_H
+#define _DT_BINDINGS_MSCC_VSC8531_H
+
+/* MAC interface Edge rate control pad */
+#define MSCC_EDGE_RATE_CNTL_SLOWEST 0
+#define MSCC_EDGE_RATE_CNTL_PLUS_1 1
+#define MSCC_EDGE_RATE_CNTL_PLUS_2 2
+#define MSCC_EDGE_RATE_CNTL_PLUS_3 3
+#define MSCC_EDGE_RATE_CNTL_PLUS_4 4
+#define MSCC_EDGE_RATE_CNTL_PLUS_5 5
+#define MSCC_EDGE_RATE_CNTL_PLUS_6 6
+#define MSCC_EDGE_RATE_CNTL_FASTEST 7
+
+#endif
--
2.7.4
^ permalink raw reply related
* [PATCH v7 7/8] thunderbolt: Networking doc
From: Amir Levy @ 2016-09-27 13:43 UTC (permalink / raw)
To: gregkh
Cc: andreas.noever, bhelgaas, corbet, linux-kernel, linux-pci, netdev,
linux-doc, mario_limonciello, thunderbolt-linux, mika.westerberg,
tomas.winkler, xiong.y.zhang, Amir Levy
In-Reply-To: <1474983821-2313-1-git-send-email-amir.jer.levy@intel.com>
Adding Thunderbolt(TM) networking documentation.
Signed-off-by: Amir Levy <amir.jer.levy@intel.com>
---
Documentation/00-INDEX | 2 +
Documentation/thunderbolt/networking.txt | 132 +++++++++++++++++++++++++++++++
2 files changed, 134 insertions(+)
create mode 100644 Documentation/thunderbolt/networking.txt
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index cb9a6c6..a448ba1 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -439,6 +439,8 @@ this_cpu_ops.txt
- List rationale behind and the way to use this_cpu operations.
thermal/
- directory with information on managing thermal issues (CPU/temp)
+thunderbolt/
+ - directory with info regarding Thunderbolt.
trace/
- directory with info on tracing technologies within linux
unaligned-memory-access.txt
diff --git a/Documentation/thunderbolt/networking.txt b/Documentation/thunderbolt/networking.txt
new file mode 100644
index 0000000..88d1c12
--- /dev/null
+++ b/Documentation/thunderbolt/networking.txt
@@ -0,0 +1,132 @@
+Intel Thunderbolt(TM) Networking driver
+=======================================
+
+Copyright(c) 2013 - 2016 Intel Corporation.
+
+Contact Information:
+Intel Thunderbolt mailing list <thunderbolt-software@lists.01.org>
+Edited by Amir Levy <amir.jer.levy@intel.com>
+
+Overview
+========
+
+* The Thunderbolt Networking driver enables peer to peer networking on non-Apple
+ platforms running Linux.
+
+* The driver creates a virtual Ethernet device that enables computer to computer
+ communication over the Thunderbolt cable.
+
+* Using Thunderbolt Networking you can perform high speed file transfers between
+ computers, perform PC migrations and/or set up small workgroups with shared
+ storage without compromising any other Thunderbolt functionality.
+
+* The driver is located in drivers/thunderbolt/icm.
+
+* This driver will function only on non-Apple platforms with firmware based
+ Thunderbolt controllers that support Thunderbolt Networking.
+
+ +----------------+ +----------------+
+ |Host 1 | |Host 2 |
+ | | | |
+ | +-------+ | | +-------+ |
+ | |Network| | | |Network| |
+ | |Stack | | | |Stack | |
+ | +-------+ | | +-------+ |
+ | ^ | | ^ |
+ | | | | | |
+ | v | | v |
+ | +-----------+ | | +-----------+ |
+ | |Thunderbolt| | | |Thunderbolt| |
+ | |Networking | | | |Networking | |
+ | |Driver | | | |Driver | |
+ | +-----------+ | | +-----------+ |
+ | ^ | | ^ |
+ | | | | | |
+ | v | | v |
+ | +-----------+ | | +-----------+ |
+ | |Thunderbolt| | | |Thunderbolt| |
+ | |Controller |<-+------------+->|Controller | |
+ | |with ICM | | | |with ICM | |
+ | |enabled | | | |enabled | |
+ | +-----------+ | | +-----------+ |
+ +----------------+ +----------------+
+
+Files
+=====
+
+The following files are located in the drivers/thunderbolt/icm directory:
+
+- icm_nhi.c/h: These files allow communication with the firmware (Intel
+ Connection Manager) based controller. They also create an interface for
+ netlink communication with a user space daemon.
+
+- net.c/net.h: These files implement the 'eth' interface for the
+ Thunderbolt(TM) Networking.
+
+Interface to User Space
+=======================
+
+The interface to the user space module is implemented through a Generic Netlink.
+This is the communications protocol between the Thunderbolt driver and the user
+space application.
+
+Note that this interface mediates user space communication with ICM.
+(Existing Linux tools can be used to configure the network interface.)
+
+The Thunderbolt Daemon utilizes this interface to communicate with the driver.
+To be accessed by the user space module, both kernel and user space modules
+have to register with the same GENL_NAME.
+For the purpose of the Thunderbolt Network driver, "thunderbolt" is used.
+The registration is done at driver initialization time for all instances
+of the Thunderbolt controllers. The communication is carried through pre-defined
+Thunderbolt messages. Each specific message has a callback function that is
+called when the related message is received.
+
+Message Definitions:
+* NHI_CMD_UNSPEC: Not used.
+* NHI_CMD_SUBSCRIBE: Subscription request from daemon to driver to open the
+ communication channel.
+* NHI_CMD_UNSUBSCRIBE: Request from daemon to driver to unsubscribe and
+ to close communication channel.
+* NHI_CMD_QUERY_INFORMATION: Request information from the driver such as
+ driver version, FW version offset, number of ports in the controller
+ and DMA port.
+* NHI_CMD_MSG_TO_ICM: Message from user space module to FW.
+* NHI_CMD_MSG_FROM_ICM: Response from FW to user space module.
+* NHI_CMD_MAILBOX: Message that uses mailbox mechanism such as FW policy
+ changes or disconnect path.
+* NHI_CMD_APPROVE_TBT_NETWORKING: Request from user space module to FW to
+ establish path.
+* NHI_CMD_ICM_IN_SAFE_MODE: Indication that the FW has entered safe mode.
+
+Communication with Intel Connection Manager(ICM) Firmware
+=========================================================
+
+There are several circular buffers in Thunderbolt each using Direct Memory
+Access (DMA).
+
+Communication with ICM utilizes circular buffer ring #0. (The other rings are
+used for peer to peer communication, packet transmission and receiving).
+
+The driver allocates a shared memory that is physically mapped onto the DMA
+physical space at ring #0.
+For the software to communicate with the firmware, the driver sends a command
+in ring #0. The command contains a pre-defined field (PDF) value notifying the
+firmware that the driver is ready. To proceed, the driver must receive the
+appropriate PDF value in response from the firmware.
+
+Once the exchange is completed, messages can be sent to the firmware through
+the driver. Similarly, the firmware can now send notifications about hardware
+and firmware events.
+
+Information
+===========
+
+Mailing list:
+ thunderbolt-software@lists.01.org
+ Register at: https://lists.01.org/mailman/listinfo/thunderbolt-software
+ Archives at: https://lists.01.org/pipermail/thunderbolt-software/
+
+For additional information about Thunderbolt technology visit:
+ https://01.org/thunderbolt-sw
+ https://thunderbolttechnology.net/
--
2.7.4
^ permalink raw reply related
* [PATCH v7 5/8] thunderbolt: Networking state machine
From: Amir Levy @ 2016-09-27 13:43 UTC (permalink / raw)
To: gregkh
Cc: andreas.noever, bhelgaas, corbet, linux-kernel, linux-pci, netdev,
linux-doc, mario_limonciello, thunderbolt-linux, mika.westerberg,
tomas.winkler, xiong.y.zhang, Amir Levy
In-Reply-To: <1474983821-2313-1-git-send-email-amir.jer.levy@intel.com>
This patch builds the peer to peer communication path.
Communication is established by a negotiation process whereby messages are
sent back and forth between the peers until a connection is established.
This includes the Thunderbolt Network driver communication with the second
peer via Intel Connection Manager(ICM) firmware.
+--------------------+ +--------------------+
|Host 1 | |Host 2 |
| | | |
| +-----------+ | | +-----------+ |
| |Thunderbolt| | | |Thunderbolt| |
| |Networking | | | |Networking | |
| |Driver | | | |Driver | |
| +-----------+ | | +-----------+ |
| ^ | | ^ |
| | | | | |
| +------------+---+ | | +------------+---+ |
| |Thunderbolt | | | | |Thunderbolt | | |
| |Controller v | | | |Controller v | |
| | +---+ | | | | +---+ | |
| | |ICM|<-+-+------------+-+-------->|ICM| | |
| | +---+ | | | | +---+ | |
| +----------------+ | | +----------------+ |
+--------------------+ +--------------------+
Note that this patch only establishes the link between the two hosts and
not Network Packet handling - this is dealt with in the next patch.
Signed-off-by: Amir Levy <amir.jer.levy@intel.com>
---
drivers/thunderbolt/icm/Makefile | 2 +-
drivers/thunderbolt/icm/icm_nhi.c | 303 ++++++++++++++-
drivers/thunderbolt/icm/net.c | 793 ++++++++++++++++++++++++++++++++++++++
drivers/thunderbolt/icm/net.h | 70 ++++
4 files changed, 1157 insertions(+), 11 deletions(-)
create mode 100644 drivers/thunderbolt/icm/net.c
diff --git a/drivers/thunderbolt/icm/Makefile b/drivers/thunderbolt/icm/Makefile
index f0d0fbb..94a2797 100644
--- a/drivers/thunderbolt/icm/Makefile
+++ b/drivers/thunderbolt/icm/Makefile
@@ -1,2 +1,2 @@
obj-${CONFIG_THUNDERBOLT_ICM} += thunderbolt-icm.o
-thunderbolt-icm-objs := icm_nhi.o
+thunderbolt-icm-objs := icm_nhi.o net.o
diff --git a/drivers/thunderbolt/icm/icm_nhi.c b/drivers/thunderbolt/icm/icm_nhi.c
index 984aa7c..578eb14 100644
--- a/drivers/thunderbolt/icm/icm_nhi.c
+++ b/drivers/thunderbolt/icm/icm_nhi.c
@@ -74,6 +74,12 @@ static const struct nla_policy nhi_genl_policy[NHI_ATTR_MAX + 1] = {
.len = TBT_ICM_RING_MAX_FRAME_SIZE },
[NHI_ATTR_MSG_FROM_ICM] = { .type = NLA_BINARY,
.len = TBT_ICM_RING_MAX_FRAME_SIZE },
+ [NHI_ATTR_LOCAL_ROUTE_STRING] = {.len = sizeof(struct route_string)},
+ [NHI_ATTR_LOCAL_UUID] = { .len = sizeof(uuid_be) },
+ [NHI_ATTR_REMOTE_UUID] = { .len = sizeof(uuid_be) },
+ [NHI_ATTR_LOCAL_DEPTH] = { .type = NLA_U8, },
+ [NHI_ATTR_ENABLE_FULL_E2E] = { .type = NLA_FLAG, },
+ [NHI_ATTR_MATCH_FRAME_ID] = { .type = NLA_FLAG, },
};
/* NHI genetlink family */
@@ -522,6 +528,29 @@ int nhi_mailbox(struct tbt_nhi_ctxt *nhi_ctxt, u32 cmd, u32 data, bool deinit)
return 0;
}
+static inline bool nhi_is_path_disconnected(u32 cmd, u8 num_ports)
+{
+ return (cmd >= DISCONNECT_PORT_A_INTER_DOMAIN_PATH &&
+ cmd < (DISCONNECT_PORT_A_INTER_DOMAIN_PATH + num_ports));
+}
+
+static int nhi_mailbox_disconn_path(struct tbt_nhi_ctxt *nhi_ctxt, u32 cmd)
+ __releases(&controllers_list_mutex)
+{
+ struct port_net_dev *port;
+ u32 port_num = cmd - DISCONNECT_PORT_A_INTER_DOMAIN_PATH;
+
+ port = &(nhi_ctxt->net_devices[port_num]);
+ mutex_lock(&port->state_mutex);
+
+ mutex_unlock(&controllers_list_mutex);
+ port->medium_sts = MEDIUM_READY_FOR_APPROVAL;
+ if (port->net_dev)
+ negotiation_events(port->net_dev, MEDIUM_DISCONNECTED);
+ mutex_unlock(&port->state_mutex);
+ return 0;
+}
+
static int nhi_mailbox_generic(struct tbt_nhi_ctxt *nhi_ctxt, u32 mb_cmd)
__releases(&controllers_list_mutex)
{
@@ -571,13 +600,94 @@ static int nhi_genl_mailbox(__always_unused struct sk_buff *u_skb,
return -ERESTART;
nhi_ctxt = nhi_search_ctxt(*(u32 *)info->userhdr);
- if (nhi_ctxt && !nhi_ctxt->d0_exit)
- return nhi_mailbox_generic(nhi_ctxt, mb_cmd);
+ if (nhi_ctxt && !nhi_ctxt->d0_exit) {
+
+ /* rwsem is released later by the below functions */
+ if (nhi_is_path_disconnected(cmd, nhi_ctxt->num_ports))
+ return nhi_mailbox_disconn_path(nhi_ctxt, cmd);
+ else
+ return nhi_mailbox_generic(nhi_ctxt, mb_cmd);
+
+ }
mutex_unlock(&controllers_list_mutex);
return -ENODEV;
}
+static int nhi_genl_approve_networking(__always_unused struct sk_buff *u_skb,
+ struct genl_info *info)
+{
+ struct tbt_nhi_ctxt *nhi_ctxt;
+ struct route_string *route_str;
+ int res = -ENODEV;
+ u8 port_num;
+
+ if (!info || !info->userhdr || !info->attrs ||
+ !info->attrs[NHI_ATTR_LOCAL_ROUTE_STRING] ||
+ !info->attrs[NHI_ATTR_LOCAL_UUID] ||
+ !info->attrs[NHI_ATTR_REMOTE_UUID] ||
+ !info->attrs[NHI_ATTR_LOCAL_DEPTH])
+ return -EINVAL;
+
+ /*
+ * route_str is an unique topological address
+ * used for approving remote controller
+ */
+ route_str = nla_data(info->attrs[NHI_ATTR_LOCAL_ROUTE_STRING]);
+ /* extracts the port we're connected to */
+ port_num = PORT_NUM_FROM_LINK(L0_PORT_NUM(route_str->lo));
+
+ if (mutex_lock_interruptible(&controllers_list_mutex))
+ return -ERESTART;
+
+ nhi_ctxt = nhi_search_ctxt(*(u32 *)info->userhdr);
+ if (nhi_ctxt && !nhi_ctxt->d0_exit) {
+ struct port_net_dev *port;
+
+ if (port_num >= nhi_ctxt->num_ports) {
+ res = -EINVAL;
+ goto free_ctl_list;
+ }
+
+ port = &(nhi_ctxt->net_devices[port_num]);
+
+ mutex_lock(&port->state_mutex);
+ mutex_unlock(&controllers_list_mutex);
+
+ if (port->medium_sts != MEDIUM_READY_FOR_APPROVAL) {
+ dev_info(&nhi_ctxt->pdev->dev,
+ "%s: controller id %#x in state %u <> MEDIUM_READY_FOR_APPROVAL\n",
+ __func__, nhi_ctxt->id, port->medium_sts);
+ goto unlock;
+ }
+
+ port->medium_sts = MEDIUM_READY_FOR_CONNECTION;
+
+ if (!port->net_dev) {
+ port->net_dev = nhi_alloc_etherdev(nhi_ctxt, port_num,
+ info);
+ if (!port->net_dev) {
+ mutex_unlock(&port->state_mutex);
+ return -ENOMEM;
+ }
+ } else {
+ nhi_update_etherdev(nhi_ctxt, port->net_dev, info);
+
+ negotiation_events(port->net_dev,
+ MEDIUM_READY_FOR_CONNECTION);
+ }
+
+unlock:
+ mutex_unlock(&port->state_mutex);
+
+ return 0;
+ }
+
+free_ctl_list:
+ mutex_unlock(&controllers_list_mutex);
+
+ return res;
+}
static int nhi_genl_send_msg(struct tbt_nhi_ctxt *nhi_ctxt, enum pdf_value pdf,
const u8 *msg, u32 msg_len)
@@ -627,17 +737,167 @@ genl_put_reply_failure:
return res;
}
+static bool nhi_handle_inter_domain_msg(struct tbt_nhi_ctxt *nhi_ctxt,
+ struct thunderbolt_ip_header *hdr)
+{
+ struct port_net_dev *port;
+ u8 port_num;
+
+ const uuid_be proto_uuid = APPLE_THUNDERBOLT_IP_PROTOCOL_UUID;
+
+ if (uuid_be_cmp(proto_uuid, hdr->apple_tbt_ip_proto_uuid) != 0) {
+ dev_dbg(&nhi_ctxt->pdev->dev,
+ "controller id %#x XDomain discovery message\n",
+ nhi_ctxt->id);
+ return true;
+ }
+
+ dev_dbg(&nhi_ctxt->pdev->dev,
+ "controller id %#x ThunderboltIP %u\n",
+ nhi_ctxt->id, be32_to_cpu(hdr->packet_type));
+
+ port_num = PORT_NUM_FROM_LINK(
+ L0_PORT_NUM(be32_to_cpu(hdr->route_str.lo)));
+
+ if (unlikely(port_num >= nhi_ctxt->num_ports)) {
+ dev_err(&nhi_ctxt->pdev->dev,
+ "controller id %#x invalid port %u in ThunderboltIP message\n",
+ nhi_ctxt->id, port_num);
+ return false;
+ }
+
+ port = &(nhi_ctxt->net_devices[port_num]);
+ mutex_lock(&port->state_mutex);
+ if (likely(port->net_dev != NULL))
+ negotiation_messages(port->net_dev, hdr);
+ else
+ dev_notice(&nhi_ctxt->pdev->dev,
+ "controller id %#x port %u in ThunderboltIP message was not initialized\n",
+ nhi_ctxt->id, port_num);
+ mutex_unlock(&port->state_mutex);
+
+ return false;
+}
+
+static void nhi_handle_notification_msg(struct tbt_nhi_ctxt *nhi_ctxt,
+ const u8 *msg)
+{
+ struct port_net_dev *port;
+ u8 port_num;
+
+#define INTER_DOMAIN_LINK_SHIFT 0
+#define INTER_DOMAIN_LINK_MASK GENMASK(2, INTER_DOMAIN_LINK_SHIFT)
+ switch (msg[3]) {
+
+ case NC_INTER_DOMAIN_CONNECTED:
+ port_num = PORT_NUM_FROM_MSG(msg[5]);
+#define INTER_DOMAIN_APPROVED BIT(3)
+ if (likely(port_num < nhi_ctxt->num_ports)) {
+ if (!(msg[5] & INTER_DOMAIN_APPROVED))
+ nhi_ctxt->net_devices[port_num].medium_sts =
+ MEDIUM_READY_FOR_APPROVAL;
+ } else {
+ dev_err(&nhi_ctxt->pdev->dev,
+ "controller id %#x invalid port %u in inter domain connected message\n",
+ nhi_ctxt->id, port_num);
+ }
+ break;
+
+ case NC_INTER_DOMAIN_DISCONNECTED:
+ port_num = PORT_NUM_FROM_MSG(msg[5]);
+
+ if (unlikely(port_num >= nhi_ctxt->num_ports)) {
+ dev_err(&nhi_ctxt->pdev->dev,
+ "controller id %#x invalid port %u in inter domain disconnected message\n",
+ nhi_ctxt->id, port_num);
+ break;
+ }
+
+ port = &(nhi_ctxt->net_devices[port_num]);
+ mutex_lock(&port->state_mutex);
+ port->medium_sts = MEDIUM_DISCONNECTED;
+
+ if (likely(port->net_dev != NULL))
+ negotiation_events(port->net_dev,
+ MEDIUM_DISCONNECTED);
+ else
+ dev_notice(&nhi_ctxt->pdev->dev,
+ "controller id %#x port %u in inter domain disconnected message was not initialized\n",
+ nhi_ctxt->id, port_num);
+ mutex_unlock(&port->state_mutex);
+ break;
+ }
+}
+
+static bool nhi_handle_icm_response_msg(struct tbt_nhi_ctxt *nhi_ctxt,
+ const u8 *msg)
+{
+ struct port_net_dev *port;
+ bool send_event = true;
+ u8 port_num;
+
+ if (nhi_ctxt->ignore_icm_resp &&
+ msg[3] == RC_INTER_DOMAIN_PKT_SENT) {
+ nhi_ctxt->ignore_icm_resp = false;
+ send_event = false;
+ }
+ if (nhi_ctxt->wait_for_icm_resp) {
+ nhi_ctxt->wait_for_icm_resp = false;
+ up(&nhi_ctxt->send_sem);
+ }
+
+ if (msg[3] == RC_APPROVE_INTER_DOMAIN_CONNECTION) {
+#define APPROVE_INTER_DOMAIN_ERROR BIT(0)
+ if (unlikely(msg[2] & APPROVE_INTER_DOMAIN_ERROR)) {
+ dev_err(&nhi_ctxt->pdev->dev,
+ "controller id %#x inter domain approve error\n",
+ nhi_ctxt->id);
+ return send_event;
+ }
+ port_num = PORT_NUM_FROM_LINK((msg[5]&INTER_DOMAIN_LINK_MASK)>>
+ INTER_DOMAIN_LINK_SHIFT);
+
+ if (unlikely(port_num >= nhi_ctxt->num_ports)) {
+ dev_err(&nhi_ctxt->pdev->dev,
+ "controller id %#x invalid port %u in inter domain approve message\n",
+ nhi_ctxt->id, port_num);
+ return send_event;
+ }
+
+ port = &(nhi_ctxt->net_devices[port_num]);
+ mutex_lock(&port->state_mutex);
+ port->medium_sts = MEDIUM_CONNECTED;
+
+ if (likely(port->net_dev != NULL))
+ negotiation_events(port->net_dev, MEDIUM_CONNECTED);
+ else
+ dev_err(&nhi_ctxt->pdev->dev,
+ "controller id %#x port %u in inter domain approve message was not initialized\n",
+ nhi_ctxt->id, port_num);
+ mutex_unlock(&port->state_mutex);
+ }
+
+ return send_event;
+}
+
static bool nhi_msg_from_icm_analysis(struct tbt_nhi_ctxt *nhi_ctxt,
enum pdf_value pdf,
const u8 *msg, u32 msg_len)
{
- /*
- * preparation for messages that won't be sent,
- * currently unused in this patch.
- */
bool send_event = true;
switch (pdf) {
+ case PDF_INTER_DOMAIN_REQUEST:
+ case PDF_INTER_DOMAIN_RESPONSE:
+ send_event = nhi_handle_inter_domain_msg(
+ nhi_ctxt,
+ (struct thunderbolt_ip_header *)msg);
+ break;
+
+ case PDF_FW_TO_SW_NOTIFICATION:
+ nhi_handle_notification_msg(nhi_ctxt, msg);
+ break;
+
case PDF_ERROR_NOTIFICATION:
dev_err(&nhi_ctxt->pdev->dev,
"controller id %#x PDF_ERROR_NOTIFICATION %hhu msg len %u\n",
@@ -653,10 +913,7 @@ static bool nhi_msg_from_icm_analysis(struct tbt_nhi_ctxt *nhi_ctxt,
break;
case PDF_FW_TO_SW_RESPONSE:
- if (nhi_ctxt->wait_for_icm_resp) {
- nhi_ctxt->wait_for_icm_resp = false;
- up(&nhi_ctxt->send_sem);
- }
+ send_event = nhi_handle_icm_response_msg(nhi_ctxt, msg);
break;
default:
@@ -861,6 +1118,12 @@ static const struct genl_ops nhi_ops[] = {
.doit = nhi_genl_mailbox,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NHI_CMD_APPROVE_TBT_NETWORKING,
+ .policy = nhi_genl_policy,
+ .doit = nhi_genl_approve_networking,
+ .flags = GENL_ADMIN_PERM,
+ },
};
static int nhi_suspend(struct device *dev) __releases(&nhi_ctxt->send_sem)
@@ -868,6 +1131,17 @@ static int nhi_suspend(struct device *dev) __releases(&nhi_ctxt->send_sem)
struct tbt_nhi_ctxt *nhi_ctxt = pci_get_drvdata(to_pci_dev(dev));
void __iomem *rx_reg, *tx_reg;
u32 rx_reg_val, tx_reg_val;
+ int i;
+
+ for (i = 0; i < nhi_ctxt->num_ports; i++) {
+ struct port_net_dev *port = &nhi_ctxt->net_devices[i];
+
+ mutex_lock(&port->state_mutex);
+ port->medium_sts = MEDIUM_DISCONNECTED;
+ if (port->net_dev)
+ negotiation_events(port->net_dev, MEDIUM_DISCONNECTED);
+ mutex_unlock(&port->state_mutex);
+ }
/* must be after negotiation_events, since messages might be sent */
nhi_ctxt->d0_exit = true;
@@ -1027,6 +1301,15 @@ static void icm_nhi_remove(struct pci_dev *pdev)
nhi_suspend(&pdev->dev);
+ for (i = 0; i < nhi_ctxt->num_ports; i++) {
+ mutex_lock(&nhi_ctxt->net_devices[i].state_mutex);
+ if (nhi_ctxt->net_devices[i].net_dev) {
+ nhi_dealloc_etherdev(nhi_ctxt->net_devices[i].net_dev);
+ nhi_ctxt->net_devices[i].net_dev = NULL;
+ }
+ mutex_unlock(&nhi_ctxt->net_devices[i].state_mutex);
+ }
+
if (nhi_ctxt->net_workqueue)
destroy_workqueue(nhi_ctxt->net_workqueue);
diff --git a/drivers/thunderbolt/icm/net.c b/drivers/thunderbolt/icm/net.c
new file mode 100644
index 0000000..acf30ad
--- /dev/null
+++ b/drivers/thunderbolt/icm/net.c
@@ -0,0 +1,793 @@
+/*******************************************************************************
+ *
+ * Intel Thunderbolt(TM) driver
+ * Copyright(c) 2014 - 2016 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Intel Thunderbolt Mailing List <thunderbolt-software@lists.01.org>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+#include <linux/prefetch.h>
+#include <linux/highmem.h>
+#include <linux/if_vlan.h>
+#include <linux/jhash.h>
+#include <linux/vmalloc.h>
+#include <net/ip6_checksum.h>
+#include "icm_nhi.h"
+#include "net.h"
+
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_IFUP)
+static int debug = -1;
+module_param(debug, int, 0000);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+#define TBT_NET_RX_HDR_SIZE 256
+
+#define NUM_TX_LOGIN_RETRIES 60
+
+#define APPLE_THUNDERBOLT_IP_PROTOCOL_REVISION 1
+
+#define LOGIN_TX_PATH 0xf
+
+#define TBT_NET_MTU (64 * 1024)
+
+/* Number of Rx buffers we bundle into one write to the hardware */
+#define TBT_NET_RX_BUFFER_WRITE 16
+
+#define TBT_NET_MULTICAST_HASH_TABLE_SIZE 1024
+#define TBT_NET_ETHER_ADDR_HASH(addr) (((addr[4] >> 4) | (addr[5] << 4)) % \
+ TBT_NET_MULTICAST_HASH_TABLE_SIZE)
+
+#define BITS_PER_U32 (sizeof(u32) * BITS_PER_BYTE)
+
+#define TBT_NET_NUM_TX_BUFS 256
+#define TBT_NET_NUM_RX_BUFS 256
+#define TBT_NET_SIZE_TOTAL_DESCS ((TBT_NET_NUM_TX_BUFS + TBT_NET_NUM_RX_BUFS) \
+ * sizeof(struct tbt_buf_desc))
+
+
+#define TBT_NUM_FRAMES_PER_PAGE (PAGE_SIZE / TBT_RING_MAX_FRAME_SIZE)
+
+#define TBT_NUM_BUFS_BETWEEN(idx1, idx2, num_bufs) \
+ (((num_bufs) - 1) - \
+ ((((idx1) - (idx2)) + (num_bufs)) & ((num_bufs) - 1)))
+
+#define TX_WAKE_THRESHOLD (2 * DIV_ROUND_UP(TBT_NET_MTU, \
+ TBT_RING_MAX_FRM_DATA_SZ))
+
+#define TBT_NET_DESC_ATTR_SOF_EOF (((PDF_TBT_NET_START_OF_FRAME << \
+ DESC_ATTR_SOF_SHIFT) & \
+ DESC_ATTR_SOF_MASK) | \
+ ((PDF_TBT_NET_END_OF_FRAME << \
+ DESC_ATTR_EOF_SHIFT) & \
+ DESC_ATTR_EOF_MASK))
+
+/* E2E workaround */
+#define TBT_EXIST_BUT_UNUSED_HOPID 2
+
+enum tbt_net_frame_pdf {
+ PDF_TBT_NET_MIDDLE_FRAME,
+ PDF_TBT_NET_START_OF_FRAME,
+ PDF_TBT_NET_END_OF_FRAME,
+};
+
+struct thunderbolt_ip_login {
+ struct thunderbolt_ip_header header;
+ __be32 protocol_revision;
+ __be32 transmit_path;
+ __be32 reserved[4];
+ __be32 crc;
+};
+
+struct thunderbolt_ip_login_response {
+ struct thunderbolt_ip_header header;
+ __be32 status;
+ __be32 receiver_mac_address[2];
+ __be32 receiver_mac_address_length;
+ __be32 reserved[4];
+ __be32 crc;
+};
+
+struct thunderbolt_ip_logout {
+ struct thunderbolt_ip_header header;
+ __be32 crc;
+};
+
+struct thunderbolt_ip_status {
+ struct thunderbolt_ip_header header;
+ __be32 status;
+ __be32 crc;
+};
+
+struct approve_inter_domain_connection_cmd {
+ __be32 req_code;
+ __be32 attributes;
+#define AIDC_ATTR_LINK_SHIFT 16
+#define AIDC_ATTR_LINK_MASK GENMASK(18, AIDC_ATTR_LINK_SHIFT)
+#define AIDC_ATTR_DEPTH_SHIFT 20
+#define AIDC_ATTR_DEPTH_MASK GENMASK(23, AIDC_ATTR_DEPTH_SHIFT)
+ uuid_be remote_uuid;
+ __be16 transmit_ring_number;
+ __be16 transmit_path;
+ __be16 receive_ring_number;
+ __be16 receive_path;
+ __be32 crc;
+
+};
+
+enum neg_event {
+ RECEIVE_LOGOUT = NUM_MEDIUM_STATUSES,
+ RECEIVE_LOGIN_RESPONSE,
+ RECEIVE_LOGIN,
+ NUM_NEG_EVENTS
+};
+
+enum disconnect_path_stage {
+ STAGE_1 = BIT(0),
+ STAGE_2 = BIT(1)
+};
+
+/**
+ * struct tbt_port - the basic tbt_port structure
+ * @tbt_nhi_ctxt: context of the nhi controller.
+ * @net_dev: networking device object.
+ * @login_retry_work: work queue for sending login requests.
+ * @login_response_work: work queue for sending login responses.
+ * @work_struct logout_work: work queue for sending logout requests.
+ * @status_reply_work: work queue for sending logout replies.
+ * @approve_inter_domain_work: work queue for sending interdomain to icm.
+ * @route_str: allows to route the messages to destination.
+ * @interdomain_local_uuid: allows to route the messages from local source.
+ * @interdomain_remote_uuid: allows to route the messages to destination.
+ * @command_id a number that identifies the command.
+ * @negotiation_status: holds the network negotiation state.
+ * @msg_enable: used for debugging filters.
+ * @seq_num: a number that identifies the session.
+ * @login_retry_count: counts number of login retries sent.
+ * @local_depth: depth of the remote peer in the chain.
+ * @transmit_path: routing parameter for the icm.
+ * @frame_id: counting ID of frames.
+ * @num: port number.
+ * @local_path: routing parameter for the icm.
+ * @enable_full_e2e: whether to enable full E2E.
+ * @match_frame_id: whether to match frame id on incoming packets.
+ */
+struct tbt_port {
+ struct tbt_nhi_ctxt *nhi_ctxt;
+ struct net_device *net_dev;
+ struct delayed_work login_retry_work;
+ struct work_struct login_response_work;
+ struct work_struct logout_work;
+ struct work_struct status_reply_work;
+ struct work_struct approve_inter_domain_work;
+ struct route_string route_str;
+ uuid_be interdomain_local_uuid;
+ uuid_be interdomain_remote_uuid;
+ u32 command_id;
+ u16 negotiation_status;
+ u16 msg_enable;
+ u8 seq_num;
+ u8 login_retry_count;
+ u8 local_depth;
+ u8 transmit_path;
+ u16 frame_id;
+ u8 num;
+ u8 local_path;
+ bool enable_full_e2e : 1;
+ bool match_frame_id : 1;
+};
+
+static void disconnect_path(struct tbt_port *port,
+ enum disconnect_path_stage stage)
+{
+ u32 cmd = (DISCONNECT_PORT_A_INTER_DOMAIN_PATH + port->num);
+
+ cmd <<= REG_INMAIL_CMD_CMD_SHIFT;
+ cmd &= REG_INMAIL_CMD_CMD_MASK;
+ cmd |= REG_INMAIL_CMD_REQUEST;
+
+ mutex_lock(&port->nhi_ctxt->mailbox_mutex);
+ if (!mutex_trylock(&port->nhi_ctxt->d0_exit_mailbox_mutex)) {
+ netif_notice(port, link, port->net_dev, "controller id %#x is existing D0\n",
+ port->nhi_ctxt->id);
+ } else {
+ nhi_mailbox(port->nhi_ctxt, cmd, stage, false);
+
+ port->nhi_ctxt->net_devices[port->num].medium_sts =
+ MEDIUM_READY_FOR_CONNECTION;
+
+ mutex_unlock(&port->nhi_ctxt->d0_exit_mailbox_mutex);
+ }
+ mutex_unlock(&port->nhi_ctxt->mailbox_mutex);
+}
+
+static void tbt_net_tear_down(struct net_device *net_dev, bool send_logout)
+{
+ struct tbt_port *port = netdev_priv(net_dev);
+ void __iomem *iobase = port->nhi_ctxt->iobase;
+ void __iomem *tx_reg = NULL;
+ u32 tx_reg_val = 0;
+
+ netif_carrier_off(net_dev);
+ netif_stop_queue(net_dev);
+
+ if (port->negotiation_status & BIT(MEDIUM_CONNECTED)) {
+ void __iomem *rx_reg = iobase + REG_RX_OPTIONS_BASE +
+ (port->local_path * REG_OPTS_STEP);
+ u32 rx_reg_val = ioread32(rx_reg) & ~REG_OPTS_E2E_EN;
+
+ tx_reg = iobase + REG_TX_OPTIONS_BASE +
+ (port->local_path * REG_OPTS_STEP);
+ tx_reg_val = ioread32(tx_reg) & ~REG_OPTS_E2E_EN;
+
+ disconnect_path(port, STAGE_1);
+
+ /* disable RX flow control */
+ iowrite32(rx_reg_val, rx_reg);
+ /* disable TX flow control */
+ iowrite32(tx_reg_val, tx_reg);
+ /* disable RX ring */
+ iowrite32(rx_reg_val & ~REG_OPTS_VALID, rx_reg);
+
+ rx_reg = iobase + REG_RX_RING_BASE +
+ (port->local_path * REG_RING_STEP);
+ iowrite32(0, rx_reg + REG_RING_PHYS_LO_OFFSET);
+ iowrite32(0, rx_reg + REG_RING_PHYS_HI_OFFSET);
+ }
+
+ /* Stop login messages */
+ cancel_delayed_work_sync(&port->login_retry_work);
+
+ if (send_logout)
+ queue_work(port->nhi_ctxt->net_workqueue, &port->logout_work);
+
+ if (port->negotiation_status & BIT(MEDIUM_CONNECTED)) {
+ unsigned long flags;
+
+ /* wait for TX to finish */
+ usleep_range(5 * USEC_PER_MSEC, 7 * USEC_PER_MSEC);
+ /* disable TX ring */
+ iowrite32(tx_reg_val & ~REG_OPTS_VALID, tx_reg);
+
+ disconnect_path(port, STAGE_2);
+
+ spin_lock_irqsave(&port->nhi_ctxt->lock, flags);
+ /* disable RX and TX interrupts */
+ RING_INT_DISABLE_TX_RX(iobase, port->local_path,
+ port->nhi_ctxt->num_paths);
+ spin_unlock_irqrestore(&port->nhi_ctxt->lock, flags);
+ }
+}
+
+static inline int send_message(struct tbt_port *port, const char *func,
+ enum pdf_value pdf, u32 msg_len,
+ const void *msg)
+{
+ u32 crc_offset = msg_len - sizeof(__be32);
+ __be32 *crc = (__be32 *)((u8 *)msg + crc_offset);
+ bool is_intdom = (pdf == PDF_INTER_DOMAIN_RESPONSE);
+ int res;
+
+ *crc = cpu_to_be32(~__crc32c_le(~0, msg, crc_offset));
+ res = down_timeout(&port->nhi_ctxt->send_sem,
+ msecs_to_jiffies(3 * MSEC_PER_SEC));
+ if (res) {
+ netif_err(port, link, port->net_dev, "%s: controller id %#x timeout on send semaphore\n",
+ func, port->nhi_ctxt->id);
+ return res;
+ }
+
+ if (!mutex_trylock(&port->nhi_ctxt->d0_exit_send_mutex)) {
+ up(&port->nhi_ctxt->send_sem);
+ netif_notice(port, link, port->net_dev, "%s: controller id %#x is existing D0\n",
+ func, port->nhi_ctxt->id);
+ return -ENODEV;
+ }
+
+ res = nhi_send_message(port->nhi_ctxt, pdf, msg_len, msg, is_intdom);
+
+ mutex_unlock(&port->nhi_ctxt->d0_exit_send_mutex);
+ if (res)
+ up(&port->nhi_ctxt->send_sem);
+
+ return res;
+}
+
+static void approve_inter_domain(struct work_struct *work)
+{
+ struct tbt_port *port = container_of(work, typeof(*port),
+ approve_inter_domain_work);
+ struct approve_inter_domain_connection_cmd approve_msg = {
+ .req_code = cpu_to_be32(CC_APPROVE_INTER_DOMAIN_CONNECTION),
+ .transmit_path = cpu_to_be16(LOGIN_TX_PATH),
+ };
+ u32 aidc = (L0_PORT_NUM(port->route_str.lo) << AIDC_ATTR_LINK_SHIFT) &
+ AIDC_ATTR_LINK_MASK;
+
+ aidc |= (port->local_depth << AIDC_ATTR_DEPTH_SHIFT) &
+ AIDC_ATTR_DEPTH_MASK;
+
+ approve_msg.attributes = cpu_to_be32(aidc);
+
+ memcpy(&approve_msg.remote_uuid, &port->interdomain_remote_uuid,
+ sizeof(approve_msg.remote_uuid));
+ approve_msg.transmit_ring_number = cpu_to_be16(port->local_path);
+ approve_msg.receive_ring_number = cpu_to_be16(port->local_path);
+ approve_msg.receive_path = cpu_to_be16(port->transmit_path);
+
+ send_message(port, __func__, PDF_SW_TO_FW_COMMAND, sizeof(approve_msg),
+ &approve_msg);
+}
+
+static inline void prepare_header(struct thunderbolt_ip_header *header,
+ struct tbt_port *port,
+ enum thunderbolt_ip_packet_type packet_type,
+ u8 len_dwords)
+{
+ const uuid_be proto_uuid = APPLE_THUNDERBOLT_IP_PROTOCOL_UUID;
+
+ header->packet_type = cpu_to_be32(packet_type);
+ header->route_str.hi = cpu_to_be32(port->route_str.hi);
+ header->route_str.lo = cpu_to_be32(port->route_str.lo);
+ header->attributes = cpu_to_be32(
+ ((port->seq_num << HDR_ATTR_SEQ_NUM_SHIFT) &
+ HDR_ATTR_SEQ_NUM_MASK) |
+ ((len_dwords << HDR_ATTR_LEN_SHIFT) & HDR_ATTR_LEN_MASK));
+ memcpy(&header->apple_tbt_ip_proto_uuid, &proto_uuid,
+ sizeof(header->apple_tbt_ip_proto_uuid));
+ memcpy(&header->initiator_uuid, &port->interdomain_local_uuid,
+ sizeof(header->initiator_uuid));
+ memcpy(&header->target_uuid, &port->interdomain_remote_uuid,
+ sizeof(header->target_uuid));
+ header->command_id = cpu_to_be32(port->command_id);
+
+ port->command_id++;
+}
+
+static void status_reply(struct work_struct *work)
+{
+ struct tbt_port *port = container_of(work, typeof(*port),
+ status_reply_work);
+ struct thunderbolt_ip_status status_msg = {
+ .status = 0,
+ };
+
+ prepare_header(&status_msg.header, port,
+ THUNDERBOLT_IP_STATUS_TYPE,
+ (offsetof(struct thunderbolt_ip_status, crc) -
+ offsetof(struct thunderbolt_ip_status,
+ header.apple_tbt_ip_proto_uuid)) /
+ sizeof(u32));
+
+ send_message(port, __func__, PDF_INTER_DOMAIN_RESPONSE,
+ sizeof(status_msg), &status_msg);
+
+}
+
+static void logout(struct work_struct *work)
+{
+ struct tbt_port *port = container_of(work, typeof(*port),
+ logout_work);
+ struct thunderbolt_ip_logout logout_msg;
+
+ prepare_header(&logout_msg.header, port,
+ THUNDERBOLT_IP_LOGOUT_TYPE,
+ (offsetof(struct thunderbolt_ip_logout, crc) -
+ offsetof(struct thunderbolt_ip_logout,
+ header.apple_tbt_ip_proto_uuid)) / sizeof(u32));
+
+ send_message(port, __func__, PDF_INTER_DOMAIN_RESPONSE,
+ sizeof(logout_msg), &logout_msg);
+
+}
+
+static void login_response(struct work_struct *work)
+{
+ struct tbt_port *port = container_of(work, typeof(*port),
+ login_response_work);
+ struct thunderbolt_ip_login_response login_res_msg = {
+ .receiver_mac_address_length = cpu_to_be32(ETH_ALEN),
+ };
+
+ prepare_header(&login_res_msg.header, port,
+ THUNDERBOLT_IP_LOGIN_RESPONSE_TYPE,
+ (offsetof(struct thunderbolt_ip_login_response, crc) -
+ offsetof(struct thunderbolt_ip_login_response,
+ header.apple_tbt_ip_proto_uuid)) / sizeof(u32));
+
+ ether_addr_copy((u8 *)login_res_msg.receiver_mac_address,
+ port->net_dev->dev_addr);
+
+ send_message(port, __func__, PDF_INTER_DOMAIN_RESPONSE,
+ sizeof(login_res_msg), &login_res_msg);
+
+}
+
+static void login_retry(struct work_struct *work)
+{
+ struct tbt_port *port = container_of(work, typeof(*port),
+ login_retry_work.work);
+ struct thunderbolt_ip_login login_msg = {
+ .protocol_revision = cpu_to_be32(
+ APPLE_THUNDERBOLT_IP_PROTOCOL_REVISION),
+ .transmit_path = cpu_to_be32(LOGIN_TX_PATH),
+ };
+
+
+ if (port->nhi_ctxt->d0_exit)
+ return;
+
+ port->login_retry_count++;
+
+ prepare_header(&login_msg.header, port,
+ THUNDERBOLT_IP_LOGIN_TYPE,
+ (offsetof(struct thunderbolt_ip_login, crc) -
+ offsetof(struct thunderbolt_ip_login,
+ header.apple_tbt_ip_proto_uuid)) / sizeof(u32));
+
+ if (send_message(port, __func__, PDF_INTER_DOMAIN_RESPONSE,
+ sizeof(login_msg), &login_msg) == -ENODEV)
+ return;
+
+ if (likely(port->login_retry_count < NUM_TX_LOGIN_RETRIES))
+ queue_delayed_work(port->nhi_ctxt->net_workqueue,
+ &port->login_retry_work,
+ msecs_to_jiffies(5 * MSEC_PER_SEC));
+ else
+ netif_notice(port, link, port->net_dev, "port %u (%#x) login timeout after %u retries\n",
+ port->num, port->negotiation_status,
+ port->login_retry_count);
+}
+
+void negotiation_events(struct net_device *net_dev,
+ enum medium_status medium_sts)
+{
+ struct tbt_port *port = netdev_priv(net_dev);
+ void __iomem *iobase = port->nhi_ctxt->iobase;
+ u32 sof_eof_en, tx_ring_conf, rx_ring_conf, e2e_en;
+ void __iomem *reg;
+ unsigned long flags;
+ u16 hop_id;
+ bool send_logout;
+
+ if (!netif_running(net_dev)) {
+ netif_dbg(port, link, net_dev, "port %u (%#x) is down\n",
+ port->num, port->negotiation_status);
+ return;
+ }
+
+ netif_dbg(port, link, net_dev, "port %u (%#x) receive event %u\n",
+ port->num, port->negotiation_status, medium_sts);
+
+ switch (medium_sts) {
+ case MEDIUM_DISCONNECTED:
+ send_logout = (port->negotiation_status
+ & (BIT(MEDIUM_CONNECTED)
+ | BIT(MEDIUM_READY_FOR_CONNECTION)));
+ send_logout = send_logout && !(port->negotiation_status &
+ BIT(RECEIVE_LOGOUT));
+
+ tbt_net_tear_down(net_dev, send_logout);
+ port->negotiation_status = BIT(MEDIUM_DISCONNECTED);
+ break;
+
+ case MEDIUM_CONNECTED:
+ /*
+ * check if meanwhile other side sent logout
+ * if yes, just don't allow connection to take place
+ * and disconnect path
+ */
+ if (port->negotiation_status & BIT(RECEIVE_LOGOUT)) {
+ disconnect_path(port, STAGE_1 | STAGE_2);
+ break;
+ }
+
+ port->negotiation_status = BIT(MEDIUM_CONNECTED);
+
+ /* configure TX ring */
+ reg = iobase + REG_TX_RING_BASE +
+ (port->local_path * REG_RING_STEP);
+
+ tx_ring_conf = (TBT_NET_NUM_TX_BUFS << REG_RING_SIZE_SHIFT) &
+ REG_RING_SIZE_MASK;
+
+ iowrite32(tx_ring_conf, reg + REG_RING_SIZE_OFFSET);
+
+ /* enable the rings */
+ reg = iobase + REG_TX_OPTIONS_BASE +
+ (port->local_path * REG_OPTS_STEP);
+ if (port->enable_full_e2e) {
+ iowrite32(REG_OPTS_VALID | REG_OPTS_E2E_EN, reg);
+ hop_id = port->local_path;
+ } else {
+ iowrite32(REG_OPTS_VALID, reg);
+ hop_id = TBT_EXIST_BUT_UNUSED_HOPID;
+ }
+
+ reg = iobase + REG_RX_OPTIONS_BASE +
+ (port->local_path * REG_OPTS_STEP);
+
+ sof_eof_en = (BIT(PDF_TBT_NET_START_OF_FRAME) <<
+ REG_RX_OPTS_MASK_SOF_SHIFT) &
+ REG_RX_OPTS_MASK_SOF_MASK;
+
+ sof_eof_en |= (BIT(PDF_TBT_NET_END_OF_FRAME) <<
+ REG_RX_OPTS_MASK_EOF_SHIFT) &
+ REG_RX_OPTS_MASK_EOF_MASK;
+
+ iowrite32(sof_eof_en, reg + REG_RX_OPTS_MASK_OFFSET);
+
+ e2e_en = REG_OPTS_VALID | REG_OPTS_E2E_EN;
+ e2e_en |= (hop_id << REG_RX_OPTS_TX_E2E_HOP_ID_SHIFT) &
+ REG_RX_OPTS_TX_E2E_HOP_ID_MASK;
+
+ iowrite32(e2e_en, reg);
+
+ /*
+ * Configure RX ring
+ * must be after enable ring for E2E to work
+ */
+ reg = iobase + REG_RX_RING_BASE +
+ (port->local_path * REG_RING_STEP);
+
+ rx_ring_conf = (TBT_NET_NUM_RX_BUFS << REG_RING_SIZE_SHIFT) &
+ REG_RING_SIZE_MASK;
+
+ rx_ring_conf |= (TBT_RING_MAX_FRAME_SIZE <<
+ REG_RING_BUF_SIZE_SHIFT) &
+ REG_RING_BUF_SIZE_MASK;
+
+ iowrite32(rx_ring_conf, reg + REG_RING_SIZE_OFFSET);
+
+ spin_lock_irqsave(&port->nhi_ctxt->lock, flags);
+ /* enable RX interrupt */
+ iowrite32(ioread32(iobase + REG_RING_INTERRUPT_BASE) |
+ REG_RING_INT_RX_PROCESSED(port->local_path,
+ port->nhi_ctxt->num_paths),
+ iobase + REG_RING_INTERRUPT_BASE);
+ spin_unlock_irqrestore(&port->nhi_ctxt->lock, flags);
+
+ netif_info(port, link, net_dev, "Thunderbolt(TM) Networking port %u - ready\n",
+ port->num);
+
+ netif_carrier_on(net_dev);
+ netif_start_queue(net_dev);
+ break;
+
+ case MEDIUM_READY_FOR_CONNECTION:
+ /*
+ * If medium is connected, no reason to go back,
+ * keep it 'connected'.
+ * If received login response, don't need to trigger login
+ * retries again.
+ */
+ if (unlikely(port->negotiation_status &
+ (BIT(MEDIUM_CONNECTED) |
+ BIT(RECEIVE_LOGIN_RESPONSE))))
+ break;
+
+ port->negotiation_status = BIT(MEDIUM_READY_FOR_CONNECTION);
+ port->login_retry_count = 0;
+ queue_delayed_work(port->nhi_ctxt->net_workqueue,
+ &port->login_retry_work, 0);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void negotiation_messages(struct net_device *net_dev,
+ struct thunderbolt_ip_header *hdr)
+{
+ struct tbt_port *port = netdev_priv(net_dev);
+ __be32 status;
+
+ if (!netif_running(net_dev)) {
+ netif_dbg(port, link, net_dev, "port %u (%#x) is down\n",
+ port->num, port->negotiation_status);
+ return;
+ }
+
+ switch (hdr->packet_type) {
+ case cpu_to_be32(THUNDERBOLT_IP_LOGIN_TYPE):
+ port->transmit_path = be32_to_cpu(
+ ((struct thunderbolt_ip_login *)hdr)->transmit_path);
+ netif_dbg(port, link, net_dev, "port %u (%#x) receive ThunderboltIP login message with transmit path %u\n",
+ port->num, port->negotiation_status,
+ port->transmit_path);
+
+ if (unlikely(port->negotiation_status &
+ BIT(MEDIUM_DISCONNECTED)))
+ break;
+
+ queue_work(port->nhi_ctxt->net_workqueue,
+ &port->login_response_work);
+
+ if (unlikely(port->negotiation_status & BIT(MEDIUM_CONNECTED)))
+ break;
+
+ /*
+ * In case a login response received from other peer
+ * on my login and acked their login for the first time,
+ * so just approve the inter-domain now
+ */
+ if (port->negotiation_status & BIT(RECEIVE_LOGIN_RESPONSE)) {
+ if (!(port->negotiation_status & BIT(RECEIVE_LOGIN)))
+ queue_work(port->nhi_ctxt->net_workqueue,
+ &port->approve_inter_domain_work);
+ /*
+ * if we reached the number of max retries or previous
+ * logout, schedule another round of login retries
+ */
+ } else if ((port->login_retry_count >= NUM_TX_LOGIN_RETRIES) ||
+ (port->negotiation_status & BIT(RECEIVE_LOGOUT))) {
+ port->negotiation_status &= ~(BIT(RECEIVE_LOGOUT));
+ port->login_retry_count = 0;
+ queue_delayed_work(port->nhi_ctxt->net_workqueue,
+ &port->login_retry_work, 0);
+ }
+
+ port->negotiation_status |= BIT(RECEIVE_LOGIN);
+
+ break;
+
+ case cpu_to_be32(THUNDERBOLT_IP_LOGIN_RESPONSE_TYPE):
+ status = ((struct thunderbolt_ip_login_response *)hdr)->status;
+ if (likely(status == 0)) {
+ netif_dbg(port, link, net_dev, "port %u (%#x) receive ThunderboltIP login response message\n",
+ port->num,
+ port->negotiation_status);
+
+ if (unlikely(port->negotiation_status &
+ (BIT(MEDIUM_DISCONNECTED) |
+ BIT(MEDIUM_CONNECTED) |
+ BIT(RECEIVE_LOGIN_RESPONSE))))
+ break;
+
+ port->negotiation_status |=
+ BIT(RECEIVE_LOGIN_RESPONSE);
+ cancel_delayed_work_sync(&port->login_retry_work);
+ /*
+ * login was received from other peer and now response
+ * on our login so approve the inter-domain
+ */
+ if (port->negotiation_status & BIT(RECEIVE_LOGIN))
+ queue_work(port->nhi_ctxt->net_workqueue,
+ &port->approve_inter_domain_work);
+ else
+ port->negotiation_status &=
+ ~BIT(RECEIVE_LOGOUT);
+ } else {
+ netif_notice(port, link, net_dev, "port %u (%#x) receive ThunderboltIP login response message with status %u\n",
+ port->num,
+ port->negotiation_status,
+ be32_to_cpu(status));
+ }
+ break;
+
+ case cpu_to_be32(THUNDERBOLT_IP_LOGOUT_TYPE):
+ netif_dbg(port, link, net_dev, "port %u (%#x) receive ThunderboltIP logout message\n",
+ port->num, port->negotiation_status);
+
+ queue_work(port->nhi_ctxt->net_workqueue,
+ &port->status_reply_work);
+ port->negotiation_status &= ~(BIT(RECEIVE_LOGIN) |
+ BIT(RECEIVE_LOGIN_RESPONSE));
+ port->negotiation_status |= BIT(RECEIVE_LOGOUT);
+
+ if (!(port->negotiation_status & BIT(MEDIUM_CONNECTED))) {
+ tbt_net_tear_down(net_dev, false);
+ break;
+ }
+
+ tbt_net_tear_down(net_dev, true);
+
+ port->negotiation_status |= BIT(MEDIUM_READY_FOR_CONNECTION);
+ port->negotiation_status &= ~(BIT(MEDIUM_CONNECTED));
+ break;
+
+ case cpu_to_be32(THUNDERBOLT_IP_STATUS_TYPE):
+ netif_dbg(port, link, net_dev, "port %u (%#x) receive ThunderboltIP status message with status %u\n",
+ port->num, port->negotiation_status,
+ be32_to_cpu(
+ ((struct thunderbolt_ip_status *)hdr)->status));
+ break;
+ }
+}
+
+void nhi_dealloc_etherdev(struct net_device *net_dev)
+{
+ unregister_netdev(net_dev);
+ free_netdev(net_dev);
+}
+
+void nhi_update_etherdev(struct tbt_nhi_ctxt *nhi_ctxt,
+ struct net_device *net_dev, struct genl_info *info)
+{
+ struct tbt_port *port = netdev_priv(net_dev);
+
+ nla_memcpy(&(port->route_str),
+ info->attrs[NHI_ATTR_LOCAL_ROUTE_STRING],
+ sizeof(port->route_str));
+ nla_memcpy(&port->interdomain_remote_uuid,
+ info->attrs[NHI_ATTR_REMOTE_UUID],
+ sizeof(port->interdomain_remote_uuid));
+ port->local_depth = nla_get_u8(info->attrs[NHI_ATTR_LOCAL_DEPTH]);
+ port->enable_full_e2e = nhi_ctxt->support_full_e2e ?
+ nla_get_flag(info->attrs[NHI_ATTR_ENABLE_FULL_E2E]) : false;
+ port->match_frame_id =
+ nla_get_flag(info->attrs[NHI_ATTR_MATCH_FRAME_ID]);
+ port->frame_id = 0;
+}
+
+struct net_device *nhi_alloc_etherdev(struct tbt_nhi_ctxt *nhi_ctxt,
+ u8 port_num, struct genl_info *info)
+{
+ struct tbt_port *port;
+ struct net_device *net_dev = alloc_etherdev(sizeof(struct tbt_port));
+ u32 hash;
+
+ if (!net_dev)
+ return NULL;
+
+ SET_NETDEV_DEV(net_dev, &nhi_ctxt->pdev->dev);
+
+ port = netdev_priv(net_dev);
+ port->nhi_ctxt = nhi_ctxt;
+ port->net_dev = net_dev;
+ nla_memcpy(&port->interdomain_local_uuid,
+ info->attrs[NHI_ATTR_LOCAL_UUID],
+ sizeof(port->interdomain_local_uuid));
+ nhi_update_etherdev(nhi_ctxt, net_dev, info);
+ port->num = port_num;
+ port->local_path = PATH_FROM_PORT(nhi_ctxt->num_paths, port_num);
+
+ port->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
+
+ net_dev->addr_assign_type = NET_ADDR_PERM;
+ /* unicast and locally administred MAC */
+ net_dev->dev_addr[0] = (port_num << 4) | 0x02;
+ hash = jhash2((u32 *)&port->interdomain_local_uuid,
+ sizeof(port->interdomain_local_uuid)/sizeof(u32), 0);
+
+ memcpy(net_dev->dev_addr + 1, &hash, sizeof(hash));
+ hash = jhash2((u32 *)&port->interdomain_local_uuid,
+ sizeof(port->interdomain_local_uuid)/sizeof(u32), hash);
+
+ net_dev->dev_addr[5] = hash & 0xff;
+
+ scnprintf(net_dev->name, sizeof(net_dev->name), "tbtnet%%dp%hhu",
+ port_num);
+
+ INIT_DELAYED_WORK(&port->login_retry_work, login_retry);
+ INIT_WORK(&port->login_response_work, login_response);
+ INIT_WORK(&port->logout_work, logout);
+ INIT_WORK(&port->status_reply_work, status_reply);
+ INIT_WORK(&port->approve_inter_domain_work, approve_inter_domain);
+
+ netif_info(port, probe, net_dev,
+ "Thunderbolt(TM) Networking port %u - MAC Address: %pM\n",
+ port_num, net_dev->dev_addr);
+
+ return net_dev;
+}
diff --git a/drivers/thunderbolt/icm/net.h b/drivers/thunderbolt/icm/net.h
index a1e43f6..5289158 100644
--- a/drivers/thunderbolt/icm/net.h
+++ b/drivers/thunderbolt/icm/net.h
@@ -33,6 +33,10 @@
#include <linux/semaphore.h>
#include <net/genetlink.h>
+#define APPLE_THUNDERBOLT_IP_PROTOCOL_UUID \
+ UUID_BE(0x9E588F79, 0x478A, 0x1636, \
+ 0x64, 0x56, 0xC6, 0x97, 0xDD, 0xC8, 0x20, 0xA9)
+
/*
* Each physical port contains 2 channels.
* Devices are exposed to user based on physical ports.
@@ -43,6 +47,9 @@
* host channel/link which starts from 1.
*/
#define PORT_NUM_FROM_LINK(link) (((link) - 1) / CHANNELS_PER_PORT_NUM)
+#define PORT_NUM_FROM_MSG(msg) PORT_NUM_FROM_LINK(((msg) & \
+ INTER_DOMAIN_LINK_MASK) >> \
+ INTER_DOMAIN_LINK_SHIFT)
#define TBT_TX_RING_FULL(prod, cons, size) ((((prod) + 1) % (size)) == (cons))
#define TBT_TX_RING_EMPTY(prod, cons) ((prod) == (cons))
@@ -135,6 +142,17 @@ enum {
CC_SET_FW_MODE_FDA_DA_ALL
};
+struct route_string {
+ u32 hi;
+ u32 lo;
+};
+
+struct route_string_be {
+ __be32 hi;
+ __be32 lo;
+};
+
+#define L0_PORT_NUM(cpu_route_str_lo) ((cpu_route_str_lo) & GENMASK(5, 0))
/* NHI genetlink attributes */
enum {
@@ -148,12 +166,53 @@ enum {
NHI_ATTR_PDF,
NHI_ATTR_MSG_TO_ICM,
NHI_ATTR_MSG_FROM_ICM,
+ NHI_ATTR_LOCAL_ROUTE_STRING,
+ NHI_ATTR_LOCAL_UUID,
+ NHI_ATTR_REMOTE_UUID,
+ NHI_ATTR_LOCAL_DEPTH,
+ NHI_ATTR_ENABLE_FULL_E2E,
+ NHI_ATTR_MATCH_FRAME_ID,
__NHI_ATTR_MAX,
};
#define NHI_ATTR_MAX (__NHI_ATTR_MAX - 1)
+/* ThunderboltIP Packet Types */
+enum thunderbolt_ip_packet_type {
+ THUNDERBOLT_IP_LOGIN_TYPE,
+ THUNDERBOLT_IP_LOGIN_RESPONSE_TYPE,
+ THUNDERBOLT_IP_LOGOUT_TYPE,
+ THUNDERBOLT_IP_STATUS_TYPE
+};
+
+struct thunderbolt_ip_header {
+ struct route_string_be route_str;
+ __be32 attributes;
+#define HDR_ATTR_LEN_SHIFT 0
+#define HDR_ATTR_LEN_MASK GENMASK(5, HDR_ATTR_LEN_SHIFT)
+#define HDR_ATTR_SEQ_NUM_SHIFT 27
+#define HDR_ATTR_SEQ_NUM_MASK GENMASK(28, HDR_ATTR_SEQ_NUM_SHIFT)
+ uuid_be apple_tbt_ip_proto_uuid;
+ uuid_be initiator_uuid;
+ uuid_be target_uuid;
+ __be32 packet_type;
+ __be32 command_id;
+};
+
+enum medium_status {
+ /* Handle cable disconnection or peer down */
+ MEDIUM_DISCONNECTED,
+ /* Connection is fully established */
+ MEDIUM_CONNECTED,
+ /* Awaiting for being approved by user-space module */
+ MEDIUM_READY_FOR_APPROVAL,
+ /* Approved by user-space, awaiting for establishment flow to finish */
+ MEDIUM_READY_FOR_CONNECTION,
+ NUM_MEDIUM_STATUSES
+};
+
struct port_net_dev {
struct net_device *net_dev;
+ enum medium_status medium_sts;
struct mutex state_mutex;
};
@@ -223,5 +282,16 @@ struct tbt_nhi_ctxt {
int nhi_send_message(struct tbt_nhi_ctxt *nhi_ctxt, enum pdf_value pdf,
u32 msg_len, const void *msg, bool ignore_icm_resp);
int nhi_mailbox(struct tbt_nhi_ctxt *nhi_ctxt, u32 cmd, u32 data, bool deinit);
+struct net_device *nhi_alloc_etherdev(struct tbt_nhi_ctxt *nhi_ctxt,
+ u8 port_num, struct genl_info *info);
+void nhi_update_etherdev(struct tbt_nhi_ctxt *nhi_ctxt,
+ struct net_device *net_dev, struct genl_info *info);
+void nhi_dealloc_etherdev(struct net_device *net_dev);
+void negotiation_events(struct net_device *net_dev,
+ enum medium_status medium_sts);
+void negotiation_messages(struct net_device *net_dev,
+ struct thunderbolt_ip_header *hdr);
+void tbt_net_rx_msi(struct net_device *net_dev);
+void tbt_net_tx_msi(struct net_device *net_dev);
#endif
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v4 2/7] proc: Reduce cache miss in snmp_seq_show
From: David Miller @ 2016-09-27 13:45 UTC (permalink / raw)
To: hejianet
Cc: netdev, linux-sctp, linux-kernel, kuznet, jmorris, yoshfuji,
kaber, vyasevich, nhorman, steffen.klassert, herbert,
marcelo.leitner
In-Reply-To: <1474877355-12920-3-git-send-email-hejianet@gmail.com>
From: Jia He <hejianet@gmail.com>
Date: Mon, 26 Sep 2016 16:09:10 +0800
> +static int snmp_seq_show_tcp_udp(struct seq_file *seq, void *v)
> +{
> + int i;
> + unsigned long buff[TCPUDP_MIB_MAX];
> + struct net *net = seq->private;
Please always order local variables from longest to shortest
line.
Please audit your entire patch series for this problem.
Thanks.
^ permalink raw reply
* Re: [PATCH net-next 4/4] net/sched: act_mirred: Implement ingress actions
From: David Miller @ 2016-09-27 13:44 UTC (permalink / raw)
To: daniel
Cc: shmulik.ladkani, jhs, xiyou.wangcong, edumazet, netdev,
shmulik.ladkani
In-Reply-To: <57EA4C66.8070907@iogearbox.net>
From: Daniel Borkmann <daniel@iogearbox.net>
Date: Tue, 27 Sep 2016 12:39:34 +0200
> Any reason why dev_forward_skb() is not preferred over direct
> netif_receive_skb() you're using? It would, for example, implicitly
> assure that pkt_type is always PACKET_HOST, etc.
dev_forward_skb() will pull the ethernet header.
And since a direct call to netif_receive_skb() will not, one of these
two choices won't work properly.
^ 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