* Re: [PATCH v3 net-next 2/2] tools: test case for TPACKET_V3/TX_RING support
From: Willem de Bruijn @ 2017-01-03 15:57 UTC (permalink / raw)
To: Sowmini Varadhan
Cc: Network Development, Daniel Borkmann, Willem de Bruijn,
David Miller
In-Reply-To: <dcf7fe19d3248b4f523b7f7d22937c61d92a152f.1483452545.git.sowmini.varadhan@oracle.com>
On Tue, Jan 3, 2017 at 9:31 AM, Sowmini Varadhan
<sowmini.varadhan@oracle.com> wrote:
> Add a test case and sample code for (TPACKET_V3, PACKET_TX_RING)
>
> Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Thanks!
^ permalink raw reply
* Re: [PATCH v3 net-next 1/2] af_packet: TX_RING support for TPACKET_V3
From: Willem de Bruijn @ 2017-01-03 15:57 UTC (permalink / raw)
To: Sowmini Varadhan
Cc: Network Development, Daniel Borkmann, Willem de Bruijn,
David Miller
In-Reply-To: <ad0b245b49761228a99b8865693c4a60550caf61.1483452545.git.sowmini.varadhan@oracle.com>
On Tue, Jan 3, 2017 at 9:31 AM, Sowmini Varadhan
<sowmini.varadhan@oracle.com> wrote:
> Although TPACKET_V3 Rx has some benefits over TPACKET_V2 Rx, *_v3
> does not currently have TX_RING support. As a result an application
> that wants the best perf for Tx and Rx (e.g. to handle request/response
> transacations) ends up needing 2 sockets, one with *_v2 for Tx and
> another with *_v3 for Rx.
>
> This patch enables TPACKET_V2 compatible Tx features in TPACKET_V3
> so that an application can use a single descriptor to get the benefits
> of _v3 RX_RING and _v2 TX_RING. An application may do a block-send by
> first filling up multiple frames in the Tx ring and then triggering a
> transmit. This patch only support fixed size Tx frames for TPACKET_V3,
> and requires that tp_next_offset must be zero.
>
> Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Acked-by: Willem de Bruijn <willemb@google.com>
^ permalink raw reply
* Re: [PATCH] uapi: use wildcards to list files
From: David Miller @ 2017-01-03 15:56 UTC (permalink / raw)
To: nicolas.dichtel
Cc: linux-arch, linux-nfs, arnd, alsa-devel, linux-rdma, netdev,
linux-mmc, linux-kernel, dri-devel, linux-spi, linux-raid,
airlied, netfilter-devel, linux-fbdev, xen-devel, fcoe-devel,
linux-mtd, linux-media
In-Reply-To: <1483454144-10519-1-git-send-email-nicolas.dichtel@6wind.com>
From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date: Tue, 3 Jan 2017 15:35:44 +0100
> Regularly, when a new header is created in include/uapi/, the developer
> forgets to add it in the corresponding Kbuild file. This error is usually
> detected after the release is out.
>
> In fact, all headers under include/uapi/ should be exported, so let's
> use wildcards.
>
> After this patch, the following files, which were not exported, are now
> exported:
...
>
> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: David S. Miller <davem@davemloft.net>
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply
* [net-next 3/3] tipc: reduce risk of user starvation during link congestion
From: Jon Maloy @ 2017-01-03 15:55 UTC (permalink / raw)
To: davem; +Cc: Jon Maloy, netdev, tipc-discussion
In-Reply-To: <1483458911-32549-1-git-send-email-jon.maloy@ericsson.com>
The socket code currently handles link congestion by either blocking
and trying to send again when the congestion has abated, or just
returning to the user with -EAGAIN and let him re-try later.
This mechanism is prone to starvation, because the wakeup algorithm is
non-atomic. During the time the link issues a wakeup signal, until the
socket wakes up and re-attempts sending, other senders may have come
in between and occupied the free buffer space in the link. This in turn
may lead to a socket having to make many send attempts before it is
successful. In extremely loaded systems we have observed latency times
of several seconds before a low-priority socket is able to send out a
message.
In this commit, we simplify this mechanism and reduce the risk of the
described scenario happening. When a message is attempted sent via a
congested link, we now let it be added to the link's backlog queue
anyway, thus permitting an oversubscription of one message per source
socket. We still create a wakeup item and return an error code, hence
instructing the sender to block or stop sending. Only when enough space
has been freed up in the link's backlog queue do we issue a wakeup event
that allows the sender to continue with the next message, if any.
The fact that a socket now can consider a message sent even when the
link returns a congestion code means that the sending socket code can
be simplified. Also, since this is a good opportunity to get rid of the
obsolete 'mtu change' condition in the three socket send functions, we
now choose to refactor those functions completely.
Signed-off-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---
net/tipc/bcast.c | 6 +-
net/tipc/link.c | 75 +++++-------
net/tipc/msg.h | 2 -
net/tipc/node.c | 15 +--
net/tipc/socket.c | 347 ++++++++++++++++++++++++------------------------------
5 files changed, 194 insertions(+), 251 deletions(-)
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index aa1babb..c35fad3 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -174,7 +174,7 @@ static void tipc_bcbase_xmit(struct net *net, struct sk_buff_head *xmitq)
* and to identified node local sockets
* @net: the applicable net namespace
* @list: chain of buffers containing message
- * Consumes the buffer chain, except when returning -ELINKCONG
+ * Consumes the buffer chain.
* Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
*/
int tipc_bcast_xmit(struct net *net, struct sk_buff_head *list)
@@ -197,7 +197,7 @@ int tipc_bcast_xmit(struct net *net, struct sk_buff_head *list)
tipc_bcast_unlock(net);
/* Don't send to local node if adding to link failed */
- if (unlikely(rc)) {
+ if (unlikely(rc && (rc != -ELINKCONG))) {
__skb_queue_purge(&rcvq);
return rc;
}
@@ -206,7 +206,7 @@ int tipc_bcast_xmit(struct net *net, struct sk_buff_head *list)
tipc_bcbase_xmit(net, &xmitq);
tipc_sk_mcast_rcv(net, &rcvq, &inputq);
__skb_queue_purge(list);
- return 0;
+ return rc;
}
/* tipc_bcast_rcv - receive a broadcast packet, and deliver to rcv link
diff --git a/net/tipc/link.c b/net/tipc/link.c
index bda89bf..b758ca8 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -776,60 +776,47 @@ int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq)
/**
* link_schedule_user - schedule a message sender for wakeup after congestion
- * @link: congested link
- * @list: message that was attempted sent
+ * @l: congested link
+ * @hdr: header of message that is being sent
* Create pseudo msg to send back to user when congestion abates
- * Does not consume buffer list
*/
-static int link_schedule_user(struct tipc_link *link, struct sk_buff_head *list)
+static int link_schedule_user(struct tipc_link *l, struct tipc_msg *hdr)
{
- struct tipc_msg *msg = buf_msg(skb_peek(list));
- int imp = msg_importance(msg);
- u32 oport = msg_origport(msg);
- u32 addr = tipc_own_addr(link->net);
+ u32 dnode = tipc_own_addr(l->net);
+ u32 dport = msg_origport(hdr);
struct sk_buff *skb;
- /* This really cannot happen... */
- if (unlikely(imp > TIPC_CRITICAL_IMPORTANCE)) {
- pr_warn("%s<%s>, send queue full", link_rst_msg, link->name);
- return -ENOBUFS;
- }
- /* Non-blocking sender: */
- if (TIPC_SKB_CB(skb_peek(list))->wakeup_pending)
- return -ELINKCONG;
-
/* Create and schedule wakeup pseudo message */
skb = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0,
- addr, addr, oport, 0, 0);
+ dnode, l->addr, dport, 0, 0);
if (!skb)
return -ENOBUFS;
- TIPC_SKB_CB(skb)->chain_sz = skb_queue_len(list);
- TIPC_SKB_CB(skb)->chain_imp = imp;
- skb_queue_tail(&link->wakeupq, skb);
- link->stats.link_congs++;
+ msg_set_dest_droppable(buf_msg(skb), true);
+ TIPC_SKB_CB(skb)->chain_imp = msg_importance(hdr);
+ skb_queue_tail(&l->wakeupq, skb);
+ l->stats.link_congs++;
return -ELINKCONG;
}
/**
* link_prepare_wakeup - prepare users for wakeup after congestion
- * @link: congested link
- * Move a number of waiting users, as permitted by available space in
- * the send queue, from link wait queue to node wait queue for wakeup
+ * @l: congested link
+ * Wake up a number of waiting users, as permitted by available space
+ * in the send queue
*/
void link_prepare_wakeup(struct tipc_link *l)
{
- int pnd[TIPC_SYSTEM_IMPORTANCE + 1] = {0,};
- int imp, lim;
struct sk_buff *skb, *tmp;
+ int imp, i = 0;
skb_queue_walk_safe(&l->wakeupq, skb, tmp) {
imp = TIPC_SKB_CB(skb)->chain_imp;
- lim = l->backlog[imp].limit;
- pnd[imp] += TIPC_SKB_CB(skb)->chain_sz;
- if ((pnd[imp] + l->backlog[imp].len) >= lim)
+ if (l->backlog[imp].len < l->backlog[imp].limit) {
+ skb_unlink(skb, &l->wakeupq);
+ skb_queue_tail(l->inputq, skb);
+ } else if (i++ > 10) {
break;
- skb_unlink(skb, &l->wakeupq);
- skb_queue_tail(l->inputq, skb);
+ }
}
}
@@ -869,8 +856,7 @@ void tipc_link_reset(struct tipc_link *l)
* @list: chain of buffers containing message
* @xmitq: returned list of packets to be sent by caller
*
- * Consumes the buffer chain, except when returning -ELINKCONG,
- * since the caller then may want to make more send attempts.
+ * Consumes the buffer chain.
* Returns 0 if success, or errno: -ELINKCONG, -EMSGSIZE or -ENOBUFS
* Messages at TIPC_SYSTEM_IMPORTANCE are always accepted
*/
@@ -879,7 +865,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
{
struct tipc_msg *hdr = buf_msg(skb_peek(list));
unsigned int maxwin = l->window;
- unsigned int i, imp = msg_importance(hdr);
+ int imp = msg_importance(hdr);
unsigned int mtu = l->mtu;
u16 ack = l->rcv_nxt - 1;
u16 seqno = l->snd_nxt;
@@ -888,19 +874,22 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
struct sk_buff_head *backlogq = &l->backlogq;
struct sk_buff *skb, *_skb, *bskb;
int pkt_cnt = skb_queue_len(list);
+ int rc = 0;
- /* Match msg importance against this and all higher backlog limits: */
- if (!skb_queue_empty(backlogq)) {
- for (i = imp; i <= TIPC_SYSTEM_IMPORTANCE; i++) {
- if (unlikely(l->backlog[i].len >= l->backlog[i].limit))
- return link_schedule_user(l, list);
- }
- }
if (unlikely(msg_size(hdr) > mtu)) {
skb_queue_purge(list);
return -EMSGSIZE;
}
+ /* Allow oversubscription of one data msg per source at congestion */
+ if (unlikely(l->backlog[imp].len >= l->backlog[imp].limit)) {
+ if (imp == TIPC_SYSTEM_IMPORTANCE) {
+ pr_warn("%s<%s>, link overflow", link_rst_msg, l->name);
+ return -ENOBUFS;
+ }
+ rc = link_schedule_user(l, hdr);
+ }
+
if (pkt_cnt > 1) {
l->stats.sent_fragmented++;
l->stats.sent_fragments += pkt_cnt;
@@ -946,7 +935,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
skb_queue_splice_tail_init(list, backlogq);
}
l->snd_nxt = seqno;
- return 0;
+ return rc;
}
void tipc_link_advance_backlog(struct tipc_link *l, struct sk_buff_head *xmitq)
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index 8d40861..850ae0e 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -98,8 +98,6 @@ struct tipc_skb_cb {
u32 bytes_read;
struct sk_buff *tail;
bool validated;
- bool wakeup_pending;
- u16 chain_sz;
u16 chain_imp;
u16 ackers;
};
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 9d2f4c2..2883f6a 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1167,7 +1167,7 @@ static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
* @list: chain of buffers containing message
* @dnode: address of destination node
* @selector: a number used for deterministic link selection
- * Consumes the buffer chain, except when returning -ELINKCONG
+ * Consumes the buffer chain.
* Returns 0 if success, otherwise: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE,-ENOBUF
*/
int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
@@ -1206,10 +1206,10 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
spin_unlock_bh(&le->lock);
tipc_node_read_unlock(n);
- if (likely(rc == 0))
- tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr);
- else if (rc == -ENOBUFS)
+ if (unlikely(rc == -ENOBUFS))
tipc_node_link_down(n, bearer_id, false);
+ else
+ tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr);
tipc_node_put(n);
@@ -1221,20 +1221,15 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
* messages, which will not be rejected
* The only exception is datagram messages rerouted after secondary
* lookup, which are rare and safe to dispose of anyway.
- * TODO: Return real return value, and let callers use
- * tipc_wait_for_sendpkt() where applicable
*/
int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,
u32 selector)
{
struct sk_buff_head head;
- int rc;
skb_queue_head_init(&head);
__skb_queue_tail(&head, skb);
- rc = tipc_node_xmit(net, &head, dnode, selector);
- if (rc == -ELINKCONG)
- kfree_skb(skb);
+ tipc_node_xmit(net, &head, dnode, selector);
return 0;
}
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index fae6a55..d2f3539 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -67,12 +67,14 @@ enum {
* @max_pkt: maximum packet size "hint" used when building messages sent by port
* @portid: unique port identity in TIPC socket hash table
* @phdr: preformatted message header used when sending messages
+ * #cong_links: list of congested links
* @publications: list of publications for port
+ * @blocking_link: address of the congested link we are currently sleeping on
* @pub_count: total # of publications port has made during its lifetime
* @probing_state:
* @conn_timeout: the time we can wait for an unresponded setup request
* @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue
- * @link_cong: non-zero if owner must sleep because of link congestion
+ * @cong_link_cnt: number of congested links
* @sent_unacked: # messages sent by socket, and not yet acked by peer
* @rcv_unacked: # messages read by user, but not yet acked back to peer
* @peer: 'connected' peer for dgram/rdm
@@ -87,13 +89,13 @@ struct tipc_sock {
u32 max_pkt;
u32 portid;
struct tipc_msg phdr;
- struct list_head sock_list;
+ struct list_head cong_links;
struct list_head publications;
u32 pub_count;
uint conn_timeout;
atomic_t dupl_rcvcnt;
bool probe_unacked;
- bool link_cong;
+ u16 cong_link_cnt;
u16 snt_unacked;
u16 snd_win;
u16 peer_caps;
@@ -118,8 +120,7 @@ static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid);
static int tipc_sk_insert(struct tipc_sock *tsk);
static void tipc_sk_remove(struct tipc_sock *tsk);
-static int __tipc_send_stream(struct socket *sock, struct msghdr *m,
- size_t dsz);
+static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dsz);
static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz);
static const struct proto_ops packet_ops;
@@ -424,6 +425,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
tsk = tipc_sk(sk);
tsk->max_pkt = MAX_PKT_DEFAULT;
INIT_LIST_HEAD(&tsk->publications);
+ INIT_LIST_HEAD(&tsk->cong_links);
msg = &tsk->phdr;
tn = net_generic(sock_net(sk), tipc_net_id);
tipc_msg_init(tn->own_addr, msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG,
@@ -474,9 +476,14 @@ static void __tipc_shutdown(struct socket *sock, int error)
struct sock *sk = sock->sk;
struct tipc_sock *tsk = tipc_sk(sk);
struct net *net = sock_net(sk);
+ long timeout = CONN_TIMEOUT_DEFAULT;
u32 dnode = tsk_peer_node(tsk);
struct sk_buff *skb;
+ /* Avoid that hi-prio shutdown msgs bypass msgs in link wakeup queue */
+ tipc_wait_for_cond(sock, &timeout, (!tsk->cong_link_cnt &&
+ !tsk_conn_cong(tsk)));
+
/* Reject all unreceived messages, except on an active connection
* (which disconnects locally & sends a 'FIN+' to peer).
*/
@@ -547,7 +554,8 @@ static int tipc_release(struct socket *sock)
/* Reject any messages that accumulated in backlog queue */
release_sock(sk);
-
+ u32_list_purge(&tsk->cong_links);
+ tsk->cong_link_cnt = 0;
call_rcu(&tsk->rcu, tipc_sk_callback);
sock->sk = NULL;
@@ -690,7 +698,7 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
switch (sk->sk_state) {
case TIPC_ESTABLISHED:
- if (!tsk->link_cong && !tsk_conn_cong(tsk))
+ if (!tsk->cong_link_cnt && !tsk_conn_cong(tsk))
mask |= POLLOUT;
/* fall thru' */
case TIPC_LISTEN:
@@ -699,7 +707,7 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
mask |= (POLLIN | POLLRDNORM);
break;
case TIPC_OPEN:
- if (!tsk->link_cong)
+ if (!tsk->cong_link_cnt)
mask |= POLLOUT;
if (tipc_sk_type_connectionless(sk) &&
(!skb_queue_empty(&sk->sk_receive_queue)))
@@ -718,63 +726,48 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
* @sock: socket structure
* @seq: destination address
* @msg: message to send
- * @dsz: total length of message data
- * @timeo: timeout to wait for wakeup
+ * @dlen: length of data to send
+ * @timeout: timeout to wait for wakeup
*
* Called from function tipc_sendmsg(), which has done all sanity checks
* Returns the number of bytes sent on success, or errno
*/
static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
- struct msghdr *msg, size_t dsz, long timeo)
+ struct msghdr *msg, size_t dlen, long timeout)
{
struct sock *sk = sock->sk;
struct tipc_sock *tsk = tipc_sk(sk);
+ struct tipc_msg *hdr = &tsk->phdr;
struct net *net = sock_net(sk);
- struct tipc_msg *mhdr = &tsk->phdr;
- struct sk_buff_head pktchain;
- struct iov_iter save = msg->msg_iter;
- uint mtu;
+ int mtu = tipc_bcast_get_mtu(net);
+ struct sk_buff_head pkts;
int rc;
- if (!timeo && tsk->link_cong)
- return -ELINKCONG;
-
- msg_set_type(mhdr, TIPC_MCAST_MSG);
- msg_set_lookup_scope(mhdr, TIPC_CLUSTER_SCOPE);
- msg_set_destport(mhdr, 0);
- msg_set_destnode(mhdr, 0);
- msg_set_nametype(mhdr, seq->type);
- msg_set_namelower(mhdr, seq->lower);
- msg_set_nameupper(mhdr, seq->upper);
- msg_set_hdr_sz(mhdr, MCAST_H_SIZE);
-
- skb_queue_head_init(&pktchain);
+ rc = tipc_wait_for_cond(sock, &timeout, !tsk->cong_link_cnt);
+ if (unlikely(rc))
+ return rc;
-new_mtu:
- mtu = tipc_bcast_get_mtu(net);
- rc = tipc_msg_build(mhdr, msg, 0, dsz, mtu, &pktchain);
- if (unlikely(rc < 0))
+ msg_set_type(hdr, TIPC_MCAST_MSG);
+ msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE);
+ msg_set_destport(hdr, 0);
+ msg_set_destnode(hdr, 0);
+ msg_set_nametype(hdr, seq->type);
+ msg_set_namelower(hdr, seq->lower);
+ msg_set_nameupper(hdr, seq->upper);
+ msg_set_hdr_sz(hdr, MCAST_H_SIZE);
+
+ skb_queue_head_init(&pkts);
+ rc = tipc_msg_build(hdr, msg, 0, dlen, mtu, &pkts);
+ if (unlikely(rc != dlen))
return rc;
- do {
- rc = tipc_bcast_xmit(net, &pktchain);
- if (likely(!rc))
- return dsz;
-
- if (rc == -ELINKCONG) {
- tsk->link_cong = 1;
- rc = tipc_wait_for_cond(sock, &timeo, !tsk->link_cong);
- if (!rc)
- continue;
- }
- __skb_queue_purge(&pktchain);
- if (rc == -EMSGSIZE) {
- msg->msg_iter = save;
- goto new_mtu;
- }
- break;
- } while (1);
- return rc;
+ rc = tipc_bcast_xmit(net, &pkts);
+ if (unlikely(rc == -ELINKCONG)) {
+ tsk->cong_link_cnt = 1;
+ rc = 0;
+ }
+
+ return rc ? rc : dlen;
}
/**
@@ -898,35 +891,38 @@ static int tipc_sendmsg(struct socket *sock,
return ret;
}
-static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
+static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
{
- DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
struct sock *sk = sock->sk;
- struct tipc_sock *tsk = tipc_sk(sk);
struct net *net = sock_net(sk);
- struct tipc_msg *mhdr = &tsk->phdr;
- u32 dnode, dport;
- struct sk_buff_head pktchain;
- bool is_connectionless = tipc_sk_type_connectionless(sk);
- struct sk_buff *skb;
+ struct tipc_sock *tsk = tipc_sk(sk);
+ DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
+ long timeout = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
+ struct list_head *clinks = &tsk->cong_links;
+ bool syn = !tipc_sk_type_connectionless(sk);
+ struct tipc_msg *hdr = &tsk->phdr;
struct tipc_name_seq *seq;
- struct iov_iter save;
- u32 mtu;
- long timeo;
- int rc;
+ struct sk_buff_head pkts;
+ u32 type, inst, domain;
+ u32 dnode, dport;
+ int mtu, rc;
- if (dsz > TIPC_MAX_USER_MSG_SIZE)
+ if (unlikely(dlen > TIPC_MAX_USER_MSG_SIZE))
return -EMSGSIZE;
+
if (unlikely(!dest)) {
- if (is_connectionless && tsk->peer.family == AF_TIPC)
- dest = &tsk->peer;
- else
+ dest = &tsk->peer;
+ if (!syn || dest->family != AF_TIPC)
return -EDESTADDRREQ;
- } else if (unlikely(m->msg_namelen < sizeof(*dest)) ||
- dest->family != AF_TIPC) {
- return -EINVAL;
}
- if (!is_connectionless) {
+
+ if (unlikely(m->msg_namelen < sizeof(*dest)))
+ return -EINVAL;
+
+ if (unlikely(dest->family != AF_TIPC))
+ return -EINVAL;
+
+ if (unlikely(syn)) {
if (sk->sk_state == TIPC_LISTEN)
return -EPIPE;
if (sk->sk_state != TIPC_OPEN)
@@ -938,72 +934,62 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
tsk->conn_instance = dest->addr.name.name.instance;
}
}
- seq = &dest->addr.nameseq;
- timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
- if (dest->addrtype == TIPC_ADDR_MCAST) {
- return tipc_sendmcast(sock, seq, m, dsz, timeo);
- } else if (dest->addrtype == TIPC_ADDR_NAME) {
- u32 type = dest->addr.name.name.type;
- u32 inst = dest->addr.name.name.instance;
- u32 domain = dest->addr.name.domain;
+ seq = &dest->addr.nameseq;
+ if (dest->addrtype == TIPC_ADDR_MCAST)
+ return tipc_sendmcast(sock, seq, m, dlen, timeout);
+ if (dest->addrtype == TIPC_ADDR_NAME) {
+ type = dest->addr.name.name.type;
+ inst = dest->addr.name.name.instance;
+ domain = dest->addr.name.domain;
dnode = domain;
- msg_set_type(mhdr, TIPC_NAMED_MSG);
- msg_set_hdr_sz(mhdr, NAMED_H_SIZE);
- msg_set_nametype(mhdr, type);
- msg_set_nameinst(mhdr, inst);
- msg_set_lookup_scope(mhdr, tipc_addr_scope(domain));
+ msg_set_type(hdr, TIPC_NAMED_MSG);
+ msg_set_hdr_sz(hdr, NAMED_H_SIZE);
+ msg_set_nametype(hdr, type);
+ msg_set_nameinst(hdr, inst);
+ msg_set_lookup_scope(hdr, tipc_addr_scope(domain));
dport = tipc_nametbl_translate(net, type, inst, &dnode);
- msg_set_destnode(mhdr, dnode);
- msg_set_destport(mhdr, dport);
+ msg_set_destnode(hdr, dnode);
+ msg_set_destport(hdr, dport);
if (unlikely(!dport && !dnode))
return -EHOSTUNREACH;
+
} else if (dest->addrtype == TIPC_ADDR_ID) {
dnode = dest->addr.id.node;
- msg_set_type(mhdr, TIPC_DIRECT_MSG);
- msg_set_lookup_scope(mhdr, 0);
- msg_set_destnode(mhdr, dnode);
- msg_set_destport(mhdr, dest->addr.id.ref);
- msg_set_hdr_sz(mhdr, BASIC_H_SIZE);
+ msg_set_type(hdr, TIPC_DIRECT_MSG);
+ msg_set_lookup_scope(hdr, 0);
+ msg_set_destnode(hdr, dnode);
+ msg_set_destport(hdr, dest->addr.id.ref);
+ msg_set_hdr_sz(hdr, BASIC_H_SIZE);
}
- skb_queue_head_init(&pktchain);
- save = m->msg_iter;
-new_mtu:
+ /* Block or return if destination link is congested */
+ rc = tipc_wait_for_cond(sock, &timeout, !u32_find(clinks, dnode));
+ if (unlikely(rc))
+ return rc;
+
+ skb_queue_head_init(&pkts);
mtu = tipc_node_get_mtu(net, dnode, tsk->portid);
- rc = tipc_msg_build(mhdr, m, 0, dsz, mtu, &pktchain);
- if (rc < 0)
+ rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts);
+ if (unlikely(rc != dlen))
return rc;
- do {
- skb = skb_peek(&pktchain);
- TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong;
- rc = tipc_node_xmit(net, &pktchain, dnode, tsk->portid);
- if (likely(!rc)) {
- if (!is_connectionless)
- tipc_set_sk_state(sk, TIPC_CONNECTING);
- return dsz;
- }
- if (rc == -ELINKCONG) {
- tsk->link_cong = 1;
- rc = tipc_wait_for_cond(sock, &timeo, !tsk->link_cong);
- if (!rc)
- continue;
- }
- __skb_queue_purge(&pktchain);
- if (rc == -EMSGSIZE) {
- m->msg_iter = save;
- goto new_mtu;
- }
- break;
- } while (1);
+ rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);
+ if (unlikely(rc == -ELINKCONG)) {
+ u32_push(clinks, dnode);
+ tsk->cong_link_cnt++;
+ rc = 0;
+ }
- return rc;
+ if (unlikely(syn && !rc))
+ tipc_set_sk_state(sk, TIPC_CONNECTING);
+
+ return rc ? rc : dlen;
}
/**
- * tipc_send_stream - send stream-oriented data
+ * tipc_sendstream - send stream-oriented data
* @sock: socket structure
* @m: data to send
* @dsz: total length of data to be transmitted
@@ -1013,97 +999,69 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
* Returns the number of bytes sent on success (or partial success),
* or errno if no data sent
*/
-static int tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
+static int tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dsz)
{
struct sock *sk = sock->sk;
int ret;
lock_sock(sk);
- ret = __tipc_send_stream(sock, m, dsz);
+ ret = __tipc_sendstream(sock, m, dsz);
release_sock(sk);
return ret;
}
-static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
+static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dlen)
{
struct sock *sk = sock->sk;
- struct net *net = sock_net(sk);
- struct tipc_sock *tsk = tipc_sk(sk);
- struct tipc_msg *mhdr = &tsk->phdr;
- struct sk_buff_head pktchain;
DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
- u32 portid = tsk->portid;
- int rc = -EINVAL;
- long timeo;
- u32 dnode;
- uint mtu, send, sent = 0;
- struct iov_iter save;
- int hlen = MIN_H_SIZE;
-
- /* Handle implied connection establishment */
- if (unlikely(dest)) {
- rc = __tipc_sendmsg(sock, m, dsz);
- hlen = msg_hdr_sz(mhdr);
- if (dsz && (dsz == rc))
- tsk->snt_unacked = tsk_inc(tsk, dsz + hlen);
- return rc;
- }
- if (dsz > (uint)INT_MAX)
- return -EMSGSIZE;
-
- if (unlikely(!tipc_sk_connected(sk))) {
- if (sk->sk_state == TIPC_DISCONNECTING)
- return -EPIPE;
- else
- return -ENOTCONN;
- }
+ long timeout = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
+ struct tipc_sock *tsk = tipc_sk(sk);
+ struct tipc_msg *hdr = &tsk->phdr;
+ struct net *net = sock_net(sk);
+ struct sk_buff_head pkts;
+ u32 dnode = tsk_peer_node(tsk);
+ int send, sent = 0;
+ int rc = 0;
- timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
- if (!timeo && tsk->link_cong)
- return -ELINKCONG;
+ skb_queue_head_init(&pkts);
- dnode = tsk_peer_node(tsk);
- skb_queue_head_init(&pktchain);
+ if (unlikely(dlen > INT_MAX))
+ return -EMSGSIZE;
-next:
- save = m->msg_iter;
- mtu = tsk->max_pkt;
- send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE);
- rc = tipc_msg_build(mhdr, m, sent, send, mtu, &pktchain);
- if (unlikely(rc < 0))
+ /* Handle implicit connection setup */
+ if (unlikely(dest)) {
+ rc = __tipc_sendmsg(sock, m, dlen);
+ if (dlen && (dlen == rc))
+ tsk->snt_unacked = tsk_inc(tsk, dlen + msg_hdr_sz(hdr));
return rc;
+ }
do {
- if (likely(!tsk_conn_cong(tsk))) {
- rc = tipc_node_xmit(net, &pktchain, dnode, portid);
- if (likely(!rc)) {
- tsk->snt_unacked += tsk_inc(tsk, send + hlen);
- sent += send;
- if (sent == dsz)
- return dsz;
- goto next;
- }
- if (rc == -EMSGSIZE) {
- __skb_queue_purge(&pktchain);
- tsk->max_pkt = tipc_node_get_mtu(net, dnode,
- portid);
- m->msg_iter = save;
- goto next;
- }
- if (rc != -ELINKCONG)
- break;
-
- tsk->link_cong = 1;
- }
- rc = tipc_wait_for_cond(sock, &timeo,
- (!tsk->link_cong &&
+ rc = tipc_wait_for_cond(sock, &timeout,
+ (!tsk->cong_link_cnt &&
!tsk_conn_cong(tsk) &&
tipc_sk_connected(sk)));
- } while (!rc);
+ if (unlikely(rc))
+ break;
+
+ send = min_t(size_t, dlen - sent, TIPC_MAX_USER_MSG_SIZE);
+ rc = tipc_msg_build(hdr, m, sent, send, tsk->max_pkt, &pkts);
+ if (unlikely(rc != send))
+ break;
+
+ rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);
+ if (unlikely(rc == -ELINKCONG)) {
+ tsk->cong_link_cnt = 1;
+ rc = 0;
+ }
+ if (likely(!rc)) {
+ tsk->snt_unacked += tsk_inc(tsk, send + MIN_H_SIZE);
+ sent += send;
+ }
+ } while (sent < dlen && !rc);
- __skb_queue_purge(&pktchain);
- return sent ? sent : rc;
+ return rc ? rc : sent;
}
/**
@@ -1121,7 +1079,7 @@ static int tipc_send_packet(struct socket *sock, struct msghdr *m, size_t dsz)
if (dsz > TIPC_MAX_USER_MSG_SIZE)
return -EMSGSIZE;
- return tipc_send_stream(sock, m, dsz);
+ return tipc_sendstream(sock, m, dsz);
}
/* tipc_sk_finish_conn - complete the setup of a connection
@@ -1688,6 +1646,7 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb,
unsigned int limit = rcvbuf_limit(sk, skb);
int err = TIPC_OK;
int usr = msg_user(hdr);
+ u32 onode;
if (unlikely(msg_user(hdr) == CONN_MANAGER)) {
tipc_sk_proto_rcv(tsk, skb, xmitq);
@@ -1695,8 +1654,10 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb,
}
if (unlikely(usr == SOCK_WAKEUP)) {
+ onode = msg_orignode(hdr);
kfree_skb(skb);
- tsk->link_cong = 0;
+ u32_del(&tsk->cong_links, onode);
+ tsk->cong_link_cnt--;
sk->sk_write_space(sk);
return false;
}
@@ -2104,7 +2065,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
struct msghdr m = {NULL,};
tsk_advance_rx_queue(sk);
- __tipc_send_stream(new_sock, &m, 0);
+ __tipc_sendstream(new_sock, &m, 0);
} else {
__skb_dequeue(&sk->sk_receive_queue);
__skb_queue_head(&new_sk->sk_receive_queue, buf);
@@ -2565,7 +2526,7 @@ static const struct proto_ops stream_ops = {
.shutdown = tipc_shutdown,
.setsockopt = tipc_setsockopt,
.getsockopt = tipc_getsockopt,
- .sendmsg = tipc_send_stream,
+ .sendmsg = tipc_sendstream,
.recvmsg = tipc_recv_stream,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage
--
2.7.4
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
^ permalink raw reply related
* [net-next 2/3] tipc: modify struct tipc_plist to be more versatile
From: Jon Maloy @ 2017-01-03 15:55 UTC (permalink / raw)
To: davem; +Cc: Jon Maloy, netdev, tipc-discussion
In-Reply-To: <1483458911-32549-1-git-send-email-jon.maloy@ericsson.com>
During multicast reception we currently use a simple linked list with
push/pop semantics to store port numbers.
We now see a need for a more generic list for storing values of type
u32. We therefore make some modifications to this list, while replacing
the prefix 'tipc_plist_' with 'u32_'. We also add a couple of new
functions which will come to use in the next commits.
Acked-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---
net/tipc/name_table.c | 100 ++++++++++++++++++++++++++++++++++++--------------
net/tipc/name_table.h | 21 ++++-------
net/tipc/socket.c | 8 ++--
3 files changed, 83 insertions(+), 46 deletions(-)
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index e190460..5a86df1 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -608,7 +608,7 @@ u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance,
* Returns non-zero if any off-node ports overlap
*/
int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
- u32 limit, struct tipc_plist *dports)
+ u32 limit, struct list_head *dports)
{
struct name_seq *seq;
struct sub_seq *sseq;
@@ -633,7 +633,7 @@ int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
info = sseq->info;
list_for_each_entry(publ, &info->node_list, node_list) {
if (publ->scope <= limit)
- tipc_plist_push(dports, publ->ref);
+ u32_push(dports, publ->ref);
}
if (info->cluster_list_size != info->node_list_size)
@@ -1022,40 +1022,84 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
-void tipc_plist_push(struct tipc_plist *pl, u32 port)
+struct u32_item {
+ struct list_head list;
+ u32 value;
+};
+
+bool u32_find(struct list_head *l, u32 value)
{
- struct tipc_plist *nl;
+ struct u32_item *item;
- if (likely(!pl->port)) {
- pl->port = port;
- return;
+ list_for_each_entry(item, l, list) {
+ if (item->value == value)
+ return true;
}
- if (pl->port == port)
- return;
- list_for_each_entry(nl, &pl->list, list) {
- if (nl->port == port)
- return;
+ return false;
+}
+
+bool u32_push(struct list_head *l, u32 value)
+{
+ struct u32_item *item;
+
+ list_for_each_entry(item, l, list) {
+ if (item->value == value)
+ return false;
+ }
+ item = kmalloc(sizeof(*item), GFP_ATOMIC);
+ if (unlikely(!item))
+ return false;
+
+ item->value = value;
+ list_add(&item->list, l);
+ return true;
+}
+
+u32 u32_pop(struct list_head *l)
+{
+ struct u32_item *item;
+ u32 value = 0;
+
+ if (list_empty(l))
+ return 0;
+ item = list_first_entry(l, typeof(*item), list);
+ value = item->value;
+ list_del(&item->list);
+ kfree(item);
+ return value;
+}
+
+bool u32_del(struct list_head *l, u32 value)
+{
+ struct u32_item *item, *tmp;
+
+ list_for_each_entry_safe(item, tmp, l, list) {
+ if (item->value != value)
+ continue;
+ list_del(&item->list);
+ kfree(item);
+ return true;
}
- nl = kmalloc(sizeof(*nl), GFP_ATOMIC);
- if (nl) {
- nl->port = port;
- list_add(&nl->list, &pl->list);
+ return false;
+}
+
+void u32_list_purge(struct list_head *l)
+{
+ struct u32_item *item, *tmp;
+
+ list_for_each_entry_safe(item, tmp, l, list) {
+ list_del(&item->list);
+ kfree(item);
}
}
-u32 tipc_plist_pop(struct tipc_plist *pl)
+int u32_list_len(struct list_head *l)
{
- struct tipc_plist *nl;
- u32 port = 0;
+ struct u32_item *item;
+ int i = 0;
- if (likely(list_empty(&pl->list))) {
- port = pl->port;
- pl->port = 0;
- return port;
+ list_for_each_entry(item, l, list) {
+ i++;
}
- nl = list_first_entry(&pl->list, typeof(*nl), list);
- port = nl->port;
- list_del(&nl->list);
- kfree(nl);
- return port;
+ return i;
}
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index 1524a73..c89bb3f 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -99,7 +99,7 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb);
u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *node);
int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
- u32 limit, struct tipc_plist *dports);
+ u32 limit, struct list_head *dports);
struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,
u32 upper, u32 scope, u32 port_ref,
u32 key);
@@ -116,18 +116,11 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
int tipc_nametbl_init(struct net *net);
void tipc_nametbl_stop(struct net *net);
-struct tipc_plist {
- struct list_head list;
- u32 port;
-};
-
-static inline void tipc_plist_init(struct tipc_plist *pl)
-{
- INIT_LIST_HEAD(&pl->list);
- pl->port = 0;
-}
-
-void tipc_plist_push(struct tipc_plist *pl, u32 port);
-u32 tipc_plist_pop(struct tipc_plist *pl);
+bool u32_push(struct list_head *l, u32 value);
+u32 u32_pop(struct list_head *l);
+bool u32_find(struct list_head *l, u32 value);
+bool u32_del(struct list_head *l, u32 value);
+void u32_list_purge(struct list_head *l);
+int u32_list_len(struct list_head *l);
#endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index f27462e..fae6a55 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -788,7 +788,7 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
struct sk_buff_head *inputq)
{
struct tipc_msg *msg;
- struct tipc_plist dports;
+ struct list_head dports;
u32 portid;
u32 scope = TIPC_CLUSTER_SCOPE;
struct sk_buff_head tmpq;
@@ -796,7 +796,7 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
struct sk_buff *skb, *_skb;
__skb_queue_head_init(&tmpq);
- tipc_plist_init(&dports);
+ INIT_LIST_HEAD(&dports);
skb = tipc_skb_peek(arrvq, &inputq->lock);
for (; skb; skb = tipc_skb_peek(arrvq, &inputq->lock)) {
@@ -810,8 +810,8 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
tipc_nametbl_mc_translate(net,
msg_nametype(msg), msg_namelower(msg),
msg_nameupper(msg), scope, &dports);
- portid = tipc_plist_pop(&dports);
- for (; portid; portid = tipc_plist_pop(&dports)) {
+ portid = u32_pop(&dports);
+ for (; portid; portid = u32_pop(&dports)) {
_skb = __pskb_copy(skb, hsz, GFP_ATOMIC);
if (_skb) {
msg_set_destport(buf_msg(_skb), portid);
--
2.7.4
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
^ permalink raw reply related
* [net-next 1/3] tipc: unify tipc_wait_for_sndpkt() and tipc_wait_for_sndmsg() functions
From: Jon Maloy @ 2017-01-03 15:55 UTC (permalink / raw)
To: davem; +Cc: Jon Maloy, netdev, tipc-discussion
In-Reply-To: <1483458911-32549-1-git-send-email-jon.maloy@ericsson.com>
The functions tipc_wait_for_sndpkt() and tipc_wait_for_sndmsg() are very
similar. The latter function is also called from two locations, and
there will be more in the coming commits, which will all need to test on
different conditions.
Instead of making yet another duplicates of the function, we now
introduce a new macro tipc_wait_for_cond() where the wakeup condition
can be stated as an argument to the call. This macro replaces all
current and future uses of the two functions, which can now be
eliminated.
Acked-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---
net/tipc/socket.c | 108 +++++++++++++++++++++++++-----------------------------
1 file changed, 49 insertions(+), 59 deletions(-)
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 800caaa..f27462e 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -110,7 +110,6 @@ static void tipc_write_space(struct sock *sk);
static void tipc_sock_destruct(struct sock *sk);
static int tipc_release(struct socket *sock);
static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);
-static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p);
static void tipc_sk_timeout(unsigned long data);
static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
struct tipc_name_seq const *seq);
@@ -334,6 +333,49 @@ static int tipc_set_sk_state(struct sock *sk, int state)
return res;
}
+static int tipc_sk_sock_err(struct socket *sock, long *timeout)
+{
+ struct sock *sk = sock->sk;
+ int err = sock_error(sk);
+ int typ = sock->type;
+
+ if (err)
+ return err;
+ if (typ == SOCK_STREAM || typ == SOCK_SEQPACKET) {
+ if (sk->sk_state == TIPC_DISCONNECTING)
+ return -EPIPE;
+ else if (!tipc_sk_connected(sk))
+ return -ENOTCONN;
+ }
+ if (!*timeout)
+ return -EAGAIN;
+ if (signal_pending(current))
+ return sock_intr_errno(*timeout);
+
+ return 0;
+}
+
+#define tipc_wait_for_cond(sock_, timeout_, condition_) \
+({ \
+ int rc_ = 0; \
+ int done_ = 0; \
+ \
+ while (!(condition_) && !done_) { \
+ struct sock *sk_ = sock->sk; \
+ DEFINE_WAIT_FUNC(wait_, woken_wake_function); \
+ \
+ rc_ = tipc_sk_sock_err(sock_, timeout_); \
+ if (rc_) \
+ break; \
+ prepare_to_wait(sk_sleep(sk_), &wait_, \
+ TASK_INTERRUPTIBLE); \
+ done_ = sk_wait_event(sk_, timeout_, \
+ (condition_), &wait_); \
+ remove_wait_queue(sk_sleep(sk_), &wait_); \
+ } \
+ rc_; \
+})
+
/**
* tipc_sk_create - create a TIPC socket
* @net: network namespace (must be default network)
@@ -721,7 +763,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
if (rc == -ELINKCONG) {
tsk->link_cong = 1;
- rc = tipc_wait_for_sndmsg(sock, &timeo);
+ rc = tipc_wait_for_cond(sock, &timeo, !tsk->link_cong);
if (!rc)
continue;
}
@@ -830,31 +872,6 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
kfree_skb(skb);
}
-static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)
-{
- DEFINE_WAIT_FUNC(wait, woken_wake_function);
- struct sock *sk = sock->sk;
- struct tipc_sock *tsk = tipc_sk(sk);
- int done;
-
- do {
- int err = sock_error(sk);
- if (err)
- return err;
- if (sk->sk_shutdown & SEND_SHUTDOWN)
- return -EPIPE;
- if (!*timeo_p)
- return -EAGAIN;
- if (signal_pending(current))
- return sock_intr_errno(*timeo_p);
-
- add_wait_queue(sk_sleep(sk), &wait);
- done = sk_wait_event(sk, timeo_p, !tsk->link_cong, &wait);
- remove_wait_queue(sk_sleep(sk), &wait);
- } while (!done);
- return 0;
-}
-
/**
* tipc_sendmsg - send message in connectionless manner
* @sock: socket structure
@@ -970,7 +987,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
}
if (rc == -ELINKCONG) {
tsk->link_cong = 1;
- rc = tipc_wait_for_sndmsg(sock, &timeo);
+ rc = tipc_wait_for_cond(sock, &timeo, !tsk->link_cong);
if (!rc)
continue;
}
@@ -985,36 +1002,6 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
return rc;
}
-static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p)
-{
- DEFINE_WAIT_FUNC(wait, woken_wake_function);
- struct sock *sk = sock->sk;
- struct tipc_sock *tsk = tipc_sk(sk);
- int done;
-
- do {
- int err = sock_error(sk);
- if (err)
- return err;
- if (sk->sk_state == TIPC_DISCONNECTING)
- return -EPIPE;
- else if (!tipc_sk_connected(sk))
- return -ENOTCONN;
- if (!*timeo_p)
- return -EAGAIN;
- if (signal_pending(current))
- return sock_intr_errno(*timeo_p);
-
- add_wait_queue(sk_sleep(sk), &wait);
- done = sk_wait_event(sk, timeo_p,
- (!tsk->link_cong &&
- !tsk_conn_cong(tsk)) ||
- !tipc_sk_connected(sk), &wait);
- remove_wait_queue(sk_sleep(sk), &wait);
- } while (!done);
- return 0;
-}
-
/**
* tipc_send_stream - send stream-oriented data
* @sock: socket structure
@@ -1109,7 +1096,10 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
tsk->link_cong = 1;
}
- rc = tipc_wait_for_sndpkt(sock, &timeo);
+ rc = tipc_wait_for_cond(sock, &timeo,
+ (!tsk->link_cong &&
+ !tsk_conn_cong(tsk) &&
+ tipc_sk_connected(sk)));
} while (!rc);
__skb_queue_purge(&pktchain);
--
2.7.4
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
^ permalink raw reply related
* [net-next 0/3] tipc: improve interaction socket-link
From: Jon Maloy @ 2017-01-03 15:55 UTC (permalink / raw)
To: davem; +Cc: Jon Maloy, netdev, tipc-discussion
We fix a very real starvation problem that may occur when a link
encounters send buffer congestion. At the same time we make the
interaction between the socket and link layer simpler and more
consistent.
Jon Maloy (3):
tipc: unify tipc_wait_for_sndpkt() and tipc_wait_for_sndmsg()
functions
tipc: modify struct tipc_plist to be more versatile
tipc: reduce risk of user starvation during link congestion
net/tipc/bcast.c | 6 +-
net/tipc/link.c | 75 ++++-----
net/tipc/msg.h | 2 -
net/tipc/name_table.c | 100 +++++++----
net/tipc/name_table.h | 21 +--
net/tipc/node.c | 15 +-
net/tipc/socket.c | 449 ++++++++++++++++++++++----------------------------
7 files changed, 319 insertions(+), 349 deletions(-)
--
2.7.4
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
^ permalink raw reply
* Re: [PATCH net-next] sfc-falcon: declare module version (same as ethtool drvinfo version)
From: David Miller @ 2017-01-03 15:54 UTC (permalink / raw)
To: ecree; +Cc: linux-net-drivers, bkenward, netdev
In-Reply-To: <f718c632-3a59-b841-1836-0a6f04553489@solarflare.com>
From: Edward Cree <ecree@solarflare.com>
Date: Tue, 3 Jan 2017 15:46:15 +0000
> Signed-off-by: Edward Cree <ecree@solarflare.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next] sfc: declare module version (same as ethtool drvinfo version)
From: David Miller @ 2017-01-03 15:54 UTC (permalink / raw)
To: ecree; +Cc: linux-net-drivers, bkenward, netdev
In-Reply-To: <3453b0f7-a522-e332-590a-e04d4d4b50a5@solarflare.com>
From: Edward Cree <ecree@solarflare.com>
Date: Tue, 3 Jan 2017 15:46:00 +0000
> Signed-off-by: Edward Cree <ecree@solarflare.com>
Applied.
^ permalink raw reply
* [PATCH net-next] sfc: declare module version (same as ethtool drvinfo version)
From: Edward Cree @ 2017-01-03 15:46 UTC (permalink / raw)
To: linux-net-drivers, davem; +Cc: bkenward, netdev
Signed-off-by: Edward Cree <ecree@solarflare.com>
---
drivers/net/ethernet/sfc/efx.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 5a5dcad..bbbed2e 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -3585,3 +3585,4 @@ MODULE_AUTHOR("Solarflare Communications and "
MODULE_DESCRIPTION("Solarflare network driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, efx_pci_table);
+MODULE_VERSION(EFX_DRIVER_VERSION);
^ permalink raw reply related
* Re: [PATCH] Ipvlan should return an error when an address is already in use.
From: Aaron Conole @ 2017-01-03 15:50 UTC (permalink / raw)
To: Krister Johansen; +Cc: David S. Miller, Mahesh Bandewar, netdev
In-Reply-To: <20161231041058.GC2448@templeofstupid.com>
Hi Krister,
Krister Johansen <kjlx@templeofstupid.com> writes:
> The ipvlan code already knows how to detect when a duplicate address is
> about to be assigned to an ipvlan device. However, that failure is not
> propogated outward and leads to a silent failure. This teaches the ip
> address addition functions how to report this error to the user
> applications so that a notifier chain failure during ip address addition
> will not appear to succeed when it actually has not.
>
> This can be especially useful if it is necessary to provision many
> ipvlans in containers. The provisioning software (or operator) can use
> this to detect situations where an ip address is unexpectedly in use.
>
> Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
> ---
...
> @@ -489,7 +490,12 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
> Notifier will trigger FIB update, so that
> listeners of netlink will know about new ifaddr */
> rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
> - blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
> + ret = blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Why are you doing this assignment if you aren't using the result?
> + ret = notifier_to_errno(ret);
> + if (ret) {
> + __inet_del_ifa(in_dev, ifap, 1, NULL, portid);
> + return ret;
> + }
>
> return 0;
> }
<<snip>>
> @@ -1031,9 +1032,15 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
> out2:
> rcu_read_unlock_bh();
>
> - if (likely(err == 0))
> - inet6addr_notifier_call_chain(NETDEV_UP, ifa);
> - else {
> + if (likely(err == 0)) {
> + err = inet6addr_notifier_call_chain(NETDEV_UP, ifa);
Same here...
> + err = notifier_to_errno(err);
> + if (err) {
> + __ipv6_del_addr(ifa, false);
> + ifa = ERR_PTR(err);
> + return ifa;
> + }
> + } else {
> kfree(ifa);
> ifa = ERR_PTR(err);
> }
^ permalink raw reply
* [PATCH net-next] sfc-falcon: declare module version (same as ethtool drvinfo version)
From: Edward Cree @ 2017-01-03 15:46 UTC (permalink / raw)
To: linux-net-drivers, davem; +Cc: bkenward, netdev
Signed-off-by: Edward Cree <ecree@solarflare.com>
---
drivers/net/ethernet/sfc/falcon/efx.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c
index 438ef9e..ec3ac0e 100644
--- a/drivers/net/ethernet/sfc/falcon/efx.c
+++ b/drivers/net/ethernet/sfc/falcon/efx.c
@@ -3348,3 +3348,4 @@ MODULE_AUTHOR("Solarflare Communications and "
MODULE_DESCRIPTION("Solarflare Falcon network driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, ef4_pci_table);
+MODULE_VERSION(EF4_DRIVER_VERSION);
^ permalink raw reply related
* [PATCH net-next] net/sched: cls_matchall: Fix error path
From: Yotam Gigi @ 2017-01-03 15:47 UTC (permalink / raw)
To: jhs, davem, eladr, jiri, netdev; +Cc: Yotam Gigi
Fix several error paths in matchall:
- Release reference to actions in case the hardware fails offloading
(relevant to skip_sw only)
- Fix error path in case tcf_exts initialization fails
Fixes: bf3994d2ed31 ("net/sched: introduce Match-all classifier")
Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
---
net/sched/cls_matchall.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c
index f935429..ce7d28b 100644
--- a/net/sched/cls_matchall.c
+++ b/net/sched/cls_matchall.c
@@ -144,7 +144,7 @@ static int mall_set_parms(struct net *net, struct tcf_proto *tp,
tcf_exts_init(&e, TCA_MATCHALL_ACT, 0);
err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
if (err < 0)
- return err;
+ goto errout;
if (tb[TCA_MATCHALL_CLASSID]) {
f->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
@@ -154,6 +154,9 @@ static int mall_set_parms(struct net *net, struct tcf_proto *tp,
tcf_exts_change(tp, &f->exts, &e);
return 0;
+errout:
+ tcf_exts_destroy(&e);
+ return err;
}
static int mall_change(struct net *net, struct sk_buff *in_skb,
@@ -220,6 +223,7 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
return 0;
errout:
+ tcf_exts_destroy(&f->exts);
kfree(f);
return err;
}
--
2.4.11
^ permalink raw reply related
* Re: [PATCH 2/2] can: spi: hi311x: Add Holt HI-311x CAN driver
From: Marc Kleine-Budde @ 2017-01-03 15:31 UTC (permalink / raw)
To: Akshay Bhat, wg, robh+dt
Cc: mark.rutland, linux-can, netdev, devicetree, linux-kernel,
Akshay Bhat
In-Reply-To: <1479146144-29143-2-git-send-email-akshay.bhat@timesys.com>
[-- Attachment #1.1: Type: text/plain, Size: 34565 bytes --]
On 11/14/2016 06:55 PM, Akshay Bhat wrote:
> This patch adds support for the Holt HI-311x CAN controller. The HI311x
> CAN controller is capable of transmitting and receiving standard data
> frames, extended data frames and remote frames. The HI311x interfaces
> with the host over SPI.
Don't use uint8_t and similar in the kernel, please use u8 instead.
>
> Datasheet: www.holtic.com/documents/371-hi-3110_v-rev-jpdf.do
>
> Signed-off-by: Akshay Bhat <nodeax@gmail.com>
> ---
> drivers/net/can/spi/Kconfig | 6 +
> drivers/net/can/spi/Makefile | 1 +
> drivers/net/can/spi/hi311x.c | 1071 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 1078 insertions(+)
> create mode 100644 drivers/net/can/spi/hi311x.c
>
> diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
> index 148cae5..9eb1bb1 100644
> --- a/drivers/net/can/spi/Kconfig
> +++ b/drivers/net/can/spi/Kconfig
> @@ -7,4 +7,10 @@ config CAN_MCP251X
> ---help---
> Driver for the Microchip MCP251x SPI CAN controllers.
>
> +config CAN_HI311X
> + tristate "Holt HI311x SPI CAN controllers"
> + depends on CAN_DEV && SPI && HAS_DMA
> + ---help---
> + Driver for the Holt HI311x SPI CAN controllers.
> +
> endmenu
> diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
> index 0e86040..eac7c3a 100644
> --- a/drivers/net/can/spi/Makefile
> +++ b/drivers/net/can/spi/Makefile
> @@ -4,3 +4,4 @@
>
>
> obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
> +obj-$(CONFIG_CAN_HI311X) += hi311x.o
Please keep sorted alphabetically. Same for the Kconfig.
> diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
> new file mode 100644
> index 0000000..1020166
> --- /dev/null
> +++ b/drivers/net/can/spi/hi311x.c
> @@ -0,0 +1,1071 @@
> +/* CAN bus driver for Holt HI3110 CAN Controller with SPI Interface
> + *
> + * Based on Microchip 251x CAN Controller (mcp251x) Linux kernel driver
You might want to add the copyright of the mcp authors.
> + *
> + * Copyright(C) Timesys Corporation 2016
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/can/core.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/led.h>
> +#include <linux/clk.h>
> +#include <linux/completion.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/freezer.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/slab.h>
> +#include <linux/spi/spi.h>
> +#include <linux/uaccess.h>
> +
Please use just a single space after each macro.
VVVVVVVV
> +#define HI3110_MASTER_RESET 0x56
> +#define HI3110_READ_CTRL0 0xD2
> +#define HI3110_READ_CTRL1 0xD4
> +#define HI3110_READ_STATF 0xE2
> +#define HI3110_WRITE_CTRL0 0x14
> +#define HI3110_WRITE_CTRL1 0x16
> +#define HI3110_WRITE_INTE 0x1C
> +#define HI3110_WRITE_BTR0 0x18
> +#define HI3110_WRITE_BTR1 0x1A
> +#define HI3110_READ_BTR0 0xD6
> +#define HI3110_READ_BTR1 0xD8
> +#define HI3110_READ_INTF 0xDE
> +#define HI3110_READ_ERR 0xDC
> +#define HI3110_READ_FIFO_WOTIME 0x48
> +#define HI3110_WRITE_FIFO 0x12
> +#define HI3110_READ_MESSTAT 0xDA
> +#define HI3110_READ_TEC 0xEC
> +
> +#define HI3110_CTRL0_MODE_MASK (7 << 5)
> +#define HI3110_CTRL0_NORMAL_MODE (0 << 5)
> +#define HI3110_CTRL0_LOOPBACK_MODE (1 << 5)
> +#define HI3110_CTRL0_MONITOR_MODE (2 << 5)
> +#define HI3110_CTRL0_SLEEP_MODE (3 << 5)
> +#define HI3110_CTRL0_INIT_MODE (4 << 5)
> +
> +#define HI3110_CTRL1_TXEN BIT(7)
> +
> +#define HI3110_INT_RXTMP BIT(7)
> +#define HI3110_INT_RXFIFO BIT(6)
> +#define HI3110_INT_TXCPLT BIT(5)
> +#define HI3110_INT_BUSERR BIT(4)
> +#define HI3110_INT_MCHG BIT(3)
> +#define HI3110_INT_WAKEUP BIT(2)
> +#define HI3110_INT_F1MESS BIT(1)
> +#define HI3110_INT_F0MESS BIT(0)
> +
> +#define HI3110_ERR_BUSOFF BIT(7)
> +#define HI3110_ERR_TXERRP BIT(6)
> +#define HI3110_ERR_RXERRP BIT(5)
> +#define HI3110_ERR_BITERR BIT(4)
> +#define HI3110_ERR_FRMERR BIT(3)
> +#define HI3110_ERR_CRCERR BIT(2)
> +#define HI3110_ERR_ACKERR BIT(1)
> +#define HI3110_ERR_STUFERR BIT(0)
> +#define HI3110_ERR_PROTOCOL_MASK (0x1F)
> +
> +#define HI3110_STAT_RXFMTY BIT(1)
> +
> +#define HI3110_BTR0_SJW_SHIFT 6
> +#define HI3110_BTR0_BRP_SHIFT 0
> +
> +#define HI3110_BTR1_SAMP_3PERBIT (1 << 7)
> +#define HI3110_BTR1_SAMP_1PERBIT (0 << 7)
> +#define HI3110_BTR1_TSEG2_SHIFT 4
> +#define HI3110_BTR1_TSEG1_SHIFT 0
> +
> +#define HI3110_FIFO_WOTIME_TAG_OFF 0
> +#define HI3110_FIFO_WOTIME_ID_OFF 1
> +#define HI3110_FIFO_WOTIME_DLC_OFF 5
> +#define HI3110_FIFO_WOTIME_DAT_OFF 6
> +
> +#define HI3110_FIFO_WOTIME_TAG_IDE BIT(7)
> +#define HI3110_FIFO_WOTIME_ID_RTR BIT(0)
> +
> +#define HI3110_FIFO_TAG_OFF 0
> +#define HI3110_FIFO_ID_OFF 1
> +#define HI3110_FIFO_STD_DLC_OFF 3
> +#define HI3110_FIFO_STD_DATA_OFF 4
> +#define HI3110_FIFO_EXT_DLC_OFF 5
> +#define HI3110_FIFO_EXT_DATA_OFF 6
> +
Please add the already used HI3110_ namespace to these defines, too.
> +#define CAN_FRAME_MAX_DATA_LEN 8
> +#define RX_BUF_LEN 15
> +#define TX_STD_BUF_LEN 12
> +#define TX_EXT_BUF_LEN 14
> +#define CAN_FRAME_MAX_BITS 128
> +
> +#define TX_ECHO_SKB_MAX 1
> +
> +#define HI3110_OST_DELAY_MS (10)
> +
> +#define DEVICE_NAME "hi3110"
> +
> +static int hi3110_enable_dma = 1; /* Enable SPI DMA. Default: 1 (On) */
> +module_param(hi3110_enable_dma, int, 0444);
> +MODULE_PARM_DESC(hi3110_enable_dma, "Enable SPI DMA. Default: 1 (On)");
> +
> +static const struct can_bittiming_const hi3110_bittiming_const = {
> + .name = DEVICE_NAME,
> + .tseg1_min = 2,
> + .tseg1_max = 16,
> + .tseg2_min = 2,
> + .tseg2_max = 8,
> + .sjw_max = 4,
> + .brp_min = 1,
> + .brp_max = 64,
> + .brp_inc = 1,
> +};
> +
> +enum hi3110_model {
> + CAN_HI3110_HI3110 = 0x3110,
^^^^^^^
single space here, too
> +};
> +
> +struct hi3110_priv {
> + struct can_priv can;
^^^^
here too
> + struct net_device *net;
> + struct spi_device *spi;
> + enum hi3110_model model;
> +
> + struct mutex hi3110_lock; /* SPI device lock */
> +
> + u8 *spi_tx_buf;
> + u8 *spi_rx_buf;
> + dma_addr_t spi_tx_dma;
> + dma_addr_t spi_rx_dma;
> +
> + struct sk_buff *tx_skb;
> + int tx_len;
> +
> + struct workqueue_struct *wq;
> + struct work_struct tx_work;
> + struct work_struct restart_work;
> +
> + int force_quit;
> + int after_suspend;
Please add the already used HI3110_ namespace to these defines, too.
> +#define AFTER_SUSPEND_UP 1
> +#define AFTER_SUSPEND_DOWN 2
> +#define AFTER_SUSPEND_POWER 4
> +#define AFTER_SUSPEND_RESTART 8
> + int restart_tx;
> + struct regulator *power;
> + struct regulator *transceiver;
> + struct clk *clk;
> +};
> +
> +static void hi3110_clean(struct net_device *net)
> +{
> + struct hi3110_priv *priv = netdev_priv(net);
> +
> + if (priv->tx_skb || priv->tx_len)
> + net->stats.tx_errors++;
> + if (priv->tx_skb)
> + dev_kfree_skb(priv->tx_skb);
> + if (priv->tx_len)
> + can_free_echo_skb(priv->net, 0);
> + priv->tx_skb = NULL;
> + priv->tx_len = 0;
> +}
> +
> +/* Note about handling of error return of hi3110_spi_trans: accessing
> + * registers via SPI is not really different conceptually than using
> + * normal I/O assembler instructions, although it's much more
> + * complicated from a practical POV. So it's not advisable to always
> + * check the return value of this function. Imagine that every
> + * read{b,l}, write{b,l} and friends would be bracketed in "if ( < 0)
> + * error();", it would be a great mess (well there are some situation
> + * when exception handling C++ like could be useful after all). So we
> + * just check that transfers are OK at the beginning of our
> + * conversation with the chip and to avoid doing really nasty things
> + * (like injecting bogus packets in the network stack).
> + */
> +static int hi3110_spi_trans(struct spi_device *spi, int len)
> +{
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> + struct spi_transfer t = {
> + .tx_buf = priv->spi_tx_buf,
> + .rx_buf = priv->spi_rx_buf,
> + .len = len,
> + .cs_change = 0,
> + };
> + struct spi_message m;
> + int ret;
> +
> + spi_message_init(&m);
> +
> + if (hi3110_enable_dma) {
> + t.tx_dma = priv->spi_tx_dma;
> + t.rx_dma = priv->spi_rx_dma;
> + m.is_dma_mapped = 1;
> + }
> +
> + spi_message_add_tail(&t, &m);
> +
> + ret = spi_sync(spi, &m);
> +
> + if (ret)
> + dev_err(&spi->dev, "spi transfer failed: ret = %d\n", ret);
> + return ret;
> +}
> +
> +static u8 hi3110_cmd(struct spi_device *spi, uint8_t command)
> +{
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> +
> + priv->spi_tx_buf[0] = command;
> + dev_dbg(&spi->dev, "hi3110_cmd: %02X\n", command);
> +
> + return hi3110_spi_trans(spi, 1);
> +}
> +
> +static u8 hi3110_read(struct spi_device *spi, uint8_t command)
> +{
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> + u8 val = 0;
> +
> + priv->spi_tx_buf[0] = command;
> + hi3110_spi_trans(spi, 2);
> + val = priv->spi_rx_buf[1];
> + dev_dbg(&spi->dev, "hi3110_read: %02X, %02X\n", command, val);
> +
> + return val;
> +}
> +
> +static void hi3110_write(struct spi_device *spi, u8 reg, uint8_t val)
> +{
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> +
> + priv->spi_tx_buf[0] = reg;
> + priv->spi_tx_buf[1] = val;
> + dev_dbg(&spi->dev, "hi3110_write: %02X, %02X\n", reg, val);
> +
> + hi3110_spi_trans(spi, 2);
> +}
> +
> +static void hi3110_hw_tx_frame(struct spi_device *spi, u8 *buf, int len)
> +{
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> +
> + priv->spi_tx_buf[0] = HI3110_WRITE_FIFO;
> + memcpy(priv->spi_tx_buf + 1, buf, len);
> + hi3110_spi_trans(spi, len + 1);
> +}
> +
> +static void hi3110_hw_tx(struct spi_device *spi, struct can_frame *frame)
> +{
> + u8 buf[TX_EXT_BUF_LEN];
> +
> + buf[HI3110_FIFO_TAG_OFF] = 0;
> +
> + if (frame->can_id & CAN_EFF_FLAG) {
> + /* Extended frame */
> + buf[HI3110_FIFO_ID_OFF] = (frame->can_id & CAN_EFF_MASK) >> 21;
> + buf[HI3110_FIFO_ID_OFF + 1] =
> + ((((frame->can_id & CAN_EFF_MASK) >> 18) & 0x07) << 5) |
Why do you first shift down then up?
> + 0x18 | /* Recessive SRR and IDE */
Can you add a define for the 0x18?
> + (((frame->can_id & CAN_EFF_MASK) >> 15) & 0x07);
> + buf[HI3110_FIFO_ID_OFF + 2] =
> + (frame->can_id & CAN_EFF_MASK) >> 7;
> + buf[HI3110_FIFO_ID_OFF + 3] =
> + ((frame->can_id & CAN_EFF_MASK) << 1) |
> + ((frame->can_id & CAN_RTR_FLAG) ? 1 : 0);
> +
> + buf[HI3110_FIFO_EXT_DLC_OFF] = frame->can_dlc;
> +
> + memcpy(buf + HI3110_FIFO_EXT_DATA_OFF,
> + frame->data, frame->can_dlc);
> +
> + hi3110_hw_tx_frame(spi, buf, TX_EXT_BUF_LEN -
> + (CAN_FRAME_MAX_DATA_LEN - frame->can_dlc));
> + } else {
> + /* Standard frame */
> + buf[HI3110_FIFO_ID_OFF] = (frame->can_id & CAN_SFF_MASK) >> 3;
> + buf[HI3110_FIFO_ID_OFF + 1] =
> + ((frame->can_id & CAN_SFF_MASK) << 5) |
> + ((frame->can_id & CAN_RTR_FLAG) ? (1 << 4) : 0);
> +
> + buf[HI3110_FIFO_STD_DLC_OFF] = frame->can_dlc;
> +
> + memcpy(buf + HI3110_FIFO_STD_DATA_OFF,
> + frame->data, frame->can_dlc);
> +
> + hi3110_hw_tx_frame(spi, buf, TX_STD_BUF_LEN -
> + (CAN_FRAME_MAX_DATA_LEN - frame->can_dlc));
> + }
> +}
> +
> +static void hi3110_hw_rx_frame(struct spi_device *spi, u8 *buf)
> +{
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> +
> + priv->spi_tx_buf[0] = HI3110_READ_FIFO_WOTIME;
> + hi3110_spi_trans(spi, RX_BUF_LEN);
> + memcpy(buf, priv->spi_rx_buf + 1, RX_BUF_LEN - 1);
> +}
> +
> +static void hi3110_hw_rx(struct spi_device *spi)
> +{
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> + struct sk_buff *skb;
> + struct can_frame *frame;
> + u8 buf[RX_BUF_LEN - 1];
> +
> + skb = alloc_can_skb(priv->net, &frame);
> + if (!skb) {
> + dev_err(&spi->dev, "cannot allocate RX skb\n");
> + priv->net->stats.rx_dropped++;
> + return;
> + }
> +
> + hi3110_hw_rx_frame(spi, buf);
> + if (buf[HI3110_FIFO_WOTIME_TAG_OFF] & HI3110_FIFO_WOTIME_TAG_IDE) {
> + /* IDE is recessive (1), indicating extended 29-bit frame */
> + frame->can_id = CAN_EFF_FLAG;
> + frame->can_id |=
> + (buf[HI3110_FIFO_WOTIME_ID_OFF] << 21) |
> + (((buf[HI3110_FIFO_WOTIME_ID_OFF + 1] & 0xE0) >> 5) << 18) |
> + ((buf[HI3110_FIFO_WOTIME_ID_OFF + 1] & 0x07) << 15) |
> + (buf[HI3110_FIFO_WOTIME_ID_OFF + 2] << 7) |
> + (buf[HI3110_FIFO_WOTIME_ID_OFF + 3] >> 1);
> + } else {
> + /* IDE is dominant (0), frame indicating standard 11-bit */
> + frame->can_id =
> + (buf[HI3110_FIFO_WOTIME_ID_OFF] << 3) |
> + ((buf[HI3110_FIFO_WOTIME_ID_OFF + 1] & 0xE0) >> 5);
> + }
> +
> + if (buf[HI3110_FIFO_WOTIME_ID_OFF + 3] & HI3110_FIFO_WOTIME_ID_RTR) {
> + /* RTR is recessive (1), indicating remote request frame */
> + frame->can_id |= CAN_RTR_FLAG;
> + }
> +
> + /* Data length */
> + frame->can_dlc = get_can_dlc(buf[HI3110_FIFO_WOTIME_DLC_OFF] & 0x0F);
> + memcpy(frame->data, buf + HI3110_FIFO_WOTIME_DAT_OFF, frame->can_dlc);
> +
> + priv->net->stats.rx_packets++;
> + priv->net->stats.rx_bytes += frame->can_dlc;
> +
> + can_led_event(priv->net, CAN_LED_EVENT_RX);
> +
> + netif_rx_ni(skb);
> +}
> +
> +static void hi3110_hw_sleep(struct spi_device *spi)
> +{
> + hi3110_write(spi, HI3110_WRITE_CTRL0, HI3110_CTRL0_SLEEP_MODE);
> +}
> +
> +static netdev_tx_t hi3110_hard_start_xmit(struct sk_buff *skb,
> + struct net_device *net)
> +{
> + struct hi3110_priv *priv = netdev_priv(net);
> + struct spi_device *spi = priv->spi;
> +
> + if (priv->tx_skb || priv->tx_len) {
> + dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
> + return NETDEV_TX_BUSY;
> + }
> +
> + if (can_dropped_invalid_skb(net, skb))
> + return NETDEV_TX_OK;
> +
> + netif_stop_queue(net);
> + priv->tx_skb = skb;
> + queue_work(priv->wq, &priv->tx_work);
> +
> + return NETDEV_TX_OK;
> +}
> +
> +static int hi3110_do_set_mode(struct net_device *net, enum can_mode mode)
> +{
> + struct hi3110_priv *priv = netdev_priv(net);
> +
> + switch (mode) {
> + case CAN_MODE_START:
> + hi3110_clean(net);
> + /* We have to delay work since SPI I/O may sleep */
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + priv->restart_tx = 1;
> + if (priv->can.restart_ms == 0)
> + priv->after_suspend = AFTER_SUSPEND_RESTART;
> + queue_work(priv->wq, &priv->restart_work);
> + break;
> + default:
> + return -EOPNOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +static int hi3110_set_normal_mode(struct spi_device *spi)
> +{
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> + u8 reg;
> +
> + hi3110_write(spi, HI3110_WRITE_INTE, HI3110_INT_BUSERR |
> + HI3110_INT_RXFIFO | HI3110_INT_TXCPLT);
> +
> + /* Enable TX */
> + hi3110_write(spi, HI3110_WRITE_CTRL1, HI3110_CTRL1_TXEN);
> +
> + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
> + /* Put device into loopback mode */
> + hi3110_write(spi, HI3110_WRITE_CTRL0,
> + HI3110_CTRL0_LOOPBACK_MODE);
> + } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
> + /* Put device into listen-only mode */
> + hi3110_write(spi, HI3110_WRITE_CTRL0,
> + HI3110_CTRL0_MONITOR_MODE);
> + } else {
> + /* Put device into normal mode */
> + hi3110_write(spi, HI3110_WRITE_CTRL0,
> + HI3110_CTRL0_NORMAL_MODE);
> +
> + /* Wait for the device to enter normal mode */
> + mdelay(HI3110_OST_DELAY_MS);
> + reg = hi3110_read(spi, HI3110_READ_CTRL0);
> + if ((reg & HI3110_CTRL0_MODE_MASK) != HI3110_CTRL0_NORMAL_MODE)
> + return -EBUSY;
> + }
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + return 0;
> +}
> +
> +static int hi3110_do_set_bittiming(struct net_device *net)
> +{
> + struct hi3110_priv *priv = netdev_priv(net);
> + struct can_bittiming *bt = &priv->can.bittiming;
> + struct spi_device *spi = priv->spi;
> +
> + hi3110_write(spi, HI3110_WRITE_BTR0,
> + ((bt->sjw - 1) << HI3110_BTR0_SJW_SHIFT) |
> + ((bt->brp - 1) << HI3110_BTR0_BRP_SHIFT));
> +
> + hi3110_write(spi, HI3110_WRITE_BTR1,
> + (priv->can.ctrlmode &
> + CAN_CTRLMODE_3_SAMPLES ?
> + HI3110_BTR1_SAMP_3PERBIT : HI3110_BTR1_SAMP_1PERBIT) |
> + ((bt->phase_seg1 + bt->prop_seg - 1)
> + << HI3110_BTR1_TSEG1_SHIFT) |
> + ((bt->phase_seg2 - 1) << HI3110_BTR1_TSEG2_SHIFT));
> +
> + dev_dbg(&spi->dev, "BT: 0x%02x 0x%02x\n",
> + hi3110_read(spi, HI3110_READ_BTR0),
> + hi3110_read(spi, HI3110_READ_BTR1));
> +
> + return 0;
> +}
> +
> +static int hi3110_setup(struct net_device *net, struct hi3110_priv *priv,
> + struct spi_device *spi)
onlt the first parameter is used.
> +{
> + hi3110_do_set_bittiming(net);
> + return 0;
> +}
> +
> +static int hi3110_hw_reset(struct spi_device *spi)
> +{
> + u8 reg;
> + int ret;
> +
> + /* Wait for oscillator startup timer after power up */
> + mdelay(HI3110_OST_DELAY_MS);
> +
> + ret = hi3110_cmd(spi, HI3110_MASTER_RESET);
> + if (ret)
> + return ret;
> +
> + /* Wait for oscillator startup timer after reset */
> + mdelay(HI3110_OST_DELAY_MS);
> +
> + reg = hi3110_read(spi, HI3110_READ_CTRL0);
> + if ((reg & HI3110_CTRL0_MODE_MASK) != HI3110_CTRL0_INIT_MODE)
> + return -ENODEV;
> +
> + /* As per the datasheet it appears the error flags are
> + * not cleared on reset. Explicitly clear them by performing a read
> + */
> + hi3110_read(spi, HI3110_READ_ERR);
> +
> + return 0;
> +}
> +
> +static int hi3110_hw_probe(struct spi_device *spi)
> +{
> + u8 statf;
> +
> + hi3110_hw_reset(spi);
> +
> + /* Confirm correct operation by checking against reset values
> + * in datasheet
> + */
> + statf = hi3110_read(spi, HI3110_READ_STATF);
> +
> + dev_dbg(&spi->dev, "statf: %02X\n", statf);
> +
> + if (statf != 0x82)
> + return -ENODEV;
> +
> + return 0;
> +}
> +
> +static int hi3110_power_enable(struct regulator *reg, int enable)
> +{
> + if (IS_ERR_OR_NULL(reg))
> + return 0;
> +
> + if (enable)
> + return regulator_enable(reg);
> + else
> + return regulator_disable(reg);
> +}
> +
> +static void hi3110_open_clean(struct net_device *net)
> +{
> + struct hi3110_priv *priv = netdev_priv(net);
> + struct spi_device *spi = priv->spi;
> +
> + free_irq(spi->irq, priv);
> + hi3110_hw_sleep(spi);
> + hi3110_power_enable(priv->transceiver, 0);
> + close_candev(net);
> +}
> +
> +static int hi3110_stop(struct net_device *net)
> +{
> + struct hi3110_priv *priv = netdev_priv(net);
> + struct spi_device *spi = priv->spi;
> +
> + close_candev(net);
> +
> + priv->force_quit = 1;
> + free_irq(spi->irq, priv);
> + destroy_workqueue(priv->wq);
> + priv->wq = NULL;
> +
> + mutex_lock(&priv->hi3110_lock);
> +
> + /* Disable transmit, interrupts and clear flags */
> + hi3110_write(spi, HI3110_WRITE_CTRL1, 0x0);
> + hi3110_write(spi, HI3110_WRITE_INTE, 0x0);
> + hi3110_read(spi, HI3110_READ_INTF);
> +
> + hi3110_clean(net);
> +
> + hi3110_hw_sleep(spi);
> +
> + hi3110_power_enable(priv->transceiver, 0);
> +
> + priv->can.state = CAN_STATE_STOPPED;
> +
> + mutex_unlock(&priv->hi3110_lock);
> +
> + can_led_event(net, CAN_LED_EVENT_STOP);
> +
> + return 0;
> +}
> +
> +static void hi3110_error_skb(struct net_device *net, int can_id,
> + int data1, int data2)
> +{
> + struct sk_buff *skb;
> + struct can_frame *frame;
> +
> + skb = alloc_can_err_skb(net, &frame);
> + if (skb) {
> + frame->can_id |= can_id;
> + frame->data[1] = data1;
> + frame->data[2] = data2;
> + netif_rx_ni(skb);
> + } else {
> + netdev_err(net, "cannot allocate error skb\n");
> + }
> +}
> +
> +static void hi3110_tx_work_handler(struct work_struct *ws)
> +{
> + struct hi3110_priv *priv = container_of(ws, struct hi3110_priv,
> + tx_work);
> + struct spi_device *spi = priv->spi;
> + struct net_device *net = priv->net;
> + struct can_frame *frame;
> +
> + mutex_lock(&priv->hi3110_lock);
> + if (priv->tx_skb) {
> + if (priv->can.state == CAN_STATE_BUS_OFF) {
> + hi3110_clean(net);
> + } else {
> + frame = (struct can_frame *)priv->tx_skb->data;
> +
> + if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
> + frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
this has already been checked
> + hi3110_hw_tx(spi, frame);
> + priv->tx_len = 1 + frame->can_dlc;
> + can_put_echo_skb(priv->tx_skb, net, 0);
> + priv->tx_skb = NULL;
> + }
> + }
> + mutex_unlock(&priv->hi3110_lock);
> +}
> +
> +static void hi3110_restart_work_handler(struct work_struct *ws)
> +{
> + struct hi3110_priv *priv = container_of(ws, struct hi3110_priv,
> + restart_work);
> + struct spi_device *spi = priv->spi;
> + struct net_device *net = priv->net;
> +
> + mutex_lock(&priv->hi3110_lock);
> + if (priv->after_suspend) {
> + hi3110_hw_reset(spi);
> + hi3110_setup(net, priv, spi);
> + if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
> + hi3110_set_normal_mode(spi);
> + } else if (priv->after_suspend & AFTER_SUSPEND_UP) {
> + netif_device_attach(net);
> + hi3110_clean(net);
> + hi3110_set_normal_mode(spi);
> + netif_wake_queue(net);
> + } else {
> + hi3110_hw_sleep(spi);
> + }
> + priv->after_suspend = 0;
> + priv->force_quit = 0;
> + }
> +
> + if (priv->restart_tx) {
> + priv->restart_tx = 0;
> + hi3110_clean(net);
> + netif_wake_queue(net);
> + hi3110_error_skb(net, CAN_ERR_RESTARTED, 0, 0);
> + }
> + mutex_unlock(&priv->hi3110_lock);
> +}
> +
> +static irqreturn_t hi3110_can_ist(int irq, void *dev_id)
> +{
> + struct hi3110_priv *priv = dev_id;
> + struct spi_device *spi = priv->spi;
> + struct net_device *net = priv->net;
> +
> + mutex_lock(&priv->hi3110_lock);
> +
> + while (!priv->force_quit) {
> + enum can_state new_state;
> + u8 intf;
> + u8 eflag;
> + int can_id = 0, data1 = 0, data2 = 0;
> +
> + while (!(HI3110_STAT_RXFMTY &
> + hi3110_read(spi, HI3110_READ_STATF))) {
> + hi3110_hw_rx(spi);
> + };
> +
> + intf = hi3110_read(spi, HI3110_READ_INTF);
> + eflag = hi3110_read(spi, HI3110_READ_ERR);
does the hardware supports multiple reads with a single transfer? If so
make use of it, for performance reasons.
> + /* Update can state */
> + if (eflag & HI3110_ERR_BUSOFF) {
> + new_state = CAN_STATE_BUS_OFF;
> + can_id |= CAN_ERR_BUSOFF;
> + } else if (eflag & HI3110_ERR_TXERRP) {
> + new_state = CAN_STATE_ERROR_PASSIVE;
> + can_id |= CAN_ERR_CRTL;
> + data1 |= CAN_ERR_CRTL_TX_PASSIVE;
> + } else if (eflag & HI3110_ERR_RXERRP) {
> + new_state = CAN_STATE_ERROR_PASSIVE;
> + can_id |= CAN_ERR_CRTL;
> + data1 |= CAN_ERR_CRTL_RX_PASSIVE;
> + } else {
> + new_state = CAN_STATE_ERROR_ACTIVE;
> + }
> +
> + /* Check for protocol errors */
> + if (eflag & HI3110_ERR_PROTOCOL_MASK) {
> + can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
> + priv->can.can_stats.bus_error++;
> + priv->net->stats.rx_errors++;
> + if (eflag & HI3110_ERR_BITERR)
> + data2 |= CAN_ERR_PROT_BIT;
> + else if (eflag & HI3110_ERR_FRMERR)
> + data2 |= CAN_ERR_PROT_FORM;
> + else if (eflag & HI3110_ERR_STUFERR)
> + data2 |= CAN_ERR_PROT_STUFF;
> + else
> + data2 |= CAN_ERR_PROT_UNSPEC;
> + }
> +
> + /* Update can state statistics */
> + switch (priv->can.state) {
> + case CAN_STATE_ERROR_ACTIVE:
> + if (new_state >= CAN_STATE_ERROR_WARNING &&
> + new_state <= CAN_STATE_BUS_OFF)
> + priv->can.can_stats.error_warning++;
> + /* fallthrough */
> + case CAN_STATE_ERROR_WARNING:
> + if (new_state >= CAN_STATE_ERROR_PASSIVE &&
> + new_state <= CAN_STATE_BUS_OFF)
> + priv->can.can_stats.error_passive++;
> + break;
> + default:
> + break;
> + }
> + priv->can.state = new_state;
> +
> + if (intf & HI3110_INT_BUSERR) {
> + /* Note: HI3110 Does report overflow errors */
> + hi3110_error_skb(net, can_id, data1, data2);
> + }
> +
> + if (priv->can.state == CAN_STATE_BUS_OFF) {
> + if (priv->can.restart_ms == 0) {
> + priv->force_quit = 1;
> + priv->can.can_stats.bus_off++;
> + can_bus_off(net);
> + hi3110_hw_sleep(spi);
> + break;
> + }
> + }
> +
> + if (intf == 0)
> + break;
> +
> + if (intf & HI3110_INT_TXCPLT) {
> + net->stats.tx_packets++;
> + net->stats.tx_bytes += priv->tx_len - 1;
> + can_led_event(net, CAN_LED_EVENT_TX);
> + if (priv->tx_len) {
> + can_get_echo_skb(net, 0);
> + priv->tx_len = 0;
> + }
> + netif_wake_queue(net);
> + }
> + }
> + mutex_unlock(&priv->hi3110_lock);
> + return IRQ_HANDLED;
> +}
> +
> +static int hi3110_open(struct net_device *net)
> +{
> + struct hi3110_priv *priv = netdev_priv(net);
> + struct spi_device *spi = priv->spi;
> + unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_RISING;
> + int ret;
> +
> + ret = open_candev(net);
> + if (ret) {
> + dev_err(&spi->dev, "unable to set initial baudrate!\n");
> + return ret;
> + }
> +
> + mutex_lock(&priv->hi3110_lock);
> + hi3110_power_enable(priv->transceiver, 1);
> +
> + priv->force_quit = 0;
> + priv->tx_skb = NULL;
> + priv->tx_len = 0;
> +
> + ret = request_threaded_irq(spi->irq, NULL, hi3110_can_ist,
> + flags, DEVICE_NAME, priv);
> + if (ret) {
> + dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
add propoer goto targets at the and of this function, for easier error
handling cleanup. This mean basically get rid of hi3110_open_clean(net).
> + hi3110_power_enable(priv->transceiver, 0);
> + close_candev(net);
> + goto open_unlock;
> + }
> +
> + priv->wq = alloc_workqueue("hi3110_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
> + 0);
> + INIT_WORK(&priv->tx_work, hi3110_tx_work_handler);
> + INIT_WORK(&priv->restart_work, hi3110_restart_work_handler);
> +
> + ret = hi3110_hw_reset(spi);
> + if (ret) {
> + hi3110_open_clean(net);
> + goto open_unlock;
> + }
> + ret = hi3110_setup(net, priv, spi);
> + if (ret) {
> + hi3110_open_clean(net);
> + goto open_unlock;
> + }
> + ret = hi3110_set_normal_mode(spi);
> + if (ret) {
> + hi3110_open_clean(net);
> + goto open_unlock;
> + }
> + can_led_event(net, CAN_LED_EVENT_OPEN);
> + netif_wake_queue(net);
> +
> +open_unlock:
> + mutex_unlock(&priv->hi3110_lock);
> + return ret;
> +}
> +
> +static const struct net_device_ops hi3110_netdev_ops = {
> + .ndo_open = hi3110_open,
> + .ndo_stop = hi3110_stop,
> + .ndo_start_xmit = hi3110_hard_start_xmit,
> +};
> +
> +static const struct of_device_id hi3110_of_match[] = {
> + {
> + .compatible = "holt,hi3110",
> + .data = (void *)CAN_HI3110_HI3110,
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, hi3110_of_match);
> +
> +static const struct spi_device_id hi3110_id_table[] = {
> + {
> + .name = "hi3110",
> + .driver_data = (kernel_ulong_t)CAN_HI3110_HI3110,
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(spi, hi3110_id_table);
> +
> +static int hi3110_can_probe(struct spi_device *spi)
> +{
> + const struct of_device_id *of_id = of_match_device(hi3110_of_match,
> + &spi->dev);
> + struct net_device *net;
> + struct hi3110_priv *priv;
> + struct clk *clk;
> + int freq, ret;
> +
> + clk = devm_clk_get(&spi->dev, NULL);
> + if (IS_ERR(clk)) {
> + dev_err(&spi->dev, "no CAN clock source defined\n");
> + return PTR_ERR(clk);
> + }
> + freq = clk_get_rate(clk);
> +
> + /* Sanity check */
> + if (freq > 40000000)
> + return -ERANGE;
> +
> + /* Allocate can/net device */
> + net = alloc_candev(sizeof(struct hi3110_priv), TX_ECHO_SKB_MAX);
> + if (!net)
> + return -ENOMEM;
> +
> + if (!IS_ERR(clk)) {
> + ret = clk_prepare_enable(clk);
> + if (ret)
> + goto out_free;
> + }
> +
> + net->netdev_ops = &hi3110_netdev_ops;
> + net->flags |= IFF_ECHO;
> +
> + priv = netdev_priv(net);
> + priv->can.bittiming_const = &hi3110_bittiming_const;
> + priv->can.do_set_mode = hi3110_do_set_mode;
> + priv->can.clock.freq = freq / 2;
> + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
> + CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
> + if (of_id)
> + priv->model = (enum hi3110_model)of_id->data;
> + else
> + priv->model = spi_get_device_id(spi)->driver_data;
> + priv->net = net;
> + priv->clk = clk;
> +
> + spi_set_drvdata(spi, priv);
> +
> + /* Configure the SPI bus */
> + spi->bits_per_word = 8;
> + ret = spi_setup(spi);
> + if (ret)
> + goto out_clk;
> +
> + priv->power = devm_regulator_get_optional(&spi->dev, "vdd");
> + priv->transceiver = devm_regulator_get_optional(&spi->dev, "xceiver");
> + if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
> + (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) {
> + ret = -EPROBE_DEFER;
> + goto out_clk;
> + }
> +
> + ret = hi3110_power_enable(priv->power, 1);
> + if (ret)
> + goto out_clk;
> +
> + priv->spi = spi;
> + mutex_init(&priv->hi3110_lock);
> +
> + /* If requested, allocate DMA buffers */
> + if (hi3110_enable_dma) {
> + spi->dev.coherent_dma_mask = ~0;
> +
> + /* Minimum coherent DMA allocation is PAGE_SIZE, so allocate
> + * that much and share it between Tx and Rx DMA buffers.
> + */
> + priv->spi_tx_buf = dmam_alloc_coherent(&spi->dev,
> + PAGE_SIZE,
> + &priv->spi_tx_dma,
> + GFP_DMA);
> +
> + if (priv->spi_tx_buf) {
> + priv->spi_rx_buf = (priv->spi_tx_buf + (PAGE_SIZE / 2));
> + priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +
> + (PAGE_SIZE / 2));
> + } else {
> + /* Fall back to non-DMA */
> + hi3110_enable_dma = 0;
> + }
> + }
> +
> + /* Allocate non-DMA buffers */
> + if (!hi3110_enable_dma) {
> + priv->spi_tx_buf = devm_kzalloc(&spi->dev, RX_BUF_LEN,
> + GFP_KERNEL);
> + if (!priv->spi_tx_buf) {
> + ret = -ENOMEM;
> + goto error_probe;
> + }
> + priv->spi_rx_buf = devm_kzalloc(&spi->dev, RX_BUF_LEN,
> + GFP_KERNEL);
> +
> + if (!priv->spi_rx_buf) {
> + ret = -ENOMEM;
> + goto error_probe;
> + }
> + }
> +
> + SET_NETDEV_DEV(net, &spi->dev);
> +
> + ret = hi3110_hw_probe(spi);
> + if (ret) {
> + if (ret == -ENODEV)
> + dev_err(&spi->dev, "Cannot initialize %x. Wrong wiring?\n",
> + priv->model);
> + goto error_probe;
> + }
> + hi3110_hw_sleep(spi);
> +
> + ret = register_candev(net);
> + if (ret)
> + goto error_probe;
> +
> + devm_can_led_init(net);
> + netdev_info(net, "%x successfully initialized.\n", priv->model);
> +
> + return 0;
> +
> +error_probe:
> + hi3110_power_enable(priv->power, 0);
> +
> +out_clk:
> + if (!IS_ERR(clk))
> + clk_disable_unprepare(clk);
> +
> +out_free:
> + free_candev(net);
> +
> + dev_err(&spi->dev, "Probe failed, err=%d\n", -ret);
> + return ret;
> +}
> +
> +static int hi3110_can_remove(struct spi_device *spi)
> +{
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> + struct net_device *net = priv->net;
> +
> + unregister_candev(net);
> +
> + hi3110_power_enable(priv->power, 0);
> +
> + if (!IS_ERR(priv->clk))
> + clk_disable_unprepare(priv->clk);
> +
> + free_candev(net);
> +
> + return 0;
> +}
> +
> +static int __maybe_unused hi3110_can_suspend(struct device *dev)
> +{
> + struct spi_device *spi = to_spi_device(dev);
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> + struct net_device *net = priv->net;
> +
> + priv->force_quit = 1;
> + disable_irq(spi->irq);
> +
> + /* Note: at this point neither IST nor workqueues are running.
> + * open/stop cannot be called anyway so locking is not needed
> + */
> + if (netif_running(net)) {
> + netif_device_detach(net);
> +
> + hi3110_hw_sleep(spi);
> + hi3110_power_enable(priv->transceiver, 0);
> + priv->after_suspend = AFTER_SUSPEND_UP;
> + } else {
> + priv->after_suspend = AFTER_SUSPEND_DOWN;
> + }
> +
> + if (!IS_ERR_OR_NULL(priv->power)) {
> + regulator_disable(priv->power);
> + priv->after_suspend |= AFTER_SUSPEND_POWER;
> + }
> +
> + return 0;
> +}
> +
> +static int __maybe_unused hi3110_can_resume(struct device *dev)
> +{
> + struct spi_device *spi = to_spi_device(dev);
> + struct hi3110_priv *priv = spi_get_drvdata(spi);
> +
> + if (priv->after_suspend & AFTER_SUSPEND_POWER)
> + hi3110_power_enable(priv->power, 1);
> +
> + if (priv->after_suspend & AFTER_SUSPEND_UP) {
> + hi3110_power_enable(priv->transceiver, 1);
> + queue_work(priv->wq, &priv->restart_work);
> + } else {
> + priv->after_suspend = 0;
> + }
> +
> + priv->force_quit = 0;
> + enable_irq(spi->irq);
> + return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(hi3110_can_pm_ops, hi3110_can_suspend,
> + hi3110_can_resume);
> +
> +static struct spi_driver hi3110_can_driver = {
> + .driver = {
> + .name = DEVICE_NAME,
> + .of_match_table = hi3110_of_match,
> + .pm = &hi3110_can_pm_ops,
> + },
> + .id_table = hi3110_id_table,
> + .probe = hi3110_can_probe,
> + .remove = hi3110_can_remove,
> +};
> +
> +module_spi_driver(hi3110_can_driver);
> +
> +MODULE_AUTHOR("Akshay Bhat <akshay.bhat@timesys.com>");
> +MODULE_AUTHOR("Casey Fitzpatrick <casey.fitzpatrick@timesys.com>");
> +MODULE_DESCRIPTION("Holt HI-3110 CAN driver");
> +MODULE_LICENSE("GPL v2");
>
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH] ixgbe: Remove pr_cont uses
From: Joe Perches @ 2017-01-03 15:28 UTC (permalink / raw)
To: Jeff Kirsher; +Cc: intel-wired-lan, netdev, linux-kernel
As pr_cont output can be interleaved by other processes,
using pr_cont should be avoided where possible.
Miscellanea:
o Use a temporary pointer to hold the next descriptions and
consolidate the pr_cont uses
o Use the temporary buffer to hold the 8 u32 register values and
emit those in a single go
o Coalesce formats and logging neatening around those changes
o Fix a defective output for the rx ring entry description when
also emitting rx_buffer_info data
This reduces overall object size a tiny bit too.
$ size drivers/net/ethernet/intel/ixgbe/*.o*
text data bss dec hex filename
62167 728 12 62907 f5bb drivers/net/ethernet/intel/ixgbe/ixgbe_main.o.new
62273 728 12 63013 f625 drivers/net/ethernet/intel/ixgbe/ixgbe_main.o.old
Signed-off-by: Joe Perches <joe@perches.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 84 +++++++++++++++------------
1 file changed, 47 insertions(+), 37 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 1e2f39ebd824..bc1c3819f520 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -504,7 +504,7 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
*/
static void ixgbe_regdump(struct ixgbe_hw *hw, struct ixgbe_reg_info *reginfo)
{
- int i = 0, j = 0;
+ int i;
char rname[16];
u32 regs[64];
@@ -566,17 +566,21 @@ static void ixgbe_regdump(struct ixgbe_hw *hw, struct ixgbe_reg_info *reginfo)
regs[i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
break;
default:
- pr_info("%-15s %08x\n", reginfo->name,
- IXGBE_READ_REG(hw, reginfo->ofs));
+ pr_info("%-15s %08x\n",
+ reginfo->name, IXGBE_READ_REG(hw, reginfo->ofs));
return;
}
- for (i = 0; i < 8; i++) {
- snprintf(rname, 16, "%s[%d-%d]", reginfo->name, i*8, i*8+7);
- pr_err("%-15s", rname);
+ i = 0;
+ while (i < 64) {
+ int j;
+ char buf[9 * 8 + 1];
+ char *p = buf;
+
+ snprintf(rname, 16, "%s[%d-%d]", reginfo->name, i, i + 7);
for (j = 0; j < 8; j++)
- pr_cont(" %08x", regs[i*8+j]);
- pr_cont("\n");
+ p += sprintf(p, " %08x", regs[i++]);
+ pr_err("%-15s%s\n", rname, buf);
}
}
@@ -698,7 +702,18 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
tx_buffer = &tx_ring->tx_buffer_info[i];
u0 = (struct my_u0 *)tx_desc;
if (dma_unmap_len(tx_buffer, len) > 0) {
- pr_info("T [0x%03X] %016llX %016llX %016llX %08X %p %016llX %p",
+ const char *ring_desc;
+
+ if (i == tx_ring->next_to_use &&
+ i == tx_ring->next_to_clean)
+ ring_desc = " NTC/U";
+ else if (i == tx_ring->next_to_use)
+ ring_desc = " NTU";
+ else if (i == tx_ring->next_to_clean)
+ ring_desc = " NTC";
+ else
+ ring_desc = "";
+ pr_info("T [0x%03X] %016llX %016llX %016llX %08X %p %016llX %p%s",
i,
le64_to_cpu(u0->a),
le64_to_cpu(u0->b),
@@ -706,16 +721,8 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
dma_unmap_len(tx_buffer, len),
tx_buffer->next_to_watch,
(u64)tx_buffer->time_stamp,
- tx_buffer->skb);
- if (i == tx_ring->next_to_use &&
- i == tx_ring->next_to_clean)
- pr_cont(" NTC/U\n");
- else if (i == tx_ring->next_to_use)
- pr_cont(" NTU\n");
- else if (i == tx_ring->next_to_clean)
- pr_cont(" NTC\n");
- else
- pr_cont("\n");
+ tx_buffer->skb,
+ ring_desc);
if (netif_msg_pktdata(adapter) &&
tx_buffer->skb)
@@ -794,34 +801,45 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
pr_info("------------------------------------\n");
pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index);
pr_info("------------------------------------\n");
- pr_info("%s%s%s",
+ pr_info("%s%s%s\n",
"R [desc] [ PktBuf A0] ",
"[ HeadBuf DD] [bi->dma ] [bi->skb ] ",
- "<-- Adv Rx Read format\n");
- pr_info("%s%s%s",
+ "<-- Adv Rx Read format");
+ pr_info("%s%s%s\n",
"RWB[desc] [PcsmIpSHl PtRs] ",
"[vl er S cks ln] ---------------- [bi->skb ] ",
- "<-- Adv Rx Write-Back format\n");
+ "<-- Adv Rx Write-Back format");
for (i = 0; i < rx_ring->count; i++) {
+ const char *ring_desc;
+
+ if (i == rx_ring->next_to_use)
+ ring_desc = " NTU";
+ else if (i == rx_ring->next_to_clean)
+ ring_desc = " NTC";
+ else
+ ring_desc = "";
+
rx_buffer_info = &rx_ring->rx_buffer_info[i];
rx_desc = IXGBE_RX_DESC(rx_ring, i);
u0 = (struct my_u0 *)rx_desc;
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
if (staterr & IXGBE_RXD_STAT_DD) {
/* Descriptor Done */
- pr_info("RWB[0x%03X] %016llX "
- "%016llX ---------------- %p", i,
+ pr_info("RWB[0x%03X] %016llX %016llX ---------------- %p%s\n",
+ i,
le64_to_cpu(u0->a),
le64_to_cpu(u0->b),
- rx_buffer_info->skb);
+ rx_buffer_info->skb,
+ ring_desc);
} else {
- pr_info("R [0x%03X] %016llX "
- "%016llX %016llX %p", i,
+ pr_info("R [0x%03X] %016llX %016llX %016llX %p%s\n",
+ i,
le64_to_cpu(u0->a),
le64_to_cpu(u0->b),
(u64)rx_buffer_info->dma,
- rx_buffer_info->skb);
+ rx_buffer_info->skb,
+ ring_desc);
if (netif_msg_pktdata(adapter) &&
rx_buffer_info->dma) {
@@ -832,14 +850,6 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
ixgbe_rx_bufsz(rx_ring), true);
}
}
-
- if (i == rx_ring->next_to_use)
- pr_cont(" NTU\n");
- else if (i == rx_ring->next_to_clean)
- pr_cont(" NTC\n");
- else
- pr_cont("\n");
-
}
}
}
--
2.10.0.rc2.1.g053435c
^ permalink raw reply related
* [net-next 1/3] tipc: unify tipc_wait_for_sndpkt() and tipc_wait_for_sndmsg() functions
From: Jon Maloy @ 2017-01-03 15:26 UTC (permalink / raw)
To: davem; +Cc: Jon Maloy, netdev, tipc-discussion, Al Viro
In-Reply-To: <1483457208-29033-1-git-send-email-jon.maloy@ericsson.com>
The functions tipc_wait_for_sndpkt() and tipc_wait_for_sndmsg() are very
similar. The latter function is also called from two locations, and
there will be more in the coming commits, which will all need to test on
different conditions.
Instead of making yet another duplicates of the function, we now
introduce a new macro tipc_wait_for_cond() where the wakeup condition
can be stated as an argument to the call. This macro replaces all
current and future uses of the two functions, which can now be
eliminated.
Acked-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---
net/tipc/socket.c | 108 +++++++++++++++++++++++++-----------------------------
1 file changed, 49 insertions(+), 59 deletions(-)
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 800caaa..f27462e 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -110,7 +110,6 @@ static void tipc_write_space(struct sock *sk);
static void tipc_sock_destruct(struct sock *sk);
static int tipc_release(struct socket *sock);
static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);
-static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p);
static void tipc_sk_timeout(unsigned long data);
static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
struct tipc_name_seq const *seq);
@@ -334,6 +333,49 @@ static int tipc_set_sk_state(struct sock *sk, int state)
return res;
}
+static int tipc_sk_sock_err(struct socket *sock, long *timeout)
+{
+ struct sock *sk = sock->sk;
+ int err = sock_error(sk);
+ int typ = sock->type;
+
+ if (err)
+ return err;
+ if (typ == SOCK_STREAM || typ == SOCK_SEQPACKET) {
+ if (sk->sk_state == TIPC_DISCONNECTING)
+ return -EPIPE;
+ else if (!tipc_sk_connected(sk))
+ return -ENOTCONN;
+ }
+ if (!*timeout)
+ return -EAGAIN;
+ if (signal_pending(current))
+ return sock_intr_errno(*timeout);
+
+ return 0;
+}
+
+#define tipc_wait_for_cond(sock_, timeout_, condition_) \
+({ \
+ int rc_ = 0; \
+ int done_ = 0; \
+ \
+ while (!(condition_) && !done_) { \
+ struct sock *sk_ = sock->sk; \
+ DEFINE_WAIT_FUNC(wait_, woken_wake_function); \
+ \
+ rc_ = tipc_sk_sock_err(sock_, timeout_); \
+ if (rc_) \
+ break; \
+ prepare_to_wait(sk_sleep(sk_), &wait_, \
+ TASK_INTERRUPTIBLE); \
+ done_ = sk_wait_event(sk_, timeout_, \
+ (condition_), &wait_); \
+ remove_wait_queue(sk_sleep(sk_), &wait_); \
+ } \
+ rc_; \
+})
+
/**
* tipc_sk_create - create a TIPC socket
* @net: network namespace (must be default network)
@@ -721,7 +763,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
if (rc == -ELINKCONG) {
tsk->link_cong = 1;
- rc = tipc_wait_for_sndmsg(sock, &timeo);
+ rc = tipc_wait_for_cond(sock, &timeo, !tsk->link_cong);
if (!rc)
continue;
}
@@ -830,31 +872,6 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
kfree_skb(skb);
}
-static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)
-{
- DEFINE_WAIT_FUNC(wait, woken_wake_function);
- struct sock *sk = sock->sk;
- struct tipc_sock *tsk = tipc_sk(sk);
- int done;
-
- do {
- int err = sock_error(sk);
- if (err)
- return err;
- if (sk->sk_shutdown & SEND_SHUTDOWN)
- return -EPIPE;
- if (!*timeo_p)
- return -EAGAIN;
- if (signal_pending(current))
- return sock_intr_errno(*timeo_p);
-
- add_wait_queue(sk_sleep(sk), &wait);
- done = sk_wait_event(sk, timeo_p, !tsk->link_cong, &wait);
- remove_wait_queue(sk_sleep(sk), &wait);
- } while (!done);
- return 0;
-}
-
/**
* tipc_sendmsg - send message in connectionless manner
* @sock: socket structure
@@ -970,7 +987,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
}
if (rc == -ELINKCONG) {
tsk->link_cong = 1;
- rc = tipc_wait_for_sndmsg(sock, &timeo);
+ rc = tipc_wait_for_cond(sock, &timeo, !tsk->link_cong);
if (!rc)
continue;
}
@@ -985,36 +1002,6 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
return rc;
}
-static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p)
-{
- DEFINE_WAIT_FUNC(wait, woken_wake_function);
- struct sock *sk = sock->sk;
- struct tipc_sock *tsk = tipc_sk(sk);
- int done;
-
- do {
- int err = sock_error(sk);
- if (err)
- return err;
- if (sk->sk_state == TIPC_DISCONNECTING)
- return -EPIPE;
- else if (!tipc_sk_connected(sk))
- return -ENOTCONN;
- if (!*timeo_p)
- return -EAGAIN;
- if (signal_pending(current))
- return sock_intr_errno(*timeo_p);
-
- add_wait_queue(sk_sleep(sk), &wait);
- done = sk_wait_event(sk, timeo_p,
- (!tsk->link_cong &&
- !tsk_conn_cong(tsk)) ||
- !tipc_sk_connected(sk), &wait);
- remove_wait_queue(sk_sleep(sk), &wait);
- } while (!done);
- return 0;
-}
-
/**
* tipc_send_stream - send stream-oriented data
* @sock: socket structure
@@ -1109,7 +1096,10 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
tsk->link_cong = 1;
}
- rc = tipc_wait_for_sndpkt(sock, &timeo);
+ rc = tipc_wait_for_cond(sock, &timeo,
+ (!tsk->link_cong &&
+ !tsk_conn_cong(tsk) &&
+ tipc_sk_connected(sk)));
} while (!rc);
__skb_queue_purge(&pktchain);
--
2.7.4
------------------------------------------------------------------------------
Developer Access Program for Intel Xeon Phi Processors
Access to Intel Xeon Phi processor-based developer platforms.
With one year of Intel Parallel Studio XE.
Training and support from Colfax.
Order your platform today. http://sdm.link/xeonphi
^ permalink raw reply related
* [net-next 0/3] tipc: improve interaction socket-link
From: Jon Maloy @ 2017-01-03 15:26 UTC (permalink / raw)
To: davem; +Cc: Jon Maloy, netdev, tipc-discussion, Al Viro
We fix a very real starvation problem that may occur when a link
encounters send buffer congestion. At the same time we make the
interaction between the socket and link layer simpler and more
consistent.
Jon Maloy (3):
tipc: unify tipc_wait_for_sndpkt() and tipc_wait_for_sndmsg()
functions
tipc: modify struct tipc_plist to be more versatile
tipc: reduce risk of user starvation during link congestion
net/tipc/bcast.c | 6 +-
net/tipc/link.c | 75 ++++-----
net/tipc/msg.h | 2 -
net/tipc/name_table.c | 100 +++++++----
net/tipc/name_table.h | 21 +--
net/tipc/node.c | 15 +-
net/tipc/socket.c | 449 ++++++++++++++++++++++----------------------------
7 files changed, 319 insertions(+), 349 deletions(-)
--
2.7.4
------------------------------------------------------------------------------
Developer Access Program for Intel Xeon Phi Processors
Access to Intel Xeon Phi processor-based developer platforms.
With one year of Intel Parallel Studio XE.
Training and support from Colfax.
Order your platform today. http://sdm.link/xeonphi
^ permalink raw reply
* [PATCH net] benet: stricter vxlan offloading check in be_features_check
From: Sabrina Dubroca @ 2017-01-03 15:26 UTC (permalink / raw)
To: netdev
Cc: Sabrina Dubroca, Sathya Perla, Ajit Khaparde,
Sriharsha Basavapatna, Somnath Kotur
When VXLAN offloading is enabled, be_features_check() tries to check if
an encapsulated packet is indeed a VXLAN packet. The check is not strict
enough, and considers any UDP-encapsulated ethernet frame with a 8-byte
tunnel header as being VXLAN. Unfortunately, both GENEVE and VXLAN-GPE
have a 8-byte header, so they get through this check.
Force the UDP destination port to be the one that has been offloaded to
hardware.
Without this, GENEVE-encapsulated packets can end up having an incorrect
checksum when both a GENEVE and a VXLAN (offloaded) tunnel are
configured.
This is similar to commit a547224dceed ("mlx4e: Do not attempt to
offload VXLAN ports that are unrecognized").
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
---
mlx4/5 already do something similar, but nfp/bnx2x/qlcnic don't.
This check was introduced in commit 16dde0d6ac15, but only made invalid
when GENEVE was introduced in 2d07dc79fe04.
drivers/net/ethernet/emulex/benet/be_main.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 7e1633bf5a22..225e9a4877d7 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -5155,7 +5155,9 @@ static netdev_features_t be_features_check(struct sk_buff *skb,
skb->inner_protocol_type != ENCAP_TYPE_ETHER ||
skb->inner_protocol != htons(ETH_P_TEB) ||
skb_inner_mac_header(skb) - skb_transport_header(skb) !=
- sizeof(struct udphdr) + sizeof(struct vxlanhdr))
+ sizeof(struct udphdr) + sizeof(struct vxlanhdr) ||
+ !adapter->vxlan_port ||
+ udp_hdr(skb)->dest != adapter->vxlan_port)
return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
return features;
--
2.11.0
^ permalink raw reply related
* Re: [PATCH 2/2] isdn: i4l: move active-isdn drivers to staging
From: Greg Kroah-Hartman @ 2017-01-03 15:24 UTC (permalink / raw)
To: Arnd Bergmann
Cc: devel, Karsten Keil, linux-doc, netdev, Jonathan Corbet,
linux-kernel, David S. Miller, linux-arm-kernel
In-Reply-To: <1456945629-1793533-2-git-send-email-arnd@arndb.de>
On Wed, Mar 02, 2016 at 08:06:46PM +0100, Arnd Bergmann wrote:
> The icn, act2000 and pcbit drivers are all for very old hardware,
> and it is highly unlikely that anyone is actually still using them
> on modern kernels, if at all.
>
> All three drivers apparently are for hardware that predates PCI
> being the common connector, as they are ISA-only and active
> PCI ISDN cards were widely available in the 1990s.
>
> Looking through the git logs, it I cannot find any indication of a
> patch to any of these drivers that has been tested on real hardware,
> only cleanups or global API changes.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Acked-by: Karsten Keil <isdn@linux-pingi.de>
This patch got added in the 4.6 kernel release. As I am now taking
patches for 4.11-rc1, I figure it is time to just delete the
drivers/staging/i4l/ directory now, given that no one has really done
anything with it. If people show up that wish to maintain it, I'll be
glad to revert it, or if someone really screams in the next week.
Otherwise it's time to just move on :)
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH] tcp: provide tx timestamps for partial writes
From: Soheil Hassas Yeganeh @ 2017-01-03 15:22 UTC (permalink / raw)
To: David Miller, netdev
Cc: Willem de Bruijn, Yuchung Cheng, Eric Dumazet, Neal Cardwell,
Martin KaFai Lau
In-Reply-To: <CACSApvbYBv4GTGDKFT9jg3p9_w=3WD6aQZh7qwB2HbgCCTFxog@mail.gmail.com>
On Mon, Jan 2, 2017 at 3:23 PM, Soheil Hassas Yeganeh <soheil@google.com> wrote:
> On Mon, Jan 2, 2017 at 3:20 PM, Soheil Hassas Yeganeh
> <soheil.kdev@gmail.com> wrote:
>> From: Soheil Hassas Yeganeh <soheil@google.com>
>>
>> For TCP sockets, tx timestamps are only captured when the user data
>> is successfully and fully written to the socket. In many cases,
>> however, TCP writes can be partial for which no timestamp is
>> collected.
>>
>> Collect timestamps when the user data is partially copied into
>> the socket.
>>
>> Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com>
>> Cc: Willem de Bruijn <willemb@google.com>
>> Cc: Yuchung Cheng <ycheng@google.com>
>> Cc: Eric Dumazet <edumazet@google.com>
>> Cc: Neal Cardwell <ncardwell@google.com>
>> Cc: Martin KaFai Lau <kafai@fb.com>
>> ---
>> net/ipv4/tcp.c | 8 ++++++--
>> 1 file changed, 6 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
>> index 2e3807d..c207b16 100644
>> --- a/net/ipv4/tcp.c
>> +++ b/net/ipv4/tcp.c
>> @@ -992,8 +992,10 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
>> return copied;
>>
>> do_error:
>> - if (copied)
>> + if (copied) {
>> + tcp_tx_timestamp(sk, sk->sk_tsflags, tcp_write_queue_tail(sk));
>> goto out;
>> + }
>> out_err:
>> /* make sure we wake any epoll edge trigger waiter */
>> if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 &&
>> @@ -1329,8 +1331,10 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
>> }
>>
>> do_error:
>> - if (copied + copied_syn)
>> + if (copied + copied_syn) {
>> + tcp_tx_timestamp(sk, sk->sk_tsflags, tcp_write_queue_tail(sk));
Thanks to Willem for noting that this should be sockc.tsflags and not
sk->sk_tsflags. I'll send V2 to fix.
Soheil
>> goto out;
>> + }
>> out_err:
>> err = sk_stream_error(sk, flags, err);
>> /* make sure we wake any epoll edge trigger waiter */
>> --
>> 2.8.0.rc3.226.g39d4020
>>
>
> I'm sorry for the incomplete annotation. This is for [net-next].
>
> Thanks,
> Soheil
^ permalink raw reply
* Re: [PATCH net-next] ipmr, ip6mr: add RTNH_F_UNRESOLVED flag to unresolved cache entries
From: David Miller @ 2017-01-03 15:04 UTC (permalink / raw)
To: nikolay; +Cc: netdev, roopa
In-Reply-To: <1483442019-20917-1-git-send-email-nikolay@cumulusnetworks.com>
From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Date: Tue, 3 Jan 2017 12:13:39 +0100
> While working with ipmr, we noticed that it is impossible to determine
> if an entry is actually unresolved or its IIF interface has disappeared
> (e.g. virtual interface got deleted). These entries look almost
> identical to user-space when dumping or receiving notifications. So in
> order to recognize them add a new RTNH_F_UNRESOLVED flag which is set when
> sending an unresolved cache entry to user-space.
>
> Suggested-by: Roopa Prabhu <roopa@cumulusnetworks.com>
> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
This looks fine, applied, thanks.
^ permalink raw reply
* Re: [PATCH net-next] net:mv88e6xxx: use g2 interrupt for 6097 chip
From: David Miller @ 2017-01-03 15:03 UTC (permalink / raw)
To: volodymyr.bendiuga
Cc: andrew, vivien.didelot, f.fainelli, netdev, volodymyr.bendiuga
In-Reply-To: <1483438437-19601-1-git-send-email-volodymyr.bendiuga@gmail.com>
From: Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
Date: Tue, 3 Jan 2017 11:13:57 +0100
> @@ -575,6 +575,7 @@ enum mv88e6xxx_cap {
> (MV88E6XXX_FLAG_G1_ATU_FID | \
> MV88E6XXX_FLAG_G1_VTU_FID | \
> MV88E6XXX_FLAG_GLOBAL2 | \
> + MV88E6XXX_FLAG_G2_INT | \
There is a space character before the TAB in this new line you
are adding, please remove it.
^ permalink raw reply
* Re: [PATCH v2 net-next] dsa:mv88e6xxx: allow address 0x1 in smi_init
From: David Miller @ 2017-01-03 15:02 UTC (permalink / raw)
To: volodymyr.bendiuga
Cc: andrew, vivien.didelot, f.fainelli, netdev, volodymyr.bendiuga
In-Reply-To: <1483436949-4527-1-git-send-email-volodymyr.bendiuga@gmail.com>
From: Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
Date: Tue, 3 Jan 2017 10:49:09 +0100
> From: Volodymyr Bendiuga <volodymyr.bendiuga@westermo.se>
>
> Some devices, such as the mv88e6097 do have ADDR[0] external and so it
> is possible to configure the device to use SMI address 0x1. Remove the
> restriction, as there are boards using this address.
>
> Signed-off-by: Volodymyr Bendiuga <volodymyr.bendiuga@westermo.se>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH] drop_monitor: consider inserted data in genlmsg_end
From: David Miller @ 2017-01-03 14:54 UTC (permalink / raw)
To: wr0112358; +Cc: nhorman, netdev, linux-kernel
In-Reply-To: <20170103003910.8984-1-wr0112358@gmail.com>
From: Reiter Wolfgang <wr0112358@gmail.com>
Date: Tue, 3 Jan 2017 01:39:10 +0100
> Final nlmsg_len field update must reflect inserted net_dm_drop_point
> data.
>
> This patch depends on previous patch:
> "drop_monitor: add missing call to genlmsg_end"
>
> Signed-off-by: Reiter Wolfgang <wr0112358@gmail.com>
I don't understand why the current code doesn't work properly.
All over the tree, the pattern is:
x = genlmsg_put(skb, ...);
...
genlmsg_end(skb, x);
And that is exactly what the code is doing right now.
^ permalink raw reply
* Re: [PATCH] net: freescale: dpaa: use new api ethtool_{get|set}_link_ksettings
From: David Miller @ 2017-01-03 14:49 UTC (permalink / raw)
To: tremyfr; +Cc: madalin.bucur, netdev, linux-kernel
In-Reply-To: <1483397355-18738-1-git-send-email-tremyfr@gmail.com>
From: Philippe Reynes <tremyfr@gmail.com>
Date: Mon, 2 Jan 2017 23:49:15 +0100
> The ethtool api {get|set}_settings is deprecated.
> We move this driver to new api {get|set}_link_ksettings.
>
> Signed-off-by: Philippe Reynes <tremyfr@gmail.com>
Applied.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox