64035ac463
Prepare for better device categorization by moving everything to testing subdir first. [skip-ci]: chicken-egg problem: passing pmaports CI depends on pmbootstrap MR depends on this MR Related: postmarketos#16
2028 lines
No EOL
61 KiB
Diff
2028 lines
No EOL
61 KiB
Diff
This patch fixes ethernet gadget/rndis support so the phone is detected as usb device
|
|
and can assign ip to the PC, as well as allow for ssh connections through usb
|
|
---
|
|
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
|
|
index 4b7e1593c787..f13fc6a58565 100644
|
|
--- a/drivers/usb/gadget/function/f_rndis.c
|
|
+++ b/drivers/usb/gadget/function/f_rndis.c
|
|
@@ -70,22 +70,6 @@
|
|
* - MS-Windows drivers sometimes emit undocumented requests.
|
|
*/
|
|
|
|
-static unsigned int rndis_dl_max_pkt_per_xfer = 10;
|
|
-module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
|
|
-MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer,
|
|
- "Maximum packets per transfer for DL aggregation");
|
|
-
|
|
-static unsigned int rndis_ul_max_pkt_per_xfer = 1;
|
|
-module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
|
|
-MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
|
|
- "Maximum packets per transfer for UL aggregation");
|
|
-
|
|
-static unsigned int f_rndis_debug;
|
|
-module_param(f_rndis_debug, uint, S_IRUGO | S_IWUSR);
|
|
-MODULE_PARM_DESC(f_rndis_debug,
|
|
- "f_rndis debug flag");
|
|
-#define F_RNDIS_DBG(fmt, args...) pr_debug("F_RNDIS,%s, " fmt, __func__, ## args)
|
|
-
|
|
struct f_rndis {
|
|
struct gether port;
|
|
u8 ctrl_id, data_id;
|
|
@@ -389,35 +373,13 @@ static struct sk_buff *rndis_add_header(struct gether *port,
|
|
struct sk_buff *skb)
|
|
{
|
|
struct sk_buff *skb2;
|
|
- struct rndis_packet_msg_type *header = NULL;
|
|
- struct f_rndis *rndis = func_to_rndis(&port->func);
|
|
-
|
|
- if (rndis->port.multi_pkt_xfer) {
|
|
- if (port->header) {
|
|
- header = port->header;
|
|
- memset(header, 0, sizeof(*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;
|
|
- }
|
|
- 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);
|
|
+ skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
|
|
+ if (skb2)
|
|
+ rndis_add_hdr(skb2);
|
|
|
|
- dev_kfree_skb(skb);
|
|
- return skb2;
|
|
- }
|
|
+ dev_kfree_skb(skb);
|
|
+ return skb2;
|
|
}
|
|
|
|
static void rndis_response_available(void *_rndis)
|
|
@@ -449,14 +411,9 @@ 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;
|
|
+ struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
|
|
int status = req->status;
|
|
|
|
- if (!rndis->port.func.config || !rndis->port.func.config->cdev)
|
|
- return;
|
|
-
|
|
- cdev = rndis->port.func.config->cdev;
|
|
-
|
|
/* after TX:
|
|
* - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
|
|
* - RNDIS_RESPONSE_AVAILABLE (status/irq)
|
|
@@ -493,14 +450,7 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
|
|
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;
|
|
-
|
|
- cdev = rndis->port.func.config->cdev;
|
|
|
|
/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
|
|
// spin_lock(&dev->lock);
|
|
@@ -508,24 +458,6 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
|
|
if (status < 0)
|
|
pr_err("RNDIS command error %d, %d/%d\n",
|
|
status, req->actual, req->length);
|
|
-
|
|
- buf = (rndis_init_msg_type *)req->buf;
|
|
-
|
|
- if (buf->MessageType == RNDIS_MSG_INIT) {
|
|
- if (buf->MaxTransferSize > 2048) {
|
|
- rndis->port.multi_pkt_xfer = 1;
|
|
- rndis->port.dl_max_transfer_len = buf->MaxTransferSize;
|
|
- gether_update_dl_max_xfer_size(&rndis->port,
|
|
- rndis->port.dl_max_transfer_len);
|
|
- } else
|
|
- rndis->port.multi_pkt_xfer = 0;
|
|
- pr_info("%s: MaxTransferSize: %d : Multi_pkt_txr: %s\n",
|
|
- __func__, buf->MaxTransferSize,
|
|
- rndis->port.multi_pkt_xfer ? "enabled" :
|
|
- "disabled");
|
|
- if (rndis_dl_max_pkt_per_xfer <= 1)
|
|
- rndis->port.multi_pkt_xfer = 0;
|
|
- }
|
|
// spin_unlock(&dev->lock);
|
|
}
|
|
|
|
@@ -543,9 +475,6 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|
/* composite driver infrastructure handles everything except
|
|
* CDC class messages; interface activation uses set_alt().
|
|
*/
|
|
- if (f_rndis_debug)
|
|
- F_RNDIS_DBG("ctrl->bRequestType:0x%x, ctrl->bRequest:0x%x, w_index:0x%x, w_value:0x%x\n",
|
|
- ctrl->bRequestType , ctrl->bRequest, w_index, w_value);
|
|
switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
|
|
|
|
/* RNDIS uses the CDC command encapsulation mechanism to implement
|
|
@@ -569,8 +498,6 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|
else {
|
|
u8 *buf;
|
|
u32 n;
|
|
- u32 MsgType, MsgLength, MsgID;
|
|
- __le32 *tmp;
|
|
|
|
/* return the result */
|
|
buf = rndis_get_next_response(rndis->config, &n);
|
|
@@ -578,19 +505,8 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|
memcpy(req->buf, buf, n);
|
|
req->complete = rndis_response_complete;
|
|
req->context = rndis;
|
|
-
|
|
- tmp = (__le32 *)buf;
|
|
- MsgType = get_unaligned_le32(tmp++);
|
|
- MsgLength = get_unaligned_le32(tmp++);
|
|
- MsgID = get_unaligned_le32(tmp++);
|
|
-
|
|
rndis_free_response(rndis->config, buf);
|
|
value = n;
|
|
-
|
|
- if (f_rndis_debug)
|
|
- F_RNDIS_DBG("response MsgLength %d, msg type:0x%x, RequestID:0x%x\n",
|
|
- MsgLength, MsgType, MsgID);
|
|
- rndis_test_last_resp_id = MsgID;
|
|
}
|
|
/* else stalls ... spec says to avoid that */
|
|
}
|
|
@@ -598,10 +514,6 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|
|
|
default:
|
|
invalid:
|
|
- F_RNDIS_DBG("invalid control req%02x.%02x v%04x i%04x l%d\n",
|
|
- ctrl->bRequestType, ctrl->bRequest,
|
|
- w_value, w_index, w_length);
|
|
-
|
|
VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
|
|
ctrl->bRequestType, ctrl->bRequest,
|
|
w_value, w_index, w_length);
|
|
@@ -630,18 +542,13 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|
struct usb_composite_dev *cdev = f->config->cdev;
|
|
|
|
/* we know alt == 0 */
|
|
- F_RNDIS_DBG("interface :%d, rndis ctrl id :%d, rndis data id :%d\n" ,
|
|
- intf, rndis->ctrl_id, rndis->data_id);
|
|
-
|
|
|
|
if (intf == rndis->ctrl_id) {
|
|
if (rndis->notify->driver_data) {
|
|
- F_RNDIS_DBG("reset rndis control %d\n", intf);
|
|
VDBG(cdev, "reset rndis control %d\n", intf);
|
|
usb_ep_disable(rndis->notify);
|
|
}
|
|
if (!rndis->notify->desc) {
|
|
- F_RNDIS_DBG("init rndis ctrl %d\n", intf);
|
|
VDBG(cdev, "init rndis ctrl %d\n", intf);
|
|
if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
|
|
goto fail;
|
|
@@ -653,13 +560,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|
struct net_device *net;
|
|
|
|
if (rndis->port.in_ep->driver_data) {
|
|
- F_RNDIS_DBG("reset rndis\n");
|
|
DBG(cdev, "reset rndis\n");
|
|
gether_disconnect(&rndis->port);
|
|
}
|
|
|
|
if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
|
|
- F_RNDIS_DBG("init rndis\n");
|
|
DBG(cdev, "init rndis\n");
|
|
if (config_ep_by_speed(cdev->gadget, f,
|
|
rndis->port.in_ep) ||
|
|
@@ -688,7 +593,7 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|
*/
|
|
rndis->port.cdc_filter = 0;
|
|
|
|
- DBG(cdev, "RNDIS RX/TX early activation ...\n");
|
|
+ DBG(cdev, "RNDIS RX/TX early activation ... \n");
|
|
net = gether_connect(&rndis->port);
|
|
if (IS_ERR(net))
|
|
return PTR_ERR(net);
|
|
@@ -711,7 +616,6 @@ static void rndis_disable(struct usb_function *f)
|
|
if (!rndis->notify->driver_data)
|
|
return;
|
|
|
|
- F_RNDIS_DBG("\n");
|
|
DBG(cdev, "rndis deactivated\n");
|
|
|
|
rndis_uninit(rndis->config);
|
|
@@ -735,7 +639,6 @@ static void rndis_open(struct gether *geth)
|
|
struct f_rndis *rndis = func_to_rndis(&geth->func);
|
|
struct usb_composite_dev *cdev = geth->func.config->cdev;
|
|
|
|
- F_RNDIS_DBG("\n");
|
|
DBG(cdev, "%s\n", __func__);
|
|
|
|
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3,
|
|
@@ -747,7 +650,6 @@ static void rndis_close(struct gether *geth)
|
|
{
|
|
struct f_rndis *rndis = func_to_rndis(&geth->func);
|
|
|
|
- F_RNDIS_DBG("\n");
|
|
DBG(geth->func.config->cdev, "%s\n", __func__);
|
|
|
|
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
|
|
@@ -776,8 +678,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|
|
|
struct f_rndis_opts *rndis_opts;
|
|
|
|
- F_RNDIS_DBG("\n");
|
|
-
|
|
if (!can_support_rndis(c))
|
|
return -EINVAL;
|
|
|
|
@@ -799,9 +699,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|
* with list_for_each_entry, so we assume no race condition
|
|
* with regard to rndis_opts->bound access
|
|
*/
|
|
-
|
|
- /* if (!rndis_opts->bound) { */
|
|
- if (rndis_opts && !rndis_opts->bound) {
|
|
+ if (!rndis_opts->bound) {
|
|
gether_set_gadget(rndis_opts->net, cdev->gadget);
|
|
status = gether_register_netdev(rndis_opts->net);
|
|
if (status)
|
|
@@ -872,11 +770,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|
rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
|
|
if (!rndis->notify_req)
|
|
goto fail;
|
|
-#if defined(CONFIG_64BIT) && defined(CONFIG_MTK_LM_MODE)
|
|
- rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL | GFP_DMA);
|
|
-#else
|
|
rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
|
|
-#endif
|
|
if (!rndis->notify_req->buf)
|
|
goto fail;
|
|
rndis->notify_req->length = STATUS_BYTECOUNT;
|
|
@@ -905,7 +799,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|
|
|
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
|
|
rndis_set_host_mac(rndis->config, rndis->ethaddr);
|
|
- rndis_set_max_pkt_xfer(rndis->config, rndis_ul_max_pkt_per_xfer);
|
|
|
|
if (rndis->manufacturer && rndis->vendorID &&
|
|
rndis_set_param_vendor(rndis->config, rndis->vendorID,
|
|
@@ -919,11 +812,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|
* until we're activated via set_alt().
|
|
*/
|
|
|
|
- F_RNDIS_DBG("RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
|
|
- gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
|
- gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
|
- rndis->port.in_ep->name, rndis->port.out_ep->name,
|
|
- rndis->notify->name);
|
|
DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
|
|
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
|
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
|
@@ -955,76 +843,6 @@ fail:
|
|
return status;
|
|
}
|
|
|
|
-static void
|
|
-rndis_old_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
-{
|
|
- struct f_rndis *rndis = func_to_rndis(f);
|
|
-
|
|
- F_RNDIS_DBG("\n");
|
|
-
|
|
- rndis_deregister(rndis->config);
|
|
-
|
|
- usb_free_all_descriptors(f);
|
|
-
|
|
- kfree(rndis->notify_req->buf);
|
|
- usb_ep_free_request(rndis->notify, rndis->notify_req);
|
|
-
|
|
- kfree(rndis);
|
|
-}
|
|
-
|
|
-int
|
|
-rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
|
- u32 vendorID, const char *manufacturer, struct eth_dev *dev)
|
|
-{
|
|
- struct f_rndis *rndis;
|
|
- int status;
|
|
-
|
|
- /* allocate and initialize one new instance */
|
|
- status = -ENOMEM;
|
|
- rndis = kzalloc(sizeof(*rndis), GFP_KERNEL);
|
|
- if (!rndis)
|
|
- goto fail;
|
|
-
|
|
- ether_addr_copy(rndis->ethaddr, ethaddr);
|
|
- rndis->vendorID = vendorID;
|
|
- rndis->manufacturer = manufacturer;
|
|
-
|
|
- rndis->port.ioport = dev;
|
|
- /* RNDIS activates when the host changes this filter */
|
|
- rndis->port.cdc_filter = 0;
|
|
-
|
|
- /* RNDIS has special (and complex) framing */
|
|
- 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 */
|
|
- rndis->port.func.bind = rndis_bind;
|
|
- /* note here use rndis_old_unbind */
|
|
- rndis->port.func.unbind = rndis_old_unbind;
|
|
- rndis->port.func.set_alt = rndis_set_alt;
|
|
- rndis->port.func.setup = rndis_setup;
|
|
- rndis->port.func.disable = rndis_disable;
|
|
-
|
|
- status = rndis_register(rndis_response_available, rndis);
|
|
- if (status < 0) {
|
|
- kfree(rndis);
|
|
- return status;
|
|
- }
|
|
- rndis->config = status;
|
|
-
|
|
- status = usb_add_function(c, &rndis->port.func);
|
|
- if (status)
|
|
- kfree(rndis);
|
|
-fail:
|
|
-
|
|
- F_RNDIS_DBG("done, status %d\n", status);
|
|
- return status;
|
|
-}
|
|
-
|
|
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)
|
|
{
|
|
struct f_rndis_opts *opts;
|
|
@@ -1139,7 +957,6 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
{
|
|
struct f_rndis *rndis = func_to_rndis(f);
|
|
|
|
- F_RNDIS_DBG("\n");
|
|
kfree(f->os_desc_table);
|
|
f->os_desc_n = 0;
|
|
usb_free_all_descriptors(f);
|
|
@@ -1176,8 +993,6 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
|
|
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 */
|
|
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
|
|
index 411ba6f934ad..95d2324f6977 100644
|
|
--- a/drivers/usb/gadget/function/rndis.c
|
|
+++ b/drivers/usb/gadget/function/rndis.c
|
|
@@ -49,7 +49,7 @@
|
|
* and will be happier if you provide the host_addr module parameter.
|
|
*/
|
|
|
|
-#if 1
|
|
+#if 0
|
|
static int rndis_debug = 0;
|
|
module_param (rndis_debug, int, 0);
|
|
MODULE_PARM_DESC (rndis_debug, "enable debugging");
|
|
@@ -59,16 +59,6 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
|
|
|
|
#define RNDIS_MAX_CONFIGS 1
|
|
|
|
-int rndis_ul_max_pkt_per_xfer_rcvd;
|
|
-module_param(rndis_ul_max_pkt_per_xfer_rcvd, int, S_IRUGO);
|
|
-MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer_rcvd,
|
|
- "Max num of REMOTE_NDIS_PACKET_MSGs received in a single transfer");
|
|
-
|
|
-int rndis_ul_max_xfer_size_rcvd;
|
|
-module_param(rndis_ul_max_xfer_size_rcvd, int, S_IRUGO);
|
|
-MODULE_PARM_DESC(rndis_ul_max_xfer_size_rcvd,
|
|
- "Max size of bus transfer received");
|
|
-
|
|
|
|
static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
|
|
|
|
@@ -168,7 +158,6 @@ static const u32 oid_supported_list[] =
|
|
#endif /* RNDIS_PM */
|
|
};
|
|
|
|
-#define RNDIS_DBG(fmt, args...) pr_debug("RNDIS,%s, " fmt, __func__, ## args)
|
|
|
|
/* NDIS Functions */
|
|
static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
@@ -206,9 +195,6 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
net = rndis_per_dev_params[configNr].dev;
|
|
stats = dev_get_stats(net, &temp);
|
|
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID is 0x%x, configNr is %d\n", OID, configNr);
|
|
-
|
|
switch (OID) {
|
|
|
|
/* general oids (table 4-1) */
|
|
@@ -271,17 +257,6 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
else
|
|
*outbuf = cpu_to_le32(
|
|
rndis_per_dev_params[configNr].speed);
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID_GEN_LINK_SPEED, speed %d, data: rx_in %lu\n"
|
|
- "rx_out %lu, rx_nomem %lu, rx_error %lu, tx_in %lu\n"
|
|
- "tx_out %lu, tx_busy %lu, tx_complete %lu, last_msg_id: 0x%x\n"
|
|
- "last_resp_id: 0x%x, RNDIS reset cnt: 0x%lu, queue stopped? %d\n",
|
|
- rndis_per_dev_params[configNr].speed, rndis_test_rx_usb_in,
|
|
- rndis_test_rx_net_out, rndis_test_rx_nomem, rndis_test_rx_error,
|
|
- rndis_test_tx_net_in, rndis_test_tx_usb_out, rndis_test_tx_busy,
|
|
- rndis_test_tx_complete, rndis_test_last_msg_id,
|
|
- rndis_test_last_resp_id, rndis_test_reset_msg_cnt,
|
|
- netif_queue_stopped(rndis_per_dev_params[configNr].dev));
|
|
retval = 0;
|
|
break;
|
|
|
|
@@ -355,9 +330,6 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
|
|
*outbuf = cpu_to_le32(rndis_per_dev_params[configNr]
|
|
.media_state);
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID_GEN_MEDIA_CONNECT_STATUS, media_state %d\n",
|
|
- rndis_per_dev_params[configNr].media_state);
|
|
retval = 0;
|
|
break;
|
|
|
|
@@ -409,8 +381,6 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
pr_debug("%s: RNDIS_OID_GEN_XMIT_ERROR\n", __func__);
|
|
if (stats) {
|
|
*outbuf = cpu_to_le32(stats->tx_errors);
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID_GEN_XMIT_ERROR, stats->tx_errors %llu\n", stats->tx_errors);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
@@ -421,8 +391,6 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
pr_debug("%s: RNDIS_OID_GEN_RCV_ERROR\n", __func__);
|
|
if (stats) {
|
|
*outbuf = cpu_to_le32(stats->rx_errors);
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID_GEN_RCV_ERROR, stats->rx_errors %llu\n", stats->rx_errors);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
@@ -432,8 +400,6 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
pr_debug("%s: RNDIS_OID_GEN_RCV_NO_BUFFER\n", __func__);
|
|
if (stats) {
|
|
*outbuf = cpu_to_le32(stats->rx_dropped);
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID_GEN_RCV_NO_BUFFER, stats->rx_dropped %llu\n", stats->rx_dropped);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
@@ -449,10 +415,6 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
rndis_per_dev_params[configNr].host_mac,
|
|
length);
|
|
retval = 0;
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID_802_3_PERMANENT_ADDRESS, host_mac is %x %x ....\n",
|
|
- rndis_per_dev_params[configNr].host_mac[0],
|
|
- rndis_per_dev_params[configNr].host_mac[1]);
|
|
}
|
|
break;
|
|
|
|
@@ -464,10 +426,6 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
memcpy(outbuf,
|
|
rndis_per_dev_params [configNr].host_mac,
|
|
length);
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID_802_3_CURRENT_ADDRESS, host_mac is %x %x ....\n",
|
|
- rndis_per_dev_params[configNr].host_mac[0],
|
|
- rndis_per_dev_params[configNr].host_mac[1]);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
@@ -500,9 +458,6 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
case RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
pr_debug("%s: RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
|
|
if (stats) {
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID_802_3_RCV_ERROR_ALIGNMENT, stats->rx_frame_errors is %llu\n",
|
|
- stats->rx_frame_errors);
|
|
*outbuf = cpu_to_le32(stats->rx_frame_errors);
|
|
retval = 0;
|
|
}
|
|
@@ -526,10 +481,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
|
|
pr_warning("%s: query unknown OID 0x%08X\n",
|
|
__func__, OID);
|
|
}
|
|
- if (retval < 0) {
|
|
+ if (retval < 0)
|
|
length = 0;
|
|
- RNDIS_DBG("bad gen_ndis_query_resp, retval is 0x%d\n", retval);
|
|
- }
|
|
|
|
resp->InformationBufferLength = cpu_to_le32(length);
|
|
r->length = length + sizeof(*resp);
|
|
@@ -561,9 +514,6 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
|
|
}
|
|
}
|
|
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("OID is 0x%x\n", OID);
|
|
-
|
|
params = &rndis_per_dev_params[configNr];
|
|
switch (OID) {
|
|
case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
|
|
@@ -606,8 +556,6 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
|
|
__func__, OID, buf_len);
|
|
}
|
|
|
|
- if (retval)
|
|
- RNDIS_DBG("retval is 0x%d\n", retval);
|
|
return retval;
|
|
}
|
|
|
|
@@ -637,12 +585,12 @@ static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
|
|
resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
|
|
resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
|
|
resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
|
|
- resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer);
|
|
- resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer *
|
|
- (params->dev->mtu
|
|
+ resp->MaxPacketsPerTransfer = cpu_to_le32(1);
|
|
+ resp->MaxTransferSize = cpu_to_le32(
|
|
+ params->dev->mtu
|
|
+ sizeof(struct ethhdr)
|
|
+ sizeof(struct rndis_packet_msg_type)
|
|
- + 22));
|
|
+ + 22);
|
|
resp->PacketAlignmentFactor = cpu_to_le32(0);
|
|
resp->AFListOffset = cpu_to_le32(0);
|
|
resp->AFListSize = cpu_to_le32(0);
|
|
@@ -669,10 +617,8 @@ static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
|
|
*/
|
|
r = rndis_add_response(configNr,
|
|
sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
|
|
- if (!r) {
|
|
- RNDIS_DBG("rndis_add_response return NULL\n");
|
|
+ if (!r)
|
|
return -ENOMEM;
|
|
- }
|
|
resp = (rndis_query_cmplt_type *)r->buf;
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C);
|
|
@@ -703,10 +649,8 @@ static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
|
|
struct rndis_params *params = rndis_per_dev_params + configNr;
|
|
|
|
r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
|
|
- if (!r) {
|
|
- RNDIS_DBG("rndis_add_response return NULL\n");
|
|
+ if (!r)
|
|
return -ENOMEM;
|
|
- }
|
|
resp = (rndis_set_cmplt_type *)r->buf;
|
|
|
|
BufLength = le32_to_cpu(buf->InformationBufferLength);
|
|
@@ -742,15 +686,6 @@ static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
|
|
rndis_reset_cmplt_type *resp;
|
|
rndis_resp_t *r;
|
|
struct rndis_params *params = rndis_per_dev_params + configNr;
|
|
- u32 length;
|
|
- u8 *xbuf;
|
|
-
|
|
- RNDIS_DBG("reset, clean old response\n");
|
|
- /* drain the response queue */
|
|
- while ((xbuf = rndis_get_next_response(configNr, &length)))
|
|
- rndis_free_response(configNr, xbuf);
|
|
-
|
|
- rndis_test_reset_msg_cnt++;
|
|
|
|
r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
|
|
if (!r)
|
|
@@ -777,10 +712,8 @@ static int rndis_keepalive_response(int configNr,
|
|
/* host "should" check only in RNDIS_DATA_INITIALIZED state */
|
|
|
|
r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type));
|
|
- if (!r) {
|
|
- RNDIS_DBG("rndis_add_response return NULL\n");
|
|
+ if (!r)
|
|
return -ENOMEM;
|
|
- }
|
|
resp = (rndis_keepalive_cmplt_type *)r->buf;
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C);
|
|
@@ -789,17 +722,6 @@ static int rndis_keepalive_response(int configNr,
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
|
|
params->resp_avail(params->v);
|
|
-
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("data: rx_in %lu\n"
|
|
- "rx_out %lu, rx_nomem %lu, rx_error %lu, tx_in %lu\n"
|
|
- "tx_out %lu, tx_busy %lu, tx_complete %lu, last_msg_id: 0x%x\n"
|
|
- "last_resp_id: 0x%x, RNDIS reset cnt: 0x%lu, queue stopped? %d\n",
|
|
- rndis_test_rx_usb_in, rndis_test_rx_net_out, rndis_test_rx_nomem, rndis_test_rx_error,
|
|
- rndis_test_tx_net_in, rndis_test_tx_usb_out, rndis_test_tx_busy,
|
|
- rndis_test_tx_complete, rndis_test_last_msg_id,
|
|
- rndis_test_last_resp_id,
|
|
- rndis_test_reset_msg_cnt, netif_queue_stopped(params->dev));
|
|
return 0;
|
|
}
|
|
|
|
@@ -876,7 +798,7 @@ EXPORT_SYMBOL_GPL(rndis_set_host_mac);
|
|
*/
|
|
int rndis_msg_parser(u8 configNr, u8 *buf)
|
|
{
|
|
- u32 MsgType, MsgLength, MsgID;
|
|
+ u32 MsgType, MsgLength;
|
|
__le32 *tmp;
|
|
struct rndis_params *params;
|
|
|
|
@@ -886,10 +808,6 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
|
|
tmp = (__le32 *)buf;
|
|
MsgType = get_unaligned_le32(tmp++);
|
|
MsgLength = get_unaligned_le32(tmp++);
|
|
- MsgID = get_unaligned_le32(tmp++);
|
|
- if (rndis_debug)
|
|
- RNDIS_DBG("MsgType is %d,configNr is %d, RequestID is 0x%x\n", MsgType, configNr, MsgID);
|
|
- rndis_test_last_msg_id = MsgID;
|
|
|
|
if (configNr >= RNDIS_MAX_CONFIGS)
|
|
return -ENOTSUPP;
|
|
@@ -949,27 +867,8 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
|
|
*/
|
|
pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
|
|
__func__, MsgType, MsgLength);
|
|
- {
|
|
- unsigned i;
|
|
-
|
|
- for (i = 0; i < MsgLength; i += 16) {
|
|
- pr_debug("%03d\n"
|
|
- "%02x %02x %02x %02x\n"
|
|
- "%02x %02x %02x %02x\n"
|
|
- "%02x %02x %02x %02x\n"
|
|
- "%02x %02x %02x %02x\n",
|
|
- i, buf[i], buf[i+1],
|
|
- buf[i+2], buf[i+3],
|
|
- buf[i+4], buf[i+5],
|
|
- buf[i+6], buf[i+7],
|
|
- buf[i+8], buf[i+9],
|
|
- buf[i+10], buf[i+11],
|
|
- buf[i+12], buf[i+13],
|
|
- buf[i+14], buf[i+15]);
|
|
- }
|
|
- }
|
|
- /* print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
|
|
- buf, MsgLength); */
|
|
+ print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
|
|
+ buf, MsgLength);
|
|
break;
|
|
}
|
|
|
|
@@ -989,7 +888,6 @@ 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;
|
|
pr_debug("%s: configNr = %d\n", __func__, i);
|
|
return i;
|
|
}
|
|
@@ -1019,8 +917,6 @@ 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;
|
|
|
|
- rndis_ul_max_xfer_size_rcvd = 0;
|
|
- rndis_ul_max_pkt_per_xfer_rcvd = 0;
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_set_param_dev);
|
|
@@ -1050,13 +946,6 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_set_param_medium);
|
|
|
|
-void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer)
|
|
-{
|
|
- pr_debug("%s:\n", __func__);
|
|
-
|
|
- rndis_per_dev_params[configNr].max_pkt_per_xfer = max_pkt_per_xfer;
|
|
-}
|
|
-
|
|
void rndis_add_hdr(struct sk_buff *skb)
|
|
{
|
|
struct rndis_packet_msg_type *header;
|
|
@@ -1080,9 +969,6 @@ void rndis_free_response(int configNr, u8 *buf)
|
|
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);
|
|
@@ -1135,73 +1021,23 @@ int rndis_rm_hdr(struct gether *port,
|
|
struct sk_buff *skb,
|
|
struct sk_buff_head *list)
|
|
{
|
|
- int num_pkts = 1;
|
|
-
|
|
- if (skb->len > rndis_ul_max_xfer_size_rcvd)
|
|
- rndis_ul_max_xfer_size_rcvd = skb->len;
|
|
-
|
|
- while (skb->len) {
|
|
- struct rndis_packet_msg_type *hdr;
|
|
- 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:%u",
|
|
- (unsigned int)(skb->len), (unsigned int)sizeof(*hdr));
|
|
- dev_kfree_skb_any(skb);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- hdr = (void *)skb->data;
|
|
- msg_len = le32_to_cpu(hdr->MessageLength);
|
|
- data_offset = le32_to_cpu(hdr->DataOffset);
|
|
- data_len = le32_to_cpu(hdr->DataLength);
|
|
-
|
|
- if (skb->len < msg_len ||
|
|
- ((data_offset + data_len + 8) > msg_len)) {
|
|
- pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
|
|
- le32_to_cpu(hdr->MessageType),
|
|
- msg_len, data_offset, data_len, skb->len);
|
|
- 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),
|
|
- msg_len, data_offset, data_len, skb->len);
|
|
- dev_kfree_skb_any(skb);
|
|
- return -EINVAL;
|
|
- }
|
|
+ /* tmp points to a struct rndis_packet_msg_type */
|
|
+ __le32 *tmp = (void *)skb->data;
|
|
|
|
- skb_pull(skb, data_offset + 8);
|
|
-
|
|
- if (msg_len == skb->len) {
|
|
- skb_trim(skb, data_len);
|
|
- break;
|
|
- }
|
|
-
|
|
- skb2 = skb_clone(skb, GFP_ATOMIC);
|
|
- if (!skb2) {
|
|
- pr_err("%s:skb clone failed\n", __func__);
|
|
- dev_kfree_skb_any(skb);
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
- skb_pull(skb, msg_len - sizeof *hdr);
|
|
- skb_trim(skb2, data_len);
|
|
- skb_queue_tail(list, skb2);
|
|
-
|
|
- num_pkts++;
|
|
+ /* MessageType, MessageLength */
|
|
+ if (cpu_to_le32(RNDIS_MSG_PACKET)
|
|
+ != get_unaligned(tmp++)) {
|
|
+ dev_kfree_skb_any(skb);
|
|
+ return -EINVAL;
|
|
}
|
|
+ tmp++;
|
|
|
|
- if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
|
|
- rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;
|
|
+ /* DataOffset, DataLength */
|
|
+ if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
|
|
+ dev_kfree_skb_any(skb);
|
|
+ return -EOVERFLOW;
|
|
+ }
|
|
+ skb_trim(skb, get_unaligned_le32(tmp++));
|
|
|
|
skb_queue_tail(list, skb);
|
|
return 0;
|
|
@@ -1222,9 +1058,7 @@ 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"
|
|
- "ul-max-xfer-size:%d max-xfer-size-rcvd: %d\n"
|
|
- "ul-max-pkts-per-xfer:%d max-pkts-per-xfer-rcvd:%d\n",
|
|
+ "vendor : %s\n",
|
|
param->confignr, (param->used) ? "y" : "n",
|
|
({ char *s = "?";
|
|
switch (param->state) {
|
|
@@ -1238,13 +1072,7 @@ 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->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->vendorID, param->vendorDescr);
|
|
return 0;
|
|
}
|
|
|
|
@@ -1307,12 +1135,13 @@ static const struct file_operations rndis_proc_fops = {
|
|
.write = rndis_proc_write,
|
|
};
|
|
|
|
-define NAME_TEMPLATE "driver/rndis-%03d"
|
|
+#define NAME_TEMPLATE "driver/rndis-%03d"
|
|
|
|
static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
|
|
|
|
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
|
|
|
|
+
|
|
int rndis_init(void)
|
|
{
|
|
u8 i;
|
|
diff --git a/drivers/usb/gadget/function/rndis.h b/drivers/usb/gadget/function/rndis.h
|
|
index 145f01b18190..0f4abb4c3775 100644
|
|
--- a/drivers/usb/gadget/function/rndis.h
|
|
+++ b/drivers/usb/gadget/function/rndis.h
|
|
@@ -190,7 +190,6 @@ typedef struct rndis_params
|
|
struct net_device *dev;
|
|
|
|
u32 vendorID;
|
|
- u8 max_pkt_per_xfer;
|
|
const char *vendorDescr;
|
|
void (*resp_avail)(void *v);
|
|
void *v;
|
|
@@ -206,7 +205,6 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
|
|
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);
|
|
void rndis_add_hdr (struct sk_buff *skb);
|
|
int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
|
|
struct sk_buff_head *list);
|
|
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
|
|
index 05cef7e1b718..33011f8ee865 100644
|
|
--- a/drivers/usb/gadget/function/u_ether.c
|
|
+++ b/drivers/usb/gadget/function/u_ether.c
|
|
@@ -23,8 +23,7 @@
|
|
#include <linux/if_vlan.h>
|
|
|
|
#include "u_ether.h"
|
|
-#include "usb_boost.h"
|
|
-#include "rndis.h"
|
|
+
|
|
|
|
/*
|
|
* This component encapsulates the Ethernet link glue needed to provide
|
|
@@ -49,9 +48,6 @@
|
|
|
|
#define UETH__VERSION "29-May-2008"
|
|
|
|
-static struct workqueue_struct *uether_wq;
|
|
-static struct workqueue_struct *uether_wq1;
|
|
-
|
|
struct eth_dev {
|
|
/* lock is held while accessing port_usb
|
|
*/
|
|
@@ -61,32 +57,21 @@ struct eth_dev {
|
|
struct net_device *net;
|
|
struct usb_gadget *gadget;
|
|
|
|
- spinlock_t req_lock; /* guard {tx}_reqs */
|
|
- spinlock_t reqrx_lock; /* guard {rx}_reqs */
|
|
+ spinlock_t req_lock; /* guard {rx,tx}_reqs */
|
|
struct list_head tx_reqs, rx_reqs;
|
|
- unsigned tx_qlen;
|
|
-/* Minimum number of TX USB request queued to UDC */
|
|
-#define TX_REQ_THRESHOLD 5
|
|
- int no_tx_req_used;
|
|
- int tx_skb_hold_count;
|
|
- u32 tx_req_bufsize;
|
|
+ atomic_t tx_qlen;
|
|
|
|
struct sk_buff_head rx_frames;
|
|
|
|
unsigned qmult;
|
|
|
|
unsigned header_len;
|
|
- unsigned ul_max_pkts_per_xfer;
|
|
- unsigned dl_max_pkts_per_xfer;
|
|
- uint32_t dl_max_xfer_size;
|
|
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
|
|
int (*unwrap)(struct gether *,
|
|
struct sk_buff *skb,
|
|
struct sk_buff_head *list);
|
|
|
|
struct work_struct work;
|
|
- struct work_struct rx_work;
|
|
- struct work_struct rx_work1;
|
|
|
|
unsigned long todo;
|
|
#define WORK_RX_MEMORY 0
|
|
@@ -102,14 +87,6 @@ struct eth_dev {
|
|
|
|
#define DEFAULT_QLEN 2 /* double buffering by default */
|
|
|
|
-static unsigned tx_wakeup_threshold = 13;
|
|
-module_param(tx_wakeup_threshold, uint, S_IRUGO|S_IWUSR);
|
|
-MODULE_PARM_DESC(tx_wakeup_threshold, "tx wakeup threshold value");
|
|
-
|
|
-#define U_ETHER_RX_PENDING_TSHOLD 100
|
|
-static unsigned int u_ether_rx_pending_thld = U_ETHER_RX_PENDING_TSHOLD;
|
|
-module_param(u_ether_rx_pending_thld, uint, S_IRUGO | S_IWUSR);
|
|
-
|
|
/* for dual-speed hardware, use deeper queues at high/super speed */
|
|
static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
|
|
{
|
|
@@ -156,23 +133,6 @@ static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
|
|
xprintk(dev , KERN_INFO , fmt , ## args)
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
-unsigned int rndis_test_last_resp_id;
|
|
-unsigned int rndis_test_last_msg_id;
|
|
-
|
|
-unsigned long rndis_test_reset_msg_cnt;
|
|
-
|
|
-unsigned long rndis_test_rx_usb_in;
|
|
-unsigned long rndis_test_rx_net_out;
|
|
-unsigned long rndis_test_rx_nomem;
|
|
-unsigned long rndis_test_rx_error;
|
|
-
|
|
-unsigned long rndis_test_tx_net_in;
|
|
-unsigned long rndis_test_tx_busy;
|
|
-unsigned long rndis_test_tx_stop;
|
|
-
|
|
-unsigned long rndis_test_tx_usb_out;
|
|
-unsigned long rndis_test_tx_complete;
|
|
-#define U_ETHER_DBG(fmt, args...) pr_debug("U_ETHER,%s, " fmt, __func__, ## args)
|
|
|
|
/* NETWORK DRIVER HOOKUP (to the layer above this driver) */
|
|
|
|
@@ -191,7 +151,6 @@ static int ueth_change_mtu(struct net_device *net, int new_mtu)
|
|
else
|
|
net->mtu = new_mtu;
|
|
spin_unlock_irqrestore(&dev->lock, flags);
|
|
- U_ETHER_DBG("mtu to %d, status is %d\n", new_mtu , status);
|
|
|
|
return status;
|
|
}
|
|
@@ -228,7 +187,6 @@ static void defer_kevent(struct eth_dev *dev, int flag)
|
|
}
|
|
|
|
static void rx_complete(struct usb_ep *ep, struct usb_request *req);
|
|
-static void tx_complete(struct usb_ep *ep, struct usb_request *req);
|
|
|
|
static int
|
|
rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
|
@@ -267,18 +225,12 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
|
size += out->maxpacket - 1;
|
|
size -= size % out->maxpacket;
|
|
|
|
- if (dev->ul_max_pkts_per_xfer)
|
|
- size *= dev->ul_max_pkts_per_xfer;
|
|
-
|
|
if (dev->port_usb->is_fixed)
|
|
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
|
|
|
|
- U_ETHER_DBG("size:%d, mtu:%d, hdr_len:%d, maxpacket:%d, ul_max_pkts_per_xfer:%d",
|
|
- (int)size, dev->net->mtu, dev->port_usb->header_len, out->maxpacket, dev->ul_max_pkts_per_xfer);
|
|
skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
|
|
if (skb == NULL) {
|
|
- U_ETHER_DBG("no rx skb\n");
|
|
- rndis_test_rx_nomem++;
|
|
+ DBG(dev, "no rx skb\n");
|
|
goto enomem;
|
|
}
|
|
|
|
@@ -290,6 +242,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
|
|
|
req->buf = skb->data;
|
|
req->length = size;
|
|
+ req->complete = rx_complete;
|
|
req->context = skb;
|
|
|
|
retval = usb_ep_queue(out, req, gfp_flags);
|
|
@@ -300,22 +253,23 @@ enomem:
|
|
DBG(dev, "rx submit --> %d\n", retval);
|
|
if (skb)
|
|
dev_kfree_skb_any(skb);
|
|
+ spin_lock_irqsave(&dev->req_lock, flags);
|
|
+ list_add(&req->list, &dev->rx_reqs);
|
|
+ spin_unlock_irqrestore(&dev->req_lock, flags);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
static void rx_complete(struct usb_ep *ep, struct usb_request *req)
|
|
{
|
|
- struct sk_buff *skb = req->context;
|
|
+ struct sk_buff *skb = req->context, *skb2;
|
|
struct eth_dev *dev = ep->driver_data;
|
|
int status = req->status;
|
|
- bool queue = 0;
|
|
|
|
switch (status) {
|
|
|
|
/* normal completion */
|
|
case 0:
|
|
- U_ETHER_DBG("len(%d)\n", req->actual);
|
|
skb_put(skb, req->actual);
|
|
|
|
if (dev->unwrap) {
|
|
@@ -326,10 +280,6 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
|
|
status = dev->unwrap(dev->port_usb,
|
|
skb,
|
|
&dev->rx_frames);
|
|
- if (status == -EINVAL)
|
|
- dev->net->stats.rx_errors++;
|
|
- else if (status == -EOVERFLOW)
|
|
- dev->net->stats.rx_over_errors++;
|
|
} else {
|
|
dev_kfree_skb_any(skb);
|
|
status = -ENOTCONN;
|
|
@@ -338,10 +288,30 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
|
|
} else {
|
|
skb_queue_tail(&dev->rx_frames, skb);
|
|
}
|
|
+ skb = NULL;
|
|
+
|
|
+ skb2 = skb_dequeue(&dev->rx_frames);
|
|
+ while (skb2) {
|
|
+ if (status < 0
|
|
+ || ETH_HLEN > skb2->len
|
|
+ || skb2->len > VLAN_ETH_FRAME_LEN) {
|
|
+ dev->net->stats.rx_errors++;
|
|
+ dev->net->stats.rx_length_errors++;
|
|
+ DBG(dev, "rx length %d\n", skb2->len);
|
|
+ dev_kfree_skb_any(skb2);
|
|
+ goto next_frame;
|
|
+ }
|
|
+ skb2->protocol = eth_type_trans(skb2, dev->net);
|
|
+ dev->net->stats.rx_packets++;
|
|
+ dev->net->stats.rx_bytes += skb2->len;
|
|
|
|
- if (!status)
|
|
- queue = 1;
|
|
- rndis_test_rx_usb_in++;
|
|
+ /* no buffer copies needed, unless hardware can't
|
|
+ * use skb buffers.
|
|
+ */
|
|
+ status = netif_rx(skb2);
|
|
+next_frame:
|
|
+ skb2 = skb_dequeue(&dev->rx_frames);
|
|
+ }
|
|
break;
|
|
|
|
/* software-driven interface shutdown */
|
|
@@ -364,37 +334,28 @@ quiesce:
|
|
/* FALLTHROUGH */
|
|
|
|
default:
|
|
- queue = 1;
|
|
- dev_kfree_skb_any(skb);
|
|
dev->net->stats.rx_errors++;
|
|
DBG(dev, "rx status %d\n", status);
|
|
break;
|
|
}
|
|
|
|
+ if (skb)
|
|
+ dev_kfree_skb_any(skb);
|
|
+ if (!netif_running(dev->net)) {
|
|
clean:
|
|
- if (queue && dev->rx_frames.qlen <= u_ether_rx_pending_thld) {
|
|
- if (rx_submit(dev, req, GFP_ATOMIC) < 0) {
|
|
- spin_lock(&dev->reqrx_lock);
|
|
- list_add(&req->list, &dev->rx_reqs);
|
|
- spin_unlock(&dev->reqrx_lock);
|
|
- }
|
|
- } else {
|
|
- spin_lock(&dev->reqrx_lock);
|
|
+ spin_lock(&dev->req_lock);
|
|
list_add(&req->list, &dev->rx_reqs);
|
|
- spin_unlock(&dev->reqrx_lock);
|
|
- }
|
|
-
|
|
- if (queue) {
|
|
- queue_work(uether_wq, &dev->rx_work);
|
|
- queue_work(uether_wq1, &dev->rx_work1);
|
|
+ spin_unlock(&dev->req_lock);
|
|
+ req = NULL;
|
|
}
|
|
+ if (req)
|
|
+ rx_submit(dev, req, GFP_ATOMIC);
|
|
}
|
|
|
|
static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
|
|
{
|
|
unsigned i;
|
|
struct usb_request *req;
|
|
- bool usb_in;
|
|
|
|
if (!n)
|
|
return -ENOMEM;
|
|
@@ -405,21 +366,10 @@ static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
|
|
if (i-- == 0)
|
|
goto extra;
|
|
}
|
|
-
|
|
- if (ep->desc->bEndpointAddress & USB_DIR_IN)
|
|
- usb_in = true;
|
|
- else
|
|
- usb_in = false;
|
|
-
|
|
while (i--) {
|
|
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
|
if (!req)
|
|
return list_empty(list) ? -ENOMEM : 0;
|
|
- /* update completion handler */
|
|
- if (usb_in)
|
|
- req->complete = tx_complete;
|
|
- else
|
|
- req->complete = rx_complete;
|
|
list_add(&req->list, list);
|
|
}
|
|
return 0;
|
|
@@ -447,22 +397,16 @@ static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n)
|
|
|
|
spin_lock(&dev->req_lock);
|
|
status = prealloc(&dev->tx_reqs, link->in_ep, n);
|
|
- if (status < 0) {
|
|
- spin_unlock(&dev->req_lock);
|
|
- U_ETHER_DBG("can't alloc tx requests\n");
|
|
- return status;
|
|
- }
|
|
- spin_unlock(&dev->req_lock);
|
|
-
|
|
- spin_lock(&dev->reqrx_lock);
|
|
+ if (status < 0)
|
|
+ goto fail;
|
|
status = prealloc(&dev->rx_reqs, link->out_ep, n);
|
|
- if (status < 0) {
|
|
- spin_unlock(&dev->reqrx_lock);
|
|
- U_ETHER_DBG("can't alloc rx requests\n");
|
|
- return status;
|
|
- }
|
|
- spin_unlock(&dev->reqrx_lock);
|
|
-
|
|
+ if (status < 0)
|
|
+ goto fail;
|
|
+ goto done;
|
|
+fail:
|
|
+ DBG(dev, "can't alloc requests\n");
|
|
+done:
|
|
+ spin_unlock(&dev->req_lock);
|
|
return status;
|
|
}
|
|
|
|
@@ -470,69 +414,23 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
|
|
{
|
|
struct usb_request *req;
|
|
unsigned long flags;
|
|
- int req_cnt = 0;
|
|
|
|
/* fill unused rxq slots with some skb */
|
|
- spin_lock_irqsave(&dev->reqrx_lock, flags);
|
|
+ spin_lock_irqsave(&dev->req_lock, flags);
|
|
while (!list_empty(&dev->rx_reqs)) {
|
|
- /* break the nexus of continuous completion and re-submission*/
|
|
- if (++req_cnt > qlen(dev->gadget, dev->qmult))
|
|
- break;
|
|
-
|
|
req = container_of(dev->rx_reqs.next,
|
|
struct usb_request, list);
|
|
list_del_init(&req->list);
|
|
- spin_unlock_irqrestore(&dev->reqrx_lock, flags);
|
|
+ spin_unlock_irqrestore(&dev->req_lock, flags);
|
|
|
|
if (rx_submit(dev, req, gfp_flags) < 0) {
|
|
- spin_lock_irqsave(&dev->reqrx_lock, flags);
|
|
- list_add(&req->list, &dev->rx_reqs);
|
|
- spin_unlock_irqrestore(&dev->reqrx_lock, flags);
|
|
defer_kevent(dev, WORK_RX_MEMORY);
|
|
return;
|
|
}
|
|
|
|
- spin_lock_irqsave(&dev->reqrx_lock, flags);
|
|
- }
|
|
- spin_unlock_irqrestore(&dev->reqrx_lock, flags);
|
|
-}
|
|
-
|
|
-static void process_rx_w(struct work_struct *work)
|
|
-{
|
|
- struct eth_dev *dev = container_of(work, struct eth_dev, rx_work);
|
|
- struct sk_buff *skb;
|
|
- int status = 0;
|
|
-
|
|
- if (!dev->port_usb)
|
|
- return;
|
|
-
|
|
- while ((skb = skb_dequeue(&dev->rx_frames))) {
|
|
- if (status < 0
|
|
- || ETH_HLEN > skb->len
|
|
- || skb->len > ETH_FRAME_LEN) {
|
|
- dev->net->stats.rx_errors++;
|
|
- dev->net->stats.rx_length_errors++;
|
|
- rndis_test_rx_error++;
|
|
- DBG(dev, "rx length %d\n", skb->len);
|
|
- dev_kfree_skb_any(skb);
|
|
- continue;
|
|
- }
|
|
- skb->protocol = eth_type_trans(skb, dev->net);
|
|
- dev->net->stats.rx_packets++;
|
|
- dev->net->stats.rx_bytes += skb->len;
|
|
-#if defined(NETDEV_TRACE) && defined(NETDEV_UL_TRACE)
|
|
- skb->dbg_flag = 0x4;
|
|
-#endif
|
|
-
|
|
- rndis_test_rx_net_out++;
|
|
- status = netif_rx_ni(skb);
|
|
+ spin_lock_irqsave(&dev->req_lock, flags);
|
|
}
|
|
-
|
|
-/* move to another workthread */
|
|
-#if 0
|
|
- if (netif_running(dev->net))
|
|
- rx_fill(dev, GFP_KERNEL);
|
|
-#endif
|
|
+ spin_unlock_irqrestore(&dev->req_lock, flags);
|
|
}
|
|
|
|
static void eth_work(struct work_struct *work)
|
|
@@ -548,39 +446,10 @@ static void eth_work(struct work_struct *work)
|
|
DBG(dev, "work done, flags = 0x%lx\n", dev->todo);
|
|
}
|
|
|
|
-static void process_rx_w1(struct work_struct *work)
|
|
-{
|
|
- struct eth_dev *dev = container_of(work, struct eth_dev, rx_work1);
|
|
-
|
|
- if (!dev->port_usb)
|
|
- return;
|
|
-
|
|
- if (netif_running(dev->net))
|
|
- rx_fill(dev, GFP_KERNEL);
|
|
-}
|
|
-
|
|
static void tx_complete(struct usb_ep *ep, struct usb_request *req)
|
|
{
|
|
- struct sk_buff *skb;
|
|
- struct eth_dev *dev;
|
|
- struct net_device *net;
|
|
- struct usb_request *new_req;
|
|
- struct usb_ep *in;
|
|
- int length;
|
|
- int retval;
|
|
-
|
|
- if (!ep->driver_data) {
|
|
- usb_ep_free_request(ep, req);
|
|
- return;
|
|
- }
|
|
-
|
|
- dev = ep->driver_data;
|
|
- net = dev->net;
|
|
-
|
|
- if (!dev->port_usb) {
|
|
- usb_ep_free_request(ep, req);
|
|
- return;
|
|
- }
|
|
+ struct sk_buff *skb = req->context;
|
|
+ struct eth_dev *dev = ep->driver_data;
|
|
|
|
switch (req->status) {
|
|
default:
|
|
@@ -591,104 +460,18 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
|
|
case -ESHUTDOWN: /* disconnect etc */
|
|
break;
|
|
case 0:
|
|
- if (!req->zero)
|
|
- dev->net->stats.tx_bytes += req->length-1;
|
|
- else
|
|
- dev->net->stats.tx_bytes += req->length;
|
|
+ dev->net->stats.tx_bytes += skb->len;
|
|
}
|
|
dev->net->stats.tx_packets++;
|
|
- rndis_test_tx_complete++;
|
|
|
|
spin_lock(&dev->req_lock);
|
|
- list_add_tail(&req->list, &dev->tx_reqs);
|
|
-
|
|
- if (dev->port_usb->multi_pkt_xfer && !req->context) {
|
|
- dev->no_tx_req_used--;
|
|
- req->length = 0;
|
|
- in = dev->port_usb->in_ep;
|
|
-
|
|
- if (!list_empty(&dev->tx_reqs)) {
|
|
- new_req = container_of(dev->tx_reqs.next,
|
|
- struct usb_request, list);
|
|
- list_del(&new_req->list);
|
|
- spin_unlock(&dev->req_lock);
|
|
- if (new_req->length > 0) {
|
|
- length = new_req->length;
|
|
-
|
|
- /* NCM requires no zlp if transfer is
|
|
- * dwNtbInMaxSize */
|
|
- if (dev->port_usb->is_fixed &&
|
|
- length == dev->port_usb->fixed_in_len &&
|
|
- (length % in->maxpacket) == 0)
|
|
- new_req->zero = 0;
|
|
- else
|
|
- new_req->zero = 1;
|
|
-
|
|
- /* use zlp framing on tx for strict CDC-Ether
|
|
- * conformance, though any robust network rx
|
|
- * path ignores extra padding. and some hardware
|
|
- * doesn't like to write zlps.
|
|
- */
|
|
- if (new_req->zero && !dev->zlp &&
|
|
- (length % in->maxpacket) == 0) {
|
|
- new_req->zero = 0;
|
|
- length++;
|
|
- }
|
|
-
|
|
- new_req->length = length;
|
|
- retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
|
|
- switch (retval) {
|
|
- default:
|
|
- DBG(dev, "tx queue err %d\n", retval);
|
|
- new_req->length = 0;
|
|
- spin_lock(&dev->req_lock);
|
|
- list_add_tail(&new_req->list, &dev->tx_reqs);
|
|
- spin_unlock(&dev->req_lock);
|
|
- break;
|
|
- case 0:
|
|
- spin_lock(&dev->req_lock);
|
|
- dev->no_tx_req_used++;
|
|
- spin_unlock(&dev->req_lock);
|
|
- net->trans_start = jiffies;
|
|
- }
|
|
- } else {
|
|
- spin_lock(&dev->req_lock);
|
|
- /*
|
|
- * Put the idle request at the back of the
|
|
- * queue. The xmit function will put the
|
|
- * unfinished request at the beginning of the
|
|
- * queue.
|
|
- */
|
|
- list_add_tail(&new_req->list, &dev->tx_reqs);
|
|
- spin_unlock(&dev->req_lock);
|
|
- }
|
|
- } else {
|
|
- spin_unlock(&dev->req_lock);
|
|
- }
|
|
- } else {
|
|
- skb = req->context;
|
|
- /* Is aggregation already enabled and buffers allocated ? */
|
|
- if (dev->port_usb->multi_pkt_xfer && dev->tx_req_bufsize) {
|
|
-#if defined(CONFIG_64BIT) && defined(CONFIG_MTK_LM_MODE)
|
|
- req->buf = kzalloc(dev->tx_req_bufsize, GFP_ATOMIC | GFP_DMA);
|
|
-#else
|
|
- req->buf = kzalloc(dev->tx_req_bufsize, GFP_ATOMIC);
|
|
-#endif
|
|
- req->context = NULL;
|
|
- } else {
|
|
- req->buf = NULL;
|
|
- }
|
|
-
|
|
- spin_unlock(&dev->req_lock);
|
|
- dev_kfree_skb_any(skb);
|
|
- }
|
|
+ list_add(&req->list, &dev->tx_reqs);
|
|
+ spin_unlock(&dev->req_lock);
|
|
+ dev_kfree_skb_any(skb);
|
|
|
|
- if (netif_carrier_ok(dev->net)) {
|
|
- spin_lock(&dev->req_lock);
|
|
- if (dev->no_tx_req_used < tx_wakeup_threshold)
|
|
- netif_wake_queue(dev->net);
|
|
- spin_unlock(&dev->req_lock);
|
|
- }
|
|
+ atomic_dec(&dev->tx_qlen);
|
|
+ if (netif_carrier_ok(dev->net))
|
|
+ netif_wake_queue(dev->net);
|
|
}
|
|
|
|
static inline int is_promisc(u16 cdc_filter)
|
|
@@ -696,47 +479,6 @@ static inline int is_promisc(u16 cdc_filter)
|
|
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
|
|
}
|
|
|
|
-static int alloc_tx_buffer(struct eth_dev *dev)
|
|
-{
|
|
- struct list_head *act;
|
|
- struct usb_request *req;
|
|
-
|
|
- dev->tx_req_bufsize = (dev->dl_max_pkts_per_xfer *
|
|
- (dev->net->mtu
|
|
- + sizeof(struct ethhdr)
|
|
- /* size of rndis_packet_msg_type */
|
|
- + 44
|
|
- + 22));
|
|
-
|
|
- list_for_each(act, &dev->tx_reqs) {
|
|
- req = container_of(act, struct usb_request, list);
|
|
- if (!req->buf) {
|
|
-#if defined(CONFIG_64BIT) && defined(CONFIG_MTK_LM_MODE)
|
|
- req->buf = kzalloc(dev->tx_req_bufsize,
|
|
- GFP_ATOMIC | GFP_DMA);
|
|
-#else
|
|
- req->buf = kzalloc(dev->tx_req_bufsize,
|
|
- GFP_ATOMIC);
|
|
-#endif
|
|
- if (!req->buf)
|
|
- goto free_buf;
|
|
- }
|
|
- /* req->context is not used for multi_pkt_xfers */
|
|
- req->context = NULL;
|
|
- }
|
|
- return 0;
|
|
-
|
|
-free_buf:
|
|
- /* tx_req_bufsize = 0 retries mem alloc on next eth_start_xmit */
|
|
- dev->tx_req_bufsize = 0;
|
|
- list_for_each(act, &dev->tx_reqs) {
|
|
- req = container_of(act, struct usb_request, list);
|
|
- kfree(req->buf);
|
|
- req->buf = NULL;
|
|
- }
|
|
- return -ENOMEM;
|
|
-}
|
|
-
|
|
static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
|
struct net_device *net)
|
|
{
|
|
@@ -745,20 +487,16 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
|
int retval;
|
|
struct usb_request *req = NULL;
|
|
unsigned long flags;
|
|
- struct usb_ep *in = NULL;
|
|
- u16 cdc_filter = 0;
|
|
- bool multi_pkt_xfer = false;
|
|
- uint32_t max_size = 0;
|
|
- static unsigned int okCnt, busyCnt;
|
|
- static DEFINE_RATELIMIT_STATE(ratelimit1, 1 * HZ, 2);
|
|
- static DEFINE_RATELIMIT_STATE(ratelimit2, 1 * HZ, 2);
|
|
+ struct usb_ep *in;
|
|
+ u16 cdc_filter;
|
|
|
|
spin_lock_irqsave(&dev->lock, flags);
|
|
if (dev->port_usb) {
|
|
in = dev->port_usb->in_ep;
|
|
cdc_filter = dev->port_usb->cdc_filter;
|
|
- multi_pkt_xfer = dev->port_usb->multi_pkt_xfer;
|
|
- max_size = dev->dl_max_xfer_size;
|
|
+ } else {
|
|
+ in = NULL;
|
|
+ cdc_filter = 0;
|
|
}
|
|
spin_unlock_irqrestore(&dev->lock, flags);
|
|
|
|
@@ -767,7 +505,6 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
|
return NETDEV_TX_OK;
|
|
}
|
|
|
|
-
|
|
/* apply outgoing CDC or RNDIS filters */
|
|
if (skb && !is_promisc(cdc_filter)) {
|
|
u8 *dest = skb->data;
|
|
@@ -784,122 +521,57 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
|
type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
|
|
if (!(cdc_filter & type)) {
|
|
dev_kfree_skb_any(skb);
|
|
- U_ETHER_DBG("cdc_filter error, cdc_filter is 0x%x , type is 0x%x\n",
|
|
- cdc_filter , type);
|
|
return NETDEV_TX_OK;
|
|
}
|
|
}
|
|
/* ignores USB_CDC_PACKET_TYPE_DIRECTED */
|
|
}
|
|
- /*
|
|
- * No buffer copies needed, unless the network stack did it
|
|
- * or the hardware can't use skb buffers or there's not enough
|
|
- * enough space for extra headers we need.
|
|
- */
|
|
- spin_lock_irqsave(&dev->lock, flags);
|
|
- if (dev->wrap && dev->port_usb)
|
|
- skb = dev->wrap(dev->port_usb, skb);
|
|
- spin_unlock_irqrestore(&dev->lock, flags);
|
|
-
|
|
- if (!skb) {
|
|
- if (!dev->port_usb->supports_multi_frame)
|
|
- dev->net->stats.tx_dropped++;
|
|
- /* no error code for dropped packets */
|
|
- return NETDEV_TX_OK;
|
|
- }
|
|
|
|
spin_lock_irqsave(&dev->req_lock, flags);
|
|
- /* Allocate memory for tx_reqs to support multi packet transfer */
|
|
- if (multi_pkt_xfer && !dev->tx_req_bufsize) {
|
|
- retval = alloc_tx_buffer(dev);
|
|
- if (retval < 0) {
|
|
- spin_unlock_irqrestore(&dev->req_lock, flags);
|
|
- return -ENOMEM;
|
|
- }
|
|
- }
|
|
- if (__ratelimit(&ratelimit1)) {
|
|
- usb_boost();
|
|
- U_ETHER_DBG("spd %d,ms %d,rin %lu,rout %lu,rxmem %lu,rxerr %lu\n"
|
|
- "tin %lu,tout %lu,tb %lu,ts %lu,tx_com %lu,lmsg: 0x%x,lrsp:0x%x,rst:%lu\n",
|
|
- dev->gadget->speed, max_size, rndis_test_rx_usb_in, rndis_test_rx_net_out,
|
|
- rndis_test_rx_nomem, rndis_test_rx_error, rndis_test_tx_net_in,
|
|
- rndis_test_tx_usb_out, rndis_test_tx_busy, rndis_test_tx_stop,
|
|
- rndis_test_tx_complete, rndis_test_last_msg_id, rndis_test_last_resp_id,
|
|
- rndis_test_reset_msg_cnt);
|
|
- }
|
|
- rndis_test_tx_net_in++;
|
|
/*
|
|
* this freelist can be empty if an interrupt triggered disconnect()
|
|
* and reconfigured the gadget (shutting down this queue) after the
|
|
* network stack decided to xmit but before we got the spinlock.
|
|
*/
|
|
if (list_empty(&dev->tx_reqs)) {
|
|
- busyCnt++;
|
|
- if (__ratelimit(&ratelimit2))
|
|
- U_ETHER_DBG("okCnt : %u, busyCnt : %u\n",
|
|
- okCnt, busyCnt);
|
|
spin_unlock_irqrestore(&dev->req_lock, flags);
|
|
- rndis_test_tx_busy++;
|
|
return NETDEV_TX_BUSY;
|
|
}
|
|
- okCnt++;
|
|
|
|
req = container_of(dev->tx_reqs.next, struct usb_request, list);
|
|
list_del(&req->list);
|
|
|
|
/* temporarily stop TX queue when the freelist empties */
|
|
- if (list_empty(&dev->tx_reqs)) {
|
|
- rndis_test_tx_stop++;
|
|
+ if (list_empty(&dev->tx_reqs))
|
|
netif_stop_queue(net);
|
|
- }
|
|
spin_unlock_irqrestore(&dev->req_lock, flags);
|
|
|
|
- if (dev->port_usb == NULL) {
|
|
- dev_kfree_skb_any(skb);
|
|
- U_ETHER_DBG("port_usb NULL\n");
|
|
- return NETDEV_TX_OK;
|
|
- }
|
|
-
|
|
- if (multi_pkt_xfer) {
|
|
- pr_debug("req->length:%d header_len:%u\n"
|
|
- "skb->len:%d skb->data_len:%d\n",
|
|
- req->length, dev->header_len,
|
|
- skb->len, skb->data_len);
|
|
- /* Add RNDIS Header */
|
|
- memcpy(req->buf + req->length, dev->port_usb->header,
|
|
- dev->header_len);
|
|
- /* Increment req length by header size */
|
|
- req->length += dev->header_len;
|
|
- /* Copy received IP data from SKB */
|
|
- memcpy(req->buf + req->length, skb->data, skb->len);
|
|
- /* Increment req length by skb data length */
|
|
- req->length += skb->len;
|
|
- length = req->length;
|
|
- dev_kfree_skb_any(skb);
|
|
-
|
|
- spin_lock_irqsave(&dev->req_lock, flags);
|
|
- dev->tx_skb_hold_count++;
|
|
- /* if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) { */
|
|
- if ((dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer)
|
|
- && (length < (max_size - dev->net->mtu))) {
|
|
-
|
|
- if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
|
|
- list_add(&req->list, &dev->tx_reqs);
|
|
- spin_unlock_irqrestore(&dev->req_lock, flags);
|
|
- goto success;
|
|
- }
|
|
+ /* no buffer copies needed, unless the network stack did it
|
|
+ * or the hardware can't use skb buffers.
|
|
+ * or there's not enough space for extra headers we need
|
|
+ */
|
|
+ if (dev->wrap) {
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&dev->lock, flags);
|
|
+ if (dev->port_usb)
|
|
+ skb = dev->wrap(dev->port_usb, skb);
|
|
+ spin_unlock_irqrestore(&dev->lock, flags);
|
|
+ if (!skb) {
|
|
+ /* Multi frame CDC protocols may store the frame for
|
|
+ * later which is not a dropped frame.
|
|
+ */
|
|
+ if (dev->port_usb->supports_multi_frame)
|
|
+ goto multiframe;
|
|
+ goto drop;
|
|
}
|
|
-
|
|
- dev->no_tx_req_used++;
|
|
- dev->tx_skb_hold_count = 0;
|
|
- spin_unlock_irqrestore(&dev->req_lock, flags);
|
|
-
|
|
- } else {
|
|
- length = skb->len;
|
|
- req->buf = skb->data;
|
|
- req->context = skb;
|
|
}
|
|
|
|
+ length = skb->len;
|
|
+ req->buf = skb->data;
|
|
+ req->context = skb;
|
|
+ req->complete = tx_complete;
|
|
+
|
|
/* NCM requires no zlp if transfer is dwNtbInMaxSize */
|
|
if (dev->port_usb->is_fixed &&
|
|
length == dev->port_usb->fixed_in_len &&
|
|
@@ -912,36 +584,32 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
|
* though any robust network rx path ignores extra padding.
|
|
* and some hardware doesn't like to write zlps.
|
|
*/
|
|
- if (req->zero && !dev->zlp && (length % in->maxpacket) == 0) {
|
|
- req->zero = 0;
|
|
+ if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
|
|
length++;
|
|
- }
|
|
|
|
req->length = length;
|
|
|
|
retval = usb_ep_queue(in, req, GFP_ATOMIC);
|
|
switch (retval) {
|
|
default:
|
|
- U_ETHER_DBG("tx queue err %d\n", retval);
|
|
+ DBG(dev, "tx queue err %d\n", retval);
|
|
break;
|
|
case 0:
|
|
- rndis_test_tx_usb_out++;
|
|
net->trans_start = jiffies;
|
|
+ atomic_inc(&dev->tx_qlen);
|
|
}
|
|
|
|
if (retval) {
|
|
- if (!multi_pkt_xfer)
|
|
- dev_kfree_skb_any(skb);
|
|
- else
|
|
- req->length = 0;
|
|
+ dev_kfree_skb_any(skb);
|
|
+drop:
|
|
dev->net->stats.tx_dropped++;
|
|
+multiframe:
|
|
spin_lock_irqsave(&dev->req_lock, flags);
|
|
if (list_empty(&dev->tx_reqs))
|
|
netif_start_queue(net);
|
|
- list_add_tail(&req->list, &dev->tx_reqs);
|
|
+ list_add(&req->list, &dev->tx_reqs);
|
|
spin_unlock_irqrestore(&dev->req_lock, flags);
|
|
}
|
|
-success:
|
|
return NETDEV_TX_OK;
|
|
}
|
|
|
|
@@ -949,13 +617,13 @@ success:
|
|
|
|
static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
|
|
{
|
|
- U_ETHER_DBG("\n");
|
|
+ DBG(dev, "%s\n", __func__);
|
|
|
|
/* fill the rx queue */
|
|
rx_fill(dev, gfp_flags);
|
|
|
|
/* and open the tx floodgates */
|
|
- dev->tx_qlen = 0;
|
|
+ atomic_set(&dev->tx_qlen, 0);
|
|
netif_wake_queue(dev->net);
|
|
}
|
|
|
|
@@ -964,7 +632,7 @@ static int eth_open(struct net_device *net)
|
|
struct eth_dev *dev = netdev_priv(net);
|
|
struct gether *link;
|
|
|
|
- U_ETHER_DBG("\n");
|
|
+ DBG(dev, "%s\n", __func__);
|
|
if (netif_carrier_ok(dev->net))
|
|
eth_start(dev, GFP_KERNEL);
|
|
|
|
@@ -982,7 +650,7 @@ static int eth_stop(struct net_device *net)
|
|
struct eth_dev *dev = netdev_priv(net);
|
|
unsigned long flags;
|
|
|
|
- U_ETHER_DBG("\n");
|
|
+ VDBG(dev, "%s\n", __func__);
|
|
netif_stop_queue(net);
|
|
|
|
DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
|
|
@@ -1028,7 +696,6 @@ static int eth_stop(struct net_device *net)
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
-
|
|
static int get_ether_addr(const char *str, u8 *dev_addr)
|
|
{
|
|
if (str) {
|
|
@@ -1060,20 +727,6 @@ static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len)
|
|
dev_addr[3], dev_addr[4], dev_addr[5]);
|
|
return 18;
|
|
}
|
|
-/* defined but not used due to MAC customization */
|
|
-#if 0
|
|
-static u8 host_ethaddr[ETH_ALEN];
|
|
-static int get_host_ether_addr(u8 *str, u8 *dev_addr)
|
|
-{
|
|
- memcpy(dev_addr, str, ETH_ALEN);
|
|
- if (is_valid_ether_addr(dev_addr))
|
|
- return 0;
|
|
-
|
|
- random_ether_addr(dev_addr);
|
|
- memcpy(str, dev_addr, ETH_ALEN);
|
|
- return 1;
|
|
-}
|
|
-#endif
|
|
|
|
static const struct net_device_ops eth_netdev_ops = {
|
|
.ndo_open = eth_open,
|
|
@@ -1117,10 +770,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
|
|
dev = netdev_priv(net);
|
|
spin_lock_init(&dev->lock);
|
|
spin_lock_init(&dev->req_lock);
|
|
- spin_lock_init(&dev->reqrx_lock);
|
|
INIT_WORK(&dev->work, eth_work);
|
|
- INIT_WORK(&dev->rx_work, process_rx_w);
|
|
- INIT_WORK(&dev->rx_work1, process_rx_w1);
|
|
INIT_LIST_HEAD(&dev->tx_reqs);
|
|
INIT_LIST_HEAD(&dev->rx_reqs);
|
|
|
|
@@ -1134,7 +784,6 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
|
|
if (get_ether_addr(dev_addr, net->dev_addr))
|
|
dev_warn(&g->dev,
|
|
"using random %s ethernet address\n", "self");
|
|
-
|
|
if (get_ether_addr(host_addr, dev->host_mac))
|
|
dev_warn(&g->dev,
|
|
"using random %s ethernet address\n", "host");
|
|
@@ -1184,8 +833,6 @@ struct net_device *gether_setup_name_default(const char *netname)
|
|
spin_lock_init(&dev->lock);
|
|
spin_lock_init(&dev->req_lock);
|
|
INIT_WORK(&dev->work, eth_work);
|
|
- INIT_WORK(&dev->rx_work, process_rx_w);
|
|
- INIT_WORK(&dev->rx_work1, process_rx_w1);
|
|
INIT_LIST_HEAD(&dev->tx_reqs);
|
|
INIT_LIST_HEAD(&dev->rx_reqs);
|
|
|
|
@@ -1352,16 +999,6 @@ int gether_get_ifname(struct net_device *net, char *name, int len)
|
|
}
|
|
EXPORT_SYMBOL_GPL(gether_get_ifname);
|
|
|
|
-void gether_update_dl_max_xfer_size(struct gether *link, uint32_t s)
|
|
-{
|
|
- struct eth_dev *dev = link->ioport;
|
|
- unsigned long flags;
|
|
-
|
|
- spin_lock_irqsave(&dev->lock, flags);
|
|
- dev->dl_max_xfer_size = s;
|
|
- spin_unlock_irqrestore(&dev->lock, flags);
|
|
-}
|
|
-
|
|
/**
|
|
* gether_cleanup - remove Ethernet-over-USB device
|
|
* Context: may sleep
|
|
@@ -1402,13 +1039,6 @@ struct net_device *gether_connect(struct gether *link)
|
|
|
|
if (!dev)
|
|
return ERR_PTR(-EINVAL);
|
|
- link->header = kzalloc(sizeof(struct rndis_packet_msg_type),
|
|
- GFP_ATOMIC);
|
|
- if (!link->header) {
|
|
- result = -ENOMEM;
|
|
- goto fail;
|
|
- }
|
|
- U_ETHER_DBG("\n");
|
|
|
|
link->in_ep->driver_data = dev;
|
|
result = usb_ep_enable(link->in_ep);
|
|
@@ -1437,14 +1067,8 @@ struct net_device *gether_connect(struct gether *link)
|
|
dev->header_len = link->header_len;
|
|
dev->unwrap = link->unwrap;
|
|
dev->wrap = link->wrap;
|
|
- dev->ul_max_pkts_per_xfer = link->ul_max_pkts_per_xfer;
|
|
- dev->dl_max_pkts_per_xfer = link->dl_max_pkts_per_xfer;
|
|
- dev->dl_max_xfer_size = link->dl_max_transfer_len;
|
|
|
|
spin_lock(&dev->lock);
|
|
- dev->tx_skb_hold_count = 0;
|
|
- dev->no_tx_req_used = 0;
|
|
- dev->tx_req_bufsize = 0;
|
|
dev->port_usb = link;
|
|
if (netif_running(dev->net)) {
|
|
if (link->open)
|
|
@@ -1465,13 +1089,10 @@ struct net_device *gether_connect(struct gether *link)
|
|
fail1:
|
|
(void) usb_ep_disable(link->in_ep);
|
|
}
|
|
- /* caller is responsible for cleanup on error */
|
|
- if (result < 0) {
|
|
fail0:
|
|
- kfree(link->header);
|
|
-fail:
|
|
+ /* caller is responsible for cleanup on error */
|
|
+ if (result < 0)
|
|
return ERR_PTR(result);
|
|
- }
|
|
return dev->net;
|
|
}
|
|
EXPORT_SYMBOL_GPL(gether_connect);
|
|
@@ -1492,25 +1113,12 @@ void gether_disconnect(struct gether *link)
|
|
{
|
|
struct eth_dev *dev = link->ioport;
|
|
struct usb_request *req;
|
|
- struct sk_buff *skb;
|
|
|
|
WARN_ON(!dev);
|
|
if (!dev)
|
|
return;
|
|
|
|
- U_ETHER_DBG("\n");
|
|
-
|
|
- rndis_test_rx_usb_in = 0;
|
|
- rndis_test_rx_net_out = 0;
|
|
- rndis_test_rx_nomem = 0;
|
|
- rndis_test_rx_error = 0;
|
|
-
|
|
- rndis_test_tx_net_in = 0;
|
|
- rndis_test_tx_busy = 0;
|
|
- rndis_test_tx_stop = 0;
|
|
-
|
|
- rndis_test_tx_usb_out = 0;
|
|
- rndis_test_tx_complete = 0;
|
|
+ DBG(dev, "%s\n", __func__);
|
|
|
|
netif_stop_queue(dev->net);
|
|
netif_carrier_off(dev->net);
|
|
@@ -1527,37 +1135,25 @@ void gether_disconnect(struct gether *link)
|
|
list_del(&req->list);
|
|
|
|
spin_unlock(&dev->req_lock);
|
|
- if (link->multi_pkt_xfer) {
|
|
- kfree(req->buf);
|
|
- req->buf = NULL;
|
|
- }
|
|
usb_ep_free_request(link->in_ep, req);
|
|
spin_lock(&dev->req_lock);
|
|
}
|
|
- kfree(link->header);
|
|
- link->header = NULL;
|
|
spin_unlock(&dev->req_lock);
|
|
link->in_ep->driver_data = NULL;
|
|
link->in_ep->desc = NULL;
|
|
|
|
usb_ep_disable(link->out_ep);
|
|
- spin_lock(&dev->reqrx_lock);
|
|
+ spin_lock(&dev->req_lock);
|
|
while (!list_empty(&dev->rx_reqs)) {
|
|
req = container_of(dev->rx_reqs.next,
|
|
struct usb_request, list);
|
|
list_del(&req->list);
|
|
|
|
- spin_unlock(&dev->reqrx_lock);
|
|
+ spin_unlock(&dev->req_lock);
|
|
usb_ep_free_request(link->out_ep, req);
|
|
- spin_lock(&dev->reqrx_lock);
|
|
+ spin_lock(&dev->req_lock);
|
|
}
|
|
- spin_unlock(&dev->reqrx_lock);
|
|
-
|
|
- spin_lock(&dev->rx_frames.lock);
|
|
- while ((skb = __skb_dequeue(&dev->rx_frames)))
|
|
- dev_kfree_skb_any(skb);
|
|
- spin_unlock(&dev->rx_frames.lock);
|
|
-
|
|
+ spin_unlock(&dev->req_lock);
|
|
link->out_ep->driver_data = NULL;
|
|
link->out_ep->desc = NULL;
|
|
|
|
@@ -1572,30 +1168,5 @@ void gether_disconnect(struct gether *link)
|
|
}
|
|
EXPORT_SYMBOL_GPL(gether_disconnect);
|
|
|
|
-static int __init gether_init(void)
|
|
-{
|
|
- uether_wq = create_singlethread_workqueue("uether");
|
|
- if (!uether_wq) {
|
|
- pr_err("%s: Unable to create workqueue: uether\n", __func__);
|
|
- return -ENOMEM;
|
|
- }
|
|
- uether_wq1 = create_singlethread_workqueue("uether_rx1");
|
|
- if (!uether_wq1) {
|
|
- destroy_workqueue(uether_wq);
|
|
- pr_err("%s: Unable to create workqueue: uether\n", __func__);
|
|
- return -ENOMEM;
|
|
- }
|
|
- return 0;
|
|
-}
|
|
-module_init(gether_init);
|
|
-
|
|
-static void __exit gether_exit(void)
|
|
-{
|
|
- destroy_workqueue(uether_wq);
|
|
- destroy_workqueue(uether_wq1);
|
|
-
|
|
-}
|
|
-module_exit(gether_exit);
|
|
+MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("David Brownell");
|
|
-MODULE_DESCRIPTION("ethernet over USB driver");
|
|
-MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h
|
|
index 22d82976ed8a..334b38947916 100644
|
|
--- a/drivers/usb/gadget/function/u_ether.h
|
|
+++ b/drivers/usb/gadget/function/u_ether.h
|
|
@@ -22,7 +22,7 @@
|
|
|
|
#include "gadget_chips.h"
|
|
|
|
-#define QMULT_DEFAULT 10
|
|
+#define QMULT_DEFAULT 5
|
|
|
|
/*
|
|
* dev_addr: initial value
|
|
@@ -35,11 +35,11 @@
|
|
MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");\
|
|
\
|
|
static char *dev_addr; \
|
|
- module_param(dev_addr, charp, S_IRUGO|S_IWUSR); \
|
|
+ module_param(dev_addr, charp, S_IRUGO); \
|
|
MODULE_PARM_DESC(dev_addr, "Device Ethernet Address"); \
|
|
\
|
|
static char *host_addr; \
|
|
- module_param(host_addr, charp, S_IRUGO|S_IWUSR); \
|
|
+ module_param(host_addr, charp, S_IRUGO); \
|
|
MODULE_PARM_DESC(host_addr, "Host Ethernet Address")
|
|
|
|
struct eth_dev;
|
|
@@ -75,10 +75,6 @@ struct gether {
|
|
bool is_fixed;
|
|
u32 fixed_out_len;
|
|
u32 fixed_in_len;
|
|
- unsigned ul_max_pkts_per_xfer;
|
|
- unsigned dl_max_pkts_per_xfer;
|
|
- unsigned dl_max_transfer_len;
|
|
- bool multi_pkt_xfer;
|
|
bool supports_multi_frame;
|
|
struct sk_buff *(*wrap)(struct gether *port,
|
|
struct sk_buff *skb);
|
|
@@ -89,7 +85,6 @@ struct gether {
|
|
/* called on network open/close */
|
|
void (*open)(struct gether *);
|
|
void (*close)(struct gether *);
|
|
- struct rndis_packet_msg_type *header;
|
|
};
|
|
|
|
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
|
|
@@ -260,7 +255,6 @@ void gether_cleanup(struct eth_dev *dev);
|
|
/* connect/disconnect is handled by individual functions */
|
|
struct net_device *gether_connect(struct gether *);
|
|
void gether_disconnect(struct gether *);
|
|
-void gether_update_dl_max_xfer_size(struct gether *link, uint32_t s);
|
|
|
|
/* Some controllers can't support CDC Ethernet (ECM) ... */
|
|
static inline bool can_support_ecm(struct usb_gadget *gadget)
|
|
@@ -275,21 +269,4 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
|
|
return true;
|
|
}
|
|
|
|
-extern unsigned int rndis_test_last_resp_id;
|
|
-extern unsigned int rndis_test_last_msg_id;
|
|
-
|
|
-extern unsigned long rndis_test_reset_msg_cnt;
|
|
-
|
|
-extern unsigned long rndis_test_rx_usb_in;
|
|
-extern unsigned long rndis_test_rx_net_out;
|
|
-extern unsigned long rndis_test_rx_nomem;
|
|
-extern unsigned long rndis_test_rx_error;
|
|
-
|
|
-extern unsigned long rndis_test_tx_net_in;
|
|
-extern unsigned long rndis_test_tx_busy;
|
|
-extern unsigned long rndis_test_tx_stop;
|
|
-
|
|
-extern unsigned long rndis_test_tx_usb_out;
|
|
-extern unsigned long rndis_test_tx_complete;
|
|
-
|
|
#endif /* __U_ETHER_H */
|
|
|