diff options
Diffstat (limited to 'drivers/net/usb/usbnet.c')
| -rw-r--r-- | drivers/net/usb/usbnet.c | 95 | 
1 files changed, 54 insertions, 41 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 7b331e613e0..f9e96c42755 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -14,8 +14,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * along with this program; if not, see <http://www.gnu.org/licenses/>.   */  /* @@ -204,9 +203,6 @@ static void intr_complete (struct urb *urb)  		break;  	} -	if (!netif_running (dev->net)) -		return; -  	status = usb_submit_urb (urb, GFP_ATOMIC);  	if (status != 0)  		netif_err(dev, timer, dev->net, @@ -546,17 +542,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)  	}  	// else network stack removes extra byte if we forced a short packet -	if (skb->len) { -		/* all data was already cloned from skb inside the driver */ -		if (dev->driver_info->flags & FLAG_MULTI_PACKET) -			dev_kfree_skb_any(skb); -		else -			usbnet_skb_return(dev, skb); +	/* all data was already cloned from skb inside the driver */ +	if (dev->driver_info->flags & FLAG_MULTI_PACKET) +		goto done; + +	if (skb->len < ETH_HLEN) { +		dev->net->stats.rx_errors++; +		dev->net->stats.rx_length_errors++; +		netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len); +	} else { +		usbnet_skb_return(dev, skb);  		return;  	} -	netif_dbg(dev, rx_err, dev->net, "drop\n"); -	dev->net->stats.rx_errors++;  done:  	skb_queue_tail(&dev->done, skb);  } @@ -578,13 +576,6 @@ static void rx_complete (struct urb *urb)  	switch (urb_status) {  	/* success */  	case 0: -		if (skb->len < dev->net->hard_header_len) { -			state = rx_cleanup; -			dev->net->stats.rx_errors++; -			dev->net->stats.rx_length_errors++; -			netif_dbg(dev, rx_err, dev->net, -				  "rx length %d\n", skb->len); -		}  		break;  	/* stalls need manual reset. this is rare ... except that @@ -761,14 +752,12 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);  // precondition: never called in_interrupt  static void usbnet_terminate_urbs(struct usbnet *dev)  { -	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);  	DECLARE_WAITQUEUE(wait, current);  	int temp;  	/* ensure there are no more active urbs */ -	add_wait_queue(&unlink_wakeup, &wait); +	add_wait_queue(&dev->wait, &wait);  	set_current_state(TASK_UNINTERRUPTIBLE); -	dev->wait = &unlink_wakeup;  	temp = unlink_urbs(dev, &dev->txq) +  		unlink_urbs(dev, &dev->rxq); @@ -782,15 +771,14 @@ static void usbnet_terminate_urbs(struct usbnet *dev)  				  "waited for %d urb completions\n", temp);  	}  	set_current_state(TASK_RUNNING); -	dev->wait = NULL; -	remove_wait_queue(&unlink_wakeup, &wait); +	remove_wait_queue(&dev->wait, &wait);  }  int usbnet_stop (struct net_device *net)  {  	struct usbnet		*dev = netdev_priv(net);  	struct driver_info	*info = dev->driver_info; -	int			retval; +	int			retval, pm;  	clear_bit(EVENT_DEV_OPEN, &dev->flags);  	netif_stop_queue (net); @@ -800,6 +788,8 @@ int usbnet_stop (struct net_device *net)  		   net->stats.rx_packets, net->stats.tx_packets,  		   net->stats.rx_errors, net->stats.tx_errors); +	/* to not race resume */ +	pm = usb_autopm_get_interface(dev->intf);  	/* allow minidriver to stop correctly (wireless devices to turn off  	 * radio etc) */  	if (info->stop) { @@ -826,6 +816,9 @@ int usbnet_stop (struct net_device *net)  	dev->flags = 0;  	del_timer_sync (&dev->delay);  	tasklet_kill (&dev->bh); +	if (!pm) +		usb_autopm_put_interface(dev->intf); +  	if (info->manage_power &&  	    !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))  		info->manage_power(dev, 0); @@ -1241,12 +1234,14 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)  	if (num_sgs == 1)  		return 0; -	urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC); +	/* reserve one for zero packet */ +	urb->sg = kmalloc((num_sgs + 1) * sizeof(struct scatterlist), +			  GFP_ATOMIC);  	if (!urb->sg)  		return -ENOMEM;  	urb->num_sgs = num_sgs; -	sg_init_table(urb->sg, urb->num_sgs); +	sg_init_table(urb->sg, urb->num_sgs + 1);  	sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb));  	total_len += skb_headlen(skb); @@ -1305,7 +1300,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,  		if (build_dma_sg(skb, urb) < 0)  			goto drop;  	} -	entry->length = length = urb->transfer_buffer_length; +	length = urb->transfer_buffer_length;  	/* don't assume the hardware handles USB_ZERO_PACKET  	 * NOTE:  strictly conforming cdc-ether devices should expect @@ -1317,15 +1312,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,  	if (length % dev->maxpacket == 0) {  		if (!(info->flags & FLAG_SEND_ZLP)) {  			if (!(info->flags & FLAG_MULTI_PACKET)) { -				urb->transfer_buffer_length++; -				if (skb_tailroom(skb)) { +				length++; +				if (skb_tailroom(skb) && !urb->num_sgs) {  					skb->data[skb->len] = 0;  					__skb_put(skb, 1); -				} +				} else if (urb->num_sgs) +					sg_set_buf(&urb->sg[urb->num_sgs++], +							dev->padding_pkt, 1);  			}  		} else  			urb->transfer_flags |= URB_ZERO_PACKET;  	} +	entry->length = urb->transfer_buffer_length = length;  	spin_lock_irqsave(&dev->txq.lock, flags);  	retval = usb_autopm_get_interface_async(dev->intf); @@ -1441,11 +1439,12 @@ static void usbnet_bh (unsigned long param)  	/* restart RX again after disabling due to high error rate */  	clear_bit(EVENT_RX_KILL, &dev->flags); -	// waiting for all pending urbs to complete? -	if (dev->wait) { -		if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { -			wake_up (dev->wait); -		} +	/* waiting for all pending urbs to complete? +	 * only then can we forgo submitting anew +	 */ +	if (waitqueue_active(&dev->wait)) { +		if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0) +			wake_up_all(&dev->wait);  	// or are we maybe short a few urbs?  	} else if (netif_running (dev->net) && @@ -1509,6 +1508,7 @@ void usbnet_disconnect (struct usb_interface *intf)  	usb_kill_urb(dev->interrupt);  	usb_free_urb(dev->interrupt); +	kfree(dev->padding_pkt);  	free_netdev(net);  } @@ -1583,6 +1583,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)  	dev->driver_name = name;  	dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV  				| NETIF_MSG_PROBE | NETIF_MSG_LINK); +	init_waitqueue_head(&dev->wait);  	skb_queue_head_init (&dev->rxq);  	skb_queue_head_init (&dev->txq);  	skb_queue_head_init (&dev->done); @@ -1679,9 +1680,18 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)  	/* initialize max rx_qlen and tx_qlen */  	usbnet_update_max_qlen(dev); +	if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) && +		!(info->flags & FLAG_MULTI_PACKET)) { +		dev->padding_pkt = kzalloc(1, GFP_KERNEL); +		if (!dev->padding_pkt) { +			status = -ENOMEM; +			goto out4; +		} +	} +  	status = register_netdev (net);  	if (status) -		goto out4; +		goto out5;  	netif_info(dev, probe, dev->net,  		   "register '%s' at usb-%s-%s, %s, %pM\n",  		   udev->dev.driver->name, @@ -1699,6 +1709,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)  	return 0; +out5: +	kfree(dev->padding_pkt);  out4:  	usb_free_urb(dev->interrupt);  out3: @@ -1783,9 +1795,10 @@ int usbnet_resume (struct usb_interface *intf)  		spin_unlock_irq(&dev->txq.lock);  		if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { -			/* handle remote wakeup ASAP */ -			if (!dev->wait && -				netif_device_present(dev->net) && +			/* handle remote wakeup ASAP +			 * we cannot race against stop +			 */ +			if (netif_device_present(dev->net) &&  				!timer_pending(&dev->delay) &&  				!test_bit(EVENT_RX_HALT, &dev->flags))  					rx_alloc_submit(dev, GFP_NOIO);  | 
