diff options
Diffstat (limited to 'drivers/net/usb')
| -rw-r--r-- | drivers/net/usb/asix_devices.c | 6 | ||||
| -rw-r--r-- | drivers/net/usb/ax88179_178a.c | 12 | ||||
| -rw-r--r-- | drivers/net/usb/cdc_ether.c | 5 | ||||
| -rw-r--r-- | drivers/net/usb/cdc_mbim.c | 4 | ||||
| -rw-r--r-- | drivers/net/usb/cdc_ncm.c | 18 | ||||
| -rw-r--r-- | drivers/net/usb/dm9601.c | 7 | ||||
| -rw-r--r-- | drivers/net/usb/mcs7830.c | 6 | ||||
| -rw-r--r-- | drivers/net/usb/pegasus.c | 441 | ||||
| -rw-r--r-- | drivers/net/usb/pegasus.h | 11 | ||||
| -rw-r--r-- | drivers/net/usb/sierra_net.c | 3 | ||||
| -rw-r--r-- | drivers/net/usb/usbnet.c | 45 | 
11 files changed, 182 insertions, 376 deletions
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 70975346909..ad5d1e4384d 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -55,11 +55,7 @@ static void asix_status(struct usbnet *dev, struct urb *urb)  	event = urb->transfer_buffer;  	link = event->link & 0x01;  	if (netif_carrier_ok(dev->net) != link) { -		if (link) { -			netif_carrier_on(dev->net); -			usbnet_defer_kevent (dev, EVENT_LINK_RESET ); -		} else -			netif_carrier_off(dev->net); +		usbnet_link_change(dev, link, 1);  		netdev_dbg(dev->net, "Link Status is: %d\n", link);  	}  } diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 71c27d8d214..bd8758fa38c 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -352,11 +352,7 @@ static void ax88179_status(struct usbnet *dev, struct urb *urb)  	link = (((__force u32)event->intdata1) & AX_INT_PPLS_LINK) >> 16;  	if (netif_carrier_ok(dev->net) != link) { -		if (link) -			usbnet_defer_kevent(dev, EVENT_LINK_RESET); -		else -			netif_carrier_off(dev->net); - +		usbnet_link_change(dev, link, 1);  		netdev_info(dev->net, "ax88179 - Link status is: %d\n", link);  	}  } @@ -455,7 +451,7 @@ static int ax88179_resume(struct usb_interface *intf)  	u16 tmp16;  	u8 tmp8; -	netif_carrier_off(dev->net); +	usbnet_link_change(dev, 0, 0);  	/* Power up ethernet PHY */  	tmp16 = 0; @@ -1068,7 +1064,7 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)  	/* Restart autoneg */  	mii_nway_restart(&dev->mii); -	netif_carrier_off(dev->net); +	usbnet_link_change(dev, 0, 0);  	return 0;  } @@ -1356,7 +1352,7 @@ static int ax88179_reset(struct usbnet *dev)  	/* Restart autoneg */  	mii_nway_restart(&dev->mii); -	netif_carrier_off(dev->net); +	usbnet_link_change(dev, 0, 0);  	return 0;  } diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 57136dc1b88..4ff71d619cd 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -406,10 +406,7 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)  	case USB_CDC_NOTIFY_NETWORK_CONNECTION:  		netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",  			  event->wValue ? "on" : "off"); -		if (event->wValue) -			netif_carrier_on(dev->net); -		else -			netif_carrier_off(dev->net); +		usbnet_link_change(dev, !!event->wValue, 0);  		break;  	case USB_CDC_NOTIFY_SPEED_CHANGE:	/* tx/rx rates */  		netif_dbg(dev, timer, dev->net, "CDC: speed change (len %d)\n", diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 32a76059e7d..872819851ae 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -101,7 +101,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)  	dev->net->flags |= IFF_NOARP;  	/* no need to put the VLAN tci in the packet headers */ -	dev->net->features |= NETIF_F_HW_VLAN_TX; +	dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX;  err:  	return ret;  } @@ -221,7 +221,7 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_  	/* map MBIM session to VLAN */  	if (tci) -		vlan_put_tag(skb, tci); +		vlan_put_tag(skb, htons(ETH_P_8021Q), tci);  err:  	return skb;  } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 4709fa3497c..43afde8f48d 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -362,8 +362,8 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_  	u8 iface_no;  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); -	if (ctx == NULL) -		return -ENODEV; +	if (!ctx) +		return -ENOMEM;  	hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);  	ctx->tx_timer.function = &cdc_ncm_tx_timer_cb; @@ -610,7 +610,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)  	 * (carrier is OFF) during attach, so the IP network stack does not  	 * start IPv6 negotiation and more.  	 */ -	netif_carrier_off(dev->net); +	usbnet_link_change(dev, 0, 0);  	return ret;  } @@ -1106,12 +1106,9 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)  			" %sconnected\n",  			ctx->netdev->name, ctx->connected ? "" : "dis"); -		if (ctx->connected) -			netif_carrier_on(dev->net); -		else { -			netif_carrier_off(dev->net); +		usbnet_link_change(dev, ctx->connected, 0); +		if (!ctx->connected)  			ctx->tx_speed = ctx->rx_speed = 0; -		}  		break;  	case USB_CDC_NOTIFY_SPEED_CHANGE: @@ -1124,8 +1121,9 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)  		break;  	default: -		dev_err(&dev->udev->dev, "NCM: unexpected " -			"notification 0x%02x!\n", event->bNotificationType); +		dev_dbg(&dev->udev->dev, +			"NCM: unexpected notification 0x%02x!\n", +			event->bNotificationType);  		break;  	}  } diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 174e5ecea4c..2dbb9460349 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -524,12 +524,7 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb)  	link = !!(buf[0] & 0x40);  	if (netif_carrier_ok(dev->net) != link) { -		if (link) { -			netif_carrier_on(dev->net); -			usbnet_defer_kevent (dev, EVENT_LINK_RESET); -		} -		else -			netif_carrier_off(dev->net); +		usbnet_link_change(dev, link, 1);  		netdev_dbg(dev->net, "Link Status is: %d\n", link);  	}  } diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 3f3f566afa0..03832d3780a 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -576,11 +576,7 @@ static void mcs7830_status(struct usbnet *dev, struct urb *urb)  		 */  		if (data->link_counter > 20) {  			data->link_counter = 0; -			if (link) { -				netif_carrier_on(dev->net); -				usbnet_defer_kevent(dev, EVENT_LINK_RESET); -			} else -				netif_carrier_off(dev->net); +			usbnet_link_change(dev, link, 0);  			netdev_dbg(dev->net, "Link Status is: %d\n", link);  		}  	} else diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 73051d10ead..09699054b54 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1,5 +1,5 @@  /* - *  Copyright (c) 1999-2005 Petko Manolov (petkan@users.sourceforge.net) + *  Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com)   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as @@ -26,6 +26,9 @@   *		v0.5.1	ethtool support added   *		v0.5.5	rx socket buffers are in a pool and the their allocation   *			is out of the interrupt routine. + *		... + *		v0.9.3	simplified [get|set]_register(s), async update registers + *			logic revisited, receive skb_pool removed.   */  #include <linux/sched.h> @@ -45,8 +48,8 @@  /*   * Version Information   */ -#define DRIVER_VERSION "v0.6.14 (2006/09/27)" -#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" +#define DRIVER_VERSION "v0.9.3 (2013/04/25)" +#define DRIVER_AUTHOR "Petko Manolov <petkan@nucleusys.com>"  #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"  static const char driver_name[] = "pegasus"; @@ -108,251 +111,137 @@ MODULE_PARM_DESC(msg_level, "Override default message level");  MODULE_DEVICE_TABLE(usb, pegasus_ids);  static const struct net_device_ops pegasus_netdev_ops; -static int update_eth_regs_async(pegasus_t *); -/* Aargh!!! I _really_ hate such tweaks */ -static void ctrl_callback(struct urb *urb) +/*****/ + +static void async_ctrl_callback(struct urb *urb)  { -	pegasus_t *pegasus = urb->context; +	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;  	int status = urb->status; -	if (!pegasus) -		return; - -	switch (status) { -	case 0: -		if (pegasus->flags & ETH_REGS_CHANGE) { -			pegasus->flags &= ~ETH_REGS_CHANGE; -			pegasus->flags |= ETH_REGS_CHANGED; -			update_eth_regs_async(pegasus); -			return; -		} -		break; -	case -EINPROGRESS: -		return; -	case -ENOENT: -		break; -	default: -		if (net_ratelimit()) -			netif_dbg(pegasus, drv, pegasus->net, -				  "%s, status %d\n", __func__, status); -		break; -	} -	pegasus->flags &= ~ETH_REGS_CHANGED; -	wake_up(&pegasus->ctrl_wait); +	if (status < 0) +		dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status); +	kfree(req); +	usb_free_urb(urb);  } -static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, -			 void *data) +static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)  {  	int ret; -	char *buffer; -	DECLARE_WAITQUEUE(wait, current); - -	buffer = kmalloc(size, GFP_KERNEL); -	if (!buffer) -		return -ENOMEM; - -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); -	while (pegasus->flags & ETH_REGS_CHANGED) -		schedule(); -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_RUNNING); - -	pegasus->dr.bRequestType = PEGASUS_REQT_READ; -	pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS; -	pegasus->dr.wValue = cpu_to_le16(0); -	pegasus->dr.wIndex = cpu_to_le16(indx); -	pegasus->dr.wLength = cpu_to_le16(size); -	pegasus->ctrl_urb->transfer_buffer_length = size; - -	usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, -			     usb_rcvctrlpipe(pegasus->usb, 0), -			     (char *) &pegasus->dr, -			     buffer, size, ctrl_callback, pegasus); - -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); - -	/* using ATOMIC, we'd never wake up if we slept */ -	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { -		set_current_state(TASK_RUNNING); -		if (ret == -ENODEV) -			netif_device_detach(pegasus->net); -		if (net_ratelimit()) -			netif_err(pegasus, drv, pegasus->net, -				  "%s, status %d\n", __func__, ret); -		goto out; -	} - -	schedule(); -out: -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	memcpy(data, buffer, size); -	kfree(buffer); +	ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0), +			      PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0, +			      indx, data, size, 1000); +	if (ret < 0) +		netif_dbg(pegasus, drv, pegasus->net, +			  "%s returned %d\n", __func__, ret);  	return ret;  } -static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, -			 void *data) +static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)  {  	int ret; -	char *buffer; -	DECLARE_WAITQUEUE(wait, current); - -	buffer = kmemdup(data, size, GFP_KERNEL); -	if (!buffer) { -		netif_warn(pegasus, drv, pegasus->net, -			   "out of memory in %s\n", __func__); -		return -ENOMEM; -	} - -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); -	while (pegasus->flags & ETH_REGS_CHANGED) -		schedule(); -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_RUNNING); - -	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; -	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; -	pegasus->dr.wValue = cpu_to_le16(0); -	pegasus->dr.wIndex = cpu_to_le16(indx); -	pegasus->dr.wLength = cpu_to_le16(size); -	pegasus->ctrl_urb->transfer_buffer_length = size; - -	usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, -			     usb_sndctrlpipe(pegasus->usb, 0), -			     (char *) &pegasus->dr, -			     buffer, size, ctrl_callback, pegasus); - -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); - -	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { -		if (ret == -ENODEV) -			netif_device_detach(pegasus->net); -		netif_err(pegasus, drv, pegasus->net, -			  "%s, status %d\n", __func__, ret); -		goto out; -	} - -	schedule(); -out: -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	kfree(buffer); +	ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), +			      PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0, +			      indx, data, size, 100); +	if (ret < 0) +		netif_dbg(pegasus, drv, pegasus->net, +			  "%s returned %d\n", __func__, ret);  	return ret;  }  static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)  {  	int ret; -	char *tmp; -	DECLARE_WAITQUEUE(wait, current); - -	tmp = kmemdup(&data, 1, GFP_KERNEL); -	if (!tmp) { -		netif_warn(pegasus, drv, pegasus->net, -			   "out of memory in %s\n", __func__); -		return -ENOMEM; -	} -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); -	while (pegasus->flags & ETH_REGS_CHANGED) -		schedule(); -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_RUNNING); - -	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; -	pegasus->dr.bRequest = PEGASUS_REQ_SET_REG; -	pegasus->dr.wValue = cpu_to_le16(data); -	pegasus->dr.wIndex = cpu_to_le16(indx); -	pegasus->dr.wLength = cpu_to_le16(1); -	pegasus->ctrl_urb->transfer_buffer_length = 1; - -	usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, -			     usb_sndctrlpipe(pegasus->usb, 0), -			     (char *) &pegasus->dr, -			     tmp, 1, ctrl_callback, pegasus); - -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); - -	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { -		if (ret == -ENODEV) -			netif_device_detach(pegasus->net); -		if (net_ratelimit()) -			netif_err(pegasus, drv, pegasus->net, -				  "%s, status %d\n", __func__, ret); -		goto out; -	} - -	schedule(); -out: -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	kfree(tmp); +	ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), +			      PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data, +			      indx, &data, 1, 1000); +	if (ret < 0) +		netif_dbg(pegasus, drv, pegasus->net, +			  "%s returned %d\n", __func__, ret);  	return ret;  }  static int update_eth_regs_async(pegasus_t *pegasus)  { -	int ret; +	int ret = -ENOMEM; +	struct urb *async_urb; +	struct usb_ctrlrequest *req; -	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; -	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; -	pegasus->dr.wValue = cpu_to_le16(0); -	pegasus->dr.wIndex = cpu_to_le16(EthCtrl0); -	pegasus->dr.wLength = cpu_to_le16(3); -	pegasus->ctrl_urb->transfer_buffer_length = 3; +	req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); +	if (req == NULL) +		return ret; -	usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, -			     usb_sndctrlpipe(pegasus->usb, 0), -			     (char *) &pegasus->dr, -			     pegasus->eth_regs, 3, ctrl_callback, pegasus); +	async_urb = usb_alloc_urb(0, GFP_ATOMIC); +	if (async_urb == NULL) { +		kfree(req); +		return ret; +	} +	req->bRequestType = PEGASUS_REQT_WRITE; +	req->bRequest = PEGASUS_REQ_SET_REGS; +	req->wValue = cpu_to_le16(0); +	req->wIndex = cpu_to_le16(EthCtrl0); +	req->wLength = cpu_to_le16(3); + +	usb_fill_control_urb(async_urb, pegasus->usb, +			     usb_sndctrlpipe(pegasus->usb, 0), (void *)req, +			     pegasus->eth_regs, 3, async_ctrl_callback, req); -	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { +	ret = usb_submit_urb(async_urb, GFP_ATOMIC); +	if (ret) {  		if (ret == -ENODEV)  			netif_device_detach(pegasus->net);  		netif_err(pegasus, drv, pegasus->net, -			  "%s, status %d\n", __func__, ret); +			  "%s returned %d\n", __func__, ret);  	} -  	return ret;  } -/* Returns 0 on success, error on failure */ -static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) +static int __mii_op(pegasus_t *p, __u8 phy, __u8 indx, __u16 *regd, __u8 cmd)  {  	int i;  	__u8 data[4] = { phy, 0, 0, indx };  	__le16 regdi; -	int ret; +	int ret = -ETIMEDOUT; -	set_register(pegasus, PhyCtrl, 0); -	set_registers(pegasus, PhyAddr, sizeof(data), data); -	set_register(pegasus, PhyCtrl, (indx | PHY_READ)); +	if (cmd & PHY_WRITE) { +		__le16 *t = (__le16 *) & data[1]; +		*t = cpu_to_le16(*regd); +	} +	set_register(p, PhyCtrl, 0); +	set_registers(p, PhyAddr, sizeof(data), data); +	set_register(p, PhyCtrl, (indx | cmd));  	for (i = 0; i < REG_TIMEOUT; i++) { -		ret = get_registers(pegasus, PhyCtrl, 1, data); -		if (ret == -ESHUTDOWN) +		ret = get_registers(p, PhyCtrl, 1, data); +		if (ret < 0)  			goto fail;  		if (data[0] & PHY_DONE)  			break;  	} -  	if (i >= REG_TIMEOUT)  		goto fail; - -	ret = get_registers(pegasus, PhyData, 2, ®di); -	*regd = le16_to_cpu(regdi); +	if (cmd & PHY_READ) { +		ret = get_registers(p, PhyData, 2, ®di); +		*regd = le16_to_cpu(regdi); +		return ret; +	} +	return 0; +fail: +	netif_dbg(p, drv, p->net, "%s failed\n", __func__);  	return ret; +} -fail: -	netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); +/* Returns non-negative int on success, error on failure */ +static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) +{ +	return __mii_op(pegasus, phy, indx, regd, PHY_READ); +} -	return ret; +/* Returns zero on success, error on failure */ +static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) +{ +	return __mii_op(pegasus, phy, indx, regd, PHY_WRITE);  }  static int mdio_read(struct net_device *dev, int phy_id, int loc) @@ -364,40 +253,11 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc)  	return (int)res;  } -static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd) -{ -	int i; -	__u8 data[4] = { phy, 0, 0, indx }; -	int ret; - -	data[1] = (u8) regd; -	data[2] = (u8) (regd >> 8); -	set_register(pegasus, PhyCtrl, 0); -	set_registers(pegasus, PhyAddr, sizeof(data), data); -	set_register(pegasus, PhyCtrl, (indx | PHY_WRITE)); -	for (i = 0; i < REG_TIMEOUT; i++) { -		ret = get_registers(pegasus, PhyCtrl, 1, data); -		if (ret == -ESHUTDOWN) -			goto fail; -		if (data[0] & PHY_DONE) -			break; -	} - -	if (i >= REG_TIMEOUT) -		goto fail; - -	return ret; - -fail: -	netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); -	return -ETIMEDOUT; -} -  static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)  {  	pegasus_t *pegasus = netdev_priv(dev); -	write_mii_word(pegasus, phy_id, loc, val); +	write_mii_word(pegasus, phy_id, loc, (__u16 *)&val);  }  static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata) @@ -434,7 +294,6 @@ fail:  static inline void enable_eprom_write(pegasus_t *pegasus)  {  	__u8 tmp; -	int ret;  	get_registers(pegasus, EthCtrl2, 1, &tmp);  	set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE); @@ -443,7 +302,6 @@ static inline void enable_eprom_write(pegasus_t *pegasus)  static inline void disable_eprom_write(pegasus_t *pegasus)  {  	__u8 tmp; -	int ret;  	get_registers(pegasus, EthCtrl2, 1, &tmp);  	set_register(pegasus, EpromCtrl, 0); @@ -537,7 +395,8 @@ static inline int reset_mac(pegasus_t *pegasus)  	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {  		__u16 auxmode;  		read_mii_word(pegasus, 3, 0x1b, &auxmode); -		write_mii_word(pegasus, 3, 0x1b, auxmode | 4); +		auxmode |= 4; +		write_mii_word(pegasus, 3, 0x1b, &auxmode);  	}  	return 0; @@ -569,57 +428,13 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)  	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {  		u16 auxmode;  		read_mii_word(pegasus, 0, 0x1b, &auxmode); -		write_mii_word(pegasus, 0, 0x1b, auxmode | 4); +		auxmode |= 4; +		write_mii_word(pegasus, 0, 0x1b, &auxmode);  	}  	return ret;  } -static void fill_skb_pool(pegasus_t *pegasus) -{ -	int i; - -	for (i = 0; i < RX_SKBS; i++) { -		if (pegasus->rx_pool[i]) -			continue; -		pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2); -		/* -		 ** we give up if the allocation fail. the tasklet will be -		 ** rescheduled again anyway... -		 */ -		if (pegasus->rx_pool[i] == NULL) -			return; -		skb_reserve(pegasus->rx_pool[i], 2); -	} -} - -static void free_skb_pool(pegasus_t *pegasus) -{ -	int i; - -	for (i = 0; i < RX_SKBS; i++) { -		if (pegasus->rx_pool[i]) { -			dev_kfree_skb(pegasus->rx_pool[i]); -			pegasus->rx_pool[i] = NULL; -		} -	} -} - -static inline struct sk_buff *pull_skb(pegasus_t * pegasus) -{ -	int i; -	struct sk_buff *skb; - -	for (i = 0; i < RX_SKBS; i++) { -		if (likely(pegasus->rx_pool[i] != NULL)) { -			skb = pegasus->rx_pool[i]; -			pegasus->rx_pool[i] = NULL; -			return skb; -		} -	} -	return NULL; -} -  static void read_bulk_callback(struct urb *urb)  {  	pegasus_t *pegasus = urb->context; @@ -704,9 +519,8 @@ static void read_bulk_callback(struct urb *urb)  	if (pegasus->flags & PEGASUS_UNPLUG)  		return; -	spin_lock(&pegasus->rx_pool_lock); -	pegasus->rx_skb = pull_skb(pegasus); -	spin_unlock(&pegasus->rx_pool_lock); +	pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, PEGASUS_MTU, +						      GFP_ATOMIC);  	if (pegasus->rx_skb == NULL)  		goto tl_sched; @@ -734,24 +548,23 @@ tl_sched:  static void rx_fixup(unsigned long data)  {  	pegasus_t *pegasus; -	unsigned long flags;  	int status;  	pegasus = (pegasus_t *) data;  	if (pegasus->flags & PEGASUS_UNPLUG)  		return; -	spin_lock_irqsave(&pegasus->rx_pool_lock, flags); -	fill_skb_pool(pegasus);  	if (pegasus->flags & PEGASUS_RX_URB_FAIL)  		if (pegasus->rx_skb)  			goto try_again;  	if (pegasus->rx_skb == NULL) -		pegasus->rx_skb = pull_skb(pegasus); +		pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, +							      PEGASUS_MTU, +							      GFP_ATOMIC);  	if (pegasus->rx_skb == NULL) {  		netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n");  		tasklet_schedule(&pegasus->rx_tl); -		goto done; +		return;  	}  	usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,  			  usb_rcvbulkpipe(pegasus->usb, 1), @@ -767,8 +580,6 @@ try_again:  	} else {  		pegasus->flags &= ~PEGASUS_RX_URB_FAIL;  	} -done: -	spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags);  }  static void write_bulk_callback(struct urb *urb) @@ -963,7 +774,6 @@ static void free_all_urbs(pegasus_t *pegasus)  	usb_free_urb(pegasus->intr_urb);  	usb_free_urb(pegasus->tx_urb);  	usb_free_urb(pegasus->rx_urb); -	usb_free_urb(pegasus->ctrl_urb);  }  static void unlink_all_urbs(pegasus_t *pegasus) @@ -971,48 +781,42 @@ static void unlink_all_urbs(pegasus_t *pegasus)  	usb_kill_urb(pegasus->intr_urb);  	usb_kill_urb(pegasus->tx_urb);  	usb_kill_urb(pegasus->rx_urb); -	usb_kill_urb(pegasus->ctrl_urb);  }  static int alloc_urbs(pegasus_t *pegasus)  { -	pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); -	if (!pegasus->ctrl_urb) -		return 0; +	int res = -ENOMEM; +  	pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!pegasus->rx_urb) { -		usb_free_urb(pegasus->ctrl_urb); -		return 0; +		return res;  	}  	pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!pegasus->tx_urb) {  		usb_free_urb(pegasus->rx_urb); -		usb_free_urb(pegasus->ctrl_urb); -		return 0; +		return res;  	}  	pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!pegasus->intr_urb) {  		usb_free_urb(pegasus->tx_urb);  		usb_free_urb(pegasus->rx_urb); -		usb_free_urb(pegasus->ctrl_urb); -		return 0; +		return res;  	} -	return 1; +	return 0;  }  static int pegasus_open(struct net_device *net)  {  	pegasus_t *pegasus = netdev_priv(net); -	int res; +	int res=-ENOMEM;  	if (pegasus->rx_skb == NULL) -		pegasus->rx_skb = pull_skb(pegasus); -	/* -	 ** Note: no point to free the pool.  it is empty :-) -	 */ +		pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, +							      PEGASUS_MTU, +							      GFP_KERNEL);  	if (!pegasus->rx_skb) -		return -ENOMEM; +		goto exit;  	res = set_registers(pegasus, EthID, 6, net->dev_addr); @@ -1038,13 +842,13 @@ static int pegasus_open(struct net_device *net)  		usb_kill_urb(pegasus->rx_urb);  		goto exit;  	} -	if ((res = enable_net_traffic(net, pegasus->usb))) { +	res = enable_net_traffic(net, pegasus->usb); +	if (res < 0) {  		netif_dbg(pegasus, ifup, net,  			  "can't enable_net_traffic() - %d\n", res);  		res = -EIO;  		usb_kill_urb(pegasus->rx_urb);  		usb_kill_urb(pegasus->intr_urb); -		free_skb_pool(pegasus);  		goto exit;  	}  	set_carrier(net); @@ -1195,7 +999,7 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)  	case SIOCDEVPRIVATE + 2:  		if (!capable(CAP_NET_ADMIN))  			return -EPERM; -		write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); +		write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, &data[2]);  		res = 0;  		break;  	default: @@ -1219,11 +1023,7 @@ static void pegasus_set_multicast(struct net_device *net)  		pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;  		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;  	} - -	pegasus->ctrl_urb->status = 0; - -	pegasus->flags |= ETH_REGS_CHANGE; -	ctrl_callback(pegasus->ctrl_urb); +	update_eth_regs_async(pegasus);  }  static __u8 mii_phy_probe(pegasus_t *pegasus) @@ -1340,9 +1140,9 @@ static int pegasus_probe(struct usb_interface *intf,  	pegasus = netdev_priv(net);  	pegasus->dev_index = dev_index; -	init_waitqueue_head(&pegasus->ctrl_wait); -	if (!alloc_urbs(pegasus)) { +	res = alloc_urbs(pegasus); +	if (res < 0) {  		dev_err(&intf->dev, "can't allocate %s\n", "urbs");  		goto out1;  	} @@ -1364,7 +1164,6 @@ static int pegasus_probe(struct usb_interface *intf,  	pegasus->mii.mdio_write = mdio_write;  	pegasus->mii.phy_id_mask = 0x1f;  	pegasus->mii.reg_num_mask = 0x1f; -	spin_lock_init(&pegasus->rx_pool_lock);  	pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV  				| NETIF_MSG_PROBE | NETIF_MSG_LINK); @@ -1376,7 +1175,6 @@ static int pegasus_probe(struct usb_interface *intf,  		goto out2;  	}  	set_ethernet_addr(pegasus); -	fill_skb_pool(pegasus);  	if (pegasus->features & PEGASUS_II) {  		dev_info(&intf->dev, "setup Pegasus II specific registers\n");  		setup_pegasus_II(pegasus); @@ -1394,17 +1192,13 @@ static int pegasus_probe(struct usb_interface *intf,  	if (res)  		goto out3;  	queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, -				CARRIER_CHECK_DELAY); - -	dev_info(&intf->dev, "%s, %s, %pM\n", -		 net->name, -		 usb_dev_id[dev_index].name, -		 net->dev_addr); +			   CARRIER_CHECK_DELAY); +	dev_info(&intf->dev, "%s, %s, %pM\n", net->name, +		 usb_dev_id[dev_index].name, net->dev_addr);  	return 0;  out3:  	usb_set_intfdata(intf, NULL); -	free_skb_pool(pegasus);  out2:  	free_all_urbs(pegasus);  out1: @@ -1429,7 +1223,6 @@ static void pegasus_disconnect(struct usb_interface *intf)  	unregister_netdev(pegasus->net);  	unlink_all_urbs(pegasus);  	free_all_urbs(pegasus); -	free_skb_pool(pegasus);  	if (pegasus->rx_skb != NULL) {  		dev_kfree_skb(pegasus->rx_skb);  		pegasus->rx_skb = NULL; diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h index 65b78b35b73..d15646244fd 100644 --- a/drivers/net/usb/pegasus.h +++ b/drivers/net/usb/pegasus.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 1999-2003 Petko Manolov - Petkan (petkan@users.sourceforge.net) + * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com)   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as published @@ -13,7 +13,6 @@  #define	HAS_HOME_PNA		0x40000000  #define	PEGASUS_MTU		1536 -#define	RX_SKBS			4  #define	EPROM_WRITE		0x01  #define	EPROM_READ		0x02 @@ -34,8 +33,6 @@  #define	CTRL_URB_SLEEP		0x00000020  #define	PEGASUS_UNPLUG		0x00000040  #define	PEGASUS_RX_URB_FAIL	0x00000080 -#define	ETH_REGS_CHANGE		0x40000000 -#define	ETH_REGS_CHANGED	0x80000000  #define	RX_MULTICAST		2  #define	RX_PROMISCUOUS		4 @@ -96,12 +93,8 @@ typedef struct pegasus {  	int			intr_interval;  	struct tasklet_struct	rx_tl;  	struct delayed_work	carrier_check; -	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb; -	struct sk_buff		*rx_pool[RX_SKBS]; +	struct urb		*rx_urb, *tx_urb, *intr_urb;  	struct sk_buff		*rx_skb; -	struct usb_ctrlrequest	dr; -	wait_queue_head_t	ctrl_wait; -	spinlock_t		rx_pool_lock;  	int			chip;  	unsigned char		intr_buff[8];  	__u8			tx_buff[PEGASUS_MTU]; diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index 79ab2435d9d..a923d61c6fc 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -413,11 +413,10 @@ static void sierra_net_handle_lsi(struct usbnet *dev, char *data,  	if (link_up) {  		sierra_net_set_ctx_index(priv, hh->msgspecific.byte);  		priv->link_up = 1; -		netif_carrier_on(dev->net);  	} else {  		priv->link_up = 0; -		netif_carrier_off(dev->net);  	} +	usbnet_link_change(dev, link_up, 0);  }  static void sierra_net_dosync(struct usbnet *dev) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 51f3192f393..1e5a9b72650 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -938,6 +938,27 @@ static const struct ethtool_ops usbnet_ethtool_ops = {  /*-------------------------------------------------------------------------*/ +static void __handle_link_change(struct usbnet *dev) +{ +	if (!test_bit(EVENT_DEV_OPEN, &dev->flags)) +		return; + +	if (!netif_carrier_ok(dev->net)) { +		/* kill URBs for reading packets to save bus bandwidth */ +		unlink_urbs(dev, &dev->rxq); + +		/* +		 * tx_timeout will unlink URBs for sending packets and +		 * tx queue is stopped by netcore after link becomes off +		 */ +	} else { +		/* submitting URBs for reading packets */ +		tasklet_schedule(&dev->bh); +	} + +	clear_bit(EVENT_LINK_CHANGE, &dev->flags); +} +  /* work that cannot be done in interrupt context uses keventd.   *   * NOTE:  with 2.5 we could do more of this using completion callbacks, @@ -1035,8 +1056,14 @@ skip_reset:  		} else {  			usb_autopm_put_interface(dev->intf);  		} + +		/* handle link change from link resetting */ +		__handle_link_change(dev);  	} +	if (test_bit (EVENT_LINK_CHANGE, &dev->flags)) +		__handle_link_change(dev); +  	if (dev->flags)  		netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags);  } @@ -1286,6 +1313,7 @@ static void usbnet_bh (unsigned long param)  	// or are we maybe short a few urbs?  	} else if (netif_running (dev->net) &&  		   netif_device_present (dev->net) && +		   netif_carrier_ok(dev->net) &&  		   !timer_pending (&dev->delay) &&  		   !test_bit (EVENT_RX_HALT, &dev->flags)) {  		int	temp = dev->rxq.qlen; @@ -1521,7 +1549,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)  	netif_device_attach (net);  	if (dev->driver_info->flags & FLAG_LINK_INTR) -		netif_carrier_off(net); +		usbnet_link_change(dev, 0, 0);  	return 0; @@ -1653,6 +1681,21 @@ int usbnet_manage_power(struct usbnet *dev, int on)  }  EXPORT_SYMBOL(usbnet_manage_power); +void usbnet_link_change(struct usbnet *dev, bool link, bool need_reset) +{ +	/* update link after link is reseted */ +	if (link && !need_reset) +		netif_carrier_on(dev->net); +	else +		netif_carrier_off(dev->net); + +	if (need_reset && link) +		usbnet_defer_kevent(dev, EVENT_LINK_RESET); +	else +		usbnet_defer_kevent(dev, EVENT_LINK_CHANGE); +} +EXPORT_SYMBOL(usbnet_link_change); +  /*-------------------------------------------------------------------------*/  static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,  			     u16 value, u16 index, void *data, u16 size)  |