Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9521aebf authored by Jack Pham's avatar Jack Pham Committed by Matt Wagantall
Browse files

usb: gadget: Add snapshot of changes to RNDIS



Add snapshot of changes to RNDIS driver from msm-3.14 made between
commit 455c6fdb (Linux 3.14) and commit 3bc54cf86b (Merge "msm:
camera: Add dummy sub module in sensor pipeline")

The is a squash of the following commits:

USB: rndis: Free the rndis response queue during REMOTE_NDIS_RESET_MSG
USB: f_rndis: Check if cdev is NULL before accessing
RNDIS: Add Data aggregation (multi packet) support
Rndis: Add debug support to disable RNDIS Multipacket Feature
Rndis: Don't request Host to send aggregated RNDIS packets
usb: Add support for rndis uplink aggregation
usb: rndis: reset ul aggregation stats for every set_alt
usb: rndis: Fix zero length skbs in up-link
rndis: usb: set ul aggregation support to 3 rndis packets
USB: gadget: rndis: Add module parameter for DL max packets per xfer
USB: IPA: RNDIS: Add both device and host side parameters
usb: gadget: Add snapshot of QC RNDIS function driver
usb: gadget: Fix invalid pointer access in rndis_free_response
USB: gadget: rndis: Optimize tx path for better performance
USB: gadget: Compilation fixes for 64-bit support
usb: gadget: u_ether: add scatter/gather support
USB: rndis: Protect rndis response queue
usb: gadget: rndis: Limit DL aggregation to 5 packets
drivers: usb: Stop transfers on MSG_HALT
USB: gadget: f_rndis: Add check before queuing notification available
f_qc_rndis: Fix issue with bus resume while using Linux Host
f_rndis: Check if rndis driver is being instantiated

Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent b0ed4dfd
Loading
Loading
Loading
Loading
+65 −10
Original line number Diff line number Diff line
@@ -383,14 +383,37 @@ static struct sk_buff *rndis_add_header(struct gether *port,
					struct sk_buff *skb)
{
	struct sk_buff *skb2;

	skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
	struct rndis_packet_msg_type *header = NULL;
	struct f_rndis *rndis = func_to_rndis(&port->func);
	struct usb_composite_dev *cdev = port->func.config->cdev;

	if (rndis->port.multi_pkt_xfer || cdev->gadget->sg_supported) {
		if (port->header) {
			header = port->header;
			header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET);
			header->MessageLength = cpu_to_le32(skb->len +
							sizeof(*header));
			header->DataOffset = cpu_to_le32(36);
			header->DataLength = cpu_to_le32(skb->len);
			pr_debug("MessageLength:%d DataLength:%d\n",
						header->MessageLength,
						header->DataLength);
			return skb;
		} else {
			dev_kfree_skb_any(skb);
			pr_err("RNDIS header is NULL.\n");
			return NULL;
		}
	} else {
		skb2 = skb_realloc_headroom(skb,
				sizeof(struct rndis_packet_msg_type));
		if (skb2)
			rndis_add_hdr(skb2);

	dev_kfree_skb(skb);
		dev_kfree_skb_any(skb);
		return skb2;
	}
}

static void rndis_response_available(void *_rndis)
{
@@ -403,6 +426,8 @@ static void rndis_response_available(void *_rndis)
	if (atomic_inc_return(&rndis->notify_count) != 1)
		return;

	if (!rndis->notify->driver_data)
		return;
	/* Send RNDIS RESPONSE_AVAILABLE notification; a
	 * USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too
	 *
@@ -421,9 +446,14 @@ static void rndis_response_available(void *_rndis)
static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
{
	struct f_rndis			*rndis = req->context;
	struct usb_composite_dev	*cdev = rndis->port.func.config->cdev;
	struct usb_composite_dev	*cdev;
	int				status = req->status;

	if (!rndis->port.func.config || !rndis->port.func.config->cdev)
		return;
	else
		cdev = rndis->port.func.config->cdev;

	/* after TX:
	 *  - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
	 *  - RNDIS_RESPONSE_AVAILABLE (status/irq)
@@ -457,12 +487,19 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
	}
}

#define MAX_PKTS_PER_XFER	10
static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
{
	struct f_rndis			*rndis = req->context;
	struct usb_composite_dev	*cdev;
	int				status;
	rndis_init_msg_type		*buf;

	if (!rndis->port.func.config || !rndis->port.func.config->cdev)
		return;
	else
		cdev = rndis->port.func.config->cdev;

	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
//	spin_lock(&dev->lock);
	status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
@@ -473,6 +510,23 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
	buf = (rndis_init_msg_type *)req->buf;

	if (buf->MessageType == RNDIS_MSG_INIT) {
		if (cdev->gadget->sg_supported) {
			rndis->port.dl_max_xfer_size = buf->MaxTransferSize;
			gether_update_dl_max_xfer_size(&rndis->port,
					rndis->port.dl_max_xfer_size);

			/* if SG is enabled multiple packets can be put
			 * together too quickly. However, module param
			 * is not honored.
			 */
			rndis->port.dl_max_pkts_per_xfer = 5;

			gether_update_dl_max_pkts_per_xfer(&rndis->port,
					 rndis->port.dl_max_pkts_per_xfer);

			return;
		}

		if (buf->MaxTransferSize > 2048)
			rndis->port.multi_pkt_xfer = 1;
		else
@@ -892,8 +946,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
	struct f_rndis	*rndis;
	int		status;

	/* allocate and initialize one new
	   instance */
	/* allocate and initialize one new instance */
	status = -ENOMEM;
	rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
	if (!rndis)
@@ -911,6 +964,8 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
	rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
	rndis->port.wrap = rndis_add_header;
	rndis->port.unwrap = rndis_rm_hdr;
	rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
	rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer;

	rndis->port.func.name = "rndis";
	/* descriptors are per-instance copies */
+125 −25
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <asm/unaligned.h>

#include "u_rndis.h"
#include "u_bam_data.h"

#undef	VERBOSE_DEBUG

@@ -544,14 +545,11 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
		 */
		retval = 0;
		if (*params->filter) {
			params->state = RNDIS_DATA_INITIALIZED;
			netif_carrier_on(params->dev);
			if (netif_running(params->dev))
				netif_wake_queue(params->dev);
			pr_debug("%s(): disable flow control\n", __func__);
			rndis_flow_control(configNr, false);
		} else {
			params->state = RNDIS_INITIALIZED;
			netif_carrier_off(params->dev);
			netif_stop_queue(params->dev);
			pr_debug("%s(): enable flow control\n", __func__);
			rndis_flow_control(configNr, true);
		}
		break;

@@ -601,10 +599,11 @@ static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
		+ sizeof(struct ethhdr)
		+ sizeof(struct rndis_packet_msg_type)
		+ 22));
	resp->PacketAlignmentFactor = cpu_to_le32(0);
	resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor);
	resp->AFListOffset = cpu_to_le32(0);
	resp->AFListSize = cpu_to_le32(0);

	params->ul_max_xfer_size = le32_to_cpu(resp->MaxTransferSize);
	params->resp_avail(params->v);
	return 0;
}
@@ -814,7 +813,7 @@ EXPORT_SYMBOL_GPL(rndis_set_host_mac);
 */
int rndis_msg_parser(u8 configNr, u8 *buf)
{
	u32 MsgType, MsgLength;
	u32 MsgType, MsgLength, major, minor, max_transfer_size;
	__le32 *tmp;
	struct rndis_params *params;

@@ -839,6 +838,19 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
	case RNDIS_MSG_INIT:
		pr_debug("%s: RNDIS_MSG_INIT\n",
			__func__);
		tmp++; /* to get RequestID */
		major = get_unaligned_le32(tmp++);
		minor = get_unaligned_le32(tmp++);
		max_transfer_size = get_unaligned_le32(tmp++);

		params->host_rndis_major_ver = major;
		params->host_rndis_minor_ver = minor;
		params->dl_max_xfer_size = max_transfer_size;

		pr_debug("%s(): RNDIS Host Major:%d Minor:%d version\n",
					__func__, major, minor);
		pr_debug("%s(): UL Max Transfer size:%x\n", __func__,
					max_transfer_size);
		params->state = RNDIS_INITIALIZED;
		return rndis_init_response(configNr,
					(rndis_init_msg_type *)buf);
@@ -846,11 +858,17 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
	case RNDIS_MSG_HALT:
		pr_debug("%s: RNDIS_MSG_HALT\n",
			__func__);
		params->state = RNDIS_UNINITIALIZED;

		if (!is_rndis_ipa_supported()) {
			if (params->dev) {
				netif_carrier_off(params->dev);
				netif_stop_queue(params->dev);
			}
		} else {
			if (params->state == RNDIS_DATA_INITIALIZED)
				u_bam_data_stop_rndis_ipa();
		}
		params->state = RNDIS_UNINITIALIZED;
		return 0;

	case RNDIS_MSG_QUERY:
@@ -904,6 +922,8 @@ int rndis_register(void (*resp_avail)(void *v), void *v)
			rndis_per_dev_params[i].used = 1;
			rndis_per_dev_params[i].resp_avail = resp_avail;
			rndis_per_dev_params[i].v = v;
			rndis_per_dev_params[i].max_pkt_per_xfer = 1;
			rndis_per_dev_params[i].pkt_alignment_factor = 0;
			pr_debug("%s: configNr = %d\n", __func__, i);
			return i;
		}
@@ -933,6 +953,7 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
	rndis_per_dev_params[configNr].dev = dev;
	rndis_per_dev_params[configNr].filter = cdc_filter;

	/* reset aggregation stats for every set_alt */
	rndis_ul_max_xfer_size_rcvd = 0;
	rndis_ul_max_pkt_per_xfer_rcvd = 0;
	return 0;
@@ -964,6 +985,18 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
}
EXPORT_SYMBOL_GPL(rndis_set_param_medium);

u32 rndis_get_dl_max_xfer_size(u8 configNr)
{
	pr_debug("%s:\n", __func__);
	return rndis_per_dev_params[configNr].dl_max_xfer_size;
}

u32 rndis_get_ul_max_xfer_size(u8 configNr)
{
	pr_debug("%s:\n", __func__);
	return rndis_per_dev_params[configNr].ul_max_xfer_size;
}

void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer)
{
	pr_debug("%s:\n", __func__);
@@ -971,6 +1004,50 @@ void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer)
	rndis_per_dev_params[configNr].max_pkt_per_xfer = max_pkt_per_xfer;
}

void rndis_set_pkt_alignment_factor(u8 configNr, u8 pkt_alignment_factor)
{
	pr_debug("%s:\n", __func__);

	rndis_per_dev_params[configNr].pkt_alignment_factor =
					pkt_alignment_factor;
}

/**
 * rndis_flow_control: enable/disable flow control with USB RNDIS interface
 * confignr - RNDIS network interface number
 * enable_flow_control - true: perform flow control, false: disable flow control
 *
 * In BAM2BAM IPA mode, this function triggers functionality to start/stop
 * endless transfers, otherwise it enables/disables RNDIS network interface.
 */
void rndis_flow_control(u8 confignr, bool enable_flow_control)
{
	struct rndis_params *params;

	params = &rndis_per_dev_params[confignr];
	pr_debug("%s(): params->state:%x\n", __func__, params->state);
	if (enable_flow_control) {
		if (is_rndis_ipa_supported() &&
			params->state == RNDIS_DATA_INITIALIZED) {
			u_bam_data_stop_rndis_ipa();
		} else {
			netif_carrier_off(params->dev);
			netif_stop_queue(params->dev);
		}
		params->state = RNDIS_INITIALIZED;
	} else {
		if (is_rndis_ipa_supported() &&
			params->state != RNDIS_DATA_INITIALIZED) {
			u_bam_data_start_rndis_ipa();
		} else {
			netif_carrier_on(params->dev);
			if (netif_running(params->dev))
				netif_wake_queue(params->dev);
		}
		params->state = RNDIS_DATA_INITIALIZED;
	}
}

void rndis_add_hdr(struct sk_buff *skb)
{
	struct rndis_packet_msg_type *header;
@@ -990,16 +1067,22 @@ void rndis_free_response(int configNr, u8 *buf)
{
	rndis_resp_t *r;
	struct list_head *act, *tmp;
	unsigned long flags;

	spin_lock_irqsave(&rndis_per_dev_params[configNr].lock, flags);
	list_for_each_safe(act, tmp,
			&(rndis_per_dev_params[configNr].resp_queue))
	{
		if (!act)
			continue;

		r = list_entry(act, rndis_resp_t, list);
		if (r && r->buf == buf) {
			list_del(&r->list);
			kfree(r);
		}
	}
	spin_unlock_irqrestore(&rndis_per_dev_params[configNr].lock, flags);
}
EXPORT_SYMBOL_GPL(rndis_free_response);

@@ -1007,9 +1090,11 @@ u8 *rndis_get_next_response(int configNr, u32 *length)
{
	rndis_resp_t *r;
	struct list_head *act, *tmp;
	unsigned long flags;

	if (!length) return NULL;

	spin_lock_irqsave(&rndis_per_dev_params[configNr].lock, flags);
	list_for_each_safe(act, tmp,
			&(rndis_per_dev_params[configNr].resp_queue))
	{
@@ -1017,9 +1102,12 @@ u8 *rndis_get_next_response(int configNr, u32 *length)
		if (!r->send) {
			r->send = 1;
			*length = r->length;
			spin_unlock_irqrestore(
				&rndis_per_dev_params[configNr].lock, flags);
			return r->buf;
		}
	}
	spin_unlock_irqrestore(&rndis_per_dev_params[configNr].lock, flags);

	return NULL;
}
@@ -1028,6 +1116,7 @@ EXPORT_SYMBOL_GPL(rndis_get_next_response);
static rndis_resp_t *rndis_add_response(int configNr, u32 length)
{
	rndis_resp_t *r;
	unsigned long flags;

	/* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
	r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC);
@@ -1037,8 +1126,10 @@ static rndis_resp_t *rndis_add_response(int configNr, u32 length)
	r->length = length;
	r->send = 0;

	spin_lock_irqsave(&rndis_per_dev_params[configNr].lock, flags);
	list_add_tail(&r->list,
		&(rndis_per_dev_params[configNr].resp_queue));
	spin_unlock_irqrestore(&rndis_per_dev_params[configNr].lock, flags);
	return r;
}

@@ -1046,7 +1137,7 @@ int rndis_rm_hdr(struct gether *port,
			struct sk_buff *skb,
			struct sk_buff_head *list)
{
	int num_pkts = 1;
	int num_pkts = 0;

	if (skb->len > rndis_ul_max_xfer_size_rcvd)
		rndis_ul_max_xfer_size_rcvd = skb->len;
@@ -1056,12 +1147,6 @@ int rndis_rm_hdr(struct gether *port,
		struct sk_buff          *skb2;
		u32             msg_len, data_offset, data_len;

		/* some rndis hosts send extra byte to avoid zlp, ignore it */
		if (skb->len == 1) {
			dev_kfree_skb_any(skb);
			return 0;
		}

		if (skb->len < sizeof *hdr) {
			pr_err("invalid rndis pkt: skblen:%u hdr_len:%zu",
					skb->len, sizeof *hdr);
@@ -1082,6 +1167,7 @@ int rndis_rm_hdr(struct gether *port,
			dev_kfree_skb_any(skb);
			return -EOVERFLOW;
		}

		if (le32_to_cpu(hdr->MessageType) != RNDIS_MSG_PACKET) {
			pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
					le32_to_cpu(hdr->MessageType),
@@ -1090,9 +1176,12 @@ int rndis_rm_hdr(struct gether *port,
			return -EINVAL;
		}

		num_pkts++;

		skb_pull(skb, data_offset + 8);

		if (msg_len == skb->len) {
		if (data_len == skb->len ||
				data_len == (skb->len - 1)) {
			skb_trim(skb, data_len);
			break;
		}
@@ -1107,14 +1196,13 @@ int rndis_rm_hdr(struct gether *port,
		skb_pull(skb, msg_len - sizeof *hdr);
		skb_trim(skb2, data_len);
		skb_queue_tail(list, skb2);

		num_pkts++;
	}

	if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
		rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;

	skb_queue_tail(list, skb);

	return 0;
}
EXPORT_SYMBOL_GPL(rndis_rm_hdr);
@@ -1133,7 +1221,10 @@ static int rndis_proc_show(struct seq_file *m, void *v)
			 "speed     : %d\n"
			 "cable     : %s\n"
			 "vendor ID : 0x%08X\n"
			 "vendor    : %s\n",
			 "vendor    : %s\n"
			 "ul-max-xfer-size:%zu max-xfer-size-rcvd: %d\n"
			 "ul-max-pkts-per-xfer:%d max-pkts-per-xfer-rcvd:%d\n"
			 "pkt_alignment_factor:%d\n",
			 param->confignr, (param->used) ? "y" : "n",
			 ({ char *s = "?";
			 switch (param->state) {
@@ -1147,7 +1238,14 @@ static int rndis_proc_show(struct seq_file *m, void *v)
			 param->medium,
			 (param->media_state) ? 0 : param->speed*100,
			 (param->media_state) ? "disconnected" : "connected",
			 param->vendorID, param->vendorDescr);
			 param->vendorID, param->vendorDescr,
			 param->max_pkt_per_xfer *
				 (param->dev->mtu + sizeof(struct ethhdr) +
				  sizeof(struct rndis_packet_msg_type) + 22),
			 rndis_ul_max_xfer_size_rcvd,
			 param->max_pkt_per_xfer,
			 rndis_ul_max_pkt_per_xfer_rcvd,
			 param->pkt_alignment_factor);
	return 0;
}

@@ -1239,9 +1337,11 @@ int rndis_init(void)
			return -EIO;
		}
#endif
		spin_lock_init(&(rndis_per_dev_params[i].lock));
		rndis_per_dev_params[i].confignr = i;
		rndis_per_dev_params[i].used = 0;
		rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
		rndis_per_dev_params[i].pkt_alignment_factor = 0;
		rndis_per_dev_params[i].media_state
				= RNDIS_MEDIA_STATE_DISCONNECTED;
		INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
+10 −0
Original line number Diff line number Diff line
@@ -191,10 +191,16 @@ typedef struct rndis_params

	u32			vendorID;
	u8			max_pkt_per_xfer;
	u8			pkt_alignment_factor;
	const char		*vendorDescr;
	void			(*resp_avail)(void *v);
	void			*v;
	struct list_head	resp_queue;
	spinlock_t		lock;
	u32			host_rndis_major_ver;
	u32			host_rndis_minor_ver;
	u32			ul_max_xfer_size;
	u32			dl_max_xfer_size;
} rndis_params;

/* RNDIS Message parser and other useless functions */
@@ -207,6 +213,8 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID,
			    const char *vendorDescr);
int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer);
u32  rndis_get_ul_max_xfer_size(u8 configNr);
u32  rndis_get_dl_max_xfer_size(u8 configNr);
void rndis_add_hdr (struct sk_buff *skb);
int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
			struct sk_buff_head *list);
@@ -218,5 +226,7 @@ int rndis_signal_connect (int configNr);
int  rndis_signal_disconnect (int configNr);
int  rndis_state (int configNr);
extern void rndis_set_host_mac (int configNr, const u8 *addr);
extern bool is_rndis_ipa_supported(void);
void rndis_flow_control(u8 confignr, bool enable_flow_control);

#endif  /* _LINUX_RNDIS_H */