diff options
Diffstat (limited to 'drivers/usb/wusbcore')
| -rw-r--r-- | drivers/usb/wusbcore/devconnect.c | 6 | ||||
| -rw-r--r-- | drivers/usb/wusbcore/mmc.c | 33 | ||||
| -rw-r--r-- | drivers/usb/wusbcore/pal.c | 5 | ||||
| -rw-r--r-- | drivers/usb/wusbcore/reservation.c | 3 | ||||
| -rw-r--r-- | drivers/usb/wusbcore/rh.c | 20 | ||||
| -rw-r--r-- | drivers/usb/wusbcore/wa-nep.c | 3 | ||||
| -rw-r--r-- | drivers/usb/wusbcore/wa-rpipe.c | 45 | ||||
| -rw-r--r-- | drivers/usb/wusbcore/wa-xfer.c | 181 | ||||
| -rw-r--r-- | drivers/usb/wusbcore/wusbhc.c | 79 | ||||
| -rw-r--r-- | drivers/usb/wusbcore/wusbhc.h | 7 | 
10 files changed, 303 insertions, 79 deletions
| diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index 1d365316960c..33a12788f9ca 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -455,8 +455,8 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc)  			dev_err(dev, "KEEPALIVE: device %u timed out\n",  				wusb_dev->addr);  			__wusbhc_dev_disconnect(wusbhc, wusb_port); -		} else if (time_after(jiffies, wusb_dev->entry_ts + tt/2)) { -			/* Approaching timeout cut out, need to refresh */ +		} else if (time_after(jiffies, wusb_dev->entry_ts + tt/3)) { +			/* Approaching timeout cut off, need to refresh */  			ie->bDeviceAddress[keep_alives++] = wusb_dev->addr;  		}  	} @@ -1062,7 +1062,7 @@ int wusbhc_devconnect_start(struct wusbhc *wusbhc)  	wusbhc->wuie_host_info = hi;  	queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, -			   (wusbhc->trust_timeout*CONFIG_HZ)/1000/2); +			   msecs_to_jiffies(wusbhc->trust_timeout / 2));  	return 0; diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c index b8c72583c040..b71760c8d3ad 100644 --- a/drivers/usb/wusbcore/mmc.c +++ b/drivers/usb/wusbcore/mmc.c @@ -195,6 +195,7 @@ int wusbhc_start(struct wusbhc *wusbhc)  	struct device *dev = wusbhc->dev;  	WARN_ON(wusbhc->wuie_host_info != NULL); +	BUG_ON(wusbhc->uwb_rc == NULL);  	result = wusbhc_rsv_establish(wusbhc);  	if (result < 0) { @@ -214,9 +215,9 @@ int wusbhc_start(struct wusbhc *wusbhc)  		dev_err(dev, "error starting security in the HC: %d\n", result);  		goto error_sec_start;  	} -	/* FIXME: the choice of the DNTS parameters is somewhat -	 * arbitrary */ -	result = wusbhc->set_num_dnts(wusbhc, 0, 15); + +	result = wusbhc->set_num_dnts(wusbhc, wusbhc->dnts_interval, +		wusbhc->dnts_num_slots);  	if (result < 0) {  		dev_err(dev, "Cannot set DNTS parameters: %d\n", result);  		goto error_set_num_dnts; @@ -276,12 +277,38 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)  		}  		wusbhc->chid = *chid;  	} + +	/* register with UWB if we haven't already since we are about to start +	    the radio. */ +	if ((chid) && (wusbhc->uwb_rc == NULL)) { +		wusbhc->uwb_rc = uwb_rc_get_by_grandpa(wusbhc->dev->parent); +		if (wusbhc->uwb_rc == NULL) { +			result = -ENODEV; +			dev_err(wusbhc->dev, "Cannot get associated UWB Host Controller\n"); +			goto error_rc_get; +		} + +		result = wusbhc_pal_register(wusbhc); +		if (result < 0) { +			dev_err(wusbhc->dev, "Cannot register as a UWB PAL\n"); +			goto error_pal_register; +		} +	}  	mutex_unlock(&wusbhc->mutex);  	if (chid)  		result = uwb_radio_start(&wusbhc->pal);  	else  		uwb_radio_stop(&wusbhc->pal); + +	return result; + +error_pal_register: +	uwb_rc_put(wusbhc->uwb_rc); +	wusbhc->uwb_rc = NULL; +error_rc_get: +	mutex_unlock(&wusbhc->mutex); +  	return result;  }  EXPORT_SYMBOL_GPL(wusbhc_chid_set); diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c index d0b172c5ecc7..59e100c2eb50 100644 --- a/drivers/usb/wusbcore/pal.c +++ b/drivers/usb/wusbcore/pal.c @@ -45,10 +45,11 @@ int wusbhc_pal_register(struct wusbhc *wusbhc)  }  /** - * wusbhc_pal_register - unregister the WUSB HC as a UWB PAL + * wusbhc_pal_unregister - unregister the WUSB HC as a UWB PAL   * @wusbhc: the WUSB HC   */  void wusbhc_pal_unregister(struct wusbhc *wusbhc)  { -	uwb_pal_unregister(&wusbhc->pal); +	if (wusbhc->uwb_rc) +		uwb_pal_unregister(&wusbhc->pal);  } diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c index 6f4fafdc2401..ead79f793927 100644 --- a/drivers/usb/wusbcore/reservation.c +++ b/drivers/usb/wusbcore/reservation.c @@ -80,6 +80,9 @@ int wusbhc_rsv_establish(struct wusbhc *wusbhc)  	struct uwb_dev_addr bcid;  	int ret; +	if (rc == NULL) +		return -ENODEV; +  	rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc);  	if (rsv == NULL)  		return -ENOMEM; diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c index 59ff254dfb6f..bdb0cc3046b5 100644 --- a/drivers/usb/wusbcore/rh.c +++ b/drivers/usb/wusbcore/rh.c @@ -393,26 +393,6 @@ int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue,  }  EXPORT_SYMBOL_GPL(wusbhc_rh_control); -int wusbhc_rh_suspend(struct usb_hcd *usb_hcd) -{ -	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); -	dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, -		usb_hcd, wusbhc); -	/* dump_stack(); */ -	return -ENOSYS; -} -EXPORT_SYMBOL_GPL(wusbhc_rh_suspend); - -int wusbhc_rh_resume(struct usb_hcd *usb_hcd) -{ -	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); -	dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, -		usb_hcd, wusbhc); -	/* dump_stack(); */ -	return -ENOSYS; -} -EXPORT_SYMBOL_GPL(wusbhc_rh_resume); -  int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx)  {  	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c index f67f7f1e6df9..ada4e0870623 100644 --- a/drivers/usb/wusbcore/wa-nep.c +++ b/drivers/usb/wusbcore/wa-nep.c @@ -134,9 +134,10 @@ static void wa_notif_dispatch(struct work_struct *ws)  		case WA_NOTIF_TRANSFER:  			wa_handle_notif_xfer(wa, notif_hdr);  			break; +		case HWA_NOTIF_BPST_ADJ: +			break; /* no action needed for BPST ADJ. */  		case DWA_NOTIF_RWAKE:  		case DWA_NOTIF_PORTSTATUS: -		case HWA_NOTIF_BPST_ADJ:  			/* FIXME: unimplemented WA NOTIFs */  			/* fallthru */  		default: diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index f0d546c5a089..9a595c1ed867 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -251,8 +251,8 @@ static int __rpipe_reset(struct wahc *wa, unsigned index)  static struct usb_wireless_ep_comp_descriptor epc0 = {  	.bLength = sizeof(epc0),  	.bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP, -/*	.bMaxBurst = 1, */ -	.bMaxSequence = 31, +	.bMaxBurst = 1, +	.bMaxSequence = 2,  };  /* @@ -317,6 +317,7 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,  	struct device *dev = &wa->usb_iface->dev;  	struct usb_device *usb_dev = urb->dev;  	struct usb_wireless_ep_comp_descriptor *epcd; +	u32 ack_window, epcd_max_sequence;  	u8 unauth;  	epcd = rpipe_epc_find(dev, ep); @@ -333,8 +334,11 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,  	rpipe->descr.wBlocks = cpu_to_le16(16);		/* given */  	/* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */  	rpipe->descr.wMaxPacketSize = cpu_to_le16(ep->desc.wMaxPacketSize); -	rpipe->descr.bHSHubAddress = 0;			/* reserved: zero */ -	rpipe->descr.bHSHubPort = wusb_port_no_to_idx(urb->dev->portnum); + +	rpipe->descr.hwa_bMaxBurst = max(min_t(unsigned int, +				epcd->bMaxBurst, 16U), 1U); +	rpipe->descr.hwa_bDeviceInfoIndex = +			wusb_port_no_to_idx(urb->dev->portnum);  	/* FIXME: use maximum speed as supported or recommended by device */  	rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ?  		UWB_PHY_RATE_53 : UWB_PHY_RATE_200; @@ -344,26 +348,26 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,  		le16_to_cpu(rpipe->descr.wRPipeIndex),  		usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed); -	/* see security.c:wusb_update_address() */ -	if (unlikely(urb->dev->devnum == 0x80)) -		rpipe->descr.bDeviceAddress = 0; -	else -		rpipe->descr.bDeviceAddress = urb->dev->devnum | unauth; +	rpipe->descr.hwa_reserved = 0; +  	rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress;  	/* FIXME: bDataSequence */  	rpipe->descr.bDataSequence = 0; -	/* FIXME: dwCurrentWindow */ -	rpipe->descr.dwCurrentWindow = cpu_to_le32(1); -	/* FIXME: bMaxDataSequence */ -	rpipe->descr.bMaxDataSequence = epcd->bMaxSequence - 1; + +	/* start with base window of hwa_bMaxBurst bits starting at 0. */ +	ack_window = 0xFFFFFFFF >> (32 - rpipe->descr.hwa_bMaxBurst); +	rpipe->descr.dwCurrentWindow = cpu_to_le32(ack_window); +	epcd_max_sequence = max(min_t(unsigned int, +			epcd->bMaxSequence, 32U), 2U); +	rpipe->descr.bMaxDataSequence = epcd_max_sequence - 1;  	rpipe->descr.bInterval = ep->desc.bInterval;  	/* FIXME: bOverTheAirInterval */  	rpipe->descr.bOverTheAirInterval = 0;	/* 0 if not isoc */  	/* FIXME: xmit power & preamble blah blah */ -	rpipe->descr.bmAttribute = ep->desc.bmAttributes & 0x03; +	rpipe->descr.bmAttribute = (ep->desc.bmAttributes & +					USB_ENDPOINT_XFERTYPE_MASK);  	/* rpipe->descr.bmCharacteristics RO */ -	/* FIXME: bmRetryOptions */ -	rpipe->descr.bmRetryOptions = 15; +	rpipe->descr.bmRetryOptions = (wa->wusb->retry_count & 0xF);  	/* FIXME: use for assessing link quality? */  	rpipe->descr.wNumTransactionErrors = 0;  	result = __rpipe_set_descr(wa, &rpipe->descr, @@ -387,10 +391,8 @@ static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa,  			   const struct usb_host_endpoint *ep,  			   const struct urb *urb, gfp_t gfp)  { -	int result = 0;		/* better code for lack of companion? */ +	int result = 0;  	struct device *dev = &wa->usb_iface->dev; -	struct usb_device *usb_dev = urb->dev; -	u8 unauth = (usb_dev->wusb && !usb_dev->authenticated) ? 0x80 : 0;  	u8 portnum = wusb_port_no_to_idx(urb->dev->portnum);  #define AIM_CHECK(rdf, val, text)					\ @@ -403,13 +405,10 @@ static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa,  			WARN_ON(1);					\  		}							\  	} while (0) -	AIM_CHECK(wMaxPacketSize, cpu_to_le16(ep->desc.wMaxPacketSize), -		  "(%u vs %u)"); -	AIM_CHECK(bHSHubPort, portnum, "(%u vs %u)"); +	AIM_CHECK(hwa_bDeviceInfoIndex, portnum, "(%u vs %u)");  	AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ?  			UWB_PHY_RATE_53 : UWB_PHY_RATE_200,  		  "(%u vs %u)"); -	AIM_CHECK(bDeviceAddress, urb->dev->devnum | unauth, "(%u vs %u)");  	AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)");  	AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)");  	AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)"); diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 6ef94bce8c0d..16968c899493 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -85,6 +85,7 @@  #include <linux/hash.h>  #include <linux/ratelimit.h>  #include <linux/export.h> +#include <linux/scatterlist.h>  #include "wa-hc.h"  #include "wusbhc.h" @@ -442,8 +443,7 @@ static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer,  		goto error;  	}  	xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize; -	xfer->segs = (urb->transfer_buffer_length + xfer->seg_size - 1) -		/ xfer->seg_size; +	xfer->segs = DIV_ROUND_UP(urb->transfer_buffer_length, xfer->seg_size);  	if (xfer->segs >= WA_SEGS_MAX) {  		dev_err(dev, "BUG? ops, number of segments %d bigger than %d\n",  			(int)(urb->transfer_buffer_length / xfer->seg_size), @@ -627,6 +627,86 @@ static void wa_seg_cb(struct urb *urb)  	}  } +/* allocate an SG list to store bytes_to_transfer bytes and copy the + * subset of the in_sg that matches the buffer subset + * we are about to transfer. */ +static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg, +	const unsigned int bytes_transferred, +	const unsigned int bytes_to_transfer, unsigned int *out_num_sgs) +{ +	struct scatterlist *out_sg; +	unsigned int bytes_processed = 0, offset_into_current_page_data = 0, +		nents; +	struct scatterlist *current_xfer_sg = in_sg; +	struct scatterlist *current_seg_sg, *last_seg_sg; + +	/* skip previously transferred pages. */ +	while ((current_xfer_sg) && +			(bytes_processed < bytes_transferred)) { +		bytes_processed += current_xfer_sg->length; + +		/* advance the sg if current segment starts on or past the +			next page. */ +		if (bytes_processed <= bytes_transferred) +			current_xfer_sg = sg_next(current_xfer_sg); +	} + +	/* the data for the current segment starts in current_xfer_sg. +		calculate the offset. */ +	if (bytes_processed > bytes_transferred) { +		offset_into_current_page_data = current_xfer_sg->length - +			(bytes_processed - bytes_transferred); +	} + +	/* calculate the number of pages needed by this segment. */ +	nents = DIV_ROUND_UP((bytes_to_transfer + +		offset_into_current_page_data + +		current_xfer_sg->offset), +		PAGE_SIZE); + +	out_sg = kmalloc((sizeof(struct scatterlist) * nents), GFP_ATOMIC); +	if (out_sg) { +		sg_init_table(out_sg, nents); + +		/* copy the portion of the incoming SG that correlates to the +		 * data to be transferred by this segment to the segment SG. */ +		last_seg_sg = current_seg_sg = out_sg; +		bytes_processed = 0; + +		/* reset nents and calculate the actual number of sg entries +			needed. */ +		nents = 0; +		while ((bytes_processed < bytes_to_transfer) && +				current_seg_sg && current_xfer_sg) { +			unsigned int page_len = min((current_xfer_sg->length - +				offset_into_current_page_data), +				(bytes_to_transfer - bytes_processed)); + +			sg_set_page(current_seg_sg, sg_page(current_xfer_sg), +				page_len, +				current_xfer_sg->offset + +				offset_into_current_page_data); + +			bytes_processed += page_len; + +			last_seg_sg = current_seg_sg; +			current_seg_sg = sg_next(current_seg_sg); +			current_xfer_sg = sg_next(current_xfer_sg); + +			/* only the first page may require additional offset. */ +			offset_into_current_page_data = 0; +			nents++; +		} + +		/* update num_sgs and terminate the list since we may have +		 *  concatenated pages. */ +		sg_mark_end(last_seg_sg); +		*out_num_sgs = nents; +	} + +	return out_sg; +} +  /*   * Allocate the segs array and initialize each of them   * @@ -663,9 +743,9 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)  						  dto_epd->bEndpointAddress),  				  &seg->xfer_hdr, xfer_hdr_size,  				  wa_seg_cb, seg); -		buf_itr_size = buf_size > xfer->seg_size ? -			xfer->seg_size : buf_size; +		buf_itr_size = min(buf_size, xfer->seg_size);  		if (xfer->is_inbound == 0 && buf_size > 0) { +			/* outbound data. */  			seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC);  			if (seg->dto_urb == NULL)  				goto error_dto_alloc; @@ -679,9 +759,42 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)  					xfer->urb->transfer_dma + buf_itr;  				seg->dto_urb->transfer_flags |=  					URB_NO_TRANSFER_DMA_MAP; -			} else -				seg->dto_urb->transfer_buffer = -					xfer->urb->transfer_buffer + buf_itr; +				seg->dto_urb->transfer_buffer = NULL; +				seg->dto_urb->sg = NULL; +				seg->dto_urb->num_sgs = 0; +			} else { +				/* do buffer or SG processing. */ +				seg->dto_urb->transfer_flags &= +					~URB_NO_TRANSFER_DMA_MAP; +				/* this should always be 0 before a resubmit. */ +				seg->dto_urb->num_mapped_sgs = 0; + +				if (xfer->urb->transfer_buffer) { +					seg->dto_urb->transfer_buffer = +						xfer->urb->transfer_buffer + +						buf_itr; +					seg->dto_urb->sg = NULL; +					seg->dto_urb->num_sgs = 0; +				} else { +					/* allocate an SG list to store seg_size +					    bytes and copy the subset of the +					    xfer->urb->sg that matches the +					    buffer subset we are about to read. +					*/ +					seg->dto_urb->sg = +						wa_xfer_create_subset_sg( +						xfer->urb->sg, +						buf_itr, buf_itr_size, +						&(seg->dto_urb->num_sgs)); + +					if (!(seg->dto_urb->sg)) { +						seg->dto_urb->num_sgs	= 0; +						goto error_sg_alloc; +					} + +					seg->dto_urb->transfer_buffer = NULL; +				} +			}  			seg->dto_urb->transfer_buffer_length = buf_itr_size;  		}  		seg->status = WA_SEG_READY; @@ -690,6 +803,8 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)  	}  	return 0; +error_sg_alloc: +	kfree(seg->dto_urb);  error_dto_alloc:  	kfree(xfer->seg[cnt]);  	cnt--; @@ -1026,7 +1141,8 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,  	unsigned long my_flags;  	unsigned cant_sleep = irqs_disabled() | in_atomic(); -	if (urb->transfer_buffer == NULL +	if ((urb->transfer_buffer == NULL) +	    && (urb->sg == NULL)  	    && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)  	    && urb->transfer_buffer_length != 0) {  		dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb); @@ -1261,7 +1377,7 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)  	seg = xfer->seg[seg_idx];  	rpipe = xfer->ep->hcpriv;  	usb_status = xfer_result->bTransferStatus; -	dev_dbg(dev, "xfer %p#%u: bTransferStatus 0x%02x (seg %u)\n", +	dev_dbg(dev, "xfer %p#%u: bTransferStatus 0x%02x (seg status %u)\n",  		xfer, seg_idx, usb_status, seg->status);  	if (seg->status == WA_SEG_ABORTED  	    || seg->status == WA_SEG_ERROR)	/* already handled */ @@ -1276,8 +1392,8 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)  	}  	if (usb_status & 0x80) {  		seg->result = wa_xfer_status_to_errno(usb_status); -		dev_err(dev, "DTI: xfer %p#%u failed (0x%02x)\n", -			xfer, seg->index, usb_status); +		dev_err(dev, "DTI: xfer %p#:%08X:%u failed (0x%02x)\n", +			xfer, xfer->id, seg->index, usb_status);  		goto error_complete;  	}  	/* FIXME: we ignore warnings, tally them for stats */ @@ -1286,18 +1402,47 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)  	if (xfer->is_inbound) {	/* IN data phase: read to buffer */  		seg->status = WA_SEG_DTI_PENDING;  		BUG_ON(wa->buf_in_urb->status == -EINPROGRESS); +		/* this should always be 0 before a resubmit. */ +		wa->buf_in_urb->num_mapped_sgs	= 0; +  		if (xfer->is_dma) {  			wa->buf_in_urb->transfer_dma =  				xfer->urb->transfer_dma -				+ seg_idx * xfer->seg_size; +				+ (seg_idx * xfer->seg_size);  			wa->buf_in_urb->transfer_flags  				|= URB_NO_TRANSFER_DMA_MAP; +			wa->buf_in_urb->transfer_buffer = NULL; +			wa->buf_in_urb->sg = NULL; +			wa->buf_in_urb->num_sgs = 0;  		} else { -			wa->buf_in_urb->transfer_buffer = -				xfer->urb->transfer_buffer -				+ seg_idx * xfer->seg_size; +			/* do buffer or SG processing. */  			wa->buf_in_urb->transfer_flags  				&= ~URB_NO_TRANSFER_DMA_MAP; + +			if (xfer->urb->transfer_buffer) { +				wa->buf_in_urb->transfer_buffer = +					xfer->urb->transfer_buffer +					+ (seg_idx * xfer->seg_size); +				wa->buf_in_urb->sg = NULL; +				wa->buf_in_urb->num_sgs = 0; +			} else { +				/* allocate an SG list to store seg_size bytes +					and copy the subset of the xfer->urb->sg +					that matches the buffer subset we are +					about to read. */ +				wa->buf_in_urb->sg = wa_xfer_create_subset_sg( +					xfer->urb->sg, +					seg_idx * xfer->seg_size, +					le32_to_cpu( +						xfer_result->dwTransferLength), +					&(wa->buf_in_urb->num_sgs)); + +				if (!(wa->buf_in_urb->sg)) { +					wa->buf_in_urb->num_sgs	= 0; +					goto error_sg_alloc; +				} +				wa->buf_in_urb->transfer_buffer = NULL; +			}  		}  		wa->buf_in_urb->transfer_buffer_length =  			le32_to_cpu(xfer_result->dwTransferLength); @@ -1330,6 +1475,8 @@ error_submit_buf_in:  		dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n",  			xfer, seg_idx, result);  	seg->result = result; +	kfree(wa->buf_in_urb->sg); +error_sg_alloc:  error_complete:  	seg->status = WA_SEG_ERROR;  	xfer->segs_done++; @@ -1381,6 +1528,10 @@ static void wa_buf_in_cb(struct urb *urb)  	unsigned long flags;  	u8 done = 0; +	/* free the sg if it was used. */ +	kfree(urb->sg); +	urb->sg = NULL; +  	switch (urb->status) {  	case 0:  		spin_lock_irqsave(&xfer->lock, flags); diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c index 0faca16df765..742c607d1fa3 100644 --- a/drivers/usb/wusbcore/wusbhc.c +++ b/drivers/usb/wusbcore/wusbhc.c @@ -75,12 +75,11 @@ static ssize_t wusb_trust_timeout_store(struct device *dev,  		result = -EINVAL;  		goto out;  	} -	/* FIXME: maybe we should check for range validity? */ -	wusbhc->trust_timeout = trust_timeout; +	wusbhc->trust_timeout = min_t(unsigned, trust_timeout, 500);  	cancel_delayed_work(&wusbhc->keep_alive_timer);  	flush_workqueue(wusbd);  	queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, -			   (trust_timeout * CONFIG_HZ)/1000/2); +			   msecs_to_jiffies(wusbhc->trust_timeout / 2));  out:  	return result < 0 ? result : size;  } @@ -176,11 +175,72 @@ static ssize_t wusb_phy_rate_store(struct device *dev,  }  static DEVICE_ATTR(wusb_phy_rate, 0644, wusb_phy_rate_show, wusb_phy_rate_store); +static ssize_t wusb_dnts_show(struct device *dev, +				  struct device_attribute *attr, +				  char *buf) +{ +	struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); + +	return sprintf(buf, "num slots: %d\ninterval: %dms\n", +			wusbhc->dnts_num_slots, wusbhc->dnts_interval); +} + +static ssize_t wusb_dnts_store(struct device *dev, +				   struct device_attribute *attr, +				   const char *buf, size_t size) +{ +	struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); +	uint8_t num_slots, interval; +	ssize_t result; + +	result = sscanf(buf, "%hhu %hhu", &num_slots, &interval); + +	if (result != 2) +		return -EINVAL; + +	wusbhc->dnts_num_slots = num_slots; +	wusbhc->dnts_interval = interval; + +	return size; +} +static DEVICE_ATTR(wusb_dnts, 0644, wusb_dnts_show, wusb_dnts_store); + +static ssize_t wusb_retry_count_show(struct device *dev, +				  struct device_attribute *attr, +				  char *buf) +{ +	struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); + +	return sprintf(buf, "%d\n", wusbhc->retry_count); +} + +static ssize_t wusb_retry_count_store(struct device *dev, +				   struct device_attribute *attr, +				   const char *buf, size_t size) +{ +	struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); +	uint8_t retry_count; +	ssize_t result; + +	result = sscanf(buf, "%hhu", &retry_count); + +	if (result != 1) +		return -EINVAL; + +	wusbhc->retry_count = max_t(uint8_t, retry_count, WUSB_RETRY_COUNT_MAX); + +	return size; +} +static DEVICE_ATTR(wusb_retry_count, 0644, wusb_retry_count_show, +	wusb_retry_count_store); +  /* Group all the WUSBHC attributes */  static struct attribute *wusbhc_attrs[] = {  		&dev_attr_wusb_trust_timeout.attr,  		&dev_attr_wusb_chid.attr,  		&dev_attr_wusb_phy_rate.attr, +		&dev_attr_wusb_dnts.attr, +		&dev_attr_wusb_retry_count.attr,  		NULL,  }; @@ -206,8 +266,12 @@ int wusbhc_create(struct wusbhc *wusbhc)  {  	int result = 0; +	/* set defaults.  These can be overwritten using sysfs attributes. */  	wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS;  	wusbhc->phy_rate = UWB_PHY_RATE_INVALID - 1; +	wusbhc->dnts_num_slots = 4; +	wusbhc->dnts_interval = 2; +	wusbhc->retry_count = WUSB_RETRY_COUNT_INFINITE;  	mutex_init(&wusbhc->mutex);  	result = wusbhc_mmcie_create(wusbhc); @@ -261,13 +325,7 @@ int wusbhc_b_create(struct wusbhc *wusbhc)  		goto error_create_attr_group;  	} -	result = wusbhc_pal_register(wusbhc); -	if (result < 0) -		goto error_pal_register;  	return 0; - -error_pal_register: -	sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);  error_create_attr_group:  	return result;  } @@ -393,7 +451,8 @@ EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);   */  void wusbhc_reset_all(struct wusbhc *wusbhc)  { -	uwb_rc_reset_all(wusbhc->uwb_rc); +	if (wusbhc->uwb_rc) +		uwb_rc_reset_all(wusbhc->uwb_rc);  }  EXPORT_SYMBOL_GPL(wusbhc_reset_all); diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h index 3a2d09162e70..711b1952b114 100644 --- a/drivers/usb/wusbcore/wusbhc.h +++ b/drivers/usb/wusbcore/wusbhc.h @@ -69,6 +69,8 @@   * zone 0.   */  #define WUSB_CHANNEL_STOP_DELAY_MS 8 +#define WUSB_RETRY_COUNT_MAX 15 +#define WUSB_RETRY_COUNT_INFINITE 0  /**   * Wireless USB device @@ -252,6 +254,9 @@ struct wusbhc {  	unsigned trust_timeout;			/* in jiffies */  	struct wusb_ckhdid chid;  	uint8_t phy_rate; +	uint8_t dnts_num_slots; +	uint8_t dnts_interval; +	uint8_t retry_count;  	struct wuie_host_info *wuie_host_info;  	struct mutex mutex;			/* locks everything else */ @@ -399,8 +404,6 @@ extern void wusbhc_rh_destroy(struct wusbhc *);  extern int wusbhc_rh_status_data(struct usb_hcd *, char *);  extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16); -extern int wusbhc_rh_suspend(struct usb_hcd *); -extern int wusbhc_rh_resume(struct usb_hcd *);  extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned);  /* MMC handling */ |