Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH vhost] vhost_net: Fix too many vring kick on busypoll
From: Jason Wang @ 2018-07-02  2:41 UTC (permalink / raw)
  To: Michael S. Tsirkin, Toshiaki Makita; +Cc: netdev, kvm, virtualization
In-Reply-To: <20180629193448-mutt-send-email-mst@kernel.org>



On 2018年06月30日 00:38, Michael S. Tsirkin wrote:
> On Fri, Jun 29, 2018 at 05:09:50PM +0900, Toshiaki Makita wrote:
>> Under heavy load vhost busypoll may run without suppressing
>> notification. For example tx zerocopy callback can push tx work while
>> handle_tx() is running, then busyloop exits due to vhost_has_work()
>> condition and enables notification but immediately reenters handle_tx()
>> because the pushed work was tx. In this case handle_tx() tries to
>> disable notification again, but when using event_idx it by design
>> cannot. Then busyloop will run without suppressing notification.
>> Another example is the case where handle_tx() tries to enable
>> notification but avail idx is advanced so disables it again. This case
>> also lead to the same situation with event_idx.
>>
>> The problem is that once we enter this situation busyloop does not work
>> under heavy load for considerable amount of time, because notification
>> is likely to happen during busyloop and handle_tx() immediately enables
>> notification after notification happens. Specifically busyloop detects
>> notification by vhost_has_work() and then handle_tx() calls
>> vhost_enable_notify().
> I'd like to understand the problem a bit better.
> Why does this happen?
> Doesn't this only happen if ring is empty?
>

My understanding is:

vhost_zerocopy_callback() try to poll vhost virtqueue. This will cause 
the busy loop in vhost_net_tx_get_vq_desc() to exit because of 
vhost_has_work() return true. Then handle_tx() tends to enable 
notification. Then guest may kick us even if handle_tx() call 
vhost_disable_notify() which in fact did nothing for even index.

Maybe we can try to call vhost_zerocopy_signal_used() if we found 
there's pending used from zerocopy instead.

Thanks

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply

* Re: [PATCH net-next v3 4/4] net: vhost: add rx busy polling in tx path
From: Jason Wang @ 2018-07-02  2:32 UTC (permalink / raw)
  To: xiangxia.m.yue; +Cc: netdev, virtualization, Tonghao Zhang, mst
In-Reply-To: <1530340438-3039-5-git-send-email-xiangxia.m.yue@gmail.com>



On 2018年06月30日 14:33, xiangxia.m.yue@gmail.com wrote:
> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
>
> This patch improves the guest receive and transmit performance.
> On the handle_tx side, we poll the sock receive queue at the
> same time. handle_rx do that in the same way.
>
> We set the poll-us=100us and use the iperf3 to test
> its bandwidth, use the netperf to test throughput and mean
> latency. When running the tests, the vhost-net kthread of
> that VM, is alway 100% CPU. The commands are shown as below.
>
> iperf3  -s -D
> iperf3  -c IP -i 1 -P 1 -t 20 -M 1400
>
> or
> netserver
> netperf -H IP -t TCP_RR -l 20 -- -O "THROUGHPUT,MEAN_LATENCY"
>
> host -> guest:
> iperf3:
> * With the patch:     27.0 Gbits/sec
> * Without the patch:  14.4 Gbits/sec
>
> netperf (TCP_RR):
> * With the patch:     48039.56 trans/s, 20.64us mean latency
> * Without the patch:  46027.07 trans/s, 21.58us mean latency
>
> This patch also improves the guest transmit performance.
>
> guest -> host:
> iperf3:
> * With the patch:     27.2 Gbits/sec
> * Without the patch:  24.4 Gbits/sec
>
> netperf (TCP_RR):
> * With the patch:     47963.25 trans/s, 20.71us mean latency
> * Without the patch:  45796.70 trans/s, 21.68us mean latency
>
> Signed-off-by: Tonghao Zhang <zhangtonghao@didichuxing.com>
> ---
>   drivers/vhost/net.c | 10 +++-------
>   1 file changed, 3 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index 458f81d..fb43d82 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -478,17 +478,13 @@ static int vhost_net_tx_get_vq_desc(struct vhost_net *net,
>   				    struct iovec iov[], unsigned int iov_size,
>   				    unsigned int *out_num, unsigned int *in_num)
>   {
> -	unsigned long uninitialized_var(endtime);
> +	struct vhost_net_virtqueue *nvq_rx = &net->vqs[VHOST_NET_VQ_RX];
>   	int r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
>   				  out_num, in_num, NULL, NULL);
>   
>   	if (r == vq->num && vq->busyloop_timeout) {
> -		preempt_disable();
> -		endtime = busy_clock() + vq->busyloop_timeout;
> -		while (vhost_can_busy_poll(vq->dev, endtime) &&
> -		       vhost_vq_avail_empty(vq->dev, vq))
> -			cpu_relax();
> -		preempt_enable();
> +		vhost_net_busy_poll(net, &nvq_rx->vq, vq, false);
> +
>   		r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
>   				      out_num, in_num, NULL, NULL);
>   	}

Looks good to me.

A nit is "rnvq" looks better.

Thanks

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply

* Re: [PATCH net-next v3 3/4] net: vhost: factor out busy polling logic to vhost_net_busy_poll()
From: Jason Wang @ 2018-07-02  2:29 UTC (permalink / raw)
  To: xiangxia.m.yue; +Cc: netdev, virtualization, Tonghao Zhang, mst
In-Reply-To: <1530340438-3039-4-git-send-email-xiangxia.m.yue@gmail.com>



On 2018年06月30日 14:33, xiangxia.m.yue@gmail.com wrote:
> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
>
> Factor out generic busy polling logic and will be
> used for tx path in the next patch. And with the patch,
> qemu can set differently the busyloop_timeout for rx queue.
>
> Signed-off-by: Tonghao Zhang <zhangtonghao@didichuxing.com>
> ---
>   drivers/vhost/net.c | 92 ++++++++++++++++++++++++++++++-----------------------
>   1 file changed, 53 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index 62bb8e8..458f81d 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -429,6 +429,50 @@ static int vhost_net_enable_vq(struct vhost_net *n,
>   	return vhost_poll_start(poll, sock->file);
>   }
>   
> +static int sk_has_rx_data(struct sock *sk)
> +{
> +	struct socket *sock = sk->sk_socket;
> +
> +	if (sock->ops->peek_len)
> +		return sock->ops->peek_len(sock);
> +
> +	return skb_queue_empty(&sk->sk_receive_queue);
> +}
> +
> +static void vhost_net_busy_poll(struct vhost_net *net,
> +				struct vhost_virtqueue *rvq,
> +				struct vhost_virtqueue *tvq,
> +				bool rx)
> +{
> +	unsigned long uninitialized_var(endtime);
> +	struct socket *sock = rvq->private_data;
> +	struct vhost_virtqueue *vq = rx ? tvq : rvq;
> +	unsigned long busyloop_timeout = rx ? rvq->busyloop_timeout :
> +					      tvq->busyloop_timeout;

As simple as vq->busyloop_timeout?

> +
> +	mutex_lock_nested(&vq->mutex, rx ? VHOST_NET_VQ_TX: VHOST_NET_VQ_RX);

We need move sock = rvq->private_data under the protection of vq mutex 
if rx is false.

> +	vhost_disable_notify(&net->dev, vq);
> +
> +	preempt_disable();
> +	endtime = busy_clock() + busyloop_timeout;
> +	while (vhost_can_busy_poll(tvq->dev, endtime) &&
> +	       !(sock && sk_has_rx_data(sock->sk)) &&
> +	       vhost_vq_avail_empty(tvq->dev, tvq))
> +		cpu_relax();
> +	preempt_enable();
> +
> +	if ((rx && !vhost_vq_avail_empty(&net->dev, vq)) ||
> +	    (!rx && (sock && sk_has_rx_data(sock->sk)))) {
> +		vhost_poll_queue(&vq->poll);
> +	} else if (unlikely(vhost_enable_notify(&net->dev, vq))) {
> +		vhost_disable_notify(&net->dev, vq);
> +		vhost_poll_queue(&vq->poll);
> +	}
> +
> +	mutex_unlock(&vq->mutex);
> +}
> +
> +
>   static int vhost_net_tx_get_vq_desc(struct vhost_net *net,
>   				    struct vhost_virtqueue *vq,
>   				    struct iovec iov[], unsigned int iov_size,
> @@ -621,16 +665,6 @@ static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk)
>   	return len;
>   }
>   
> -static int sk_has_rx_data(struct sock *sk)
> -{
> -	struct socket *sock = sk->sk_socket;
> -
> -	if (sock->ops->peek_len)
> -		return sock->ops->peek_len(sock);
> -
> -	return skb_queue_empty(&sk->sk_receive_queue);
> -}
> -
>   static void vhost_rx_signal_used(struct vhost_net_virtqueue *nvq)
>   {
>   	struct vhost_virtqueue *vq = &nvq->vq;
> @@ -645,39 +679,19 @@ static void vhost_rx_signal_used(struct vhost_net_virtqueue *nvq)
>   
>   static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk)
>   {
> -	struct vhost_net_virtqueue *rvq = &net->vqs[VHOST_NET_VQ_RX];
> -	struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX];
> -	struct vhost_virtqueue *vq = &nvq->vq;
> -	unsigned long uninitialized_var(endtime);
> -	int len = peek_head_len(rvq, sk);
> +	struct vhost_net_virtqueue *nvq_rx = &net->vqs[VHOST_NET_VQ_RX];
> +	struct vhost_net_virtqueue *nvq_tx = &net->vqs[VHOST_NET_VQ_TX];

It looks to me rnvq and tnvq is slightly better.

Other looks good to me.

Thanks

>   
> -	if (!len && vq->busyloop_timeout) {
> -		/* Flush batched heads first */
> -		vhost_rx_signal_used(rvq);
> -		/* Both tx vq and rx socket were polled here */
> -		mutex_lock_nested(&vq->mutex, VHOST_NET_VQ_TX);
> -		vhost_disable_notify(&net->dev, vq);
> +	int len = peek_head_len(nvq_rx, sk);
>   
> -		preempt_disable();
> -		endtime = busy_clock() + vq->busyloop_timeout;
> -
> -		while (vhost_can_busy_poll(&net->dev, endtime) &&
> -		       !sk_has_rx_data(sk) &&
> -		       vhost_vq_avail_empty(&net->dev, vq))
> -			cpu_relax();
> -
> -		preempt_enable();
> -
> -		if (!vhost_vq_avail_empty(&net->dev, vq))
> -			vhost_poll_queue(&vq->poll);
> -		else if (unlikely(vhost_enable_notify(&net->dev, vq))) {
> -			vhost_disable_notify(&net->dev, vq);
> -			vhost_poll_queue(&vq->poll);
> -		}
> +	if (!len && nvq_rx->vq.busyloop_timeout) {
> +		/* Flush batched heads first */
> +		vhost_rx_signal_used(nvq_rx);
>   
> -		mutex_unlock(&vq->mutex);
> +		/* Both tx vq and rx socket were polled here */
> +		vhost_net_busy_poll(net, &nvq_rx->vq, &nvq_tx->vq, true);
>   
> -		len = peek_head_len(rvq, sk);
> +		len = peek_head_len(nvq_rx, sk);
>   	}
>   
>   	return len;

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply

* Re: [PATCH net-next v3 2/4] net: vhost: replace magic number of lock annotation
From: Jason Wang @ 2018-07-02  2:21 UTC (permalink / raw)
  To: xiangxia.m.yue; +Cc: netdev, virtualization, Tonghao Zhang, mst
In-Reply-To: <1530340438-3039-3-git-send-email-xiangxia.m.yue@gmail.com>



On 2018年06月30日 14:33, xiangxia.m.yue@gmail.com wrote:
> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
>
> Use the VHOST_NET_VQ_XXX as a subclass for mutex_lock_nested.
>
> Signed-off-by: Tonghao Zhang <zhangtonghao@didichuxing.com>
> ---
>   drivers/vhost/net.c | 6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index e7cf7d2..62bb8e8 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -484,7 +484,7 @@ static void handle_tx(struct vhost_net *net)
>   	bool zcopy, zcopy_used;
>   	int sent_pkts = 0;
>   
> -	mutex_lock(&vq->mutex);
> +	mutex_lock_nested(&vq->mutex, VHOST_NET_VQ_TX);
>   	sock = vq->private_data;
>   	if (!sock)
>   		goto out;
> @@ -655,7 +655,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk)
>   		/* Flush batched heads first */
>   		vhost_rx_signal_used(rvq);
>   		/* Both tx vq and rx socket were polled here */
> -		mutex_lock_nested(&vq->mutex, 1);
> +		mutex_lock_nested(&vq->mutex, VHOST_NET_VQ_TX);
>   		vhost_disable_notify(&net->dev, vq);
>   
>   		preempt_disable();
> @@ -789,7 +789,7 @@ static void handle_rx(struct vhost_net *net)
>   	__virtio16 num_buffers;
>   	int recv_pkts = 0;
>   
> -	mutex_lock_nested(&vq->mutex, 0);
> +	mutex_lock_nested(&vq->mutex, VHOST_NET_VQ_RX);
>   	sock = vq->private_data;
>   	if (!sock)
>   		goto out;

Acked-by: Jason Wang <jasowang@redhat.com>

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply

* Re: [PATCH net-next v3 1/4] net: vhost: lock the vqs one by one
From: Jason Wang @ 2018-07-02  2:21 UTC (permalink / raw)
  To: xiangxia.m.yue
  Cc: mst, makita.toshiaki, virtualization, netdev, Tonghao Zhang
In-Reply-To: <1530340438-3039-2-git-send-email-xiangxia.m.yue@gmail.com>



On 2018年06月30日 14:33, xiangxia.m.yue@gmail.com wrote:
> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
>
> This patch changes the way that lock all vqs
> at the same, to lock them one by one. It will
> be used for next patch to avoid the deadlock.
>
> Signed-off-by: Tonghao Zhang <zhangtonghao@didichuxing.com>
> ---
>   drivers/vhost/vhost.c | 24 +++++++-----------------
>   1 file changed, 7 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index 895eaa2..4ca9383 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -294,8 +294,11 @@ static void vhost_vq_meta_reset(struct vhost_dev *d)
>   {
>   	int i;
>   
> -	for (i = 0; i < d->nvqs; ++i)
> +	for (i = 0; i < d->nvqs; ++i) {
> +		mutex_lock(&d->vqs[i]->mutex);
>   		__vhost_vq_meta_reset(d->vqs[i]);
> +		mutex_unlock(&d->vqs[i]->mutex);
> +	}
>   }
>   
>   static void vhost_vq_reset(struct vhost_dev *dev,
> @@ -887,20 +890,6 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq,
>   #define vhost_get_used(vq, x, ptr) \
>   	vhost_get_user(vq, x, ptr, VHOST_ADDR_USED)
>   
> -static void vhost_dev_lock_vqs(struct vhost_dev *d)
> -{
> -	int i = 0;
> -	for (i = 0; i < d->nvqs; ++i)
> -		mutex_lock_nested(&d->vqs[i]->mutex, i);
> -}
> -
> -static void vhost_dev_unlock_vqs(struct vhost_dev *d)
> -{
> -	int i = 0;
> -	for (i = 0; i < d->nvqs; ++i)
> -		mutex_unlock(&d->vqs[i]->mutex);
> -}
> -
>   static int vhost_new_umem_range(struct vhost_umem *umem,
>   				u64 start, u64 size, u64 end,
>   				u64 userspace_addr, int perm)
> @@ -950,7 +939,10 @@ static void vhost_iotlb_notify_vq(struct vhost_dev *d,
>   		if (msg->iova <= vq_msg->iova &&
>   		    msg->iova + msg->size - 1 > vq_msg->iova &&
>   		    vq_msg->type == VHOST_IOTLB_MISS) {
> +			mutex_lock(&node->vq->mutex);
>   			vhost_poll_queue(&node->vq->poll);
> +			mutex_unlock(&node->vq->mutex);
> +
>   			list_del(&node->node);
>   			kfree(node);
>   		}
> @@ -982,7 +974,6 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev,
>   	int ret = 0;
>   
>   	mutex_lock(&dev->mutex);
> -	vhost_dev_lock_vqs(dev);
>   	switch (msg->type) {
>   	case VHOST_IOTLB_UPDATE:
>   		if (!dev->iotlb) {
> @@ -1016,7 +1007,6 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev,
>   		break;
>   	}
>   
> -	vhost_dev_unlock_vqs(dev);
>   	mutex_unlock(&dev->mutex);
>   
>   	return ret;

Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>

Thanks

^ permalink raw reply

* Re: [net-next 01/12] net/mlx5e: Add UDP GSO support
From: Willem de Bruijn @ 2018-07-02  1:45 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: borisp, David Miller, Network Development, Saeed Mahameed,
	ogerlitz, yossiku
In-Reply-To: <CAKgT0UfFMG+i9z_nxB0vkJesDE4CHWbudCh6kJ_1+=Vd1hv=wA@mail.gmail.com>

>> I've noticed that we could get cleaner code in our driver if we remove
>> these two lines from net/ipv4/udp_offload.c:
>> if (skb_is_gso(segs))
>>               mss *= skb_shinfo(segs)->gso_segs;
>>
>> I think that this is correct in case of GSO_PARTIAL segmentation for the
>> following reasons:
>> 1. After this change the UDP payload field is consistent with the IP
>> header payload length field. Currently, IPv4 length is 1500 and UDP
>> total length is the full unsegmented length.

How does this simplify the driver? Does it currently have to
change the udph->length field to the mss on the wire, because the
device only splits + replicates the headers + computes the csum?

> I don’t recall that the UDP header length field will match the IP length
> field. I had intentionally left it at the original value used to compute
> the UDP header checksum. That way you could just adjust it by
> cancelling out the length from the partial checksum.

>> 2. AFAIU, in GSO_PARTIAL no tunnel headers should be modified except the
>> IP ID field, including the UDP length field.
>> What do you think?
>
>
> For outer headers this is correct. For inner headers this is not. The inner
> UDP header will need to have the length updated and the checksum
> recomputed as a part of the segmentation.

^ permalink raw reply

* Re: [PATCH] lib: rhashtable: Correct self-assignment in rhashtable.c
From: NeilBrown @ 2018-07-02  1:32 UTC (permalink / raw)
  To: Linux Kernel Network Developers, Rishabh Bhatnagar, tgraf,
	linux-arm-msm
  Cc: herbert, linux-kernel, Rishabh Bhatnagar
In-Reply-To: <1530493906-19711-1-git-send-email-rishabhb@codeaurora.org>

[-- Attachment #1: Type: text/plain, Size: 1261 bytes --]


(added netdev@vger.kernel.org)

On Sun, Jul 01 2018, Rishabh Bhatnagar wrote:

> In file lib/rhashtable.c line 777, skip variable is assigned to
> itself. The following error was observed:
>
> lib/rhashtable.c:777:41: warning: explicitly assigning value of
> variable of type 'int' to itself [-Wself-assign] error, forbidden
> warning: rhashtable.c:777
> This error was found when compiling with Clang 6.0. Change it to iter->skip.
>
> Change-Id: I5abd1ce5ba76737a73bd6eca94b07b1bd5267523
> Signed-off-by: Rishabh Bhatnagar <rishabhb@codeaurora.org>

Thanks for catching that!
Reviewed-by: NeilBrown <neilb@suse.com>

Thanks,
NeilBrown

> ---
>  lib/rhashtable.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/rhashtable.c b/lib/rhashtable.c
> index 9427b57..3109b2e 100644
> --- a/lib/rhashtable.c
> +++ b/lib/rhashtable.c
> @@ -774,7 +774,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter)
>  				skip++;
>  				if (list == iter->list) {
>  					iter->p = p;
> -					skip = skip;
> +					iter->skip = skip;
>  					goto found;
>  				}
>  			}
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply

* linux-next: manual merge of the net-next tree with the rdma tree
From: Stephen Rothwell @ 2018-07-02  0:21 UTC (permalink / raw)
  To: David Miller, Networking, Doug Ledford, Jason Gunthorpe
  Cc: Linux-Next Mailing List, Linux Kernel Mailing List, Parav Pandit

[-- Attachment #1: Type: text/plain, Size: 3302 bytes --]

Hi all,

Today's linux-next merge of the net-next tree got a conflict in:

  net/smc/smc_ib.c

between commit:

  ddb457c6993b ("net/smc: Replace ib_query_gid with rdma_get_gid_attr")

from the rdma tree and commit:

  be6a3f38ff2a ("net/smc: determine port attributes independent from pnet table")

from the net-next tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

-- 
Cheers,
Stephen Rothwell

diff --cc net/smc/smc_ib.c
index 74f29f814ec1,36de2fd76170..000000000000
--- a/net/smc/smc_ib.c
+++ b/net/smc/smc_ib.c
@@@ -144,6 -143,62 +144,66 @@@ out
  	return rc;
  }
  
+ static int smc_ib_fill_gid_and_mac(struct smc_ib_device *smcibdev, u8 ibport)
+ {
 -	struct ib_gid_attr gattr;
 -	int rc;
 -
 -	rc = ib_query_gid(smcibdev->ibdev, ibport, 0,
 -			  &smcibdev->gid[ibport - 1], &gattr);
 -	if (rc || !gattr.ndev)
 -		return -ENODEV;
++	const struct ib_gid_attr *gattr;
++	int rc = 0;
+ 
 -	memcpy(smcibdev->mac[ibport - 1], gattr.ndev->dev_addr, ETH_ALEN);
 -	dev_put(gattr.ndev);
 -	return 0;
++	gattr = rdma_get_gid_attr(smcibdev->ibdev, ibport, 0);
++	if (IS_ERR(gattr))
++		return PTR_ERR(gattr);
++	if (!gattr->ndev) {
++		rc = -ENODEV;
++		goto done;
++	}
++	smcibdev->gid[ibport - 1] = gattr->gid;
++	memcpy(smcibdev->mac[ibport - 1], gattr->ndev->dev_addr, ETH_ALEN);
++done:
++	rdma_put_gid_attr(gattr);
++	return rc;
+ }
+ 
+ /* Create an identifier unique for this instance of SMC-R.
+  * The MAC-address of the first active registered IB device
+  * plus a random 2-byte number is used to create this identifier.
+  * This name is delivered to the peer during connection initialization.
+  */
+ static inline void smc_ib_define_local_systemid(struct smc_ib_device *smcibdev,
+ 						u8 ibport)
+ {
+ 	memcpy(&local_systemid[2], &smcibdev->mac[ibport - 1],
+ 	       sizeof(smcibdev->mac[ibport - 1]));
+ 	get_random_bytes(&local_systemid[0], 2);
+ }
+ 
+ bool smc_ib_port_active(struct smc_ib_device *smcibdev, u8 ibport)
+ {
+ 	return smcibdev->pattr[ibport - 1].state == IB_PORT_ACTIVE;
+ }
+ 
+ static int smc_ib_remember_port_attr(struct smc_ib_device *smcibdev, u8 ibport)
+ {
+ 	int rc;
+ 
+ 	memset(&smcibdev->pattr[ibport - 1], 0,
+ 	       sizeof(smcibdev->pattr[ibport - 1]));
+ 	rc = ib_query_port(smcibdev->ibdev, ibport,
+ 			   &smcibdev->pattr[ibport - 1]);
+ 	if (rc)
+ 		goto out;
+ 	/* the SMC protocol requires specification of the RoCE MAC address */
+ 	rc = smc_ib_fill_gid_and_mac(smcibdev, ibport);
+ 	if (rc)
+ 		goto out;
+ 	if (!strncmp(local_systemid, SMC_LOCAL_SYSTEMID_RESET,
+ 		     sizeof(local_systemid)) &&
+ 	    smc_ib_port_active(smcibdev, ibport))
+ 		/* create unique system identifier */
+ 		smc_ib_define_local_systemid(smcibdev, ibport);
+ out:
+ 	return rc;
+ }
+ 
  /* process context wrapper for might_sleep smc_ib_remember_port_attr */
  static void smc_ib_port_event_work(struct work_struct *work)
  {

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: manual merge of the net-next tree with the net tree
From: Stephen Rothwell @ 2018-07-02  0:15 UTC (permalink / raw)
  To: David Miller, Networking
  Cc: Linux-Next Mailing List, Linux Kernel Mailing List, Jose Abreu

[-- Attachment #1: Type: text/plain, Size: 3545 bytes --]

Hi all,

Today's linux-next merge of the net-next tree got conflicts in:

  drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
  drivers/net/ethernet/stmicro/stmmac/hwif.h

between commit:

  4205c88eaf17 ("net: stmmac: Set DMA buffer size in HW")

from the net tree and commit:

  1f705bc61aee ("net: stmmac: Add support for CBS QDISC")

from the net-next tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

-- 
Cheers,
Stephen Rothwell

diff --cc drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 65bc3556bd8f,6e32f8a3710b..000000000000
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@@ -407,16 -407,19 +407,29 @@@ static void dwmac4_enable_tso(void __io
  	}
  }
  
 +static void dwmac4_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan)
 +{
 +	u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
 +
 +	value &= ~DMA_RBSZ_MASK;
 +	value |= (bfsize << DMA_RBSZ_SHIFT) & DMA_RBSZ_MASK;
 +
 +	writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
 +}
 +
+ static void dwmac4_qmode(void __iomem *ioaddr, u32 channel, u8 qmode)
+ {
+ 	u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
+ 
+ 	mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK;
+ 	if (qmode != MTL_QUEUE_AVB)
+ 		mtl_tx_op |= MTL_OP_MODE_TXQEN;
+ 	else
+ 		mtl_tx_op |= MTL_OP_MODE_TXQEN_AV;
+ 
+ 	writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(channel));
+ }
+ 
  const struct stmmac_dma_ops dwmac4_dma_ops = {
  	.reset = dwmac4_dma_reset,
  	.init = dwmac4_dma_init,
@@@ -441,7 -444,7 +454,8 @@@
  	.set_rx_tail_ptr = dwmac4_set_rx_tail_ptr,
  	.set_tx_tail_ptr = dwmac4_set_tx_tail_ptr,
  	.enable_tso = dwmac4_enable_tso,
 +	.set_bfsize = dwmac4_set_bfsize,
+ 	.qmode = dwmac4_qmode,
  };
  
  const struct stmmac_dma_ops dwmac410_dma_ops = {
@@@ -468,5 -471,5 +482,6 @@@
  	.set_rx_tail_ptr = dwmac4_set_rx_tail_ptr,
  	.set_tx_tail_ptr = dwmac4_set_tx_tail_ptr,
  	.enable_tso = dwmac4_enable_tso,
 +	.set_bfsize = dwmac4_set_bfsize,
+ 	.qmode = dwmac4_qmode,
  };
diff --cc drivers/net/ethernet/stmicro/stmmac/hwif.h
index fe8b536b13f8,e2a965790648..000000000000
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@@ -183,7 -183,7 +183,8 @@@ struct stmmac_dma_ops 
  	void (*set_rx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
  	void (*set_tx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
  	void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan);
 +	void (*set_bfsize)(void __iomem *ioaddr, int bfsize, u32 chan);
+ 	void (*qmode)(void __iomem *ioaddr, u32 channel, u8 qmode);
  };
  
  #define stmmac_reset(__priv, __args...) \
@@@ -236,8 -236,8 +237,10 @@@
  	stmmac_do_void_callback(__priv, dma, set_tx_tail_ptr, __args)
  #define stmmac_enable_tso(__priv, __args...) \
  	stmmac_do_void_callback(__priv, dma, enable_tso, __args)
 +#define stmmac_set_dma_bfsize(__priv, __args...) \
 +	stmmac_do_void_callback(__priv, dma, set_bfsize, __args)
+ #define stmmac_dma_qmode(__priv, __args...) \
+ 	stmmac_do_void_callback(__priv, dma, qmode, __args)
  
  struct mac_device_info;
  struct net_device;

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [net-next PATCH v6 0/7] Symmetric queue selection using XPS for Rx queues
From: David Miller @ 2018-07-02  0:11 UTC (permalink / raw)
  To: amritha.nambiar
  Cc: netdev, alexander.h.duyck, willemdebruijn.kernel,
	sridhar.samudrala, alexander.duyck, edumazet, hannes, tom, tom
In-Reply-To: <153033254062.8297.3821413056768389263.stgit@anamhost.jf.intel.com>

From: Amritha Nambiar <amritha.nambiar@intel.com>
Date: Fri, 29 Jun 2018 21:26:35 -0700

> This patch series implements support for Tx queue selection based on
> Rx queue(s) map. This is done by configuring Rx queue(s) map per Tx-queue
> using sysfs attribute. If the user configuration for Rx queues does
> not apply, then the Tx queue selection falls back to XPS using CPUs and
> finally to hashing.
 ...

Series applied, thanks.

^ permalink raw reply

* Reminder: Linux Plumbers Networking Track CFP
From: David Miller @ 2018-07-02  0:10 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, netfilter-devel


The deadline is only 10 days away, and slots are filling up quickly.

This is a call for proposals for the networking track at the 2018
edition of the Linux Plumbers Conference which will be held in
Vancouver on November 13th and November 14th.

The LPC Networking Track is a community event, open to everyone, and
does not require an invitation.

We are seeking talks of 40 minutes in length, accompanied by papers of
2 to 10 pages in length.

Although proposals on finished work are perfectly acceptable, there is
even more value for talks on problems, proposals, and proof-of-concept
solutions that require face-to-face discussions and debate.

Please submit your proposals to the LPC Networking Technical Committee
at:

	lpc-netdev@vger.kernel.org

Proposals must be submitted by July 11th, and submitters will be
notified of acceptance by August 15th.

The format of the submission and other details can be found at:

	http://vger.kernel.org/lpc-networking.html

We are looking forward to seeing everyone in November!

^ permalink raw reply

* [PATCH] TTY: isdn: Replace strncpy with memcpy
From: Guenter Roeck @ 2018-07-01 20:57 UTC (permalink / raw)
  To: Karsten Keil; +Cc: Kees Cook, linux-kernel, netdev, Guenter Roeck

gcc 8.1.0 complains:

drivers/isdn/i4l/isdn_tty.c: In function 'isdn_tty_suspend.isra.1':
drivers/isdn/i4l/isdn_tty.c:790:3: warning:
	'strncpy' output truncated before terminating nul copying
	as many bytes from a string as its length
drivers/isdn/i4l/isdn_tty.c:778:6: note: length computed here

drivers/isdn/i4l/isdn_tty.c: In function 'isdn_tty_resume':
drivers/isdn/i4l/isdn_tty.c:880:3: warning:
	'strncpy' output truncated before terminating nul copying
	as many bytes from a string as its length
drivers/isdn/i4l/isdn_tty.c:817:6: note: length computed here

Using strncpy() is indeed less than perfect since the length of data to
be copied has already been determined with strlen(). Replace strncpy()
with memcpy() to address the warning and optimize the code a little.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
 drivers/isdn/i4l/isdn_tty.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 960f26348bb5..b730037a0e2d 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -787,7 +787,7 @@ isdn_tty_suspend(char *id, modem_info *info, atemu *m)
 		cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
 		cmd.parm.cmsg.para[4] = 0;
 		cmd.parm.cmsg.para[5] = l;
-		strncpy(&cmd.parm.cmsg.para[6], id, l);
+		memcpy(&cmd.parm.cmsg.para[6], id, l);
 		cmd.command = CAPI_PUT_MESSAGE;
 		cmd.driver = info->isdn_driver;
 		cmd.arg = info->isdn_channel;
@@ -877,7 +877,7 @@ isdn_tty_resume(char *id, modem_info *info, atemu *m)
 		cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */
 		cmd.parm.cmsg.para[4] = 0;
 		cmd.parm.cmsg.para[5] = l;
-		strncpy(&cmd.parm.cmsg.para[6], id, l);
+		memcpy(&cmd.parm.cmsg.para[6], id, l);
 		cmd.command = CAPI_PUT_MESSAGE;
 		info->dialing = 1;
 //		strcpy(dev->num[i], n);
-- 
2.7.4

^ permalink raw reply related

* Compiler warnings in kernel 4.14.51
From: Enrico Mioso @ 2018-07-01 20:35 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Daniel Borkmann, Kirill Tkhai, Jakub Kicinski,
	Alexei Starovoitov, Rasmus Villemoes, John Fastabend,
	Jesper Dangaard Brouer, David Ahern

Hello!

While compiling kernel 4.14.51 I got the following warnings:
CC      net/core/dev.o
net/core/dev.c: In function 'validate_xmit_skb_list':
net/core/dev.c:3121:15: warning: 'tail' may be used uninitialized in this function [-Wmaybe-uninitialized]
...

CC      net/ipv4/fib_trie.o
net/ipv4/fib_trie.c: In function 'fib_trie_unmerge':
net/ipv4/fib_trie.c:1749:8: warning: 'local_tp' may be used uninitialized in this function [-Wmaybe-uninitialized]

The kernel has been compiled for the MIPS architecture, little-endian 32-bit.
My /prov/version file content is:
Linux version 4.14.51 (mrkiko@mStation) (gcc version 7.3.0 (OpenWrt GCC 7.3.0 r7360-e15565a01c)) #0 Fri Jun 29 05:54:17 2018

thank you very much to all of you for your great work.

Enrico

^ permalink raw reply

* [PATCH v5 net-next] net:sched: add action inheritdsfield to skbedit
From: Qiaobin Fu @ 2018-07-01 19:16 UTC (permalink / raw)
  To: davem
  Cc: marcelo.leitner, dcaratti, michel, netdev, jhs, xiyou.wangcong,
	qiaobinf

The new action inheritdsfield copies the field DS of
IPv4 and IPv6 packets into skb->priority. This enables
later classification of packets based on the DS field.

v5:
*Update the drop counter for TC_ACT_SHOT

v4:
*Not allow setting flags other than the expected ones.

*Allow dumping the pure flags.

v3:
*Use optional flags, so that it won't break old versions of tc.

*Allow users to set both SKBEDIT_F_PRIORITY and SKBEDIT_F_INHERITDSFIELD flags.

v2:
*Fix the style issue

*Move the code from skbmod to skbedit

Original idea by Jamal Hadi Salim <jhs@mojatatu.com>

Signed-off-by: Qiaobin Fu <qiaobinf@bu.edu>
Reviewed-by: Michel Machado <michel@digirati.com.br>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Davide Caratti <dcaratti@redhat.com>
---

Note that the motivation for this patch is found in the following discussion:
https://www.spinics.net/lists/netdev/msg501061.html
---
 include/uapi/linux/tc_act/tc_skbedit.h |  2 ++
 net/sched/act_skbedit.c                | 41 ++++++++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/include/uapi/linux/tc_act/tc_skbedit.h b/include/uapi/linux/tc_act/tc_skbedit.h
index fbcfe27a4e6c..6de6071ebed6 100644
--- a/include/uapi/linux/tc_act/tc_skbedit.h
+++ b/include/uapi/linux/tc_act/tc_skbedit.h
@@ -30,6 +30,7 @@
 #define SKBEDIT_F_MARK			0x4
 #define SKBEDIT_F_PTYPE			0x8
 #define SKBEDIT_F_MASK			0x10
+#define SKBEDIT_F_INHERITDSFIELD	0x20
 
 struct tc_skbedit {
 	tc_gen;
@@ -45,6 +46,7 @@ enum {
 	TCA_SKBEDIT_PAD,
 	TCA_SKBEDIT_PTYPE,
 	TCA_SKBEDIT_MASK,
+	TCA_SKBEDIT_FLAGS,
 	__TCA_SKBEDIT_MAX
 };
 #define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1)
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 6138d1d71900..dfaf5d8028dd 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -23,6 +23,9 @@
 #include <linux/rtnetlink.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/dsfield.h>
 
 #include <linux/tc_act/tc_skbedit.h>
 #include <net/tc_act/tc_skbedit.h>
@@ -41,6 +44,25 @@ static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
 
 	if (d->flags & SKBEDIT_F_PRIORITY)
 		skb->priority = d->priority;
+	if (d->flags & SKBEDIT_F_INHERITDSFIELD) {
+		int wlen = skb_network_offset(skb);
+
+		switch (tc_skb_protocol(skb)) {
+		case htons(ETH_P_IP):
+			wlen += sizeof(struct iphdr);
+			if (!pskb_may_pull(skb, wlen))
+				goto err;
+			skb->priority = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
+			break;
+
+		case htons(ETH_P_IPV6):
+			wlen += sizeof(struct ipv6hdr);
+			if (!pskb_may_pull(skb, wlen))
+				goto err;
+			skb->priority = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
+			break;
+		}
+	}
 	if (d->flags & SKBEDIT_F_QUEUE_MAPPING &&
 	    skb->dev->real_num_tx_queues > d->queue_mapping)
 		skb_set_queue_mapping(skb, d->queue_mapping);
@@ -53,6 +75,11 @@ static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
 
 	spin_unlock(&d->tcf_lock);
 	return d->tcf_action;
+
+err:
+	d->tcf_qstats.drops++;
+	spin_unlock(&d->tcf_lock);
+	return TC_ACT_SHOT;
 }
 
 static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
@@ -62,6 +89,7 @@ static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
 	[TCA_SKBEDIT_MARK]		= { .len = sizeof(u32) },
 	[TCA_SKBEDIT_PTYPE]		= { .len = sizeof(u16) },
 	[TCA_SKBEDIT_MASK]		= { .len = sizeof(u32) },
+	[TCA_SKBEDIT_FLAGS]		= { .len = sizeof(u64) },
 };
 
 static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
@@ -114,6 +142,13 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
 		mask = nla_data(tb[TCA_SKBEDIT_MASK]);
 	}
 
+	if (tb[TCA_SKBEDIT_FLAGS] != NULL) {
+		u64 *pure_flags = nla_data(tb[TCA_SKBEDIT_FLAGS]);
+
+		if (*pure_flags & SKBEDIT_F_INHERITDSFIELD)
+			flags |= SKBEDIT_F_INHERITDSFIELD;
+	}
+
 	parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
 
 	exists = tcf_idr_check(tn, parm->index, a, bind);
@@ -178,6 +213,7 @@ static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
 		.action  = d->tcf_action,
 	};
 	struct tcf_t t;
+	u64 pure_flags = 0;
 
 	if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt))
 		goto nla_put_failure;
@@ -196,6 +232,11 @@ static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
 	if ((d->flags & SKBEDIT_F_MASK) &&
 	    nla_put_u32(skb, TCA_SKBEDIT_MASK, d->mask))
 		goto nla_put_failure;
+	if (d->flags & SKBEDIT_F_INHERITDSFIELD)
+		pure_flags |= SKBEDIT_F_INHERITDSFIELD;
+	if (pure_flags != 0 &&
+	    nla_put(skb, TCA_SKBEDIT_FLAGS, sizeof(pure_flags), &pure_flags))
+		goto nla_put_failure;
 
 	tcf_tm_dump(&t, &d->tcf_tm);
 	if (nla_put_64bit(skb, TCA_SKBEDIT_TM, sizeof(t), &t, TCA_SKBEDIT_PAD))
-- 
2.17.1

^ permalink raw reply related

* Re: [PATCH][next] netdevsim: fix sa_idx out of bounds check
From: Shannon Nelson @ 2018-07-01 19:21 UTC (permalink / raw)
  To: Colin King, Jakub Kicinski, David S . Miller, netdev
  Cc: kernel-janitors, linux-kernel
In-Reply-To: <20180630203924.5121-1-colin.king@canonical.com>

On 6/30/2018 1:39 PM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
> 
> Currently if sa_idx is equal to NSIM_IPSEC_MAX_SA_COUNT then
> an out-of-bounds read on ipsec->sa will occur. Fix the
> incorrect bounds check by using >= rather than >.
> 
> Detected by CoverityScan, CID#1470226 ("Out-of-bounds-read")
> 
> Fixes: 7699353da875 ("netdevsim: add ipsec offload testing")
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>   drivers/net/netdevsim/ipsec.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c
> index ceff544510b9..2dcf6cc269d0 100644
> --- a/drivers/net/netdevsim/ipsec.c
> +++ b/drivers/net/netdevsim/ipsec.c
> @@ -249,7 +249,7 @@ bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
>   	}
>   
>   	sa_idx = xs->xso.offload_handle & ~NSIM_IPSEC_VALID;
> -	if (unlikely(sa_idx > NSIM_IPSEC_MAX_SA_COUNT)) {
> +	if (unlikely(sa_idx >= NSIM_IPSEC_MAX_SA_COUNT)) {
>   		netdev_err(ns->netdev, "bad sa_idx=%d max=%d\n",
>   			   sa_idx, NSIM_IPSEC_MAX_SA_COUNT);
>   		return false;
> 

Good catch - thanks!

Acked-by: Shannon Nelson <shannon.nelson@oracle.com>

^ permalink raw reply

* [PATCH net-next] net: phy: realtek: add missing entry for RTL8211 to mdio_device_id table
From: Heiner Kallweit @ 2018-07-01 17:14 UTC (permalink / raw)
  To: David Miller, Andrew Lunn, Florian Fainelli; +Cc: netdev@vger.kernel.org

When adding support for RTL8211 I forgot to update the mdio_device_id
table.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Fixes: d241d4aac93f ("net: phy: realtek: add support for RTL8211")
---
 drivers/net/phy/realtek.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 9757b162..7b516e5d 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -260,6 +260,7 @@ module_phy_driver(realtek_drvs);
 
 static struct mdio_device_id __maybe_unused realtek_tbl[] = {
 	{ 0x001cc816, 0x001fffff },
+	{ 0x001cc910, 0x001fffff },
 	{ 0x001cc912, 0x001fffff },
 	{ 0x001cc914, 0x001fffff },
 	{ 0x001cc915, 0x001fffff },
-- 
2.18.0

^ permalink raw reply related

* Re: [PATCH bpf] bpf: hash_map: decrement counter on error
From: Mauricio Vasquez @ 2018-07-01 16:33 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov; +Cc: netdev
In-Reply-To: <5f2040dc-f661-8346-c32e-5ba11ad93ae9@iogearbox.net>


On 06/30/2018 06:20 PM, Daniel Borkmann wrote:
> On 06/29/2018 02:48 PM, Mauricio Vasquez B wrote:
>> Decrement the number of elements in the map in case the allocation
>> of a new node fails.
>>
>> Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
> Thanks for the fix, Mauricio!
>
> Could you reply with a Fixes: tag in order to track the commit originally
> introducing this bug?
>
> Thanks,
> Daniel
>

Sure Daniel,

Fixes: 6c9059817432 ("bpf: pre-allocate hash map elements")

Thanks,
Mauricio

^ permalink raw reply

* [PATCH] net: expose sk wmem in sock_exceed_buf_limit tracepoint
From: Yafang Shao @ 2018-07-01 15:31 UTC (permalink / raw)
  To: davem, satoru.moriya; +Cc: netdev, linux-kernel, Yafang Shao

Currently trace_sock_exceed_buf_limit() only show rmem info,
but wmem limit may also be hit.
So expose wmem info in this tracepoint as well.

Regarding memcg, I think it is better to introduce a new tracepoint(if
that is needed), i.e. trace_memcg_limit_hit other than show memcg info in
trace_sock_exceed_buf_limit.

Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
 include/trace/events/sock.h | 30 +++++++++++++++++++++++++-----
 net/core/sock.c             |  6 ++++--
 2 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/include/trace/events/sock.h b/include/trace/events/sock.h
index 3176a39..a0c4b8a 100644
--- a/include/trace/events/sock.h
+++ b/include/trace/events/sock.h
@@ -35,6 +35,10 @@
 		EM(TCP_CLOSING)			\
 		EMe(TCP_NEW_SYN_RECV)
 
+#define skmem_kind_names			\
+		EM(SK_MEM_SEND)			\
+		EMe(SK_MEM_RECV)
+
 /* enums need to be exported to user space */
 #undef EM
 #undef EMe
@@ -44,6 +48,7 @@
 family_names
 inet_protocol_names
 tcp_state_names
+skmem_kind_names
 
 #undef EM
 #undef EMe
@@ -59,6 +64,9 @@
 #define show_tcp_state_name(val)        \
 	__print_symbolic(val, tcp_state_names)
 
+#define show_skmem_kind_names(val)	\
+	__print_symbolic(val, skmem_kind_names)
+
 TRACE_EVENT(sock_rcvqueue_full,
 
 	TP_PROTO(struct sock *sk, struct sk_buff *skb),
@@ -83,9 +91,9 @@
 
 TRACE_EVENT(sock_exceed_buf_limit,
 
-	TP_PROTO(struct sock *sk, struct proto *prot, long allocated),
+	TP_PROTO(struct sock *sk, struct proto *prot, long allocated, int kind),
 
-	TP_ARGS(sk, prot, allocated),
+	TP_ARGS(sk, prot, allocated, kind),
 
 	TP_STRUCT__entry(
 		__array(char, name, 32)
@@ -93,6 +101,10 @@
 		__field(long, allocated)
 		__field(int, sysctl_rmem)
 		__field(int, rmem_alloc)
+		__field(int, sysctl_wmem)
+		__field(int, wmem_alloc)
+		__field(int, wmem_queued)
+		__field(int, kind)
 	),
 
 	TP_fast_assign(
@@ -101,17 +113,25 @@
 		__entry->allocated = allocated;
 		__entry->sysctl_rmem = sk_get_rmem0(sk, prot);
 		__entry->rmem_alloc = atomic_read(&sk->sk_rmem_alloc);
+		__entry->sysctl_wmem = sk_get_wmem0(sk, prot);
+		__entry->wmem_alloc = refcount_read(&sk->sk_wmem_alloc);
+		__entry->wmem_queued = sk->sk_wmem_queued;
+		__entry->kind = kind;
 	),
 
-	TP_printk("proto:%s sysctl_mem=%ld,%ld,%ld allocated=%ld "
-		"sysctl_rmem=%d rmem_alloc=%d",
+	TP_printk("proto:%s sysctl_mem=%ld,%ld,%ld allocated=%ld sysctl_rmem=%d rmem_alloc=%d sysctl_wmem=%d wmem_alloc=%d wmem_queued=%d kind=%s",
 		__entry->name,
 		__entry->sysctl_mem[0],
 		__entry->sysctl_mem[1],
 		__entry->sysctl_mem[2],
 		__entry->allocated,
 		__entry->sysctl_rmem,
-		__entry->rmem_alloc)
+		__entry->rmem_alloc,
+		__entry->sysctl_wmem,
+		__entry->wmem_alloc,
+		__entry->wmem_queued,
+		show_skmem_kind_names(__entry->kind)
+	)
 );
 
 TRACE_EVENT(inet_sock_set_state,
diff --git a/net/core/sock.c b/net/core/sock.c
index bcc4182..65350ed 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2401,9 +2401,10 @@ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind)
 {
 	struct proto *prot = sk->sk_prot;
 	long allocated = sk_memory_allocated_add(sk, amt);
+	bool charged = true;
 
 	if (mem_cgroup_sockets_enabled && sk->sk_memcg &&
-	    !mem_cgroup_charge_skmem(sk->sk_memcg, amt))
+	    !(charged = mem_cgroup_charge_skmem(sk->sk_memcg, amt)))
 		goto suppress_allocation;
 
 	/* Under limit. */
@@ -2461,7 +2462,8 @@ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind)
 			return 1;
 	}
 
-	trace_sock_exceed_buf_limit(sk, prot, allocated);
+	if (kind == SK_MEM_SEND || (kind == SK_MEM_RECV && charged))
+		trace_sock_exceed_buf_limit(sk, prot, allocated, kind);
 
 	sk_memory_allocated_sub(sk, amt);
 
-- 
1.8.3.1

^ permalink raw reply related

* Re: 862591bf4("xfrm: skip policies marked as dead while rehashing")
From: Greg KH @ 2018-07-01 13:28 UTC (permalink / raw)
  To: Zubin Mithra; +Cc: netdev, groeck, stable
In-Reply-To: <20180620214118.GA37804@zsmcros.c.googlers.com>

On Wed, Jun 20, 2018 at 05:42:51PM -0400, Zubin Mithra wrote:
> Hello,
> 
> Syzkaller has reported a crash here[1] for a slab OOB read in
> xfrm_hash_rebuild.
> 
> Could the following 2 patches be applied in order to on 4.4.y?
> 
> 6916fb3b10("xfrm: Ignore socket policies when rebuilding hash tables")
> 862591bf4f("xfrm: skip policies marked as dead while rehashing")
> 
> [1] https://syzkaller.appspot.com/bug?id=1c11a638b7d27e871aa297f3b4d5fd5bc90f0cb4

Both now queued up, thanks.

greg k-h

^ permalink raw reply

* Re: [PATCH net-next] r8169: remove old PHY reset hack
From: Heiner Kallweit @ 2018-07-01 13:16 UTC (permalink / raw)
  To: Realtek linux nic maintainers, David Miller
  Cc: netdev@vger.kernel.org, Andrew Lunn, Florian Fainelli
In-Reply-To: <bcb32d0d-3a7d-6514-d73a-5f06c7008bc7@gmail.com>

On 01.07.2018 00:25, Heiner Kallweit wrote:
> This hack (affecting the non-PCIe models only) was introduced in 2004
> to deal with link negotiation failures in 1GBit mode. Based on a
> comment in the r8169 vendor driver I assume the issue affects RTL8169sb
> in combination with particular 1GBit switch models.
> 
Some remarks after further digging into this issue:
I have a card with RTL8169sb chip and the PHY identifies as RTL8211C.
This PHY seems to have a PLL issue when operating in Gigabit slave mode,
see the following commit in Uboot:
https://lists.denx.de/pipermail/u-boot/2016-March/249712.html

RTL8211C doesn't have a dedicated PHY driver yet, I'll add one incl.
the quirk to force Gigabit master mode. This should fix the root cause
and we can definitely get rid of the PHY reset hack in r8169.


> Resetting the PHY every 10s and hoping that one fine day we will make
> it to establish the link seems to be very hacky to me. I'd say:
> If 1GBit doesn't work reliably in a users environment then the user
> should remove 1GBit from the advertised modes, e.g. by using
> ethtool -s <if> advertise <10/100 modes>
> 
> If the issue affects one chip version only and that with most link
> partners, then we could also think of removing 1GBit from the
> advertised modes for this chip version in the driver.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> ---
>  drivers/net/ethernet/realtek/r8169.c | 57 +---------------------------
>  1 file changed, 1 insertion(+), 56 deletions(-)
> 
> diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
> index 72a7778b..b0a06902 100644
> --- a/drivers/net/ethernet/realtek/r8169.c
> +++ b/drivers/net/ethernet/realtek/r8169.c
> @@ -80,7 +80,6 @@ static const int multicast_filter_limit = 32;
>  #define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
>  
>  #define RTL8169_TX_TIMEOUT	(6*HZ)
> -#define RTL8169_PHY_TIMEOUT	(10*HZ)
>  
>  /* write/read MMIO register */
>  #define RTL_W8(tp, reg, val8)	writeb((val8), tp->mmio_addr + (reg))
> @@ -703,7 +702,6 @@ enum rtl_flag {
>  	RTL_FLAG_TASK_ENABLED,
>  	RTL_FLAG_TASK_SLOW_PENDING,
>  	RTL_FLAG_TASK_RESET_PENDING,
> -	RTL_FLAG_TASK_PHY_PENDING,
>  	RTL_FLAG_MAX
>  };
>  
> @@ -731,7 +729,6 @@ struct rtl8169_private {
>  	dma_addr_t RxPhyAddr;
>  	void *Rx_databuff[NUM_RX_DESC];	/* Rx data buffers */
>  	struct ring_info tx_skb[NUM_TX_DESC];	/* Tx data buffers */
> -	struct timer_list timer;
>  	u16 cp_cmd;
>  
>  	u16 event_slow;
> @@ -1788,20 +1785,7 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
>  static int rtl8169_set_speed(struct net_device *dev,
>  			     u8 autoneg, u16 speed, u8 duplex, u32 advertising)
>  {
> -	struct rtl8169_private *tp = netdev_priv(dev);
> -	int ret;
> -
> -	ret = rtl8169_set_speed_xmii(dev, autoneg, speed, duplex, advertising);
> -	if (ret < 0)
> -		goto out;
> -
> -	if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) &&
> -	    (advertising & ADVERTISED_1000baseT_Full) &&
> -	    !pci_is_pcie(tp->pci_dev)) {
> -		mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
> -	}
> -out:
> -	return ret;
> +	return rtl8169_set_speed_xmii(dev, autoneg, speed, duplex, advertising);
>  }
>  
>  static netdev_features_t rtl8169_fix_features(struct net_device *dev,
> @@ -1888,8 +1872,6 @@ static int rtl8169_set_link_ksettings(struct net_device *dev,
>  	    cmd->link_modes.advertising))
>  		return -EINVAL;
>  
> -	del_timer_sync(&tp->timer);
> -
>  	rtl_lock_work(tp);
>  	rc = rtl8169_set_speed(dev, cmd->base.autoneg, cmd->base.speed,
>  			       cmd->base.duplex, advertising);
> @@ -4293,44 +4275,12 @@ static void rtl_hw_phy_config(struct net_device *dev)
>  	}
>  }
>  
> -static void rtl_phy_work(struct rtl8169_private *tp)
> -{
> -	struct timer_list *timer = &tp->timer;
> -	unsigned long timeout = RTL8169_PHY_TIMEOUT;
> -
> -	if (rtl8169_xmii_reset_pending(tp)) {
> -		/*
> -		 * A busy loop could burn quite a few cycles on nowadays CPU.
> -		 * Let's delay the execution of the timer for a few ticks.
> -		 */
> -		timeout = HZ/10;
> -		goto out_mod_timer;
> -	}
> -
> -	if (rtl8169_xmii_link_ok(tp))
> -		return;
> -
> -	netif_dbg(tp, link, tp->dev, "PHY reset until link up\n");
> -
> -	rtl8169_xmii_reset_enable(tp);
> -
> -out_mod_timer:
> -	mod_timer(timer, jiffies + timeout);
> -}
> -
>  static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
>  {
>  	if (!test_and_set_bit(flag, tp->wk.flags))
>  		schedule_work(&tp->wk.work);
>  }
>  
> -static void rtl8169_phy_timer(struct timer_list *t)
> -{
> -	struct rtl8169_private *tp = from_timer(tp, t, timer);
> -
> -	rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING);
> -}
> -
>  DECLARE_RTL_COND(rtl_phy_reset_cond)
>  {
>  	return rtl8169_xmii_reset_pending(tp);
> @@ -6909,7 +6859,6 @@ static void rtl_task(struct work_struct *work)
>  		/* XXX - keep rtl_slow_event_work() as first element. */
>  		{ RTL_FLAG_TASK_SLOW_PENDING,	rtl_slow_event_work },
>  		{ RTL_FLAG_TASK_RESET_PENDING,	rtl_reset_work },
> -		{ RTL_FLAG_TASK_PHY_PENDING,	rtl_phy_work }
>  	};
>  	struct rtl8169_private *tp =
>  		container_of(work, struct rtl8169_private, wk.work);
> @@ -6982,8 +6931,6 @@ static void rtl8169_down(struct net_device *dev)
>  {
>  	struct rtl8169_private *tp = netdev_priv(dev);
>  
> -	del_timer_sync(&tp->timer);
> -
>  	napi_disable(&tp->napi);
>  	netif_stop_queue(dev);
>  
> @@ -7694,8 +7641,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
>  	tp->event_slow = cfg->event_slow;
>  	tp->coalesce_info = cfg->coalesce_info;
>  
> -	timer_setup(&tp->timer, rtl8169_phy_timer, 0);
> -
>  	tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
>  
>  	tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters),
> 

^ permalink raw reply

* Re: [PATCH linux-firmware] Mellanox: Add new mlxsw_spectrum firmware 13.1701.2
From: Ido Schimmel @ 2018-07-01 13:15 UTC (permalink / raw)
  To: Nir Dotan; +Cc: linux-firmware, netdev, dsahern, mlxsw
In-Reply-To: <20180619063306.1470-1-nird@mellanox.com>

On Tue, Jun 19, 2018 at 09:33:06AM +0300, Nir Dotan wrote:
> This new firmware contains:
> 	- Support for new types of cables
> 	- Support for flashing future firmware without reboot
> 	- Support for Router ARP BC and UC traps

Please disregard the patch. We found a problem with this version. Will
send a new version once it's ready.

Thanks

^ permalink raw reply

* Re: [RFC net-next 07/15] net: lora: Add Semtech SX1276
From: Andreas Färber @ 2018-07-01 12:02 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, linux-kernel, Jian-Hong Pan, Jiri Pirko,
	Marcel Holtmann, David S . Miller, Matthias Brugger, Janus Piwek,
	Michael Röder, Dollar Chen, Ken Yu
In-Reply-To: <20180701110804.32415-8-afaerber@suse.de>

Am 01.07.2018 um 13:07 schrieb Andreas Färber:
> diff --git a/drivers/net/lora/sx1276.c b/drivers/net/lora/sx1276.c
> new file mode 100644
> index 000000000000..d6732111247a
> --- /dev/null
> +++ b/drivers/net/lora/sx1276.c
[...]
> +static int sx1276_probe(struct spi_device *spi)
> +{
> +	struct net_device *netdev;
> +	struct sx1276_priv *priv;
> +	int rst, dio[6], ret, model, i;
> +	u32 freq_xosc, freq_band;
> +	unsigned long long freq_rf;
> +	u8 val;
> +
> +	rst = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
> +	if (rst == -ENOENT)
> +		dev_warn(&spi->dev, "no reset GPIO available, ignoring");
> +
> +	for (i = 0; i < 6; i++) {
> +		dio[i] = of_get_named_gpio(spi->dev.of_node, "dio-gpios", i);
> +		if (dio[i] == -ENOENT)
> +			dev_dbg(&spi->dev, "DIO%d not available, ignoring", i);
> +		else {
> +			ret = gpio_direction_input(dio[i]);
> +			if (ret)
> +				dev_err(&spi->dev, "couldn't set DIO%d to input", i);
> +		}
> +	}
> +
> +	if (gpio_is_valid(rst)) {
> +		gpio_set_value(rst, 1);
> +		udelay(100);
> +		gpio_set_value(rst, 0);
> +		msleep(5);
> +	}
> +
> +	spi->bits_per_word = 8;
> +	spi_setup(spi);
> +
> +	ret = sx1276_read_single(spi, REG_VERSION, &val);
> +	if (ret) {
> +		dev_err(&spi->dev, "version read failed");
> +		return ret;
> +	}
> +
> +	if (val == 0x22)
> +		model = 1272;
> +	else {
> +		if (gpio_is_valid(rst)) {
> +			gpio_set_value(rst, 0);
> +			udelay(100);
> +			gpio_set_value(rst, 1);
> +			msleep(5);
> +		}
> +
> +		ret = sx1276_read_single(spi, REG_VERSION, &val);
> +		if (ret) {
> +			dev_err(&spi->dev, "version read failed");
> +			return ret;
> +		}
> +
> +		if (val == 0x12)
> +			model = 1276;
> +		else {
> +			dev_err(&spi->dev, "transceiver not recognized (RegVersion = 0x%02x)", (unsigned)val);
> +			return -EINVAL;
> +		}
> +	}
[snip]

To counter my own point, this file of course still has leftover model
detection heuristics; should check for the of_device_id match instead!
SX1272 vs. SX1276 have the reset pin inverted, so - knowing which model
it's supposed to be - we can do the right reset from the start and, if
it doesn't work, report an error to the user.

Also I should update that code to use gpiod, as seen in later patches.

Cheers,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

^ permalink raw reply

* [RFC net-next 13/15] net: lora: Prepare RAK RAK811
From: Andreas Färber @ 2018-07-01 11:08 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, linux-kernel, Jian-Hong Pan, Jiri Pirko,
	Marcel Holtmann, David S . Miller, Matthias Brugger, Janus Piwek,
	Michael Röder, Dollar Chen, Ken Yu, Andreas Färber
In-Reply-To: <20180701110804.32415-1-afaerber@suse.de>

The RAK811 and RAK812 offer a UART based AT command interface.
It allows both LoRaWAN and LoRa modes.

Cc: Ken Yu (禹凯) <ken.yu@rakwireless.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 drivers/net/lora/Kconfig  |   7 ++
 drivers/net/lora/Makefile |   3 +
 drivers/net/lora/rak811.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 229 insertions(+)
 create mode 100644 drivers/net/lora/rak811.c

diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig
index 72a9d2a0f2be..3e384493cbdd 100644
--- a/drivers/net/lora/Kconfig
+++ b/drivers/net/lora/Kconfig
@@ -17,6 +17,13 @@ config LORA_DEV
 
 if LORA_DEV
 
+config LORA_RAK811
+	tristate "RAK RAK811 driver"
+	default y
+	depends on SERIAL_DEV_BUS
+	help
+	  RAK RAK811/RAK812
+
 config LORA_RN2483
 	tristate "Microchip RN2483/RN2903 driver"
 	default y
diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile
index dfa9a43dcfb3..6b6870ffbfd8 100644
--- a/drivers/net/lora/Makefile
+++ b/drivers/net/lora/Makefile
@@ -9,6 +9,9 @@ lora-dev-y := dev.o
 # Alphabetically sorted.
 #
 
+obj-$(CONFIG_LORA_RAK811) += lora-rak811.o
+lora-rak811-y := rak811.o
+
 obj-$(CONFIG_LORA_RN2483) += lora-rn2483.o
 lora-rn2483-y := rn2483.o
 lora-rn2483-y += rn2483_cmd.o
diff --git a/drivers/net/lora/rak811.c b/drivers/net/lora/rak811.c
new file mode 100644
index 000000000000..ad3d0980c489
--- /dev/null
+++ b/drivers/net/lora/rak811.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * RAK RAK811
+ *
+ * Copyright (c) 2017-2018 Andreas Färber
+ */
+
+#include <linux/delay.h>
+#include <linux/lora.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/serdev.h>
+#include <linux/lora/dev.h>
+
+struct rak811_device {
+	struct serdev_device *serdev;
+
+	char rx_buf[4096];
+	int rx_len;
+
+	struct completion line_recv_comp;
+};
+
+static int rak811_send_command(struct rak811_device *rakdev, const char *cmd, char **data, unsigned long timeout)
+{
+	struct serdev_device *sdev = rakdev->serdev;
+	const char *crlf = "\r\n";
+	char *resp;
+
+	serdev_device_write_buf(sdev, cmd, strlen(cmd));
+	serdev_device_write_buf(sdev, crlf, 2);
+
+	timeout = wait_for_completion_timeout(&rakdev->line_recv_comp, timeout);
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	resp = rakdev->rx_buf;
+	dev_dbg(&sdev->dev, "Received: '%s'\n", resp);
+	if (data)
+		*data = kstrdup(resp, GFP_KERNEL);
+
+	rakdev->rx_len = 0;
+	reinit_completion(&rakdev->line_recv_comp);
+
+	return 0;
+}
+
+static int rak811_simple_cmd(struct rak811_device *rakdev, const char *cmd, unsigned long timeout)
+{
+	char *resp;
+	int ret;
+
+	ret = rak811_send_command(rakdev, cmd, &resp, timeout);
+	if (ret)
+		return ret;
+
+	if (strncmp(resp, "OK", 2) == 0) {
+		kfree(resp);
+		return 0;
+	}
+
+	kfree(resp);
+
+	return -EINVAL;
+}
+
+static int rak811_get_version(struct rak811_device *rakdev, char **version, unsigned long timeout)
+{
+	char *resp;
+	int ret;
+
+	ret = rak811_send_command(rakdev, "at+version", &resp, timeout);
+	if (ret)
+		return ret;
+
+	if (strncmp(resp, "OK", 2) == 0) {
+		*version = kstrdup(resp + 2, GFP_KERNEL);
+		kfree(resp);
+		return 0;
+	}
+
+	kfree(resp);
+
+	return -EINVAL;
+}
+
+static int rak811_receive_buf(struct serdev_device *sdev, const u8 *data, size_t count)
+{
+	struct rak811_device *rakdev = serdev_device_get_drvdata(sdev);
+	size_t i = 0;
+	int len = 0;
+
+	dev_dbg(&sdev->dev, "Receive (%d)\n", (int)count);
+
+	for (i = 0; i < count; i++) {
+		dev_dbg(&sdev->dev, "Receive: 0x%02x\n", (int)data[i]);
+	}
+
+	if (completion_done(&rakdev->line_recv_comp)) {
+		dev_info(&sdev->dev, "RX waiting on completion\n");
+		return 0;
+	}
+	if (rakdev->rx_len == sizeof(rakdev->rx_buf) - 1) {
+		dev_warn(&sdev->dev, "RX buffer full\n");
+		return 0;
+	}
+
+	i = min(count, sizeof(rakdev->rx_buf) - 1 - rakdev->rx_len);
+	if (i > 0) {
+		memcpy(&rakdev->rx_buf[rakdev->rx_len], data, i);
+		rakdev->rx_len += i;
+		len += i;
+	}
+	if (rakdev->rx_len >= 2 && strncmp(&rakdev->rx_buf[rakdev->rx_len - 2], "\r\n", 2) == 0) {
+		rakdev->rx_len -= 2;
+		rakdev->rx_buf[rakdev->rx_len] = '\0';
+		complete(&rakdev->line_recv_comp);
+	}
+
+	return len;
+}
+
+static const struct serdev_device_ops rak811_serdev_client_ops = {
+	.receive_buf = rak811_receive_buf,
+};
+
+static int rak811_probe(struct serdev_device *sdev)
+{
+	struct rak811_device *rakdev;
+	char *sz;
+	int ret;
+
+	dev_info(&sdev->dev, "Probing\n");
+
+	rakdev = devm_kzalloc(&sdev->dev, sizeof(struct rak811_device), GFP_KERNEL);
+	if (!rakdev)
+		return -ENOMEM;
+
+	rakdev->serdev = sdev;
+	init_completion(&rakdev->line_recv_comp);
+	serdev_device_set_drvdata(sdev, rakdev);
+
+	ret = serdev_device_open(sdev);
+	if (ret) {
+		dev_err(&sdev->dev, "Failed to open (%d)\n", ret);
+		return ret;
+	}
+
+	serdev_device_set_baudrate(sdev, 115200);
+	serdev_device_set_flow_control(sdev, false);
+	serdev_device_set_client_ops(sdev, &rak811_serdev_client_ops);
+
+	ret = rak811_get_version(rakdev, &sz, HZ);
+	if (ret) {
+		dev_err(&sdev->dev, "Failed to get version (%d)\n", ret);
+		serdev_device_close(sdev);
+		return ret;
+	}
+
+	dev_info(&sdev->dev, "firmware version: %s\n", sz);
+	kfree(sz);
+
+	ret = rak811_simple_cmd(rakdev, "at+mode=1", 2 * HZ);
+	if (ret) {
+		dev_err(&sdev->dev, "Failed to set mode to P2P (%d)\n", ret);
+		serdev_device_close(sdev);
+		return ret;
+	}
+
+	dev_info(&sdev->dev, "Done.\n");
+
+	return 0;
+}
+
+static void rak811_remove(struct serdev_device *sdev)
+{
+	serdev_device_close(sdev);
+
+	dev_info(&sdev->dev, "Removed\n");
+}
+
+static const struct of_device_id rak811_of_match[] = {
+	{ .compatible = "rakwireless,rak811" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, rak811_of_match);
+
+static struct serdev_device_driver rak811_serdev_driver = {
+	.probe = rak811_probe,
+	.remove = rak811_remove,
+	.driver = {
+		.name = "rak811",
+		.of_match_table = rak811_of_match,
+	},
+};
+
+static int __init rak811_init(void)
+{
+	int ret;
+
+	ret = serdev_device_driver_register(&rak811_serdev_driver);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void __exit rak811_exit(void)
+{
+	serdev_device_driver_unregister(&rak811_serdev_driver);
+}
+
+module_init(rak811_init);
+module_exit(rak811_exit);
+
+MODULE_DESCRIPTION("RAK811 serdev driver");
+MODULE_AUTHOR("Andreas Färber <afaerber@suse.de>");
+MODULE_LICENSE("GPL");
-- 
2.16.4

^ permalink raw reply related

* [RFC net-next 00/15] net: A socket API for LoRa
From: Andreas Färber @ 2018-07-01 11:07 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, linux-kernel, Jian-Hong Pan, Jiri Pirko,
	Marcel Holtmann, David S . Miller, Matthias Brugger, Janus Piwek,
	Michael Röder, Dollar Chen, Ken Yu, Andreas Färber,
	Konstantin Böhm, Jan Jongboom, Jon Ortego, contact,
	Ben Whitten, Brian Ray, lora, lora

Hello,

LoRa is a long-range, low-power wireless technology by Semtech.
Unlike other LPWAN technologies, users don't need to rely on infrastructure
providers and SIM cards and expensive subscription plans, they can set up
their own gateways. Modules, adapters and evaluation boards are available
from a large number of vendors.

Many vendors also make available Open Source software examples on GitHub.
But when taking a closer look, many of them combine licenses in ways that are
not redistributable. My reports have remained without response or solution.

https://github.com/ernstdevreede/lmic_pi/issues/2
https://github.com/Snootlab/lmic_chisterapi/issues/2
https://github.com/Snootlab/lora_chisterapi/issues/2

Another issue was that most such projects around the Raspberry Pi make use of
spidev to communicate with the Semtech chipsets from userspace. The Linux spi
maintainers have chosen to greet any such users of spidev with a friendly
WARN_ON(), preferring in-kernel spi drivers and white-listing individual
devices only.

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/spi/spidev.c?h=v4.17#n722
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/spi/spidev.c?h=v4.17#n667

Also I don't quite see the point in having userspace probe what SPI devices
are connected to a generic spidev driver when we have an easy Device Tree
hardware description on arm/arm64 that could give us that info.

I raised the topic during Q&A of a FOSDEM 2017 talk (cut off at the end
of the video) but unfortunately found no one to collaborate on this.

https://archive.fosdem.org/2017/schedule/event/lorawan/

Instead of porting from wiringPi to a differently licensed GPIO library
and dealing with seemingly unmaintained LoRaWAN code dumps, I started a
spi kernel driver for SX1276 back in 2016. But obviously a kernel driver
isn't too helpful without a userspace API to send and receive packets.

This patchset, updated from 2017 and extended, is implementing kernel drivers
for various LoRa chipsets and modules. As API I'm proposing a PF_LORA socket
implementation. Why? LoRa uses data packets with headers and checksums
and differing MTUs and multiple protocols layered on top of it. Apart from
simple headers for addressing used by RadioHead library and IMST's LoRa P2P
protocol, the main use case (not implemented in this patchset) is expected
to be LoRaWAN. And LoRaWAN has competing proprietary protocols, such as
Link Labs' Symphony Link or GlobalSat M.O.S.T. or RadioShuttle, that might
at some point want to adopt a standard API for their implementations, too.

Ready-made LoRa hardware modules come in three flavors,
a) with SPI access to the underlying Semtech chipsets, needing a software
   implementation of e.g. LoRaWAN protocol stack (i.e., a soft MAC),
b) with a custom, often UART based interface and a pre-certified LoRaWAN
   protocol stack already integrated (i.e., hard/full MAC), and
c) with a microcontroller that serves not only for the protocol stack but
   also as application processor, not offering a ready-made interface.

This patchset focuses on option a). An SX1276 based LoRaWAN stack appeared
to be the project of Jian-Hong Pan and is not included here.
This patchset also includes drivers for b), from text based AT commands to
a binary SLIP based HCI protocol.
Hardware examples for c) are Murata CMWX1ZZABZ-078 and RAK813.

This patchset is clearly not ready for merging, but is being submitted for
discussion, as requested by Jiri, in particular of the design choices:

1) PF_LORA/AF_LORA and associated identifiers are proposed to represent
   this technology. While for an SX1276 - case a) above - it might work to
   layer LoRaWAN as a protocol option for PF_LORA and add LoRaWAN address
   fields to the union in my sockaddr_lora, how would that work for devices
   that only support LoRaWAN but not pure LoRa? Do we need both AF_LORA and
   AF_LORAWAN, or just a separate ETH_P_LORAWAN or ARPHRD_LORAWAN?

2) PF_LORA is used with SOCK_DGRAM here. The assumption is that RAW mode
   would be DGRAM plus preamble plus optional checksum.

3) Only the transmit path is partially implemented already. The assumption
   is that the devices should go into receive mode by default and only
   interrupt that when asked to transmit.

4) Some hardware settings need to be supplied externally, such as the radio
   frequency for some modules, but many others can be runtime-configured,
   such as Spreading Factor, Bandwidth, Sync Word, or which antenna to use.
   What settings should be implemented as socket option vs. netlink layer
   vs. ioctl vs. sysfs? What are the criteria to apply?

5) Many of the modules support multiple modes, such as LoRa, LoRaWAN and FSK.
   Lacking a LoRaWAN implementation, I am currently switching them into LoRa
   mode at probe time wherever possible. How do we deal with that properly?

  a) Is there any precedence from the Wifi world for dynamically selecting
     between our own trusted Open Source implementation vs. hardware/firmware
     accelerated and/or certified implementations?

  b) Would a proof of concept for FSK (non-LoRa) modes be required for
     merging any LoRa driver for chipsets that support both? Or is there any
     facility or design guidelines that would allow us to focus on LoRa and
     LoRaWAN and leave non-LoRa radio modes to later contributors?

As evident by the many questions, this is my first deep dive into the Linux
net subsystem. It's also my first experiments with the new serdev subsystem,
so in particular the receive paths will need some review and optimizations.

This patchset was developed and tested mainly as KMP, originally at
https://github.com/afaerber/lora-modules. It was recently transformed into a
linux-next based tree, still mostly tested on our openSUSE Tumbleweed kernel
with a differing AF_LORA value below current AF_MAX limit.

Some corresponding Device Tree Overlays have been collected here:
https://github.com/afaerber/dt-overlays

Only European models for 868 MHz and 433 MHz could be tested when available.
Thanks to all companies and people that have supported this project so far.

Have a lot of fun!

Cheers,
Andreas

Cc: Jian-Hong Pan <starnight@g.ncu.edu.tw>
Cc: Jiri Pirko <jiri@resnulli.us>
Cc: Marcel Holtmann <marcel@holtmann.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Matthias Brugger <mbrugger@suse.com>
Cc: Konstantin Böhm <konstantin.boehm@ancud.de>
Cc: Jan Jongboom <jan.jongboom@arm.com>
Cc: Janus Piwek <jpiwek@arroweurope.com>
Cc: Michael Röder <michael.roeder@avnet.eu>
Cc: Dollar Chen (陳義元) <dollar.chen@wtmec.com>
Cc: Ken Yu (禹凯) <ken.yu@rakwireless.com>
Cc: Jon Ortego <Jon.Ortego@imst.de>
Cc: contact@snootlab.com
Cc: Ben Whitten <ben.whitten@lairdtech.com>
Cc: Brian Ray <brian.ray@link-labs.com>
Cc: lora@globalsat.com.tw
Cc: lora@radioshuttle.de
Cc: Alexander Graf <agraf@suse.de>
Cc: Michal Kubeček <mkubecek@suse.cz>
Cc: Rob Herring <robh@kernel.org>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: Steve deRosier <derosier@gmail.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: linux-spi@vger.kernel.org

Andreas Färber (15):
  net: Reserve protocol numbers for LoRa
  net: lora: Define sockaddr_lora
  net: lora: Add protocol numbers
  net: Add lora subsystem
  HACK: net: lora: Deal with .poll_mask in 4.18-rc2
  net: lora: Prepare for device drivers
  net: lora: Add Semtech SX1276
  net: lora: sx1276: Add debugfs
  net: lora: Prepare EUI helpers
  net: lora: Add Microchip RN2483
  net: lora: Add IMST WiMOD
  net: lora: Add USI WM-SG-SM-42
  net: lora: Prepare RAK RAK811
  net: lora: Prepare Semtech SX1257
  net: lora: Add Semtech SX1301

 drivers/net/Makefile                |   1 +
 drivers/net/lora/Kconfig            |  72 ++++
 drivers/net/lora/Makefile           |  32 ++
 drivers/net/lora/dev.c              | 125 ++++++
 drivers/net/lora/rak811.c           | 219 +++++++++++
 drivers/net/lora/rn2483.c           | 344 +++++++++++++++++
 drivers/net/lora/rn2483.h           |  40 ++
 drivers/net/lora/rn2483_cmd.c       | 130 +++++++
 drivers/net/lora/sx1257.c           |  96 +++++
 drivers/net/lora/sx1276.c           | 740 ++++++++++++++++++++++++++++++++++++
 drivers/net/lora/sx1301.c           | 446 ++++++++++++++++++++++
 drivers/net/lora/usi.c              | 411 ++++++++++++++++++++
 drivers/net/lora/wimod.c            | 597 +++++++++++++++++++++++++++++
 include/linux/lora/dev.h            |  44 +++
 include/linux/lora/skb.h            |  29 ++
 include/linux/socket.h              |   4 +-
 include/uapi/linux/if_arp.h         |   1 +
 include/uapi/linux/if_ether.h       |   1 +
 include/uapi/linux/lora.h           |  24 ++
 net/Kconfig                         |   1 +
 net/Makefile                        |   1 +
 net/lora/Kconfig                    |  15 +
 net/lora/Makefile                   |   8 +
 net/lora/af_lora.c                  | 152 ++++++++
 net/lora/af_lora.h                  |  13 +
 net/lora/dgram.c                    | 297 +++++++++++++++
 security/selinux/hooks.c            |   4 +-
 security/selinux/include/classmap.h |   4 +-
 28 files changed, 3848 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/lora/Kconfig
 create mode 100644 drivers/net/lora/Makefile
 create mode 100644 drivers/net/lora/dev.c
 create mode 100644 drivers/net/lora/rak811.c
 create mode 100644 drivers/net/lora/rn2483.c
 create mode 100644 drivers/net/lora/rn2483.h
 create mode 100644 drivers/net/lora/rn2483_cmd.c
 create mode 100644 drivers/net/lora/sx1257.c
 create mode 100644 drivers/net/lora/sx1276.c
 create mode 100644 drivers/net/lora/sx1301.c
 create mode 100644 drivers/net/lora/usi.c
 create mode 100644 drivers/net/lora/wimod.c
 create mode 100644 include/linux/lora/dev.h
 create mode 100644 include/linux/lora/skb.h
 create mode 100644 include/uapi/linux/lora.h
 create mode 100644 net/lora/Kconfig
 create mode 100644 net/lora/Makefile
 create mode 100644 net/lora/af_lora.c
 create mode 100644 net/lora/af_lora.h
 create mode 100644 net/lora/dgram.c

-- 
2.16.4

^ permalink raw reply

* [RFC net-next 12/15] net: lora: Add USI WM-SG-SM-42
From: Andreas Färber @ 2018-07-01 11:08 UTC (permalink / raw)
  To: netdev
  Cc: linux-arm-kernel, linux-kernel, Jian-Hong Pan, Jiri Pirko,
	Marcel Holtmann, David S . Miller, Matthias Brugger, Janus Piwek,
	Michael Röder, Dollar Chen, Ken Yu, Andreas Färber
In-Reply-To: <20180701110804.32415-1-afaerber@suse.de>

The USI WM-SG-SM-42 offers a UART based AT command interface.

Cc: Dollar Chen (陳義元) <dollar.chen@wtmec.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 drivers/net/lora/Kconfig  |   7 +
 drivers/net/lora/Makefile |   3 +
 drivers/net/lora/usi.c    | 411 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 421 insertions(+)
 create mode 100644 drivers/net/lora/usi.c

diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig
index 2e05caef8645..72a9d2a0f2be 100644
--- a/drivers/net/lora/Kconfig
+++ b/drivers/net/lora/Kconfig
@@ -31,6 +31,13 @@ config LORA_SX1276
 	help
 	  Semtech SX1272/1276/1278
 
+config LORA_USI
+	tristate "USI WM-SG-SM-42 driver"
+	default y
+	depends on SERIAL_DEV_BUS
+	help
+	  USI WM-SG-SM-42
+
 config LORA_WIMOD
 	tristate "IMST WiMOD driver"
 	default y
diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile
index ecb326c859a5..dfa9a43dcfb3 100644
--- a/drivers/net/lora/Makefile
+++ b/drivers/net/lora/Makefile
@@ -16,5 +16,8 @@ lora-rn2483-y += rn2483_cmd.o
 obj-$(CONFIG_LORA_SX1276) += lora-sx1276.o
 lora-sx1276-y := sx1276.o
 
+obj-$(CONFIG_LORA_USI) += lora-usi.o
+lora-usi-y := usi.o
+
 obj-$(CONFIG_LORA_WIMOD) += lora-wimod.o
 lora-wimod-y := wimod.o
diff --git a/drivers/net/lora/usi.c b/drivers/net/lora/usi.c
new file mode 100644
index 000000000000..f0c697e2cde2
--- /dev/null
+++ b/drivers/net/lora/usi.c
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * USI WM-SG-SM-42
+ *
+ * Copyright (c) 2017-2018 Andreas Färber
+ */
+
+#include <linux/lora.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/serdev.h>
+#include <linux/lora/dev.h>
+
+struct usi_device {
+	struct serdev_device *serdev;
+
+	int mode;
+
+	char rx_buf[4096];
+	int rx_len;
+
+	struct completion prompt_recv_comp;
+	struct completion tx_event_recv_comp;
+};
+
+static bool usi_cmd_ok(const char *resp)
+{
+	int len = strlen(resp);
+
+	return (len == 4 && !strcmp(resp, "OK\r\n")) ||
+	       (len >= 6 && !strcmp(resp + len - 6, "\r\nOK\r\n"));
+}
+
+static int usi_send_command(struct usi_device *usidev, const char *cmd, char **data, unsigned long timeout)
+{
+	struct serdev_device *sdev = usidev->serdev;
+	const char cr = '\r';
+	int cmd_len, resp_len;
+	char *resp;
+
+	cmd_len = strlen(cmd);
+	serdev_device_write_buf(sdev, cmd, cmd_len);
+	serdev_device_write_buf(sdev, &cr, 1);
+
+	timeout = wait_for_completion_timeout(&usidev->prompt_recv_comp, timeout);
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	resp = usidev->rx_buf;
+	resp_len = usidev->rx_len;
+	if (!strncmp(resp, cmd, cmd_len) && resp[cmd_len] == '\r') {
+		dev_dbg(&sdev->dev, "Skipping echo\n");
+		resp += cmd_len + 1;
+		resp_len -= cmd_len + 1;
+	}
+	dev_dbg(&sdev->dev, "Received: '%s'\n", resp);
+	if (data)
+		*data = kstrdup(resp, GFP_KERNEL);
+
+	usidev->rx_len = 0;
+	reinit_completion(&usidev->prompt_recv_comp);
+
+	return 0;
+}
+
+static int usi_simple_cmd(struct usi_device *usidev, const char *cmd, unsigned long timeout)
+{
+	char *resp;
+	int ret;
+
+	ret = usi_send_command(usidev, cmd, &resp, timeout);
+	if (ret)
+		return ret;
+
+	if (strcmp(resp, "OK\r\n") == 0) {
+		kfree(resp);
+		return 0;
+	}
+
+	kfree(resp);
+
+	return -EINVAL;
+}
+
+static int usi_cmd_reset(struct usi_device *usidev)
+{
+	int ret;
+
+	ret = usi_send_command(usidev, "ATZ", NULL, HZ);
+	if (ret)
+		return ret;
+
+	mdelay(1000);
+
+	return 0;
+}
+
+static int usi_cmd_read_reg(struct usi_device *usidev, u8 addr, u8 *val)
+{
+	char *cmd;
+	char *resp;
+	char *sz;
+	int ret;
+
+	cmd = kasprintf(GFP_KERNEL, "AT+RREG=0x%02x", (int)addr);
+	if (!cmd)
+		return -ENOMEM;
+
+	ret = usi_send_command(usidev, cmd, &resp, HZ);
+	if (ret) {
+		kfree(cmd);
+		return ret;
+	}
+	if (!usi_cmd_ok(resp)) {
+		kfree(resp);
+		kfree(cmd);
+		return -EINVAL;
+	}
+	resp[strlen(resp) - 6] = '\0';
+	sz = resp;
+	if (strstarts(sz, "+Reg="))
+		sz += 5;
+	if (strncasecmp(sz, cmd + 8, 4) == 0 && strstarts(sz + 4, ", "))
+		sz += 6;
+
+	kfree(cmd);
+
+	dev_dbg(&usidev->serdev->dev, "Parsing '%s'\n", sz);
+	ret = kstrtou8(sz, 0, val);
+	if (ret) {
+		kfree(resp);
+		return ret;
+	}
+
+	kfree(resp);
+
+	return 0;
+}
+
+static int usi_receive_buf(struct serdev_device *sdev, const u8 *data, size_t count)
+{
+	struct usi_device *usidev = serdev_device_get_drvdata(sdev);
+	size_t i = 0;
+	int len = 0;
+
+	dev_dbg(&sdev->dev, "Receive (%d)\n", (int)count);
+
+	for (i = 0; i < count; i++) {
+		dev_dbg(&sdev->dev, "Receive: 0x%02x\n", (int)data[i]);
+	}
+	i = 0;
+
+	if (completion_done(&usidev->prompt_recv_comp) ||
+	    completion_done(&usidev->tx_event_recv_comp)) {
+		dev_info(&sdev->dev, "RX waiting on completion\n");
+		return 0;
+	}
+	if (usidev->rx_len == sizeof(usidev->rx_buf) - 1) {
+		dev_warn(&sdev->dev, "RX buffer full\n");
+		return 0;
+	}
+
+	i = min(count, sizeof(usidev->rx_buf) - 1 - usidev->rx_len);
+	if (i > 0) {
+		memcpy(&usidev->rx_buf[usidev->rx_len], data, i);
+		usidev->rx_len += i;
+		len += i;
+	}
+	if (usidev->rx_len >= 3 && strncmp(&usidev->rx_buf[usidev->rx_len - 3], "\r# ", 3) == 0) {
+		usidev->rx_len -= 3;
+		usidev->rx_buf[usidev->rx_len] = '\0';
+		complete(&usidev->prompt_recv_comp);
+	} else if (usidev->rx_len > 7 && strstarts(usidev->rx_buf, "+RCV") &&
+			strncmp(&usidev->rx_buf[usidev->rx_len - 2], "\r\n", 2) == 0) {
+		usidev->rx_buf[usidev->rx_len - 2] = '\0';
+		dev_info(&sdev->dev, "RCV event: '%s'\n", usidev->rx_buf + 4);
+		usidev->rx_len = 0;
+	} else if (usidev->rx_len > 6 && strstarts(usidev->rx_buf, "+TX: ") &&
+			strncmp(&usidev->rx_buf[usidev->rx_len - 2], "\r\n", 2) == 0) {
+		usidev->rx_buf[usidev->rx_len - 2] = '\0';
+		dev_info(&sdev->dev, "TX event: '%s'\n", usidev->rx_buf + 5);
+		complete(&usidev->tx_event_recv_comp);
+	}
+
+	return len;
+}
+
+static const struct serdev_device_ops usi_serdev_client_ops = {
+	.receive_buf = usi_receive_buf,
+};
+
+static int usi_probe(struct serdev_device *sdev)
+{
+	struct usi_device *usidev;
+	//unsigned long timeout;
+	char *resp;
+	u8 val;
+	int ret;
+
+	dev_info(&sdev->dev, "Probing");
+
+	usidev = devm_kzalloc(&sdev->dev, sizeof(struct usi_device), GFP_KERNEL);
+	if (!usidev)
+		return -ENOMEM;
+
+	usidev->serdev = sdev;
+	usidev->mode = -1;
+	init_completion(&usidev->prompt_recv_comp);
+	init_completion(&usidev->tx_event_recv_comp);
+	serdev_device_set_drvdata(sdev, usidev);
+
+	ret = serdev_device_open(sdev);
+	if (ret) {
+		dev_err(&sdev->dev, "Failed to open (%d)", ret);
+		return ret;
+	}
+
+	serdev_device_set_baudrate(sdev, 115200);
+	serdev_device_set_flow_control(sdev, false);
+	serdev_device_set_client_ops(sdev, &usi_serdev_client_ops);
+
+	ret = usi_cmd_reset(usidev);
+	if (ret)
+		dev_warn(&sdev->dev, "Reset failed\n");
+
+	ret = usi_send_command(usidev, "ATE=0", NULL, HZ);
+	if (ret)
+		dev_warn(&sdev->dev, "ATE failed\n");
+
+	/* Dropped in firmware 2.8 */
+	ret = usi_send_command(usidev, "ATI", &resp, HZ);
+	if (!ret) {
+		if (usi_cmd_ok(resp)) {
+			resp[strlen(resp) - 6] = '\0';
+			dev_info(&sdev->dev, "Firmware '%s'\n", resp);
+		}
+		kfree(resp);
+	}
+
+	ret = usi_send_command(usidev, "AT+DEFMODE", &resp, HZ);
+	if (ret) {
+		dev_err(&sdev->dev, "Checking DEFMODE failed (%d)\n", ret);
+		serdev_device_close(sdev);
+		return ret;
+	}
+	if (usi_cmd_ok(resp)) {
+		resp[strlen(resp) - 6] = '\0';
+		dev_info(&sdev->dev, "Default mode '%s'\n", resp);
+		if (!strcmp(resp, "MFG_WAN_MODE"))
+			usidev->mode = 6;
+		else if (!strcmp(resp, "MFG_TEST_IDLE"))
+			usidev->mode = 0;
+		else if (!strcmp(resp, "MFG_TX_TONE"))
+			usidev->mode = 1;
+		else if (!strcmp(resp, "MFG_TX_PACKET"))
+			usidev->mode = 2;
+		else if (!strcmp(resp, "MFG_ERROR_LESS_ARGUMENETS"))
+			usidev->mode = 3;
+		else if (!strcmp(resp, "MFG_TX_TEXT"))
+			usidev->mode = 4;
+		else if (!strcmp(resp, "MFG_TEST_STOP"))
+			usidev->mode = 5;
+	}
+	kfree(resp);
+
+	if (usidev->mode != 3) {
+		ret = usi_simple_cmd(usidev, "AT+DEFMODE=3", HZ);
+		if (ret) {
+			dev_err(&sdev->dev, "Setting DEFMODE failed (%d)\n", ret);
+			serdev_device_close(sdev);
+			return ret;
+		}
+
+#if 1
+		ret = usi_simple_cmd(usidev, "AT+WDCT", 5 * HZ);
+		if (ret) {
+			dev_err(&sdev->dev, "Writing DCT failed (%d)\n", ret);
+			serdev_device_close(sdev);
+			return ret;
+		}
+
+		ret = usi_cmd_reset(usidev);
+		if (ret) {
+			dev_err(&sdev->dev, "Reset failed\n");
+			serdev_device_close(sdev);
+			return ret;
+		}
+
+		ret = usi_send_command(usidev, "ATE=0", NULL, HZ);
+		if (ret)
+			dev_warn(&sdev->dev, "ATE failed\n");
+#endif
+
+		usidev->mode = -1;
+		ret = usi_send_command(usidev, "AT+DEFMODE", &resp, HZ);
+		if (ret) {
+			dev_err(&sdev->dev, "Checking DEFMODE failed (%d)\n", ret);
+			serdev_device_close(sdev);
+			return ret;
+		}
+		if (usi_cmd_ok(resp)) {
+			resp[strlen(resp) - 6] = '\0';
+			dev_info(&sdev->dev, "Default mode '%s'\n", resp);
+			if (!strcmp(resp, "MFG_WAN_MODE")) {
+				usidev->mode = 6;
+			}
+		}
+		kfree(resp);
+	}
+
+	ret = usi_send_command(usidev, "AT+VER", &resp, HZ);
+	if (!ret) {
+		if (usi_cmd_ok(resp)) {
+			resp[strlen(resp) - 6] = '\0';
+			dev_info(&sdev->dev, "LoRaWAN version '%s'\n",
+				(strstarts(resp, "+VER=")) ? (resp + 5) : resp);
+		}
+		kfree(resp);
+	}
+
+	ret = usi_simple_cmd(usidev, "AT+RF=20,868000000,7,0,1,0,8,0,0,0", HZ);
+	if (ret) {
+		dev_err(&sdev->dev, "AT+RF failed (%d)\n", ret);
+		serdev_device_close(sdev);
+		return ret;
+	}
+
+	/*ret = usi_simple_cmd(usidev, "AT+TXT=1,deadbeef", 2 * HZ);
+	if (ret) {
+		dev_err(&sdev->dev, "TX failed (%d)\n", ret);
+		serdev_device_close(sdev);
+		return ret;
+	}
+
+	timeout = wait_for_completion_timeout(&usidev->tx_event_recv_comp, 5 * HZ);
+	if (!timeout) {
+		serdev_device_close(sdev);
+		return -ETIMEDOUT;
+	}
+	usidev->rx_len = 0;
+	reinit_completion(&usidev->tx_event_recv_comp);*/
+
+	ret = usi_cmd_read_reg(usidev, 0x42, &val);
+	if (!ret) {
+		dev_info(&sdev->dev, "SX1272 VERSION 0x%02x\n", (int)val);
+	}
+
+	ret = usi_cmd_read_reg(usidev, 0x39, &val);
+	if (!ret) {
+		dev_info(&sdev->dev, "SX1272 SyncWord 0x%02x\n", (int)val);
+	}
+
+	ret = usi_cmd_read_reg(usidev, 0x01, &val);
+	if (!ret) {
+		dev_info(&sdev->dev, "SX1272 OpMode 0x%02x\n", (int)val);
+	}
+
+	dev_info(&sdev->dev, "Done.");
+
+	return 0;
+}
+
+static void usi_remove(struct serdev_device *sdev)
+{
+	struct usi_device *usidev = serdev_device_get_drvdata(sdev);
+
+	usi_send_command(usidev, "ATE=1\r", NULL, HZ);
+
+	serdev_device_close(sdev);
+
+	dev_info(&sdev->dev, "Removed\n");
+}
+
+static const struct of_device_id usi_of_match[] = {
+	{ .compatible = "usi,wm-sg-sm-42" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, usi_of_match);
+
+static struct serdev_device_driver usi_serdev_driver = {
+	.probe = usi_probe,
+	.remove = usi_remove,
+	.driver = {
+		.name = "usi",
+		.of_match_table = usi_of_match,
+	},
+};
+
+static int __init usi_init(void)
+{
+	int ret;
+
+	ret = serdev_device_driver_register(&usi_serdev_driver);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void __exit usi_exit(void)
+{
+	serdev_device_driver_unregister(&usi_serdev_driver);
+}
+
+module_init(usi_init);
+module_exit(usi_exit);
+
+MODULE_DESCRIPTION("USI WM-SG-SM-42 serdev driver");
+MODULE_AUTHOR("Andreas Färber <afaerber@suse.de>");
+MODULE_LICENSE("GPL");
-- 
2.16.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox