* [patch net-next RFC] tc: introduce OpenFlow classifier
From: Jiri Pirko @ 2015-01-22 13:37 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs
This patch introduces OpenFlow-based filter. So far, the very essential
packet fields are supported (according to OpenFlow v1.4 spec).
Known issues: skb_flow_dissect hashes out ipv6 addresses. That needs
to be changed to store them somewhere so they can be used later on.
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
include/uapi/linux/pkt_cls.h | 33 +++
net/sched/Kconfig | 11 +
net/sched/Makefile | 1 +
net/sched/cls_openflow.c | 514 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 559 insertions(+)
create mode 100644 net/sched/cls_openflow.c
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index 25731df..d4cef16 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -402,6 +402,39 @@ enum {
#define TCA_BPF_MAX (__TCA_BPF_MAX - 1)
+/* OpenFlow classifier */
+
+enum {
+ TCA_OF_UNSPEC,
+ TCA_OF_CLASSID,
+ TCA_OF_POLICE,
+ TCA_OF_INDEV,
+ TCA_OF_ACT,
+ TCA_OF_KEY_ETH_DST, /* ETH_ALEN */
+ TCA_OF_KEY_ETH_DST_MASK, /* ETH_ALEN */
+ TCA_OF_KEY_ETH_SRC, /* ETH_ALEN */
+ TCA_OF_KEY_ETH_SRC_MASK, /* ETH_ALEN */
+ TCA_OF_KEY_ETH_TYPE, /* be16 */
+ TCA_OF_KEY_ETH_TYPE_MASK, /* be16 */
+ TCA_OF_KEY_IP_PROTO, /* u8 */
+ TCA_OF_KEY_IP_PROTO_MASK, /* u8 */
+ TCA_OF_KEY_IPV4_SRC, /* be32 */
+ TCA_OF_KEY_IPV4_SRC_MASK, /* be32 */
+ TCA_OF_KEY_IPV4_DST, /* be32 */
+ TCA_OF_KEY_IPV4_DST_MASK, /* be32 */
+ TCA_OF_KEY_IPV6_SRC, /* struct in6_addr */
+ TCA_OF_KEY_IPV6_SRC_MASK, /* struct in6_addr */
+ TCA_OF_KEY_IPV6_DST, /* struct in6_addr */
+ TCA_OF_KEY_IPV6_DST_MASK, /* struct in6_addr */
+ TCA_OF_KEY_TP_SRC, /* be16 */
+ TCA_OF_KEY_TP_SRC_MASK, /* be16 */
+ TCA_OF_KEY_TP_DST, /* be16 */
+ TCA_OF_KEY_TP_DST_MASK, /* be16 */
+ __TCA_OF_MAX,
+};
+
+#define TCA_OF_MAX (__TCA_OF_MAX - 1)
+
/* Extended Matches */
struct tcf_ematch_tree_hdr {
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 475e35e..9b01fae 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -477,6 +477,17 @@ config NET_CLS_BPF
To compile this code as a module, choose M here: the module will
be called cls_bpf.
+config NET_CLS_OPENFLOW
+ tristate "OpenFlow classifier"
+ select NET_CLS
+ ---help---
+ If you say Y here, you will be able to classify packets based on
+ a configurable combination of packet keys and masks accordint to
+ OpenFlow standard.
+
+ To compile this code as a module, choose M here: the module will
+ be called cls_openflow.
+
config NET_EMATCH
bool "Extended Matches"
select NET_CLS
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 7ca7f4c..5faa9ca 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_NET_CLS_BASIC) += cls_basic.o
obj-$(CONFIG_NET_CLS_FLOW) += cls_flow.o
obj-$(CONFIG_NET_CLS_CGROUP) += cls_cgroup.o
obj-$(CONFIG_NET_CLS_BPF) += cls_bpf.o
+obj-$(CONFIG_NET_CLS_OPENFLOW) += cls_openflow.o
obj-$(CONFIG_NET_EMATCH) += ematch.o
obj-$(CONFIG_NET_EMATCH_CMP) += em_cmp.o
obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o
diff --git a/net/sched/cls_openflow.c b/net/sched/cls_openflow.c
new file mode 100644
index 0000000..1c261fa
--- /dev/null
+++ b/net/sched/cls_openflow.c
@@ -0,0 +1,514 @@
+/*
+ * net/sched/cls_openflow.c OpenFlow classifier
+ *
+ * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/if_ether.h>
+#include <linux/in6.h>
+
+#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
+
+struct of_flow_key {
+ int indev_ifindex;
+ struct {
+ u8 src[ETH_ALEN];
+ u8 dst[ETH_ALEN];
+ __be16 type;
+ } eth;
+ struct {
+ u8 proto;
+ } ip;
+ union {
+ struct {
+ __be32 src;
+ __be32 dst;
+ } ipv4;
+ struct {
+ struct in6_addr src;
+ struct in6_addr dst;
+ } ipv6;
+ };
+ union {
+ struct {
+ __be16 src;
+ __be16 dst;
+ } tp;
+ };
+} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
+
+struct of_flow_match {
+ struct of_flow_key key;
+ struct of_flow_key mask;
+};
+
+struct cls_of_head {
+ struct list_head filters;
+ u32 hgen;
+ struct rcu_head rcu;
+};
+
+struct cls_of_filter {
+ struct list_head list;
+ u32 handle;
+ struct tcf_exts exts;
+ struct tcf_result res;
+ struct tcf_proto *tp;
+ struct of_flow_match match;
+ struct rcu_head rcu;
+};
+
+static void of_extract_key(struct sk_buff *skb, struct of_flow_key *skb_key)
+{
+ struct flow_keys flow_keys;
+ struct ethhdr *eth;
+
+ skb_key->indev_ifindex = skb->skb_iif;
+
+ eth = eth_hdr(skb);
+ ether_addr_copy(skb_key->eth.src, eth->h_source);
+ ether_addr_copy(skb_key->eth.dst, eth->h_dest);
+
+ skb_flow_dissect(skb, &flow_keys);
+ skb_key->eth.type = flow_keys.n_proto;
+ skb_key->ip.proto = flow_keys.ip_proto;
+ skb_key->ipv4.src = flow_keys.src;
+ skb_key->ipv4.dst = flow_keys.dst;
+ skb_key->tp.src = flow_keys.port16[0];
+ skb_key->tp.dst = flow_keys.port16[1];
+}
+
+static bool of_match(struct of_flow_key *skb_key, struct cls_of_filter *f)
+{
+ const long *lkey = (const long *) &f->match.key;
+ const long *lmask = (const long *) &f->match.mask;
+ const long *lskb_key = (const long *) skb_key;
+ int i;
+
+ for (i = 0; i < sizeof(struct of_flow_key); i += sizeof(const long)) {
+ if ((*lkey++ & *lmask) != (*lskb_key++ & *lmask))
+ return false;
+ lmask++;
+ }
+ return true;
+}
+
+static int of_classify(struct sk_buff *skb, const struct tcf_proto *tp,
+ struct tcf_result *res)
+{
+ struct cls_of_head *head = rcu_dereference_bh(tp->root);
+ struct cls_of_filter *f;
+ struct of_flow_key skb_key;
+ int ret;
+
+ of_extract_key(skb, &skb_key);
+
+ list_for_each_entry_rcu(f, &head->filters, list) {
+ if (!of_match(&skb_key, f))
+ continue;
+
+ *res = f->res;
+
+ ret = tcf_exts_exec(skb, &f->exts, res);
+ if (ret < 0)
+ continue;
+
+ return ret;
+ }
+ return -1;
+}
+
+static int of_init(struct tcf_proto *tp)
+{
+ struct cls_of_head *head;
+
+ head = kzalloc(sizeof(*head), GFP_KERNEL);
+ if (!head)
+ return -ENOBUFS;
+
+ INIT_LIST_HEAD_RCU(&head->filters);
+ rcu_assign_pointer(tp->root, head);
+
+ return 0;
+}
+
+static void of_destroy_filter(struct rcu_head *head)
+{
+ struct cls_of_filter *f = container_of(head, struct cls_of_filter, rcu);
+
+ tcf_exts_destroy(&f->exts);
+ kfree(f);
+}
+
+static void of_destroy(struct tcf_proto *tp)
+{
+ struct cls_of_head *head = rtnl_dereference(tp->root);
+ struct cls_of_filter *f, *next;
+
+ list_for_each_entry_safe(f, next, &head->filters, list) {
+ list_del_rcu(&f->list);
+ call_rcu(&f->rcu, of_destroy_filter);
+ }
+ RCU_INIT_POINTER(tp->root, NULL);
+ kfree_rcu(head, rcu);
+}
+
+static unsigned long of_get(struct tcf_proto *tp, u32 handle)
+{
+ struct cls_of_head *head = rtnl_dereference(tp->root);
+ struct cls_of_filter *f;
+
+ list_for_each_entry(f, &head->filters, list)
+ if (f->handle == handle)
+ return (unsigned long) f;
+ return 0;
+}
+
+static const struct nla_policy of_policy[TCA_OF_MAX + 1] = {
+ [TCA_OF_UNSPEC] = { .type = NLA_UNSPEC },
+ [TCA_OF_CLASSID] = { .type = NLA_U32 },
+ [TCA_OF_INDEV] = { .type = NLA_STRING,
+ .len = IFNAMSIZ },
+ [TCA_OF_KEY_ETH_DST] = { .len = ETH_ALEN },
+ [TCA_OF_KEY_ETH_DST_MASK] = { .len = ETH_ALEN },
+ [TCA_OF_KEY_ETH_SRC] = { .len = ETH_ALEN },
+ [TCA_OF_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN },
+ [TCA_OF_KEY_ETH_TYPE] = { .type = NLA_U16 },
+ [TCA_OF_KEY_ETH_TYPE_MASK] = { .type = NLA_U16 },
+ [TCA_OF_KEY_IP_PROTO] = { .type = NLA_U8 },
+ [TCA_OF_KEY_IP_PROTO_MASK] = { .type = NLA_U8 },
+ [TCA_OF_KEY_IPV4_SRC] = { .type = NLA_U32 },
+ [TCA_OF_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 },
+ [TCA_OF_KEY_IPV4_DST] = { .type = NLA_U32 },
+ [TCA_OF_KEY_IPV4_DST_MASK] = { .type = NLA_U32 },
+ [TCA_OF_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) },
+ [TCA_OF_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
+ [TCA_OF_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) },
+ [TCA_OF_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
+ [TCA_OF_KEY_TP_SRC] = { .type = NLA_U16 },
+ [TCA_OF_KEY_TP_SRC_MASK] = { .type = NLA_U16 },
+ [TCA_OF_KEY_TP_DST] = { .type = NLA_U16 },
+ [TCA_OF_KEY_TP_DST_MASK] = { .type = NLA_U16 },
+};
+
+static void of_set_key_val(struct nlattr **tb,
+ void *val, int val_type,
+ void *mask, int mask_type, int len)
+{
+ if (!tb[val_type])
+ return;
+ memcpy(val, nla_data(tb[val_type]), len);
+ if (!tb[mask_type])
+ memset(mask, 0xff, len);
+ else
+ memcpy(mask, nla_data(tb[mask_type]), len);
+}
+
+static int of_set_parms(struct net *net, struct tcf_proto *tp,
+ struct cls_of_filter *f, unsigned long base,
+ struct nlattr **tb, struct nlattr *est, bool ovr)
+{
+ struct tcf_exts e;
+ struct of_flow_key *key, *mask;
+ int err;
+
+ tcf_exts_init(&e, TCA_OF_ACT, TCA_OF_POLICE);
+ err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+ if (err < 0)
+ return err;
+
+ if (tb[TCA_OF_CLASSID]) {
+ f->res.classid = nla_get_u32(tb[TCA_OF_CLASSID]);
+ tcf_bind_filter(tp, &f->res, base);
+ }
+
+ key = &f->match.key;
+ mask = &f->match.mask;
+
+ if (tb[TCA_OF_INDEV]) {
+ err = tcf_change_indev(net, tb[TCA_OF_INDEV]);
+ if (err < 0)
+ goto errout;
+ key->indev_ifindex = err;
+ mask->indev_ifindex = 0xffffffff;
+ }
+
+ of_set_key_val(tb, key->eth.dst, TCA_OF_KEY_ETH_DST,
+ mask->eth.dst, TCA_OF_KEY_ETH_DST_MASK,
+ sizeof(key->eth.dst));
+ of_set_key_val(tb, key->eth.src, TCA_OF_KEY_ETH_SRC,
+ mask->eth.src, TCA_OF_KEY_ETH_SRC_MASK,
+ sizeof(key->eth.src));
+ of_set_key_val(tb, &key->eth.type, TCA_OF_KEY_ETH_TYPE,
+ &mask->eth.type, TCA_OF_KEY_ETH_TYPE_MASK,
+ sizeof(key->eth.type));
+ of_set_key_val(tb, &key->ip.proto, TCA_OF_KEY_IP_PROTO,
+ &mask->ip.proto, TCA_OF_KEY_IP_PROTO_MASK,
+ sizeof(key->ip.proto));
+ of_set_key_val(tb, &key->ipv4.src, TCA_OF_KEY_IPV4_SRC,
+ &mask->ipv4.src, TCA_OF_KEY_IPV4_SRC_MASK,
+ sizeof(key->ipv4.src));
+ of_set_key_val(tb, &key->ipv4.dst, TCA_OF_KEY_IPV4_DST,
+ &mask->ipv4.dst, TCA_OF_KEY_IPV4_DST_MASK,
+ sizeof(key->ipv4.dst));
+ of_set_key_val(tb, &key->ipv6.src, TCA_OF_KEY_IPV6_SRC,
+ &mask->ipv6.src, TCA_OF_KEY_IPV6_SRC_MASK,
+ sizeof(key->ipv6.src));
+ of_set_key_val(tb, &key->ipv6.dst, TCA_OF_KEY_IPV6_DST,
+ &mask->ipv6.dst, TCA_OF_KEY_IPV6_DST_MASK,
+ sizeof(key->ipv6.dst));
+ of_set_key_val(tb, &key->tp.src, TCA_OF_KEY_TP_SRC,
+ &mask->tp.src, TCA_OF_KEY_TP_SRC_MASK,
+ sizeof(key->tp.src));
+ of_set_key_val(tb, &key->tp.dst, TCA_OF_KEY_TP_DST,
+ &mask->tp.dst, TCA_OF_KEY_TP_SRC_MASK,
+ sizeof(key->tp.dst));
+
+ tcf_exts_change(tp, &f->exts, &e);
+ f->tp = tp;
+
+ return 0;
+errout:
+ tcf_exts_destroy(&e);
+ return err;
+}
+
+static u32 of_grab_new_handle(struct tcf_proto *tp,
+ struct cls_of_head *head)
+{
+ unsigned int i = 0x80000000;
+ u32 handle;
+
+ do {
+ if (++head->hgen == 0x7FFFFFFF)
+ head->hgen = 1;
+ } while (--i > 0 && of_get(tp, head->hgen));
+
+ if (unlikely(i == 0)) {
+ pr_err("Insufficient number of handles\n");
+ handle = 0;
+ } else {
+ handle = head->hgen;
+ }
+
+ return handle;
+}
+
+static int of_change(struct net *net, struct sk_buff *in_skb,
+ struct tcf_proto *tp, unsigned long base,
+ u32 handle, struct nlattr **tca,
+ unsigned long *arg, bool ovr)
+{
+ struct cls_of_head *head = rtnl_dereference(tp->root);
+ struct cls_of_filter *fold = (struct cls_of_filter *) *arg;
+ struct cls_of_filter *fnew;
+ struct nlattr *tb[TCA_OF_MAX + 1];
+ int err;
+
+ if (!tca[TCA_OPTIONS])
+ return -EINVAL;
+
+ err = nla_parse_nested(tb, TCA_OF_MAX, tca[TCA_OPTIONS], of_policy);
+ if (err < 0)
+ return err;
+
+ if (fold && handle && fold->handle != handle)
+ return -EINVAL;
+
+ fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
+ if (!fnew)
+ return -ENOBUFS;
+
+ tcf_exts_init(&fnew->exts, TCA_OF_ACT, TCA_OF_POLICE);
+
+ if (!handle) {
+ handle = of_grab_new_handle(tp, head);
+ if (!handle) {
+ err = -EINVAL;
+ goto errout;
+ }
+ }
+ fnew->handle = handle;
+
+ err = of_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr);
+ if (err < 0)
+ goto errout;
+
+ *arg = (unsigned long) fnew;
+
+ if (fold) {
+ list_replace_rcu(&fnew->list, &fold->list);
+ tcf_unbind_filter(tp, &fold->res);
+ call_rcu(&fold->rcu, of_destroy_filter);
+ } else {
+ list_add_tail_rcu(&fnew->list, &head->filters);
+ }
+
+ return 0;
+
+errout:
+ kfree(fnew);
+ return err;
+}
+
+static int of_delete(struct tcf_proto *tp, unsigned long arg)
+{
+ struct cls_of_filter *f = (struct cls_of_filter *) arg;
+
+ list_del_rcu(&f->list);
+ tcf_unbind_filter(tp, &f->res);
+ call_rcu(&f->rcu, of_destroy_filter);
+ return 0;
+}
+
+static void of_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+{
+ struct cls_of_head *head = rtnl_dereference(tp->root);
+ struct cls_of_filter *f;
+
+ list_for_each_entry_rcu(f, &head->filters, list) {
+ if (arg->count < arg->skip)
+ goto skip;
+ if (arg->fn(tp, (unsigned long) f, arg) < 0) {
+ arg->stop = 1;
+ break;
+ }
+skip:
+ arg->count++;
+ }
+}
+
+static int of_dump_key_val(struct sk_buff *skb,
+ void *val, int val_type,
+ void *mask, int mask_type, int len)
+{
+ int err;
+
+ if (!memchr_inv(mask, 0, len))
+ return 0;
+ err = nla_put(skb, val_type, len, val);
+ if (err)
+ return err;
+ err = nla_put(skb, mask_type, len, mask);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int of_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
+ struct sk_buff *skb, struct tcmsg *t)
+{
+ struct cls_of_filter *f = (struct cls_of_filter *) fh;
+ struct nlattr *nest;
+ struct of_flow_key *key, *mask;
+
+ if (!f)
+ return skb->len;
+
+ t->tcm_handle = f->handle;
+
+ nest = nla_nest_start(skb, TCA_OPTIONS);
+ if (!nest)
+ goto nla_put_failure;
+
+ if (f->res.classid &&
+ nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid))
+ goto nla_put_failure;
+
+ key = &f->match.key;
+ mask = &f->match.mask;
+
+ if (mask->indev_ifindex) {
+ struct net_device *dev;
+
+ dev = __dev_get_by_index(net, key->indev_ifindex);
+ if (dev && nla_put_string(skb, TCA_OF_INDEV, dev->name))
+ goto nla_put_failure;
+ }
+
+ if (of_dump_key_val(skb, key->eth.dst, TCA_OF_KEY_ETH_DST,
+ mask->eth.dst, TCA_OF_KEY_ETH_DST_MASK,
+ sizeof(key->eth.dst)) ||
+ of_dump_key_val(skb, key->eth.src, TCA_OF_KEY_ETH_SRC,
+ mask->eth.src, TCA_OF_KEY_ETH_SRC_MASK,
+ sizeof(key->eth.src)) ||
+ of_dump_key_val(skb, &key->eth.type, TCA_OF_KEY_ETH_TYPE,
+ &mask->eth.type, TCA_OF_KEY_ETH_TYPE_MASK,
+ sizeof(key->eth.type)) ||
+ of_dump_key_val(skb, &key->ip.proto, TCA_OF_KEY_IP_PROTO,
+ &mask->ip.proto, TCA_OF_KEY_IP_PROTO_MASK,
+ sizeof(key->ip.proto)) ||
+ of_dump_key_val(skb, &key->ipv4.src, TCA_OF_KEY_IPV4_SRC,
+ &mask->ipv4.src, TCA_OF_KEY_IPV4_SRC_MASK,
+ sizeof(key->ipv4.src)) ||
+ of_dump_key_val(skb, &key->ipv4.dst, TCA_OF_KEY_IPV4_DST,
+ &mask->ipv4.dst, TCA_OF_KEY_IPV4_DST_MASK,
+ sizeof(key->ipv4.dst)) ||
+ of_dump_key_val(skb, &key->ipv6.src, TCA_OF_KEY_IPV6_SRC,
+ &mask->ipv6.src, TCA_OF_KEY_IPV6_SRC_MASK,
+ sizeof(key->ipv6.src)) ||
+ of_dump_key_val(skb, &key->ipv6.dst, TCA_OF_KEY_IPV6_DST,
+ &mask->ipv6.dst, TCA_OF_KEY_IPV6_DST_MASK,
+ sizeof(key->ipv6.dst)) ||
+ of_dump_key_val(skb, &key->tp.src, TCA_OF_KEY_TP_SRC,
+ &mask->tp.src, TCA_OF_KEY_TP_SRC_MASK,
+ sizeof(key->tp.src)) ||
+ of_dump_key_val(skb, &key->tp.dst, TCA_OF_KEY_TP_DST,
+ &mask->tp.dst, TCA_OF_KEY_TP_DST_MASK,
+ sizeof(key->tp.dst)))
+ goto nla_put_failure;
+
+ if (tcf_exts_dump(skb, &f->exts))
+ goto nla_put_failure;
+
+ nla_nest_end(skb, nest);
+
+ if (tcf_exts_dump_stats(skb, &f->exts) < 0)
+ goto nla_put_failure;
+
+ return skb->len;
+
+nla_put_failure:
+ nla_nest_cancel(skb, nest);
+ return -1;
+}
+
+static struct tcf_proto_ops cls_of_ops __read_mostly = {
+ .kind = "openflow",
+ .classify = of_classify,
+ .init = of_init,
+ .destroy = of_destroy,
+ .get = of_get,
+ .change = of_change,
+ .delete = of_delete,
+ .walk = of_walk,
+ .dump = of_dump,
+ .owner = THIS_MODULE,
+};
+
+static int __init cls_of_init(void)
+{
+ return register_tcf_proto_ops(&cls_of_ops);
+}
+
+static void __exit cls_of_exit(void)
+{
+ unregister_tcf_proto_ops(&cls_of_ops);
+}
+
+module_init(cls_of_init);
+module_exit(cls_of_exit);
+
+MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
+MODULE_DESCRIPTION("OpenFlow classifier");
+MODULE_LICENSE("GPL v2");
--
1.9.3
^ permalink raw reply related
* Re: [net-next PATCH v3 00/12] Flow API
From: Thomas Graf @ 2015-01-22 13:37 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: John Fastabend, simon.horman, sfeldma, netdev, jhs, davem,
gerlitz.or, andy, ast
In-Reply-To: <20150122125246.GA4486@salvia>
On 01/22/15 at 01:52pm, Pablo Neira Ayuso wrote:
> Hi John,
>
> On Tue, Jan 20, 2015 at 12:26:13PM -0800, John Fastabend wrote:
> > I believe I addressed all the comments so far except for the integrate
> > with 'tc'. I plan to work on the integration pieces next.
>
> I think that postponing the integration with 'tc' means that we're
> renouncing to provide some abstraction to represent the actions that
> the device provides. After this patch we'll have a standard API that
> exposes the vendor specific semantics, *so user configurations will
> not be portable anymore*.
>
> At least, we should come up with some abstraction / mapping as
> interface, so the vendors can use them to represent their operations.
> That interface will provide a trade-off: If the vendor offers an
> operation that doesn't map to our abstraction, then sorry that
> operation has to remain behind the curtain.
I thought this *is* the abstraction ;-) Can you elaborate on which
parts you consider vendor specific?
^ permalink raw reply
* Re: [bisected] no traffic on ssl vpn with 3.19rc1 - 3.19rc3
From: Billy Shuman @ 2015-01-22 13:43 UTC (permalink / raw)
To: Herbert Xu; +Cc: netdev
In-Reply-To: <CAHQNsodDfSOgmxoSk6++OQXfJ7SHo+M=bmojfUqN1KFJHtfemg@mail.gmail.com>
This patch from net-next ended up resolving my issue:
>From 957f094f221f81e457133b1f4c4d95ffa49ff731 Mon Sep 17 00:00:00 2001
From: Alex Gartrell <agartrell@fb.com>
Date: Thu, 25 Dec 2014 23:22:49 -0800
Subject: tun: return proper error code from tun_do_read
Instead of -1 with EAGAIN, read on a O_NONBLOCK tun fd will return 0. This
fixes this by properly returning the error code from __skb_recv_datagram.
On Fri, Jan 9, 2015 at 8:13 AM, Billy Shuman <wshuman3@gmail.com> wrote:
> Changeset 8c847d254146d32c86574a1b16923ff91bb784dd did not resolve the
> issue for me.
>
> Should I target any other specific changesets?
>
> Thanks,
> Billy
> William Shuman
> Tel: 260-316-9300
> Email: wshuman3@gmail.com
>
>
> On Thu, Jan 8, 2015 at 3:57 PM, Herbert Xu <herbert@gondor.apana.org.au> wrote:
>> Billy Shuman <wshuman3@gmail.com> wrote:
>>>
>>> Since 3.19rc1 I get 100% packet loss through SSL vpn. I bisected with
>>> the following result:
>>>
>>> 0b46d0ee9c240c7430a47e9b0365674d4a04522 is the first bad commit
>>> commit e0b46d0ee9c240c7430a47e9b0365674d4a04522
>>> Author: Herbert Xu <herbert@gondor.apana.org.au>
>>> Date: Fri Nov 7 21:22:23 2014 +0800
>>>
>>> tun: Use iovec iterators
>>>
>>> This patch removes the use of skb_copy_datagram_const_iovec in
>>> favour of the iovec iterator-based skb_copy_datagram_iter.
>>>
>>>
>>> https://bugzilla.kernel.org/show_bug.cgi?id=90901
>>
>> This changeset is known to be buggy. However it was fixed ages
>> ago by changeset 8c847d254146d32c86574a1b16923ff91bb784dd.
>>
>> So please test that changeset to see if it works for you. If it
>> does, then please do your bisection between that and the current
>> top of tree.
>>
>> Thanks,
>> --
>> Email: Herbert Xu <herbert@gondor.apana.org.au>
>> Home Page: http://gondor.apana.org.au/~herbert/
>> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* RE: [patch net-next RFC] tc: introduce OpenFlow classifier
From: Rosen, Rami @ 2015-01-22 13:48 UTC (permalink / raw)
To: Jiri Pirko, netdev@vger.kernel.org; +Cc: davem@davemloft.net, jhs@mojatatu.com
In-Reply-To: <1421933824-17916-1-git-send-email-jiri@resnulli.us>
+config NET_CLS_OPENFLOW
+ tristate "OpenFlow classifier"
+ select NET_CLS
+ ---help---
+ If you say Y here, you will be able to classify packets based on
+ a configurable combination of packet keys and masks accordint to
+ OpenFlow standard.
+
Should be: according to
Regards,
Rami Rosen
^ permalink raw reply
* Re: [PATCH] brcmfmac: avoid duplicated suspend/resume operation
From: Kalle Valo @ 2015-01-22 13:49 UTC (permalink / raw)
To: Fu, Zhonghui
Cc: brudley-dY08KVG/lbpWk0Htik3J/w, Arend van Spriel, Franky Lin,
meuleman-dY08KVG/lbpWk0Htik3J/w, linville-2XuSBdqkA4R54TAoqtyWWQ,
pieterpg-dY08KVG/lbpWk0Htik3J/w, hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
wens-jdAy2FN1RRM, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
brcm80211-dev-list-dY08KVG/lbpWk0Htik3J/w,
netdev-u79uwXL29TY76Z2rM5mHXA, linux-kernel@vger.kernel.org
In-Reply-To: <54BDCC06.8090107-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
"Fu, Zhonghui" <zhonghui.fu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org> writes:
>>From 04d3fa673897ca4ccbea6c76836d0092dba2484a Mon Sep 17 00:00:00 2001
> From: Zhonghui Fu <zhonghui.fu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Date: Tue, 20 Jan 2015 11:14:13 +0800
> Subject: [PATCH] brcmfmac: avoid duplicated suspend/resume operation
>
> WiFi chip has 2 SDIO functions, and PM core will trigger
> twice suspend/resume operations for one WiFi chip to do
> the same things. This patch avoid this case.
>
> Acked-by: Arend van Spriel <arend-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> Acked-by: Sergei Shtylyov <sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
> Acked-by: Kalle Valo <kvalo-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> Signed-off-by: Zhonghui Fu <zhonghui.fu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
I don't remember giving Acked-by to this (or for matter to anything for
a long time). What about Sergei or Arend?
Please do not add Acked-by, Signed-off-by or any other tags unless
explicitly specified by the person in question. I'm dropping this,
please resend with real Acked-by lines.
--
Kalle Valo
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" 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 4/4] sh_eth: Fix serialisation of interrupt disable with interrupt & NAPI handlers
From: Sergei Shtylyov @ 2015-01-22 13:50 UTC (permalink / raw)
To: Ben Hutchings, David S.Miller
Cc: netdev, linux-kernel, Nobuhiro Iwamatsu, Mitsuhiro Kimura,
Hisashi Nakamura, Yoshihiro Kaneko
In-Reply-To: <1421930648.1222.289.camel@xylophone.i.decadent.org.uk>
Hello.
On 1/22/2015 3:44 PM, Ben Hutchings wrote:
> In order to stop the RX path accessing the RX ring while it's being
> stopped or resized, we clear the interrupt mask (EESIPR) and then call
> free_irq() or synchronise_irq(). This is insufficient because the
> interrupt handler or NAPI poller may set EESIPR again after we clear
> it.
Hm, how come the interrupt handler gets called when we have disabled all
interrupts? Is it unmaskable EESR.ECI interrupt? BTW, I'm not seeing where the
interrupt handler enables interrupts again; only NAPI poller does that AFAIK.
> Also, in sh_eth_set_ringparam() we currently don't disable NAPI
> polling at all.
> I could easily trigger a crash by running the loop:
> while ethtool -G eth0 rx 128 && ethtool -G eth0 rx 64; do echo -n .; done
Oh, never done any 'ethtool' tests...
> and 'ping -f' toward the sh_eth port from another machine.
To fix this:
> - Add a software flag (irq_enabled) to signal whether interrupts
> should be enabled
> - In the interrupt handler, if the flag is clear then clear EESIPR
> and return
> - In the NAPI poller, if the flag is clear then don't set EESIPR
> - Set the flag before enabling interrupts in sh_eth_dev_init() and
> sh_eth_set_ringparam()
> - Clear the flag and serialise with the interrupt and NAPI
> handlers before clearing EESIPR in sh_eth_close() and
> sh_eth_set_ringparam()
> After this, I could run the loop for 100,000 iterations successfully.
> Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
[...]
> diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
> index 7bfaf1c..259d03f 100644
> --- a/drivers/net/ethernet/renesas/sh_eth.h
> +++ b/drivers/net/ethernet/renesas/sh_eth.h
> @@ -513,6 +513,7 @@ struct sh_eth_private {
> u32 rx_buf_sz; /* Based on MTU+slack. */
> int edmac_endian;
> struct napi_struct napi;
> + bool irq_enabled;
> /* MII transceiver section. */
> u32 phy_id; /* PHY ID */
> struct mii_bus *mii_bus; /* MDIO bus control */
In order to conserve space, I'd have added that field after
'vlan_num_ids', just before the 1-bit fields...
WBR, Sergei
^ permalink raw reply
* Re: [PATCH] brcmfmac: avoid duplicated suspend/resume operation
From: Sergei Shtylyov @ 2015-01-22 13:54 UTC (permalink / raw)
To: Kalle Valo, Fu, Zhonghui
Cc: brudley-dY08KVG/lbpWk0Htik3J/w, Arend van Spriel, Franky Lin,
meuleman-dY08KVG/lbpWk0Htik3J/w, linville-2XuSBdqkA4R54TAoqtyWWQ,
pieterpg-dY08KVG/lbpWk0Htik3J/w, hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
wens-jdAy2FN1RRM, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
brcm80211-dev-list-dY08KVG/lbpWk0Htik3J/w,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <87twzincvz.fsf-HodKDYzPHsUD5k0oWYwrnHL1okKdlPRT@public.gmane.org>
Hello.
On 1/22/2015 4:49 PM, Kalle Valo wrote:
>> >From 04d3fa673897ca4ccbea6c76836d0092dba2484a Mon Sep 17 00:00:00 2001
>> From: Zhonghui Fu <zhonghui.fu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
>> Date: Tue, 20 Jan 2015 11:14:13 +0800
>> Subject: [PATCH] brcmfmac: avoid duplicated suspend/resume operation
>> WiFi chip has 2 SDIO functions, and PM core will trigger
>> twice suspend/resume operations for one WiFi chip to do
>> the same things. This patch avoid this case.
>> Acked-by: Arend van Spriel <arend-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
>> Acked-by: Sergei Shtylyov <sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
>> Acked-by: Kalle Valo <kvalo-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> Signed-off-by: Zhonghui Fu <zhonghui.fu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> I don't remember giving Acked-by to this (or for matter to anything for
> a long time). What about Sergei or Arend?
I haven't ACK'ed this patch either.
WBR, Sergei
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" 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: [net-next PATCH v3 00/12] Flow API
From: Pablo Neira Ayuso @ 2015-01-22 14:00 UTC (permalink / raw)
To: Thomas Graf
Cc: John Fastabend, simon.horman, sfeldma, netdev, jhs, davem,
gerlitz.or, andy, ast
In-Reply-To: <20150122133713.GA25797@casper.infradead.org>
On Thu, Jan 22, 2015 at 01:37:13PM +0000, Thomas Graf wrote:
> On 01/22/15 at 01:52pm, Pablo Neira Ayuso wrote:
> > Hi John,
> >
> > On Tue, Jan 20, 2015 at 12:26:13PM -0800, John Fastabend wrote:
> > > I believe I addressed all the comments so far except for the integrate
> > > with 'tc'. I plan to work on the integration pieces next.
> >
> > I think that postponing the integration with 'tc' means that we're
> > renouncing to provide some abstraction to represent the actions that
> > the device provides. After this patch we'll have a standard API that
> > exposes the vendor specific semantics, *so user configurations will
> > not be portable anymore*.
> >
> > At least, we should come up with some abstraction / mapping as
> > interface, so the vendors can use them to represent their operations.
> > That interface will provide a trade-off: If the vendor offers an
> > operation that doesn't map to our abstraction, then sorry that
> > operation has to remain behind the curtain.
>
> I thought this *is* the abstraction ;-) Can you elaborate on which
> parts you consider vendor specific?
+/* rocker specific action definitions */
+struct net_flow_action_arg rocker_set_group_id_args[] = {
+ {
+ .name = "group_id",
+ .type = NFL_ACTION_ARG_TYPE_U32,
+ .value_u32 = 0,
+ },
that is retrieved via ndo_flow_get_actions and fully exposed to
userspace.
^ permalink raw reply
* Re: [PATCH net-next 0/9] mlx4: Fix and enhance the device reset flow
From: Or Gerlitz @ 2015-01-22 14:05 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Matan Barak, Amir Vadai, Tal Alon, Roland Dreier
In-Reply-To: <1421851557-12084-1-git-send-email-ogerlitz@mellanox.com>
On 1/21/2015 4:45 PM, Or Gerlitz wrote:
> This series from Yishai Hadas fixes the device reset flow and adds SRIOV support.
>
> Reset flows are required whenever a device experiences errors, is unresponsive,
> or is not in a deterministic state. In such cases, the driver is expected to
> reset the HW and continue operation. When SRIOV is enabled, these requirements
> apply both to PF and VF devices.
So we spotted some problem in the SRIOV flow and prefer to fix it in a
V1, which will be sent next week, please don't take this one.
Or.
^ permalink raw reply
* [PATCH v3] net: mv643xx_eth: Fix highmem support in non-TSO egress path
From: Ezequiel Garcia @ 2015-01-22 14:33 UTC (permalink / raw)
To: David Miller, Russell King
Cc: netdev, B38611, fabio.estevam, David.Laight, Ezequiel Garcia
In-Reply-To: <1421928859-17923-1-git-send-email-ezequiel.garcia@free-electrons.com>
Commit 69ad0dd7af22b61d9e0e68e56b6290121618b0fb
Author: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Date: Mon May 19 13:59:59 2014 -0300
net: mv643xx_eth: Use dma_map_single() to map the skb fragments
caused a nasty regression by removing the support for highmem skb
fragments. By using page_address() to get the address of a fragment's
page, we are assuming a lowmem page. However, such assumption is incorrect,
as fragments can be in highmem pages, resulting in very nasty issues.
This commit fixes this by using the skb_frag_dma_map() helper,
which takes care of mapping the skb fragment properly. Additionally,
the type of mapping is now tracked, so it can be unmapped using
dma_unmap_page or dma_unmap_single when appropriate.
This commit also fixes the error path in txq_init() to release the
resources properly.
Fixes: 69ad0dd7af22 ("net: mv643xx_eth: Use dma_map_single() to map the skb fragments")
Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
Changes from v2:
* Add proper resource release in txq_init() error path
Changes from v1:
* Sending the mv643xx_eth fix for now.
* Fix DMA mapping type track, to use the correct unmap call.
---
drivers/net/ethernet/marvell/mv643xx_eth.c | 59 +++++++++++++++++++++++++-----
1 file changed, 49 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index a62fc38..1c75829 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -192,6 +192,10 @@ static char mv643xx_eth_driver_version[] = "1.4";
#define IS_TSO_HEADER(txq, addr) \
((addr >= txq->tso_hdrs_dma) && \
(addr < txq->tso_hdrs_dma + txq->tx_ring_size * TSO_HEADER_SIZE))
+
+#define DESC_DMA_MAP_SINGLE 0
+#define DESC_DMA_MAP_PAGE 1
+
/*
* RX/TX descriptors.
*/
@@ -362,6 +366,7 @@ struct tx_queue {
dma_addr_t tso_hdrs_dma;
struct tx_desc *tx_desc_area;
+ char *tx_desc_mapping; /* array to track the type of the dma mapping */
dma_addr_t tx_desc_dma;
int tx_desc_area_size;
@@ -750,6 +755,7 @@ txq_put_data_tso(struct net_device *dev, struct tx_queue *txq,
if (txq->tx_curr_desc == txq->tx_ring_size)
txq->tx_curr_desc = 0;
desc = &txq->tx_desc_area[tx_index];
+ txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_SINGLE;
desc->l4i_chk = 0;
desc->byte_cnt = length;
@@ -879,14 +885,13 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb)
skb_frag_t *this_frag;
int tx_index;
struct tx_desc *desc;
- void *addr;
this_frag = &skb_shinfo(skb)->frags[frag];
- addr = page_address(this_frag->page.p) + this_frag->page_offset;
tx_index = txq->tx_curr_desc++;
if (txq->tx_curr_desc == txq->tx_ring_size)
txq->tx_curr_desc = 0;
desc = &txq->tx_desc_area[tx_index];
+ txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_PAGE;
/*
* The last fragment will generate an interrupt
@@ -902,8 +907,9 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb)
desc->l4i_chk = 0;
desc->byte_cnt = skb_frag_size(this_frag);
- desc->buf_ptr = dma_map_single(mp->dev->dev.parent, addr,
- desc->byte_cnt, DMA_TO_DEVICE);
+ desc->buf_ptr = skb_frag_dma_map(mp->dev->dev.parent,
+ this_frag, 0, desc->byte_cnt,
+ DMA_TO_DEVICE);
}
}
@@ -936,6 +942,7 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb,
if (txq->tx_curr_desc == txq->tx_ring_size)
txq->tx_curr_desc = 0;
desc = &txq->tx_desc_area[tx_index];
+ txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_SINGLE;
if (nr_frags) {
txq_submit_frag_skb(txq, skb);
@@ -1047,9 +1054,12 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
int tx_index;
struct tx_desc *desc;
u32 cmd_sts;
+ char desc_dma_map;
tx_index = txq->tx_used_desc;
desc = &txq->tx_desc_area[tx_index];
+ desc_dma_map = txq->tx_desc_mapping[tx_index];
+
cmd_sts = desc->cmd_sts;
if (cmd_sts & BUFFER_OWNED_BY_DMA) {
@@ -1065,9 +1075,19 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
reclaimed++;
txq->tx_desc_count--;
- if (!IS_TSO_HEADER(txq, desc->buf_ptr))
- dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr,
- desc->byte_cnt, DMA_TO_DEVICE);
+ if (!IS_TSO_HEADER(txq, desc->buf_ptr)) {
+
+ if (desc_dma_map == DESC_DMA_MAP_PAGE)
+ dma_unmap_page(mp->dev->dev.parent,
+ desc->buf_ptr,
+ desc->byte_cnt,
+ DMA_TO_DEVICE);
+ else
+ dma_unmap_single(mp->dev->dev.parent,
+ desc->buf_ptr,
+ desc->byte_cnt,
+ DMA_TO_DEVICE);
+ }
if (cmd_sts & TX_ENABLE_INTERRUPT) {
struct sk_buff *skb = __skb_dequeue(&txq->tx_skb);
@@ -1996,6 +2016,7 @@ static int txq_init(struct mv643xx_eth_private *mp, int index)
struct tx_queue *txq = mp->txq + index;
struct tx_desc *tx_desc;
int size;
+ int ret;
int i;
txq->index = index;
@@ -2048,18 +2069,34 @@ static int txq_init(struct mv643xx_eth_private *mp, int index)
nexti * sizeof(struct tx_desc);
}
+ txq->tx_desc_mapping = kcalloc(txq->tx_ring_size, sizeof(char),
+ GFP_KERNEL);
+ if (!txq->tx_desc_mapping) {
+ ret = -ENOMEM;
+ goto err_free_desc_area;
+ }
+
/* Allocate DMA buffers for TSO MAC/IP/TCP headers */
txq->tso_hdrs = dma_alloc_coherent(mp->dev->dev.parent,
txq->tx_ring_size * TSO_HEADER_SIZE,
&txq->tso_hdrs_dma, GFP_KERNEL);
if (txq->tso_hdrs == NULL) {
- dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size,
- txq->tx_desc_area, txq->tx_desc_dma);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_free_desc_mapping;
}
skb_queue_head_init(&txq->tx_skb);
return 0;
+
+err_free_desc_mapping:
+ kfree(txq->tx_desc_mapping);
+err_free_desc_area:
+ if (index == 0 && size <= mp->tx_desc_sram_size)
+ iounmap(txq->tx_desc_area);
+ else
+ dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size,
+ txq->tx_desc_area, txq->tx_desc_dma);
+ return ret;
}
static void txq_deinit(struct tx_queue *txq)
@@ -2077,6 +2114,8 @@ static void txq_deinit(struct tx_queue *txq)
else
dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size,
txq->tx_desc_area, txq->tx_desc_dma);
+ kfree(txq->tx_desc_mapping);
+
if (txq->tso_hdrs)
dma_free_coherent(mp->dev->dev.parent,
txq->tx_ring_size * TSO_HEADER_SIZE,
--
2.2.1
^ permalink raw reply related
* Re: [net-next PATCH v3 00/12] Flow API
From: Jamal Hadi Salim @ 2015-01-22 15:00 UTC (permalink / raw)
To: Pablo Neira Ayuso, Thomas Graf
Cc: John Fastabend, simon.horman, sfeldma, netdev, davem, gerlitz.or,
andy, ast, Jiri Pirko
In-Reply-To: <20150122140022.GA5674@salvia>
On 01/22/15 09:00, Pablo Neira Ayuso wrote:
>
> +/* rocker specific action definitions */
> +struct net_flow_action_arg rocker_set_group_id_args[] = {
> + {
> + .name = "group_id",
> + .type = NFL_ACTION_ARG_TYPE_U32,
> + .value_u32 = 0,
> + },
>
> that is retrieved via ndo_flow_get_actions and fully exposed to
> userspace.
>
My main concern is along similar lines (I did express it earlier and
I think Jiri chimed in as well).
The API exposes direct access to hardware. I am sure this was a result
of trying to replace the ethtool interface (which was primitive).
By providing vendors direct access to the hardware - they do not need
to use any traditional Linux tooling/APIs. I see this as a gaping hole
for vendor SDKs with their own definitions of their own hardware that
doesnt work with anyone else. i.e it seems to standardize proprietary
interfaces. Maybe thats what Pablo is alluding to.
Interfacing tc or nftables (or pick your favorite linux tool here) would
be preferable.
cheers,
jamal
^ permalink raw reply
* Re: [PATCH net 4/4] sh_eth: Fix serialisation of interrupt disable with interrupt & NAPI handlers
From: Ben Hutchings @ 2015-01-22 15:06 UTC (permalink / raw)
To: Sergei Shtylyov
Cc: David S.Miller, netdev, linux-kernel, Nobuhiro Iwamatsu,
Mitsuhiro Kimura, Hisashi Nakamura, Yoshihiro Kaneko
In-Reply-To: <54C1002D.7090508@cogentembedded.com>
On Thu, 2015-01-22 at 16:50 +0300, Sergei Shtylyov wrote:
> Hello.
>
> On 1/22/2015 3:44 PM, Ben Hutchings wrote:
>
> > In order to stop the RX path accessing the RX ring while it's being
> > stopped or resized, we clear the interrupt mask (EESIPR) and then call
> > free_irq() or synchronise_irq(). This is insufficient because the
> > interrupt handler or NAPI poller may set EESIPR again after we clear
> > it.
>
> Hm, how come the interrupt handler gets called when we have disabled all
> interrupts?
It may be running on another processor and racing with the function that
clears EESIPR.
> Is it unmaskable EESR.ECI interrupt? BTW, I'm not seeing where the
> interrupt handler enables interrupts again; only NAPI poller does that AFAIK.
Normally it only clears EESR_RX_CHECK, but as it cannot atomically clear
a single bit of EESIPR this can result in setting other bits.
> > Also, in sh_eth_set_ringparam() we currently don't disable NAPI
> > polling at all.
>
> > I could easily trigger a crash by running the loop:
>
> > while ethtool -G eth0 rx 128 && ethtool -G eth0 rx 64; do echo -n .; done
>
> Oh, never done any 'ethtool' tests...
You should also be able to trigger this by bringing the device up and
down, but you have to wait for the PHY to bring the link up before any
packets will be received in between. Thus each cycle takes longer.
[...]
> > diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
> > index 7bfaf1c..259d03f 100644
> > --- a/drivers/net/ethernet/renesas/sh_eth.h
> > +++ b/drivers/net/ethernet/renesas/sh_eth.h
> > @@ -513,6 +513,7 @@ struct sh_eth_private {
> > u32 rx_buf_sz; /* Based on MTU+slack. */
> > int edmac_endian;
> > struct napi_struct napi;
> > + bool irq_enabled;
> > /* MII transceiver section. */
> > u32 phy_id; /* PHY ID */
> > struct mii_bus *mii_bus; /* MDIO bus control */
>
> In order to conserve space, I'd have added that field after
> 'vlan_num_ids', just before the 1-bit fields...
I don't think it's worth micro-optimising the size of a per-device
structure.
Ben.
^ permalink raw reply
* Re: [net-next PATCH v3 00/12] Flow API
From: Thomas Graf @ 2015-01-22 15:13 UTC (permalink / raw)
To: Jamal Hadi Salim
Cc: Pablo Neira Ayuso, John Fastabend, simon.horman, sfeldma, netdev,
davem, gerlitz.or, andy, ast, Jiri Pirko
In-Reply-To: <54C11094.2000807@mojatatu.com>
On 01/22/15 at 10:00am, Jamal Hadi Salim wrote:
> On 01/22/15 09:00, Pablo Neira Ayuso wrote:
>
> >
> >+/* rocker specific action definitions */
> >+struct net_flow_action_arg rocker_set_group_id_args[] = {
> >+ {
> >+ .name = "group_id",
> >+ .type = NFL_ACTION_ARG_TYPE_U32,
> >+ .value_u32 = 0,
> >+ },
> >
> >that is retrieved via ndo_flow_get_actions and fully exposed to
> >userspace.
> >
>
> My main concern is along similar lines (I did express it earlier and
> I think Jiri chimed in as well).
> The API exposes direct access to hardware. I am sure this was a result
> of trying to replace the ethtool interface (which was primitive).
> By providing vendors direct access to the hardware - they do not need
> to use any traditional Linux tooling/APIs.
I don't follow this. John's proposal allows to decide on a case by
case basis what we want to export. Just like with ethtool or
RTNETLINK. There is no direct access to hardware. A user can only
configure what is being exposed by the kernel.
Pablo raises an interesting point though. How do we handle unique
features like Rocker groups.
Maybe Jiri and Scott can chime in and describe if we can map this to
something more generic and avoid exporting anything Rocker specific.
What would a rocker group map to in the tc world?
> I see this as a gaping hole
> for vendor SDKs with their own definitions of their own hardware that
> doesnt work with anyone else. i.e it seems to standardize proprietary
> interfaces. Maybe thats what Pablo is alluding to.
I will be the first to root for rejection if such patches appear.
^ permalink raw reply
* Re: [patch net-next RFC] tc: introduce OpenFlow classifier
From: Jiri Pirko @ 2015-01-22 15:25 UTC (permalink / raw)
To: Rosen, Rami; +Cc: netdev@vger.kernel.org, davem@davemloft.net, jhs@mojatatu.com
In-Reply-To: <9B0331B6EBBD0E4684FBFAEDA55776F918903CD5@HASMSX110.ger.corp.intel.com>
Thu, Jan 22, 2015 at 02:48:29PM CET, rami.rosen@intel.com wrote:
>+config NET_CLS_OPENFLOW
>+ tristate "OpenFlow classifier"
>+ select NET_CLS
>+ ---help---
>+ If you say Y here, you will be able to classify packets based on
>+ a configurable combination of packet keys and masks accordint to
>+ OpenFlow standard.
>+
>
>Should be: according to
I fixed this in my git. Thanks!
>
>Regards,
>Rami Rosen
>
^ permalink raw reply
* [PATCH 0/4] NFC: nxp-nci: Add support for NXP-NCI NFC controllers
From: clement.perrochaud-BPEPtVrvniRWk0Htik3J/w @ 2015-01-22 15:27 UTC (permalink / raw)
To: linux-nfc-hn68Rpc1hR1g9hUCZPvPmw
Cc: Clément Perrochaud, sunil.jogi-3arQi8VN3Tc,
jerome.pele-3arQi8VN3Tc, Charles.Gorand-Effinnov-3arQi8VN3Tc,
lauro.venancio-430g2QfJUUCGglJvpFV4uA,
aloisio.almeida-430g2QfJUUCGglJvpFV4uA,
sameo-VuQAYsv1563Yd54FQh9/CA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
grant.likely-QSEj5FYQhm4dnm+yROfE0A,
clement.perrochaud-3arQi8VN3Tc, lefrique-eYqpPyKDWXRBDgjK7y7TUQ,
christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
cuissard-eYqpPyKDWXRBDgjK7y7TUQ, bzhao-eYqpPyKDWXRBDgjK7y7TUQ,
hirent-eYqpPyKDWXRBDgjK7y7TUQ, akarwar-eYqpPyKDWXRBDgjK7y7TUQ,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
From: Clément Perrochaud <clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
This patch brings support for the NXP-NCI NFC controllers family.
It has been successfully tested on the following SoC boards:
- BeagleBone
- BeagleBone Black
- Raspberry Pi B
- Raspberry Pi B+
The submission is broken into four patches:
- The first one adds firmware download support to NCI ;
- The second one adds the NXP-NCI driver's core ;
- The third one adds I2C support to the driver ;
- The fourth one allows for module removal during download.
It is based on 767dec21d7f5a9787401ff44568852cb3782de64 (Merge tag
'nfc-next-3.19-1' of nfc-next into wireless-next) from the nfc-next master
branch.
Clément Perrochaud (4):
NFC: nci: Add FWDL support
NFC: nxp-nci: Add support for NXP NCI chips
NFC: nxp-nci_i2c: Add I2C support to NXP NCI driver
NFC: nxp-nci: Allow module removal during download
.../devicetree/bindings/net/nfc/nxp-nci.txt | 35 ++
MAINTAINERS | 9 +-
drivers/nfc/Kconfig | 2 +
drivers/nfc/Makefile | 1 +
drivers/nfc/nxp-nci/Kconfig | 24 ++
drivers/nfc/nxp-nci/Makefile | 11 +
drivers/nfc/nxp-nci/core.c | 186 ++++++++
drivers/nfc/nxp-nci/firmware.c | 324 ++++++++++++++
drivers/nfc/nxp-nci/i2c.c | 468 +++++++++++++++++++++
drivers/nfc/nxp-nci/nxp-nci.h | 91 ++++
include/linux/platform_data/nxp-nci.h | 27 ++
include/net/nfc/nci_core.h | 1 +
net/nfc/nci/core.c | 11 +
13 files changed, 1189 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
create mode 100644 drivers/nfc/nxp-nci/Kconfig
create mode 100644 drivers/nfc/nxp-nci/Makefile
create mode 100644 drivers/nfc/nxp-nci/core.c
create mode 100644 drivers/nfc/nxp-nci/firmware.c
create mode 100644 drivers/nfc/nxp-nci/i2c.c
create mode 100644 drivers/nfc/nxp-nci/nxp-nci.h
create mode 100644 include/linux/platform_data/nxp-nci.h
--
Clément Perrochaud
Eff'Innov Technologies
Caen, Aix-En-Provence, Grenoble
Eff'Innov Technologies
Campus EffiScience
2, Esplanade Anton Philips
14460 Colombelles, FRANCE
http://www.effinnov.com
--
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
* [PATCH 1/4] NFC: nci: Add FWDL support
From: clement.perrochaud-BPEPtVrvniRWk0Htik3J/w @ 2015-01-22 15:27 UTC (permalink / raw)
To: linux-nfc-hn68Rpc1hR1g9hUCZPvPmw
Cc: Clément Perrochaud, sunil.jogi-3arQi8VN3Tc,
jerome.pele-3arQi8VN3Tc, Charles.Gorand-Effinnov-3arQi8VN3Tc,
lauro.venancio-430g2QfJUUCGglJvpFV4uA,
aloisio.almeida-430g2QfJUUCGglJvpFV4uA,
sameo-VuQAYsv1563Yd54FQh9/CA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
grant.likely-QSEj5FYQhm4dnm+yROfE0A,
lefrique-eYqpPyKDWXRBDgjK7y7TUQ,
christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
cuissard-eYqpPyKDWXRBDgjK7y7TUQ, bzhao-eYqpPyKDWXRBDgjK7y7TUQ,
hirent-eYqpPyKDWXRBDgjK7y7TUQ, akarwar-eYqpPyKDWXRBDgjK7y7TUQ,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Clément Perrochaud
In-Reply-To: <1421940460-14049-1-git-send-email-clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
From: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
Signed-off-by: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
Signed-off-by: Clément Perrochaud <clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
---
include/net/nfc/nci_core.h | 1 +
net/nfc/nci/core.c | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
index 9e51bb4..137e059 100644
--- a/include/net/nfc/nci_core.h
+++ b/include/net/nfc/nci_core.h
@@ -71,6 +71,7 @@ struct nci_ops {
int (*close)(struct nci_dev *ndev);
int (*send)(struct nci_dev *ndev, struct sk_buff *skb);
int (*setup)(struct nci_dev *ndev);
+ int (*fw_download)(struct nci_dev *ndev, const char *firmware_name);
__u32 (*get_rfprotocol)(struct nci_dev *ndev, __u8 rf_protocol);
int (*discover_se)(struct nci_dev *ndev);
int (*disable_se)(struct nci_dev *ndev, u32 se_idx);
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 51feb5e..1342c7d 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -789,6 +789,16 @@ static int nci_se_io(struct nfc_dev *nfc_dev, u32 se_idx,
return 0;
}
+static int nci_fw_download(struct nfc_dev *nfc_dev, const char *firmware_name)
+{
+ struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+ if (!ndev->ops->fw_download)
+ return -ENOTSUPP;
+
+ return ndev->ops->fw_download(ndev, firmware_name);
+}
+
static struct nfc_ops nci_nfc_ops = {
.dev_up = nci_dev_up,
.dev_down = nci_dev_down,
@@ -804,6 +814,7 @@ static struct nfc_ops nci_nfc_ops = {
.disable_se = nci_disable_se,
.discover_se = nci_discover_se,
.se_io = nci_se_io,
+ .fw_download = nci_fw_download,
};
/* ---- Interface to NCI drivers ---- */
--
Clément Perrochaud
Eff'Innov Technologies
Caen, Aix-En-Provence, Grenoble
Eff'Innov Technologies
Campus EffiScience
2, Esplanade Anton Philips
14460 Colombelles, FRANCE
http://www.effinnov.com
--
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 related
* [PATCH 2/4] NFC: nxp-nci: Add support for NXP NCI chips
From: clement.perrochaud-BPEPtVrvniRWk0Htik3J/w @ 2015-01-22 15:27 UTC (permalink / raw)
To: linux-nfc-hn68Rpc1hR1g9hUCZPvPmw
Cc: Clément Perrochaud, sunil.jogi-3arQi8VN3Tc,
jerome.pele-3arQi8VN3Tc, Charles.Gorand-Effinnov-3arQi8VN3Tc,
lauro.venancio-430g2QfJUUCGglJvpFV4uA,
aloisio.almeida-430g2QfJUUCGglJvpFV4uA,
sameo-VuQAYsv1563Yd54FQh9/CA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
grant.likely-QSEj5FYQhm4dnm+yROfE0A,
lefrique-eYqpPyKDWXRBDgjK7y7TUQ,
christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
cuissard-eYqpPyKDWXRBDgjK7y7TUQ, bzhao-eYqpPyKDWXRBDgjK7y7TUQ,
hirent-eYqpPyKDWXRBDgjK7y7TUQ, akarwar-eYqpPyKDWXRBDgjK7y7TUQ,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Clément Perrochaud
In-Reply-To: <1421940460-14049-1-git-send-email-clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
From: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
Add support for NXP NCI NFC controllers.
Signed-off-by: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
Signed-off-by: Clément Perrochaud <clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
---
MAINTAINERS | 9 +-
drivers/nfc/Kconfig | 2 +
drivers/nfc/Makefile | 1 +
drivers/nfc/nxp-nci/Kconfig | 12 ++
drivers/nfc/nxp-nci/Makefile | 9 +
drivers/nfc/nxp-nci/core.c | 187 ++++++++++++++++++++
drivers/nfc/nxp-nci/firmware.c | 321 ++++++++++++++++++++++++++++++++++
drivers/nfc/nxp-nci/nxp-nci.h | 91 ++++++++++
include/linux/platform_data/nxp-nci.h | 27 +++
9 files changed, 658 insertions(+), 1 deletion(-)
create mode 100644 drivers/nfc/nxp-nci/Kconfig
create mode 100644 drivers/nfc/nxp-nci/Makefile
create mode 100644 drivers/nfc/nxp-nci/core.c
create mode 100644 drivers/nfc/nxp-nci/firmware.c
create mode 100644 drivers/nfc/nxp-nci/nxp-nci.h
create mode 100644 include/linux/platform_data/nxp-nci.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 7ec37a3..48b92f3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -686,7 +686,7 @@ L: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org (moderated for non-subscribers)
W: http://blackfin.uclinux.org/
S: Supported
F: sound/soc/blackfin/*
-
+
ANALOG DEVICES INC IIO DRIVERS
M: Lars-Peter Clausen <lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
M: Michael Hennerich <Michael.Hennerich-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>
@@ -6577,6 +6577,13 @@ S: Supported
F: drivers/block/nvme*
F: include/linux/nvme.h
+NXP-NCI NFC DRIVER
+M: Clément Perrochaud <clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
+R: Charles Gorand <charles.gorand-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
+L: linux-nfc-hn68Rpc1hR1g9hUCZPvPmw@public.gmane.org (moderated for non-subscribers)
+S: Supported
+F: drivers/nfc/nxp-nci
+
NXP TDA998X DRM DRIVER
M: Russell King <rmk+kernel-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>
S: Supported
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 7929fac..3da31e9 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -73,4 +73,6 @@ source "drivers/nfc/microread/Kconfig"
source "drivers/nfc/nfcmrvl/Kconfig"
source "drivers/nfc/st21nfca/Kconfig"
source "drivers/nfc/st21nfcb/Kconfig"
+source "drivers/nfc/nxp-nci/Kconfig"
+
endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 6b23a2c..a4292d79 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -13,5 +13,6 @@ obj-$(CONFIG_NFC_MRVL) += nfcmrvl/
obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb/
+obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nxp-nci/Kconfig b/drivers/nfc/nxp-nci/Kconfig
new file mode 100644
index 0000000..5107edd
--- /dev/null
+++ b/drivers/nfc/nxp-nci/Kconfig
@@ -0,0 +1,12 @@
+config NFC_NXP_NCI
+ tristate "NXP-NCI NFC driver"
+ depends on NFC_NCI
+ default n
+ ---help---
+ Generic core driver for NXP NCI chips.
+ This is a driver based on the NCI NFC kernel layers and
+ will thus not work with NXP libnfc library.
+
+ To compile this driver as a module, choose m here. The module will
+ be called nxp_nci.
+ Say N if unsure.
diff --git a/drivers/nfc/nxp-nci/Makefile b/drivers/nfc/nxp-nci/Makefile
new file mode 100644
index 0000000..8f1e328
--- /dev/null
+++ b/drivers/nfc/nxp-nci/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for NXP-NCI NFC driver
+#
+
+nxp-nci-objs = core.o firmware.o
+
+obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o
+
+ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nxp-nci/core.c b/drivers/nfc/nxp-nci/core.c
new file mode 100644
index 0000000..d3643ef
--- /dev/null
+++ b/drivers/nfc/nxp-nci/core.c
@@ -0,0 +1,187 @@
+/*
+ * Generic driver for NXP NCI NFC chips
+ *
+ * Copyright (C) 2014 NXP Semiconductors All rights reserved.
+ *
+ * Authors: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
+ *
+ * Derived from PN544 device driver:
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/nfc.h>
+#include <linux/platform_data/nxp-nci.h>
+
+#include <net/nfc/nci_core.h>
+
+#include "nxp-nci.h"
+
+#define NXP_NCI_HDR_LEN 4
+
+#define NXP_NCI_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
+ NFC_PROTO_MIFARE_MASK | \
+ NFC_PROTO_FELICA_MASK | \
+ NFC_PROTO_ISO14443_MASK | \
+ NFC_PROTO_ISO14443_B_MASK | \
+ NFC_PROTO_NFC_DEP_MASK)
+
+static int nxp_nci_open(struct nci_dev *ndev)
+{
+ struct nxp_nci_info *info = nci_get_drvdata(ndev);
+ int r = 0;
+
+ mutex_lock(&info->info_lock);
+
+ if (info->mode != NXP_NCI_MODE_COLD) {
+ r = -EBUSY;
+ goto open_exit;
+ }
+
+ if (info->phy_ops->enable)
+ r = info->phy_ops->enable(info->phy_id);
+
+ info->mode = NXP_NCI_MODE_NCI;
+
+open_exit:
+ mutex_unlock(&info->info_lock);
+ return r;
+}
+
+static int nxp_nci_close(struct nci_dev *ndev)
+{
+ struct nxp_nci_info *info = nci_get_drvdata(ndev);
+ int r = 0;
+
+ mutex_lock(&info->info_lock);
+
+ if (info->phy_ops->disable)
+ r = info->phy_ops->disable(info->phy_id);
+
+ info->mode = NXP_NCI_MODE_COLD;
+
+ mutex_unlock(&info->info_lock);
+ return r;
+}
+
+static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ struct nxp_nci_info *info = nci_get_drvdata(ndev);
+ int r;
+
+ if (!info->phy_ops->write) {
+ r = -ENOTSUPP;
+ goto send_exit;
+ }
+
+ if (info->mode != NXP_NCI_MODE_NCI) {
+ r = -EINVAL;
+ goto send_exit;
+ }
+
+ r = info->phy_ops->write(info->phy_id, skb);
+ if (r < 0)
+ kfree_skb(skb);
+
+send_exit:
+ return r;
+}
+
+static struct nci_ops nxp_nci_ops = {
+ .open = nxp_nci_open,
+ .close = nxp_nci_close,
+ .send = nxp_nci_send,
+ .fw_download = nxp_nci_fw_download,
+};
+
+int nxp_nci_probe(void *phy_id, struct device *pdev,
+ struct nxp_nci_phy_ops *phy_ops, unsigned int max_payload,
+ struct nci_dev **ndev)
+{
+ struct nxp_nci_info *info;
+ int r;
+
+ info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL);
+ if (!info) {
+ r = -ENOMEM;
+ goto probe_exit;
+ }
+
+ info->phy_id = phy_id;
+ info->pdev = pdev;
+ info->phy_ops = phy_ops;
+ info->max_payload = max_payload;
+ INIT_WORK(&info->fw_info.work, nxp_nci_fw_work);
+ init_completion(&info->fw_info.cmd_completion);
+ mutex_init(&info->info_lock);
+
+ if (info->phy_ops->disable) {
+ r = info->phy_ops->disable(info->phy_id);
+ if (r < 0)
+ goto probe_exit;
+ }
+
+ info->mode = NXP_NCI_MODE_COLD;
+
+ info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS,
+ NXP_NCI_HDR_LEN, 0);
+ if (!info->ndev) {
+ r = -ENOMEM;
+ goto probe_exit;
+ }
+
+ nci_set_parent_dev(info->ndev, pdev);
+ nci_set_drvdata(info->ndev, info);
+ r = nci_register_device(info->ndev);
+ if (r < 0)
+ goto probe_exit_free_nci;
+
+ *ndev = info->ndev;
+
+ goto probe_exit;
+
+probe_exit_free_nci:
+ nci_free_device(info->ndev);
+probe_exit:
+ return r;
+}
+EXPORT_SYMBOL(nxp_nci_probe);
+
+void nxp_nci_remove(struct nci_dev *ndev)
+{
+ struct nxp_nci_info *info = nci_get_drvdata(ndev);
+
+ mutex_lock(&info->info_lock);
+
+ cancel_work_sync(&info->fw_info.work);
+
+ if (info->mode == NXP_NCI_MODE_FW)
+ nxp_nci_fw_work_complete(info, -ESHUTDOWN);
+
+ if (info->phy_ops->disable)
+ info->phy_ops->disable(info->phy_id);
+
+ nci_unregister_device(ndev);
+ nci_free_device(ndev);
+
+ mutex_unlock(&info->info_lock);
+}
+EXPORT_SYMBOL(nxp_nci_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("NXP NCI NFC driver");
+MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>");
diff --git a/drivers/nfc/nxp-nci/firmware.c b/drivers/nfc/nxp-nci/firmware.c
new file mode 100644
index 0000000..1814e9f
--- /dev/null
+++ b/drivers/nfc/nxp-nci/firmware.c
@@ -0,0 +1,321 @@
+/*
+ * Generic driver for NXP NCI NFC chips
+ *
+ * Copyright (C) 2014 NXP Semiconductors All rights reserved.
+ *
+ * Author: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
+ *
+ * Derived from PN544 device driver:
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/completion.h>
+#include <linux/firmware.h>
+#include <linux/nfc.h>
+#include <linux/unaligned/access_ok.h>
+
+#include "nxp-nci.h"
+
+/* Crypto operations can take up to 30 seconds */
+#define NXP_NCI_FW_ANSWER_TIMEOUT msecs_to_jiffies(30000)
+
+#define NXP_NCI_FW_CMD_RESET 0xF0
+#define NXP_NCI_FW_CMD_GETVERSION 0xF1
+#define NXP_NCI_FW_CMD_CHECKINTEGRITY 0xE0
+#define NXP_NCI_FW_CMD_WRITE 0xC0
+#define NXP_NCI_FW_CMD_READ 0xA2
+#define NXP_NCI_FW_CMD_GETSESSIONSTATE 0xF2
+#define NXP_NCI_FW_CMD_LOG 0xA7
+#define NXP_NCI_FW_CMD_FORCE 0xD0
+#define NXP_NCI_FW_CMD_GET_DIE_ID 0xF4
+
+#define NXP_NCI_FW_CHUNK_FLAG 0x0400
+
+#define NXP_NCI_FW_RESULT_OK 0x00
+#define NXP_NCI_FW_RESULT_INVALID_ADDR 0x01
+#define NXP_NCI_FW_RESULT_GENERIC_ERROR 0x02
+#define NXP_NCI_FW_RESULT_UNKNOWN_CMD 0x0B
+#define NXP_NCI_FW_RESULT_ABORTED_CMD 0x0C
+#define NXP_NCI_FW_RESULT_PLL_ERROR 0x0D
+#define NXP_NCI_FW_RESULT_ADDR_RANGE_OFL_ERROR 0x1E
+#define NXP_NCI_FW_RESULT_BUFFER_OFL_ERROR 0x1F
+#define NXP_NCI_FW_RESULT_MEM_BSY 0x20
+#define NXP_NCI_FW_RESULT_SIGNATURE_ERROR 0x21
+#define NXP_NCI_FW_RESULT_FIRMWARE_VERSION_ERROR 0x24
+#define NXP_NCI_FW_RESULT_PROTOCOL_ERROR 0x28
+#define NXP_NCI_FW_RESULT_SFWU_DEGRADED 0x2A
+#define NXP_NCI_FW_RESULT_PH_STATUS_FIRST_CHUNK 0x2D
+#define NXP_NCI_FW_RESULT_PH_STATUS_NEXT_CHUNK 0x2E
+#define NXP_NCI_FW_RESULT_PH_STATUS_INTERNAL_ERROR_5 0xC5
+
+void nxp_nci_fw_work_complete(struct nxp_nci_info *info, int result)
+{
+ struct nxp_nci_fw_info *fw_info = &info->fw_info;
+ int r;
+
+ if (info->phy_ops->disable) {
+ r = info->phy_ops->disable(info->phy_id);
+ if (r < 0 && result == 0)
+ result = -r;
+ }
+
+ info->mode = NXP_NCI_MODE_COLD;
+
+ if (fw_info->fw) {
+ release_firmware(fw_info->fw);
+ fw_info->fw = NULL;
+ }
+
+ nfc_fw_download_done(info->ndev->nfc_dev, fw_info->name, (u32) -result);
+}
+
+/* crc_ccitt cannot be used since it is computed MSB first and not LSB first */
+static u16 nxp_nci_fw_crc(u8 const *buffer, size_t len)
+{
+ u16 crc = 0xffff;
+
+ while (len--) {
+ crc = ((crc >> 8) | (crc << 8)) ^ *buffer++;
+ crc ^= (crc & 0xff) >> 4;
+ crc ^= (crc & 0xff) << 12;
+ crc ^= (crc & 0xff) << 5;
+ }
+
+ return crc;
+}
+
+static int nxp_nci_fw_send_chunk(struct nxp_nci_info *info)
+{
+ struct nxp_nci_fw_info *fw_info = &info->fw_info;
+ u16 header, crc;
+ struct sk_buff *skb;
+ size_t chunk_len;
+ size_t remaining_len;
+ int r;
+
+ skb = nci_skb_alloc(info->ndev, info->max_payload, GFP_KERNEL);
+ if (!skb) {
+ r = -ENOMEM;
+ goto chunk_exit;
+ }
+
+ chunk_len = info->max_payload - NXP_NCI_FW_HDR_LEN - NXP_NCI_FW_CRC_LEN;
+ remaining_len = fw_info->frame_size - fw_info->written;
+
+ if (remaining_len > chunk_len) {
+ header = NXP_NCI_FW_CHUNK_FLAG;
+ } else {
+ chunk_len = remaining_len;
+ header = 0x0000;
+ }
+
+ header |= chunk_len & NXP_NCI_FW_FRAME_LEN_MASK;
+ put_unaligned_be16(header, skb_put(skb, NXP_NCI_FW_HDR_LEN));
+
+ memcpy(skb_put(skb, chunk_len), fw_info->data + fw_info->written,
+ chunk_len);
+
+ crc = nxp_nci_fw_crc(skb->data, chunk_len + NXP_NCI_FW_HDR_LEN);
+ put_unaligned_be16(crc, skb_put(skb, NXP_NCI_FW_CRC_LEN));
+
+ r = info->phy_ops->write(info->phy_id, skb);
+ if (r >= 0)
+ r = chunk_len;
+
+ kfree_skb(skb);
+
+chunk_exit:
+ return r;
+}
+
+static int nxp_nci_fw_send(struct nxp_nci_info *info)
+{
+ struct nxp_nci_fw_info *fw_info = &info->fw_info;
+ long completion_rc;
+ int r;
+
+ reinit_completion(&fw_info->cmd_completion);
+
+ if (fw_info->written == 0) {
+ fw_info->frame_size = get_unaligned_be16(fw_info->data) &
+ NXP_NCI_FW_FRAME_LEN_MASK;
+ fw_info->data += NXP_NCI_FW_HDR_LEN;
+ fw_info->size -= NXP_NCI_FW_HDR_LEN;
+ }
+
+ if (fw_info->frame_size > fw_info->size)
+ return -EMSGSIZE;
+
+ r = nxp_nci_fw_send_chunk(info);
+ if (r < 0)
+ return r;
+
+ fw_info->written += r;
+
+ if (*fw_info->data == NXP_NCI_FW_CMD_RESET) {
+ fw_info->cmd_result = 0;
+ schedule_work(&fw_info->work);
+ } else {
+ completion_rc = wait_for_completion_interruptible_timeout(
+ &fw_info->cmd_completion, NXP_NCI_FW_ANSWER_TIMEOUT);
+ if (completion_rc == 0)
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+void nxp_nci_fw_work(struct work_struct *work)
+{
+ struct nxp_nci_info *info;
+ struct nxp_nci_fw_info *fw_info;
+ int r;
+
+ fw_info = container_of(work, struct nxp_nci_fw_info, work);
+ info = container_of(fw_info, struct nxp_nci_info, fw_info);
+
+ mutex_lock(&info->info_lock);
+
+ r = fw_info->cmd_result;
+ if (r < 0)
+ goto exit_work;
+
+ if (fw_info->written == fw_info->frame_size) {
+ fw_info->data += fw_info->frame_size;
+ fw_info->size -= fw_info->frame_size;
+ fw_info->written = 0;
+ }
+
+ if (fw_info->size > 0)
+ r = nxp_nci_fw_send(info);
+
+exit_work:
+ if (r < 0 || fw_info->size == 0)
+ nxp_nci_fw_work_complete(info, r);
+ mutex_unlock(&info->info_lock);
+}
+
+int nxp_nci_fw_download(struct nci_dev *ndev, const char *firmware_name)
+{
+ struct nxp_nci_info *info = nci_get_drvdata(ndev);
+ struct nxp_nci_fw_info *fw_info = &info->fw_info;
+ int r;
+
+ mutex_lock(&info->info_lock);
+
+ if (!info->phy_ops->fw_enable || !info->phy_ops->write) {
+ r = -ENOTSUPP;
+ goto fw_download_exit;
+ }
+
+ if (!firmware_name || firmware_name[0] == '\0') {
+ r = -EINVAL;
+ goto fw_download_exit;
+ }
+
+ strcpy(fw_info->name, firmware_name);
+
+ r = request_firmware(&fw_info->fw, firmware_name,
+ ndev->nfc_dev->dev.parent);
+ if (r < 0)
+ goto fw_download_exit;
+
+ r = info->phy_ops->fw_enable(info->phy_id);
+ if (r < 0)
+ goto fw_download_exit;
+
+ info->mode = NXP_NCI_MODE_FW;
+
+ fw_info->data = fw_info->fw->data;
+ fw_info->size = fw_info->fw->size;
+ fw_info->written = 0;
+ fw_info->frame_size = 0;
+ fw_info->cmd_result = 0;
+
+ schedule_work(&fw_info->work);
+
+fw_download_exit:
+ mutex_unlock(&info->info_lock);
+ return r;
+}
+
+static int nxp_nci_fw_read_status(u8 stat)
+{
+ switch (stat) {
+ case NXP_NCI_FW_RESULT_OK:
+ return 0;
+ case NXP_NCI_FW_RESULT_INVALID_ADDR:
+ return -EINVAL;
+ case NXP_NCI_FW_RESULT_UNKNOWN_CMD:
+ return -EINVAL;
+ case NXP_NCI_FW_RESULT_ABORTED_CMD:
+ return -EMSGSIZE;
+ case NXP_NCI_FW_RESULT_ADDR_RANGE_OFL_ERROR:
+ return -EADDRNOTAVAIL;
+ case NXP_NCI_FW_RESULT_BUFFER_OFL_ERROR:
+ return -ENOBUFS;
+ case NXP_NCI_FW_RESULT_MEM_BSY:
+ return -ENOKEY;
+ case NXP_NCI_FW_RESULT_SIGNATURE_ERROR:
+ return -EKEYREJECTED;
+ case NXP_NCI_FW_RESULT_FIRMWARE_VERSION_ERROR:
+ return -EALREADY;
+ case NXP_NCI_FW_RESULT_PROTOCOL_ERROR:
+ return -EPROTO;
+ case NXP_NCI_FW_RESULT_SFWU_DEGRADED:
+ return -EHWPOISON;
+ case NXP_NCI_FW_RESULT_PH_STATUS_FIRST_CHUNK:
+ return 0;
+ case NXP_NCI_FW_RESULT_PH_STATUS_NEXT_CHUNK:
+ return 0;
+ case NXP_NCI_FW_RESULT_PH_STATUS_INTERNAL_ERROR_5:
+ return -EINVAL;
+ default:
+ return -EIO;
+ }
+}
+
+static u16 nxp_nci_fw_check_crc(struct sk_buff *skb)
+{
+ u16 crc, frame_crc;
+ size_t len = skb->len - NXP_NCI_FW_CRC_LEN;
+
+ crc = nxp_nci_fw_crc(skb->data, len);
+ frame_crc = get_unaligned_be16(skb->data + len);
+
+ return (crc ^ frame_crc);
+}
+
+void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ struct nxp_nci_info *info = nci_get_drvdata(ndev);
+ struct nxp_nci_fw_info *fw_info = &info->fw_info;
+
+ complete(&fw_info->cmd_completion);
+
+ if (skb) {
+ if (nxp_nci_fw_check_crc(skb) != 0x00)
+ fw_info->cmd_result = -EBADMSG;
+ else
+ fw_info->cmd_result = nxp_nci_fw_read_status(
+ *skb_pull(skb, NXP_NCI_FW_HDR_LEN));
+ kfree_skb(skb);
+ } else {
+ fw_info->cmd_result = -EIO;
+ }
+
+ schedule_work(&fw_info->work);
+}
+EXPORT_SYMBOL(nxp_nci_fw_recv_frame);
diff --git a/drivers/nfc/nxp-nci/nxp-nci.h b/drivers/nfc/nxp-nci/nxp-nci.h
new file mode 100644
index 0000000..4309328
--- /dev/null
+++ b/drivers/nfc/nxp-nci/nxp-nci.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 NXP Semiconductors All rights reserved.
+ *
+ * Authors: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
+ *
+ * Derived from PN544 device driver:
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LOCAL_NXP_NCI_H_
+#define __LOCAL_NXP_NCI_H_
+
+#include <linux/completion.h>
+#include <linux/firmware.h>
+#include <linux/nfc.h>
+#include <linux/platform_data/nxp-nci.h>
+
+#include <net/nfc/nci_core.h>
+
+#define NXP_NCI_FW_HDR_LEN 2
+#define NXP_NCI_FW_CRC_LEN 2
+
+#define NXP_NCI_FW_FRAME_LEN_MASK 0x03FF
+
+enum nxp_nci_mode {
+ NXP_NCI_MODE_COLD,
+ NXP_NCI_MODE_NCI,
+ NXP_NCI_MODE_FW
+};
+
+struct nxp_nci_phy_ops {
+ int (*enable)(void *id);
+ int (*fw_enable)(void *id);
+ int (*disable)(void *id);
+ int (*write)(void *id, struct sk_buff *skb);
+};
+
+struct nxp_nci_fw_info {
+ char name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
+ const struct firmware *fw;
+
+ size_t size;
+ size_t written;
+
+ const u8 *data;
+ size_t frame_size;
+
+ struct work_struct work;
+ struct completion cmd_completion;
+
+ int cmd_result;
+};
+
+struct nxp_nci_info {
+ struct nci_dev *ndev;
+ void *phy_id;
+ struct device *pdev;
+
+ enum nxp_nci_mode mode;
+
+ struct nxp_nci_phy_ops *phy_ops;
+ unsigned int max_payload;
+
+ struct mutex info_lock;
+
+ struct nxp_nci_fw_info fw_info;
+};
+
+int nxp_nci_fw_download(struct nci_dev *ndev, const char *firmware_name);
+void nxp_nci_fw_work(struct work_struct *work);
+void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb);
+void nxp_nci_fw_work_complete(struct nxp_nci_info *info, int result);
+
+int nxp_nci_probe(void *phy_id, struct device *pdev,
+ struct nxp_nci_phy_ops *phy_ops, unsigned int max_payload,
+ struct nci_dev **ndev);
+void nxp_nci_remove(struct nci_dev *ndev);
+
+#endif /* __LOCAL_NXP_NCI_H_ */
diff --git a/include/linux/platform_data/nxp-nci.h b/include/linux/platform_data/nxp-nci.h
new file mode 100644
index 0000000..d6ed286
--- /dev/null
+++ b/include/linux/platform_data/nxp-nci.h
@@ -0,0 +1,27 @@
+/*
+ * Generic platform data for the NXP NCI NFC chips.
+ *
+ * Copyright (C) 2014 NXP Semiconductors All rights reserved.
+ *
+ * Authors: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
+ *
+ * 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _NXP_NCI_H_
+#define _NXP_NCI_H_
+
+struct nxp_nci_nfc_platform_data {
+ unsigned int gpio_en;
+ unsigned int gpio_fw;
+ unsigned int irq;
+};
+
+#endif /* _NXP_NCI_H_ */
--
Clément Perrochaud
Eff'Innov Technologies
Caen, Aix-En-Provence, Grenoble
Eff'Innov Technologies
Campus EffiScience
2, Esplanade Anton Philips
14460 Colombelles, FRANCE
http://www.effinnov.com
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" 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 related
* [PATCH 3/4] NFC: nxp-nci_i2c: Add I2C support to NXP NCI driver
From: clement.perrochaud-BPEPtVrvniRWk0Htik3J/w @ 2015-01-22 15:27 UTC (permalink / raw)
To: linux-nfc-hn68Rpc1hR1g9hUCZPvPmw
Cc: Clément Perrochaud, sunil.jogi-3arQi8VN3Tc,
jerome.pele-3arQi8VN3Tc, Charles.Gorand-Effinnov-3arQi8VN3Tc,
lauro.venancio-430g2QfJUUCGglJvpFV4uA,
aloisio.almeida-430g2QfJUUCGglJvpFV4uA,
sameo-VuQAYsv1563Yd54FQh9/CA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
grant.likely-QSEj5FYQhm4dnm+yROfE0A,
lefrique-eYqpPyKDWXRBDgjK7y7TUQ,
christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
cuissard-eYqpPyKDWXRBDgjK7y7TUQ, bzhao-eYqpPyKDWXRBDgjK7y7TUQ,
hirent-eYqpPyKDWXRBDgjK7y7TUQ, akarwar-eYqpPyKDWXRBDgjK7y7TUQ,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Clément Perrochaud
In-Reply-To: <1421940460-14049-1-git-send-email-clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
From: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
Signed-off-by: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
Signed-off-by: Clément Perrochaud <clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
---
.../devicetree/bindings/net/nfc/nxp-nci.txt | 35 ++
drivers/nfc/nxp-nci/Kconfig | 12 +
drivers/nfc/nxp-nci/Makefile | 2 +
drivers/nfc/nxp-nci/i2c.c | 468 +++++++++++++++++++++
4 files changed, 517 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
create mode 100644 drivers/nfc/nxp-nci/i2c.c
diff --git a/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt b/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
new file mode 100644
index 0000000..5b6cd9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
@@ -0,0 +1,35 @@
+* NXP Semiconductors NXP NCI NFC Controllers
+
+Required properties:
+- compatible: Should be "nxp,nxp-nci-i2c".
+- clock-frequency: I²C work frequency.
+- reg: address on the bus
+- interrupt-parent: phandle for the interrupt gpio controller
+- interrupts: GPIO interrupt to which the chip is connected
+- enable-gpios: Output GPIO pin used for enabling/disabling the chip
+- firmware-gpios: Output GPIO pin used to enter firmware download mode
+
+Optional SoC Specific Properties:
+- pinctrl-names: Contains only one value - "default".
+- pintctrl-0: Specifies the pin control groups used for this controller.
+
+Example (for ARM-based BeagleBone with NPC100 NFC controller on I2C2):
+
+&i2c2 {
+
+ status = "okay";
+
+ npc100: npc100@29 {
+
+ compatible = "nxp,nxp-nci-i2c";
+
+ reg = <0x29>;
+ clock-frequency = <100000>;
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <29 GPIO_ACTIVE_HIGH>;
+
+ enable-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
+ firmware-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>;
+ };
+};
diff --git a/drivers/nfc/nxp-nci/Kconfig b/drivers/nfc/nxp-nci/Kconfig
index 5107edd..ac54016 100644
--- a/drivers/nfc/nxp-nci/Kconfig
+++ b/drivers/nfc/nxp-nci/Kconfig
@@ -10,3 +10,15 @@ config NFC_NXP_NCI
To compile this driver as a module, choose m here. The module will
be called nxp_nci.
Say N if unsure.
+
+config NFC_NXP_NCI_I2C
+ tristate "NXP-NCI I2C support"
+ depends on NFC_NXP_NCI && I2C
+ ---help---
+ This module adds support for an I2C interface to the NXP NCI
+ chips.
+ Select this if your platform is using the I2C bus.
+
+ To compile this driver as a module, choose m here. The module will
+ be called nxp_nci_i2c.
+ Say Y if unsure.
diff --git a/drivers/nfc/nxp-nci/Makefile b/drivers/nfc/nxp-nci/Makefile
index 8f1e328..c008be3 100644
--- a/drivers/nfc/nxp-nci/Makefile
+++ b/drivers/nfc/nxp-nci/Makefile
@@ -3,7 +3,9 @@
#
nxp-nci-objs = core.o firmware.o
+nxp-nci_i2c-objs = i2c.o
obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o
+obj-$(CONFIG_NFC_NXP_NCI_I2C) += nxp-nci_i2c.o
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
new file mode 100644
index 0000000..4d6293b
--- /dev/null
+++ b/drivers/nfc/nxp-nci/i2c.c
@@ -0,0 +1,468 @@
+/*
+ * I2C link layer for the NXP NCI driver
+ *
+ * Copyright (C) 2014 NXP Semiconductors All rights reserved.
+ *
+ * Authors: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
+ *
+ * Derived from PN544 device driver:
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/nfc.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/platform_data/nxp-nci.h>
+#include <linux/unaligned/access_ok.h>
+
+#include <net/nfc/nfc.h>
+
+#include "nxp-nci.h"
+
+#define NXP_NCI_I2C_DRIVER_NAME "nxp-nci_i2c"
+
+#define NXP_NCI_I2C_MAX_PAYLOAD 32
+
+struct nxp_nci_i2c_phy {
+ struct i2c_client *i2c_dev;
+ struct nci_dev *ndev;
+
+ unsigned int gpio_en;
+ unsigned int gpio_fw;
+
+ int hard_fault; /*
+ * < 0 if hardware error occurred (e.g. i2c err)
+ * and prevents normal operation.
+ */
+};
+
+static void nxp_nci_i2c_enable_mode(struct nxp_nci_i2c_phy *phy,
+ enum nxp_nci_mode mode)
+{
+ gpio_set_value(phy->gpio_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
+ gpio_set_value(phy->gpio_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
+ usleep_range(10000, 15000);
+}
+
+int nxp_nci_i2c_enable(void *phy_id)
+{
+ nxp_nci_i2c_enable_mode((struct nxp_nci_i2c_phy *) phy_id,
+ NXP_NCI_MODE_NCI);
+ return 0;
+}
+
+int nxp_nci_i2c_fw_enable(void *phy_id)
+{
+ nxp_nci_i2c_enable_mode((struct nxp_nci_i2c_phy *) phy_id,
+ NXP_NCI_MODE_FW);
+ return 0;
+}
+
+int nxp_nci_i2c_disable(void *phy_id)
+{
+ struct nxp_nci_i2c_phy *phy = phy_id;
+
+ nxp_nci_i2c_enable_mode(phy, NXP_NCI_MODE_COLD);
+ phy->hard_fault = 0;
+
+ return 0;
+}
+
+static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
+{
+ int r;
+ struct nxp_nci_i2c_phy *phy = phy_id;
+ struct i2c_client *client = phy->i2c_dev;
+
+ if (phy->hard_fault != 0)
+ return phy->hard_fault;
+
+ r = i2c_master_send(client, skb->data, skb->len);
+ if (r == -EREMOTEIO) {
+ /* Retry, chip was in standby */
+ usleep_range(110000, 120000);
+ r = i2c_master_send(client, skb->data, skb->len);
+ }
+
+ if (r < 0) {
+ nfc_err(&client->dev, "Error %d on I2C send\n", r);
+ } else if (r != skb->len) {
+ nfc_err(&client->dev,
+ "Invalid length sent: %u (expected %u)\n",
+ r, skb->len);
+ r = -EREMOTEIO;
+ } else {
+ /* Success but return 0 and not number of bytes */
+ r = 0;
+ }
+
+ return r;
+}
+
+static struct nxp_nci_phy_ops i2c_phy_ops = {
+ .enable = nxp_nci_i2c_enable,
+ .fw_enable = nxp_nci_i2c_fw_enable,
+ .disable = nxp_nci_i2c_disable,
+ .write = nxp_nci_i2c_write,
+};
+
+static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy,
+ struct sk_buff **skb)
+{
+ struct i2c_client *client = phy->i2c_dev;
+ u16 header;
+ size_t frame_len;
+ int r;
+
+ r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN);
+ if (r < 0) {
+ goto fw_read_exit;
+ } else if (r != NXP_NCI_FW_HDR_LEN) {
+ nfc_err(&client->dev, "Incorrect header length: %u\n", r);
+ r = -EBADMSG;
+ goto fw_read_exit;
+ }
+
+ frame_len = (get_unaligned_be16(&header) & NXP_NCI_FW_FRAME_LEN_MASK) +
+ NXP_NCI_FW_CRC_LEN;
+
+ *skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL);
+ if (*skb == NULL) {
+ r = -ENOMEM;
+ goto fw_read_exit;
+ }
+
+ memcpy(skb_put(*skb, NXP_NCI_FW_HDR_LEN), &header, NXP_NCI_FW_HDR_LEN);
+
+ r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len);
+ if (r != frame_len) {
+ nfc_err(&client->dev,
+ "Invalid frame length: %u (expected %u)\n",
+ r, frame_len);
+ r = -EBADMSG;
+ goto fw_read_exit_free_skb;
+ }
+
+ r = 0;
+ goto fw_read_exit;
+
+fw_read_exit_free_skb:
+ kfree_skb(*skb);
+fw_read_exit:
+ return r;
+}
+
+static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy,
+ struct sk_buff **skb)
+{
+ struct nci_ctrl_hdr header; /* May actually be a data header */
+ struct i2c_client *client = phy->i2c_dev;
+ int r;
+
+ r = i2c_master_recv(client, (u8 *) &header, NCI_CTRL_HDR_SIZE);
+ if (r < 0) {
+ goto nci_read_exit;
+ } else if (r != NCI_CTRL_HDR_SIZE) {
+ nfc_err(&client->dev, "Incorrect header length: %u\n", r);
+ r = -EBADMSG;
+ goto nci_read_exit;
+ }
+
+ *skb = alloc_skb(NCI_CTRL_HDR_SIZE + header.plen, GFP_KERNEL);
+ if (*skb == NULL) {
+ r = -ENOMEM;
+ goto nci_read_exit;
+ }
+
+ memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), (void *) &header,
+ NCI_CTRL_HDR_SIZE);
+
+ r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen);
+ if (r != header.plen) {
+ nfc_err(&client->dev,
+ "Invalid frame payload length: %u (expected %u)\n",
+ r, header.plen);
+ r = -EBADMSG;
+ goto nci_read_exit_free_skb;
+ }
+
+ r = 0;
+ goto nci_read_exit;
+
+nci_read_exit_free_skb:
+ kfree_skb(*skb);
+nci_read_exit:
+ return r;
+}
+
+static irqreturn_t nxp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
+{
+ struct nxp_nci_i2c_phy *phy = phy_id;
+ struct i2c_client *client;
+ struct nxp_nci_info *info;
+
+ struct sk_buff *skb = NULL;
+ int r = 0;
+
+ if (!phy || !phy->ndev)
+ goto exit_irq_none;
+
+ client = phy->i2c_dev;
+
+ if (!client || irq != client->irq)
+ goto exit_irq_none;
+
+ if (phy->hard_fault != 0)
+ goto exit_irq_handled;
+
+ info = nci_get_drvdata(phy->ndev);
+
+ switch (info->mode) {
+ case NXP_NCI_MODE_NCI:
+ r = nxp_nci_i2c_nci_read(phy, &skb);
+ break;
+ case NXP_NCI_MODE_FW:
+ r = nxp_nci_i2c_fw_read(phy, &skb);
+ break;
+ case NXP_NCI_MODE_COLD:
+ r = -EREMOTEIO;
+ break;
+ }
+
+ if (r == -EREMOTEIO) {
+ phy->hard_fault = r;
+ skb = NULL;
+ } else if (r < 0) {
+ nfc_err(&client->dev, "Read failed with error %d\n", r);
+ goto exit_irq_handled;
+ }
+
+ switch (info->mode) {
+ case NXP_NCI_MODE_NCI:
+ nci_recv_frame(phy->ndev, skb);
+ break;
+ case NXP_NCI_MODE_FW:
+ nxp_nci_fw_recv_frame(phy->ndev, skb);
+ break;
+ case NXP_NCI_MODE_COLD:
+ break;
+ }
+
+exit_irq_handled:
+ return IRQ_HANDLED;
+exit_irq_none:
+ WARN_ON_ONCE(1);
+ return IRQ_NONE;
+}
+
+#ifdef CONFIG_OF
+
+static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
+{
+ struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
+ struct device_node *pp;
+ int r;
+
+ pp = client->dev.of_node;
+ if (!pp)
+ return -ENODEV;
+
+ r = of_get_named_gpio(pp, "enable-gpios", 0);
+ if (r == -EPROBE_DEFER)
+ r = of_get_named_gpio(pp, "enable-gpios", 0);
+ if (r < 0) {
+ nfc_err(&client->dev, "Failed to get EN gpio, error: %d\n", r);
+ return r;
+ }
+ phy->gpio_en = r;
+
+ r = of_get_named_gpio(pp, "firmware-gpios", 0);
+ if (r == -EPROBE_DEFER)
+ r = of_get_named_gpio(pp, "firmware-gpios", 0);
+ if (r < 0) {
+ nfc_err(&client->dev, "Failed to get FW gpio, error: %d\n", r);
+ return r;
+ }
+ phy->gpio_fw = r;
+
+ r = irq_of_parse_and_map(pp, 0);
+ if (r < 0) {
+ nfc_err(&client->dev, "Unable to get irq, error: %d\n", r);
+ return r;
+ }
+ client->irq = r;
+
+ return 0;
+}
+
+#else
+
+static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
+{
+ return -ENODEV;
+}
+
+#endif
+
+static int nxp_nci_i2c_request_gpios(struct nxp_nci_i2c_phy *phy)
+{
+ int r;
+
+ r = gpio_request(phy->gpio_en, "nxp_nci_en");
+ if (r < 0)
+ goto err_out;
+
+ r = gpio_direction_output(phy->gpio_en, 0);
+ if (r < 0)
+ goto err_gpio_en;
+
+ r = gpio_request(phy->gpio_fw, "nxp_nci_fw");
+ if (r < 0)
+ goto err_gpio_en;
+
+ r = gpio_direction_output(phy->gpio_fw, 0);
+ if (r < 0)
+ goto err_gpio_fw;
+
+ goto err_out;
+
+err_gpio_fw:
+ gpio_free(phy->gpio_fw);
+err_gpio_en:
+ gpio_free(phy->gpio_en);
+err_out:
+ return r;
+}
+
+static void nxp_nci_i2c_free_gpios(struct nxp_nci_i2c_phy *phy)
+{
+ gpio_free(phy->gpio_fw);
+ gpio_free(phy->gpio_en);
+}
+
+static int nxp_nci_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct nxp_nci_i2c_phy *phy;
+ struct nxp_nci_nfc_platform_data *pdata;
+ int r;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
+ r = -ENODEV;
+ goto probe_exit;
+ }
+
+ phy = devm_kzalloc(&client->dev, sizeof(struct nxp_nci_i2c_phy),
+ GFP_KERNEL);
+ if (!phy) {
+ r = -ENOMEM;
+ goto probe_exit;
+ }
+
+ phy->i2c_dev = client;
+ i2c_set_clientdata(client, phy);
+
+ pdata = client->dev.platform_data;
+
+ if (!pdata && client->dev.of_node) {
+ r = nxp_nci_i2c_parse_devtree(client);
+ if (r < 0) {
+ nfc_err(&client->dev, "Failed to get DT data\n");
+ goto probe_exit;
+ }
+ } else if (pdata) {
+ phy->gpio_en = pdata->gpio_en;
+ phy->gpio_fw = pdata->gpio_fw;
+ client->irq = pdata->irq;
+ } else {
+ nfc_err(&client->dev, "No platform data\n");
+ r = -EINVAL;
+ goto probe_exit;
+ }
+
+ r = nxp_nci_i2c_request_gpios(phy);
+ if (r < 0)
+ goto probe_exit;
+
+ r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
+ NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
+ if (r < 0)
+ goto probe_exit_free_gpio;
+
+ r = request_threaded_irq(client->irq, NULL,
+ nxp_nci_i2c_irq_thread_fn,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ NXP_NCI_I2C_DRIVER_NAME, phy);
+ if (r < 0) {
+ nfc_err(&client->dev, "Unable to register IRQ handler\n");
+ goto probe_exit_free_gpio;
+ }
+
+ goto probe_exit;
+
+probe_exit_free_gpio:
+ nxp_nci_i2c_free_gpios(phy);
+probe_exit:
+ return r;
+}
+
+static int nxp_nci_i2c_remove(struct i2c_client *client)
+{
+ struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
+
+ nxp_nci_remove(phy->ndev);
+
+ nxp_nci_i2c_free_gpios(phy);
+ free_irq(client->irq, phy);
+
+ return 0;
+}
+
+static struct i2c_device_id nxp_nci_i2c_id_table[] = {
+ {"nxp-nci_i2c", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table);
+
+static const struct of_device_id of_nxp_nci_i2c_match[] = {
+ { .compatible = "nxp,nxp-nci-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match);
+
+static struct i2c_driver nxp_nci_i2c_driver = {
+ .driver = {
+ .name = NXP_NCI_I2C_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(of_nxp_nci_i2c_match),
+ },
+ .probe = nxp_nci_i2c_probe,
+ .id_table = nxp_nci_i2c_id_table,
+ .remove = nxp_nci_i2c_remove,
+};
+
+module_i2c_driver(nxp_nci_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers");
+MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>");
--
Clément Perrochaud
Eff'Innov Technologies
Caen, Aix-En-Provence, Grenoble
Eff'Innov Technologies
Campus EffiScience
2, Esplanade Anton Philips
14460 Colombelles, FRANCE
http://www.effinnov.com
--
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 related
* [PATCH 4/4] NFC: nxp-nci: Allow module removal during download
From: clement.perrochaud-BPEPtVrvniRWk0Htik3J/w @ 2015-01-22 15:27 UTC (permalink / raw)
To: linux-nfc-hn68Rpc1hR1g9hUCZPvPmw
Cc: Clément Perrochaud, sunil.jogi-3arQi8VN3Tc,
jerome.pele-3arQi8VN3Tc, Charles.Gorand-Effinnov-3arQi8VN3Tc,
lauro.venancio-430g2QfJUUCGglJvpFV4uA,
aloisio.almeida-430g2QfJUUCGglJvpFV4uA,
sameo-VuQAYsv1563Yd54FQh9/CA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
grant.likely-QSEj5FYQhm4dnm+yROfE0A,
lefrique-eYqpPyKDWXRBDgjK7y7TUQ,
christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
cuissard-eYqpPyKDWXRBDgjK7y7TUQ, bzhao-eYqpPyKDWXRBDgjK7y7TUQ,
hirent-eYqpPyKDWXRBDgjK7y7TUQ, akarwar-eYqpPyKDWXRBDgjK7y7TUQ,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Clément Perrochaud
In-Reply-To: <1421940460-14049-1-git-send-email-clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
From: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
Signed-off-by: Clément Perrochaud <clement.perrochaud-3arQi8VN3Tc@public.gmane.org>
Signed-off-by: Clément Perrochaud <clement.perrochaud-BPEPtVrvniRWk0Htik3J/w@public.gmane.org>
---
drivers/nfc/nxp-nci/core.c | 7 +++----
drivers/nfc/nxp-nci/firmware.c | 9 ++++++---
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/drivers/nfc/nxp-nci/core.c b/drivers/nfc/nxp-nci/core.c
index d3643ef..c15606d 100644
--- a/drivers/nfc/nxp-nci/core.c
+++ b/drivers/nfc/nxp-nci/core.c
@@ -165,12 +165,11 @@ void nxp_nci_remove(struct nci_dev *ndev)
{
struct nxp_nci_info *info = nci_get_drvdata(ndev);
- mutex_lock(&info->info_lock);
-
- cancel_work_sync(&info->fw_info.work);
-
if (info->mode == NXP_NCI_MODE_FW)
nxp_nci_fw_work_complete(info, -ESHUTDOWN);
+ cancel_work_sync(&info->fw_info.work);
+
+ mutex_lock(&info->info_lock);
if (info->phy_ops->disable)
info->phy_ops->disable(info->phy_id);
diff --git a/drivers/nfc/nxp-nci/firmware.c b/drivers/nfc/nxp-nci/firmware.c
index 1814e9f..de136e1 100644
--- a/drivers/nfc/nxp-nci/firmware.c
+++ b/drivers/nfc/nxp-nci/firmware.c
@@ -166,7 +166,8 @@ static int nxp_nci_fw_send(struct nxp_nci_info *info)
if (*fw_info->data == NXP_NCI_FW_CMD_RESET) {
fw_info->cmd_result = 0;
- schedule_work(&fw_info->work);
+ if (fw_info->fw)
+ schedule_work(&fw_info->work);
} else {
completion_rc = wait_for_completion_interruptible_timeout(
&fw_info->cmd_completion, NXP_NCI_FW_ANSWER_TIMEOUT);
@@ -244,7 +245,8 @@ int nxp_nci_fw_download(struct nci_dev *ndev, const char *firmware_name)
fw_info->frame_size = 0;
fw_info->cmd_result = 0;
- schedule_work(&fw_info->work);
+ if (fw_info->fw)
+ schedule_work(&fw_info->work);
fw_download_exit:
mutex_unlock(&info->info_lock);
@@ -316,6 +318,7 @@ void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
fw_info->cmd_result = -EIO;
}
- schedule_work(&fw_info->work);
+ if (fw_info->fw)
+ schedule_work(&fw_info->work);
}
EXPORT_SYMBOL(nxp_nci_fw_recv_frame);
--
Clément Perrochaud
Eff'Innov Technologies
Caen, Aix-En-Provence, Grenoble
Eff'Innov Technologies
Campus EffiScience
2, Esplanade Anton Philips
14460 Colombelles, FRANCE
http://www.effinnov.com
--
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 related
* Re: [net-next PATCH v3 00/12] Flow API
From: Jamal Hadi Salim @ 2015-01-22 15:28 UTC (permalink / raw)
To: Thomas Graf
Cc: Pablo Neira Ayuso, John Fastabend, simon.horman, sfeldma, netdev,
davem, gerlitz.or, andy, ast, Jiri Pirko
In-Reply-To: <20150122151316.GB25797@casper.infradead.org>
On 01/22/15 10:13, Thomas Graf wrote:
> I don't follow this. John's proposal allows to decide on a case by
> case basis what we want to export. Just like with ethtool or
> RTNETLINK. There is no direct access to hardware. A user can only
> configure what is being exposed by the kernel.
>
So if i am a vendor with my own driver, I can expose whatever i want.
Only my SDK needs to deal with what i expose. There is no needed
feature in the kernel other than the driver exposing it that is
required.
cheers,
jamal
^ permalink raw reply
* Re: [net-next PATCH v3 00/12] Flow API
From: Thomas Graf @ 2015-01-22 15:37 UTC (permalink / raw)
To: Jamal Hadi Salim
Cc: Pablo Neira Ayuso, John Fastabend, simon.horman, sfeldma, netdev,
davem, gerlitz.or, andy, ast, Jiri Pirko
In-Reply-To: <54C11703.7030702@mojatatu.com>
On 01/22/15 at 10:28am, Jamal Hadi Salim wrote:
> On 01/22/15 10:13, Thomas Graf wrote:
>
> >I don't follow this. John's proposal allows to decide on a case by
> >case basis what we want to export. Just like with ethtool or
> >RTNETLINK. There is no direct access to hardware. A user can only
> >configure what is being exposed by the kernel.
> >
>
> So if i am a vendor with my own driver, I can expose whatever i want.
No. We will reject any driver change attempting to do so on this
list.
This is the whole point of this: Coming up with a model that allows
to describe capabilities and offer flow programming capabilities
in a Vendor neutral way. A "push_vlan" or "pop_vlan" action will work
with any driver that supports it.
^ permalink raw reply
* Re: [net-next PATCH v3 00/12] Flow API
From: Jamal Hadi Salim @ 2015-01-22 15:44 UTC (permalink / raw)
To: Thomas Graf
Cc: Pablo Neira Ayuso, John Fastabend, simon.horman, sfeldma, netdev,
davem, gerlitz.or, andy, ast, Jiri Pirko
In-Reply-To: <20150122153727.GC25797@casper.infradead.org>
On 01/22/15 10:37, Thomas Graf wrote:
> On 01/22/15 at 10:28am, Jamal Hadi Salim wrote:
>> So if i am a vendor with my own driver, I can expose whatever i want.
>
> No. We will reject any driver change attempting to do so on this
> list.
>
Vendor provides a driver that exposes a discoverable interface
(capabilities exposure that is facilitated).
They dont need it to be part of the mainstream kernel.
And they dont need any of your definitions.
cheers,
jamal
^ permalink raw reply
* Re: [net-next PATCH v3 00/12] Flow API
From: Jiri Pirko @ 2015-01-22 15:48 UTC (permalink / raw)
To: Thomas Graf
Cc: Jamal Hadi Salim, Pablo Neira Ayuso, John Fastabend, simon.horman,
sfeldma, netdev, davem, gerlitz.or, andy, ast
In-Reply-To: <20150122153727.GC25797@casper.infradead.org>
Thu, Jan 22, 2015 at 04:37:27PM CET, tgraf@suug.ch wrote:
>On 01/22/15 at 10:28am, Jamal Hadi Salim wrote:
>> On 01/22/15 10:13, Thomas Graf wrote:
>>
>> >I don't follow this. John's proposal allows to decide on a case by
>> >case basis what we want to export. Just like with ethtool or
>> >RTNETLINK. There is no direct access to hardware. A user can only
>> >configure what is being exposed by the kernel.
>> >
>>
>> So if i am a vendor with my own driver, I can expose whatever i want.
>
>No. We will reject any driver change attempting to do so on this
>list.
That is not 100%, on contrary. If the infrastructure would be made to
explicitly disallow that kind of behaviour, it would be much safer.
>
>This is the whole point of this: Coming up with a model that allows
>to describe capabilities and offer flow programming capabilities
>in a Vendor neutral way. A "push_vlan" or "pop_vlan" action will work
>with any driver that supports it.
^ permalink raw reply
* Re: [patch net-next RFC] tc: introduce OpenFlow classifier
From: Jamal Hadi Salim @ 2015-01-22 15:50 UTC (permalink / raw)
To: Jiri Pirko, netdev; +Cc: davem
In-Reply-To: <1421933824-17916-1-git-send-email-jiri@resnulli.us>
On 01/22/15 08:37, Jiri Pirko wrote:
> This patch introduces OpenFlow-based filter. So far, the very essential
> packet fields are supported (according to OpenFlow v1.4 spec).
>
> Known issues: skb_flow_dissect hashes out ipv6 addresses. That needs
> to be changed to store them somewhere so they can be used later on.
>
> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
> ---
> include/uapi/linux/pkt_cls.h | 33 +++
> net/sched/Kconfig | 11 +
> net/sched/Makefile | 1 +
> net/sched/cls_openflow.c | 514 +++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 559 insertions(+)
> create mode 100644 net/sched/cls_openflow.c
>
> diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
> index 25731df..d4cef16 100644
> --- a/include/uapi/linux/pkt_cls.h
> +++ b/include/uapi/linux/pkt_cls.h
> @@ -402,6 +402,39 @@ enum {
>
> #define TCA_BPF_MAX (__TCA_BPF_MAX - 1)
>
> +/* OpenFlow classifier */
> +
> +enum {
> + TCA_OF_UNSPEC,
> + TCA_OF_CLASSID,
> + TCA_OF_POLICE,
> + TCA_OF_INDEV,
I think POLICE is an old way of doing policing and INDEV if i am not
mistaken is only legit for u32 classifier.
So i am not sure you want to keep them.
Other than that looks good - will be interested to see how perfomance
looks on this with the list walking ;->
cheers,
jamal
^ permalink raw reply
* [PATCH net] netxen: fix netxen_nic_poll() logic
From: Eric Dumazet @ 2015-01-22 15:56 UTC (permalink / raw)
To: Mike Galbraith, David Miller; +Cc: netdev, Manish Chopra
In-Reply-To: <1421915821.5286.71.camel@marge.simpson.net>
From: Eric Dumazet <edumazet@google.com>
NAPI poll logic now enforces that a poller returns exactly the budget
when it wants to be called again.
If a driver limits TX completion, it has to return budget as well when
the limit is hit, not the number of received packets.
Reported-and-tested-by: Mike Galbraith <umgwanakikbuti@gmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Fixes: d75b1ade567f ("net: less interrupt masking in NAPI")
Cc: Manish Chopra <manish.chopra@qlogic.com>
---
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 613037584d08..c531c8ae1be4 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -2388,7 +2388,10 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget)
work_done = netxen_process_rcv_ring(sds_ring, budget);
- if ((work_done < budget) && tx_complete) {
+ if (!tx_complete)
+ work_done = budget;
+
+ if (work_done < budget) {
napi_complete(&sds_ring->napi);
if (test_bit(__NX_DEV_UP, &adapter->state))
netxen_nic_enable_int(sds_ring);
^ permalink raw reply related
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