linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: vladimir.stankovic@displaylink.com
To: gregkh@linuxfoundation.org
Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
	mausb-host-devel@displaylink.com
Subject: [PATCH v5 2/8] usb: mausb_host: Add link layer implementation
Date: Sat, 25 Apr 2020 11:19:48 +0200	[thread overview]
Message-ID: <20200425091954.1610-3-vladimir.stankovic@displaylink.com> (raw)
In-Reply-To: <20200425091954.1610-1-vladimir.stankovic@displaylink.com>

Implemented link layer using kernel sockets. Link layer
manages network communication and provides interface for upper
layers of MA-USB stack.

Signed-off-by: Vladimir Stankovic <vladimir.stankovic@displaylink.com>
---
 drivers/usb/mausb_host/Makefile  |   1 +
 drivers/usb/mausb_host/ip_link.c | 374 +++++++++++++++++++++++++++++++
 drivers/usb/mausb_host/ip_link.h |  87 +++++++
 3 files changed, 462 insertions(+)
 create mode 100644 drivers/usb/mausb_host/ip_link.c
 create mode 100644 drivers/usb/mausb_host/ip_link.h

diff --git a/drivers/usb/mausb_host/Makefile b/drivers/usb/mausb_host/Makefile
index 2e353fa0958b..19445b73b50b 100644
--- a/drivers/usb/mausb_host/Makefile
+++ b/drivers/usb/mausb_host/Makefile
@@ -8,5 +8,6 @@
 obj-$(CONFIG_HOST_MAUSB) += mausb_host.o
 mausb_host-y := mausb_core.o
 mausb_host-y += utils.o
+mausb_host-y += ip_link.o
 
 ccflags-y += -I$(srctree)/$(src)
diff --git a/drivers/usb/mausb_host/ip_link.c b/drivers/usb/mausb_host/ip_link.c
new file mode 100644
index 000000000000..49b592c02210
--- /dev/null
+++ b/drivers/usb/mausb_host/ip_link.c
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#include "ip_link.h"
+
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/workqueue.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+
+#include "utils.h"
+
+static void __mausb_ip_connect(struct work_struct *work);
+static int __mausb_ip_recv(struct mausb_ip_ctx *ip_ctx);
+static void __mausb_ip_recv_work(struct work_struct *work);
+static inline void __mausb_ip_recv_ctx_clear(struct mausb_ip_recv_ctx
+					     *recv_ctx);
+static inline void __mausb_ip_recv_ctx_free(struct mausb_ip_recv_ctx
+					    *recv_ctx);
+
+int mausb_init_ip_ctx(struct mausb_ip_ctx **ip_ctx,
+		      struct net *net_ns,
+		      char ip_addr[INET6_ADDRSTRLEN],
+		      u16 port, void *context,
+		      void (*fn_callback)(void *ctx, enum mausb_channel channel,
+					  enum mausb_link_action act,
+					  int status, void *data),
+		      enum mausb_channel channel)
+{
+	struct mausb_ip_ctx *ctx;
+
+	*ip_ctx = kzalloc(sizeof(**ip_ctx), GFP_ATOMIC);
+	if (!*ip_ctx)
+		return -ENOMEM;
+
+	ctx = *ip_ctx;
+	ctx->client_socket = NULL;
+	__mausb_ip_recv_ctx_clear(&ctx->recv_ctx);
+
+	if (in4_pton(ip_addr, -1,
+		     (u8 *)&ctx->dev_addr_in.sa_in.sin_addr.s_addr, -1,
+		     NULL) == 1) {
+		ctx->dev_addr_in.sa_in.sin_family = AF_INET;
+		ctx->dev_addr_in.sa_in.sin_port = htons(port);
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (in6_pton(ip_addr, -1,
+			    (u8 *)&ctx->dev_addr_in.sa_in6.sin6_addr.in6_u, -1,
+			    NULL) == 1) {
+		ctx->dev_addr_in.sa_in6.sin6_family = AF_INET6;
+		ctx->dev_addr_in.sa_in6.sin6_port = htons(port);
+#endif
+	} else {
+		mausb_pr_err("Invalid IP address received: address=%s",
+			     ip_addr);
+		kfree(ctx);
+		return -EINVAL;
+	}
+
+	ctx->net_ns = net_ns;
+
+	if (channel == MAUSB_ISOCH_CHANNEL)
+		ctx->udp = true;
+
+	ctx->connect_workq = alloc_ordered_workqueue("connect_workq",
+						     WQ_MEM_RECLAIM);
+	if (!ctx->connect_workq) {
+		kfree(ctx);
+		return -ENOMEM;
+	}
+
+	ctx->recv_workq = alloc_ordered_workqueue("recv_workq", WQ_MEM_RECLAIM);
+	if (!ctx->recv_workq) {
+		destroy_workqueue(ctx->connect_workq);
+		kfree(ctx);
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&ctx->connect_work, __mausb_ip_connect);
+	INIT_WORK(&ctx->recv_work, __mausb_ip_recv_work);
+
+	ctx->channel	 = channel;
+	ctx->ctx	 = context;
+	ctx->fn_callback = fn_callback;
+
+	return 0;
+}
+
+void mausb_destroy_ip_ctx(struct mausb_ip_ctx *ip_ctx)
+{
+	if (!ip_ctx)
+		return;
+
+	if (ip_ctx->connect_workq) {
+		flush_workqueue(ip_ctx->connect_workq);
+		destroy_workqueue(ip_ctx->connect_workq);
+	}
+
+	if (ip_ctx->recv_workq) {
+		flush_workqueue(ip_ctx->recv_workq);
+		destroy_workqueue(ip_ctx->recv_workq);
+	}
+	if (ip_ctx->client_socket)
+		sock_release(ip_ctx->client_socket);
+	__mausb_ip_recv_ctx_free(&ip_ctx->recv_ctx);
+
+	kfree(ip_ctx);
+}
+
+static void __mausb_ip_set_options(struct socket *sock, bool udp)
+{
+	u32 optval = 0;
+	unsigned int optlen = sizeof(optval);
+	int status = 0;
+	struct __kernel_sock_timeval timeo = {.tv_sec = 0, .tv_usec = 500000U };
+	struct __kernel_sock_timeval send_timeo = {.tv_sec = 1, .tv_usec = 0 };
+
+	if (!udp) {
+		optval = 1;
+		status = kernel_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+					   (char *)&optval, optlen);
+		if (status < 0)
+			mausb_pr_warn("Failed to set tcp no delay option: status=%d",
+				      status);
+	}
+
+	status = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO_NEW,
+				   (char *)&timeo, sizeof(timeo));
+	if (status < 0)
+		mausb_pr_warn("Failed to set recv timeout option: status=%d",
+			      status);
+
+	status = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO_NEW,
+				   (char *)&send_timeo, sizeof(send_timeo));
+	if (status < 0)
+		mausb_pr_warn("Failed to set snd timeout option: status=%d",
+			      status);
+
+	optval = MAUSB_LINK_BUFF_SIZE;
+	status  = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+				    (char *)&optval, optlen);
+	if (status < 0)
+		mausb_pr_warn("Failed to set recv buffer size: status=%d",
+			      status);
+
+	optval = MAUSB_LINK_BUFF_SIZE;
+	status  = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
+				    (char *)&optval, optlen);
+	if (status < 0)
+		mausb_pr_warn("Failed to set send buffer size: status=%d",
+			      status);
+
+	optval = MAUSB_LINK_TOS_LEVEL_EF;
+	status  = kernel_setsockopt(sock, IPPROTO_IP, IP_TOS,
+				    (char *)&optval, optlen);
+	if (status < 0)
+		mausb_pr_warn("Failed to set QOS: status=%d", status);
+}
+
+static void __mausb_ip_connect(struct work_struct *work)
+{
+	int status = 0;
+	struct sockaddr *sa;
+	int sa_size;
+	struct mausb_ip_ctx *ip_ctx = container_of(work, struct mausb_ip_ctx,
+						   connect_work);
+	unsigned short int family = ip_ctx->dev_addr_in.sa_in.sin_family;
+
+	if (!ip_ctx->udp) {
+		status = sock_create_kern(ip_ctx->net_ns, family, SOCK_STREAM,
+					  IPPROTO_TCP, &ip_ctx->client_socket);
+		if (status < 0) {
+			mausb_pr_err("Failed to create socket: status=%d",
+				     status);
+			goto callback;
+		}
+	} else {
+		status = sock_create_kern(ip_ctx->net_ns, family, SOCK_DGRAM,
+					  IPPROTO_UDP, &ip_ctx->client_socket);
+		if (status < 0) {
+			mausb_pr_err("Failed to create socket: status=%d",
+				     status);
+			goto callback;
+		}
+	}
+
+	__mausb_ip_set_options((struct socket *)ip_ctx->client_socket,
+			       ip_ctx->udp);
+
+	if (family == AF_INET) {
+		sa = (struct sockaddr *)&ip_ctx->dev_addr_in.sa_in;
+		sa_size = sizeof(ip_ctx->dev_addr_in.sa_in);
+		mausb_pr_info("Connecting to %pI4:%d, status=%d",
+			      &ip_ctx->dev_addr_in.sa_in.sin_addr,
+			      htons(ip_ctx->dev_addr_in.sa_in.sin_port),
+			      status);
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (family == AF_INET6) {
+		sa = (struct sockaddr *)&ip_ctx->dev_addr_in.sa_in6;
+		sa_size = sizeof(ip_ctx->dev_addr_in.sa_in6);
+		mausb_pr_info("Connecting to %pI6c:%d, status=%d",
+			      &ip_ctx->dev_addr_in.sa_in6.sin6_addr,
+			      htons(ip_ctx->dev_addr_in.sa_in6.sin6_port),
+			      status);
+#endif
+	} else {
+		mausb_pr_err("Wrong network family provided");
+		status = -EINVAL;
+		goto callback;
+	}
+
+	status = kernel_connect(ip_ctx->client_socket, sa, sa_size, O_RDWR);
+	if (status < 0) {
+		mausb_pr_err("Failed to connect to host, status=%d", status);
+		goto clear_socket;
+	}
+
+	queue_work(ip_ctx->recv_workq, &ip_ctx->recv_work);
+
+	goto callback;
+
+clear_socket:
+	sock_release(ip_ctx->client_socket);
+	ip_ctx->client_socket = NULL;
+callback:
+	ip_ctx->fn_callback(ip_ctx->ctx, ip_ctx->channel, MAUSB_LINK_CONNECT,
+			    status, NULL);
+}
+
+void mausb_ip_connect_async(struct mausb_ip_ctx *ip_ctx)
+{
+	queue_work(ip_ctx->connect_workq, &ip_ctx->connect_work);
+}
+
+int mausb_ip_disconnect(struct mausb_ip_ctx *ip_ctx)
+{
+	if (ip_ctx && ip_ctx->client_socket)
+		return kernel_sock_shutdown(ip_ctx->client_socket, SHUT_RDWR);
+	return 0;
+}
+
+int mausb_ip_send(struct mausb_ip_ctx *ip_ctx,
+		  struct mausb_kvec_data_wrapper *wrapper)
+{
+	struct msghdr msghd;
+
+	if (!ip_ctx) {
+		mausb_pr_alert("Socket ctx is NULL!");
+		return -EINVAL;
+	}
+
+	memset(&msghd, 0, sizeof(msghd));
+	msghd.msg_flags = MSG_WAITALL;
+
+	return kernel_sendmsg(ip_ctx->client_socket, &msghd, wrapper->kvec,
+			      wrapper->kvec_num, wrapper->length);
+}
+
+static inline void __mausb_ip_recv_ctx_clear(struct mausb_ip_recv_ctx *recv_ctx)
+{
+	recv_ctx->buffer   = NULL;
+	recv_ctx->left	   = 0;
+	recv_ctx->received = 0;
+}
+
+static inline void __mausb_ip_recv_ctx_free(struct mausb_ip_recv_ctx *recv_ctx)
+{
+	kfree(recv_ctx->buffer);
+	__mausb_ip_recv_ctx_clear(recv_ctx);
+}
+
+static int __mausb_ip_recv(struct mausb_ip_ctx *ip_ctx)
+{
+	struct msghdr msghd;
+	struct kvec vec;
+	int  status;
+	bool peek = true;
+	unsigned int optval = 1;
+	struct socket *client_socket = (struct socket *)ip_ctx->client_socket;
+
+	/* receive with timeout of 0.5s */
+	while (true) {
+		memset(&msghd, 0, sizeof(msghd));
+		if (peek) {
+			vec.iov_base = ip_ctx->recv_ctx.common_hdr;
+			vec.iov_len  = sizeof(ip_ctx->recv_ctx.common_hdr);
+			msghd.msg_flags = MSG_PEEK;
+		} else {
+			vec.iov_base =
+			    ip_ctx->recv_ctx.buffer +
+			    ip_ctx->recv_ctx.received;
+			vec.iov_len = ip_ctx->recv_ctx.left;
+			msghd.msg_flags = MSG_WAITALL;
+		}
+
+		if (!ip_ctx->udp) {
+			status = kernel_setsockopt(client_socket, IPPROTO_TCP,
+						   TCP_QUICKACK,
+						   (char *)&optval,
+						   sizeof(optval));
+			if (status != 0) {
+				mausb_pr_warn("Setting TCP_QUICKACK failed, status=%d",
+					      status);
+			}
+		}
+
+		status = kernel_recvmsg(client_socket, &msghd, &vec, 1,
+					vec.iov_len, (int)msghd.msg_flags);
+		if (status == -EAGAIN) {
+			return -EAGAIN;
+		} else if (status <= 0) {
+			mausb_pr_warn("kernel_recvmsg, status=%d", status);
+
+			__mausb_ip_recv_ctx_free(&ip_ctx->recv_ctx);
+			ip_ctx->fn_callback(ip_ctx->ctx, ip_ctx->channel,
+					    MAUSB_LINK_RECV, status, NULL);
+			return status;
+		}
+
+		mausb_pr_debug("kernel_recvmsg, status=%d", status);
+
+		if (peek) {
+			if ((unsigned int)status <
+					sizeof(ip_ctx->recv_ctx.common_hdr))
+				return -EAGAIN;
+			/* length field of mausb_common_hdr */
+			ip_ctx->recv_ctx.left =
+			    *(u16 *)(&ip_ctx->recv_ctx.common_hdr[2]);
+			ip_ctx->recv_ctx.received = 0;
+			ip_ctx->recv_ctx.buffer	  =
+			    kzalloc(ip_ctx->recv_ctx.left, GFP_KERNEL);
+			peek = false;
+			if (!ip_ctx->recv_ctx.buffer) {
+				ip_ctx->fn_callback(ip_ctx->ctx,
+						    ip_ctx->channel,
+						    MAUSB_LINK_RECV,
+						    -ENOMEM, NULL);
+				return -ENOMEM;
+			}
+		} else {
+			if (status < ip_ctx->recv_ctx.left) {
+				ip_ctx->recv_ctx.left -= (u16)status;
+				ip_ctx->recv_ctx.received += (u16)status;
+			} else {
+				ip_ctx->fn_callback(ip_ctx->ctx,
+						    ip_ctx->channel,
+						    MAUSB_LINK_RECV, status,
+						    ip_ctx->recv_ctx.buffer);
+				__mausb_ip_recv_ctx_clear(&ip_ctx->recv_ctx);
+				peek = true;
+			}
+		}
+	}
+
+	return status;
+}
+
+static void __mausb_ip_recv_work(struct work_struct *work)
+{
+	struct mausb_ip_ctx *ip_ctx = container_of(work, struct mausb_ip_ctx,
+						   recv_work);
+	int status = __mausb_ip_recv(ip_ctx);
+
+	if (status <= 0 && status != -EAGAIN)
+		return;
+
+	queue_work(ip_ctx->recv_workq, &ip_ctx->recv_work);
+}
diff --git a/drivers/usb/mausb_host/ip_link.h b/drivers/usb/mausb_host/ip_link.h
new file mode 100644
index 000000000000..5946151e4e4e
--- /dev/null
+++ b/drivers/usb/mausb_host/ip_link.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#ifndef __MAUSB_IP_LINK_H__
+#define __MAUSB_IP_LINK_H__
+
+#include <linux/inet.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <net/net_namespace.h>
+
+#define MAUSB_LINK_BUFF_SIZE	16777216
+#define MAUSB_LINK_TOS_LEVEL_EF 0xB8
+
+enum mausb_link_action {
+	MAUSB_LINK_CONNECT	= 0,
+	MAUSB_LINK_DISCONNECT	= 1,
+	MAUSB_LINK_RECV		= 2,
+	MAUSB_LINK_SEND		= 3
+};
+
+enum mausb_channel {
+	MAUSB_CTRL_CHANNEL  = 0,
+	MAUSB_ISOCH_CHANNEL = 1,
+	MAUSB_BULK_CHANNEL  = 2,
+	MAUSB_INTR_CHANNEL  = 3,
+	MAUSB_MGMT_CHANNEL  = 4
+};
+
+struct mausb_kvec_data_wrapper {
+	struct kvec *kvec;
+	u32    kvec_num;
+	u32    length;
+};
+
+struct mausb_ip_recv_ctx {
+	u16  left;
+	u16  received;
+	char *buffer;
+	char common_hdr[12] __aligned(4);
+};
+
+struct mausb_ip_ctx {
+	struct socket		*client_socket;
+	union {
+		struct sockaddr_in sa_in;
+#if IS_ENABLED(CONFIG_IPV6)
+		struct sockaddr_in6 sa_in6;
+#endif
+	} dev_addr_in;
+	struct net		*net_ns;
+	bool			udp;
+
+	/* Queues to schedule rx work */
+	struct workqueue_struct	*recv_workq;
+	struct workqueue_struct	*connect_workq;
+	struct work_struct	recv_work;
+	struct work_struct	connect_work;
+
+	struct mausb_ip_recv_ctx recv_ctx; /* recv buffer */
+
+	enum mausb_channel channel;
+	void *ctx;
+	/* callback should store task into hpal queue */
+	void (*fn_callback)(void *ctx, enum mausb_channel channel,
+			    enum mausb_link_action act, int status, void *data);
+};
+
+int mausb_init_ip_ctx(struct mausb_ip_ctx **ip_ctx,
+		      struct net *net_ns,
+		      char ip_addr[INET6_ADDRSTRLEN],
+		      u16 port,
+		      void *ctx,
+		      void (*ctx_callback)(void *ctx,
+					   enum mausb_channel channel,
+					   enum mausb_link_action act,
+					   int status, void *data),
+		      enum mausb_channel channel);
+int mausb_ip_disconnect(struct mausb_ip_ctx *ip_ctx);
+int mausb_ip_send(struct mausb_ip_ctx *ip_ctx,
+		  struct mausb_kvec_data_wrapper *wrapper);
+
+void mausb_destroy_ip_ctx(struct mausb_ip_ctx *ip_ctx);
+void mausb_ip_connect_async(struct mausb_ip_ctx *ip_ctx);
+
+#endif /* __MAUSB_IP_LINK_H__ */
-- 
2.17.1


  parent reply	other threads:[~2020-04-25  9:20 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-12 14:42 [PATCH v3 0/8] Add MA USB Host driver Vladimir Stankovic
2020-03-27 15:26 ` [PATCH v4 " vladimir.stankovic
2020-03-27 15:26   ` [PATCH v4 1/8] usb: Add MA-USB Host kernel module vladimir.stankovic
2020-03-27 16:25     ` Alan Stern
2020-03-27 15:26   ` [PATCH v4 2/8] usb: mausb_host: Add link layer implementation vladimir.stankovic
2020-03-27 15:26   ` [PATCH v4 3/8] usb: mausb_host: HCD initialization vladimir.stankovic
2020-03-27 15:26   ` [PATCH v4 4/8] usb: mausb_host: Implement initial hub handlers vladimir.stankovic
2020-03-27 16:37     ` Alan Stern
2020-04-13 15:16       ` Vladimir Stankovic
2020-03-27 15:26   ` [PATCH v4 5/8] usb: mausb_host: Introduce PAL processing vladimir.stankovic
2020-03-27 16:35     ` Alan Stern
2020-03-28  3:56     ` kbuild test robot
2020-03-27 15:26   ` [PATCH v4 6/8] usb: mausb_host: Add logic for PAL-to-PAL communication vladimir.stankovic
2020-03-27 15:26   ` [PATCH v4 7/8] usb: mausb_host: MA-USB PAL events processing vladimir.stankovic
2020-03-28 10:35     ` kbuild test robot
2020-04-04 16:07     ` kbuild test robot
2020-03-27 15:26   ` [PATCH v4 8/8] usb: mausb_host: Process MA-USB data packets vladimir.stankovic
2020-04-25  9:19   ` [PATCH v5 0/8] Add MA USB Host driver vladimir.stankovic
2020-04-25  9:19     ` [PATCH v5 1/8] usb: Add MA-USB Host kernel module vladimir.stankovic
2020-04-28 11:03       ` Greg KH
2020-04-25  9:19     ` vladimir.stankovic [this message]
2020-04-25  9:19     ` [PATCH v5 3/8] usb: mausb_host: HCD initialization vladimir.stankovic
2020-04-28 11:07       ` Greg KH
2020-04-25  9:19     ` [PATCH v5 4/8] usb: mausb_host: Implement initial hub handlers vladimir.stankovic
2020-04-25  9:19     ` [PATCH v5 5/8] usb: mausb_host: Introduce PAL processing vladimir.stankovic
2020-04-26  0:32       ` Alan Stern
2020-04-26 12:32         ` Vladimir Stankovic
2020-04-26 14:31           ` Alan Stern
2020-04-26 14:45             ` [External] " Vladimir Stankovic
2020-04-26 20:56               ` Alan Stern
2020-04-30 14:37                 ` Vladimir Stankovic
2020-04-30 15:18                   ` Alan Stern
2020-04-30 15:34                     ` Vladimir Stankovic
2020-04-30 15:41                       ` Alan Stern
2020-04-25  9:19     ` [PATCH v5 6/8] usb: mausb_host: Add logic for PAL-to-PAL communication vladimir.stankovic
2020-04-25  9:19     ` [PATCH v5 7/8] usb: mausb_host: MA-USB PAL events processing vladimir.stankovic
2020-04-28 11:08       ` Greg KH
2020-04-25  9:19     ` [PATCH v5 8/8] usb: mausb_host: Process MA-USB data packets vladimir.stankovic
2020-04-28 11:04     ` [PATCH v5 0/8] Add MA USB Host driver Greg KH
2020-04-30 16:51       ` [External] " Vladimir Stankovic
2020-04-30 20:02         ` Greg KH
2020-05-15 13:04           ` Vladimir Stankovic
2020-05-29 12:48             ` Pavel Machek
2020-05-15 12:34     ` [PATCH v6 " Vladimir Stankovic
2020-05-15 12:34       ` [PATCH v6 1/8] usb: Add MA-USB Host kernel module Vladimir Stankovic
2020-05-15 13:01         ` Greg KH
2020-06-11 18:20           ` Vladimir Stankovic
2020-05-15 13:02         ` Greg KH
2020-06-11 18:19           ` [External] " Vladimir Stankovic
2020-05-15 12:34       ` [PATCH v6 2/8] usb: mausb_host: Add link layer implementation Vladimir Stankovic
2020-05-15 12:34       ` [PATCH v6 3/8] usb: mausb_host: HCD initialization Vladimir Stankovic
2020-05-15 13:03         ` Greg KH
2020-06-11 18:19           ` Vladimir Stankovic
2020-05-15 13:07         ` Greg KH
2020-06-11 18:18           ` [External] " Vladimir Stankovic
2020-06-18  8:18             ` Greg KH
2020-05-15 12:34       ` [PATCH v6 4/8] usb: mausb_host: Implement initial hub handlers Vladimir Stankovic
2020-05-15 12:34       ` [PATCH v6 5/8] usb: mausb_host: Introduce PAL processing Vladimir Stankovic
2020-05-15 12:35       ` [PATCH v6 6/8] usb: mausb_host: Add logic for PAL-to-PAL communication Vladimir Stankovic
2020-05-15 12:35       ` [PATCH v6 7/8] usb: mausb_host: MA-USB PAL events processing Vladimir Stankovic
2020-05-15 12:35       ` [PATCH v6 8/8] usb: mausb_host: Process MA-USB data packets Vladimir Stankovic
2020-05-15 13:08       ` [PATCH v6 0/8] Add MA USB Host driver Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200425091954.1610-3-vladimir.stankovic@displaylink.com \
    --to=vladimir.stankovic@displaylink.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mausb-host-devel@displaylink.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).