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

Commit 40a82917 authored by hayeswang's avatar hayeswang Committed by David S. Miller
Browse files

net/usb/r8152: enable interrupt transfer



Use the interrupt transfer to replace polling link status.

Signed-off-by: default avatarHayes Wang <hayeswang@realtek.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5bd23881
Loading
Loading
Loading
Loading
+113 −27
Original line number Diff line number Diff line
@@ -272,6 +272,9 @@ enum rtl_register_content {

#define RTL8152_MAX_TX		10
#define RTL8152_MAX_RX		10
#define INTBUFSIZE		2

#define INTR_LINK		0x0004

#define RTL8152_REQT_READ	0xc0
#define RTL8152_REQT_WRITE	0x40
@@ -292,7 +295,8 @@ enum rtl_register_content {
enum rtl8152_flags {
	RTL8152_UNPLUG = 0,
	RTL8152_SET_RX_MODE,
	WORK_ENABLE
	WORK_ENABLE,
	RTL8152_LINK_CHG,
};

/* Define these values to match your device */
@@ -347,7 +351,9 @@ struct r8152 {
	unsigned long flags;
	struct usb_device *udev;
	struct tasklet_struct tl;
	struct usb_interface *intf;
	struct net_device *netdev;
	struct urb *intr_urb;
	struct tx_agg tx_info[RTL8152_MAX_TX];
	struct rx_agg rx_info[RTL8152_MAX_RX];
	struct list_head rx_done, tx_free;
@@ -355,8 +361,10 @@ struct r8152 {
	spinlock_t rx_lock, tx_lock;
	struct delayed_work schedule;
	struct mii_if_info mii;
	int intr_interval;
	u32 msg_enable;
	u16 ocp_base;
	u8 *intr_buff;
	u8 version;
	u8 speed;
};
@@ -860,6 +868,62 @@ static void write_bulk_callback(struct urb *urb)
		tasklet_schedule(&tp->tl);
}

static void intr_callback(struct urb *urb)
{
	struct r8152 *tp;
	__u16 *d;
	int status = urb->status;
	int res;

	tp = urb->context;
	if (!tp)
		return;

	if (!test_bit(WORK_ENABLE, &tp->flags))
		return;

	if (test_bit(RTL8152_UNPLUG, &tp->flags))
		return;

	switch (status) {
	case 0:			/* success */
		break;
	case -ECONNRESET:	/* unlink */
	case -ESHUTDOWN:
		netif_device_detach(tp->netdev);
	case -ENOENT:
		return;
	case -EOVERFLOW:
		netif_info(tp, intr, tp->netdev, "intr status -EOVERFLOW\n");
		goto resubmit;
	/* -EPIPE:  should clear the halt */
	default:
		netif_info(tp, intr, tp->netdev, "intr status %d\n", status);
		goto resubmit;
	}

	d = urb->transfer_buffer;
	if (INTR_LINK & __le16_to_cpu(d[0])) {
		if (!(tp->speed & LINK_STATUS)) {
			set_bit(RTL8152_LINK_CHG, &tp->flags);
			schedule_delayed_work(&tp->schedule, 0);
		}
	} else {
		if (tp->speed & LINK_STATUS) {
			set_bit(RTL8152_LINK_CHG, &tp->flags);
			schedule_delayed_work(&tp->schedule, 0);
		}
	}

resubmit:
	res = usb_submit_urb(urb, GFP_ATOMIC);
	if (res == -ENODEV)
		netif_device_detach(tp->netdev);
	else if (res)
		netif_err(tp, intr, tp->netdev,
			"can't resubmit intr, status %d\n", res);
}

static inline void *rx_agg_align(void *data)
{
	return (void *)ALIGN((uintptr_t)data, 8);
@@ -899,11 +963,24 @@ static void free_all_mem(struct r8152 *tp)
			tp->tx_info[i].head = NULL;
		}
	}

	if (tp->intr_urb) {
		usb_free_urb(tp->intr_urb);
		tp->intr_urb = NULL;
	}

	if (tp->intr_buff) {
		kfree(tp->intr_buff);
		tp->intr_buff = NULL;
	}
}

static int alloc_all_mem(struct r8152 *tp)
{
	struct net_device *netdev = tp->netdev;
	struct usb_interface *intf = tp->intf;
	struct usb_host_interface *alt = intf->cur_altsetting;
	struct usb_host_endpoint *ep_intr = alt->endpoint + 2;
	struct urb *urb;
	int node, i;
	u8 *buf;
@@ -968,6 +1045,19 @@ static int alloc_all_mem(struct r8152 *tp)
		list_add_tail(&tp->tx_info[i].list, &tp->tx_free);
	}

	tp->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!tp->intr_urb)
		goto err1;

	tp->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
	if (!tp->intr_buff)
		goto err1;

	tp->intr_interval = (int)ep_intr->desc.bInterval;
	usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3),
		     tp->intr_buff, INTBUFSIZE, intr_callback,
		     tp, tp->intr_interval);

	return 0;

err1:
@@ -1228,8 +1318,10 @@ static void rtl8152_set_rx_mode(struct net_device *netdev)
{
	struct r8152 *tp = netdev_priv(netdev);

	if (tp->speed & LINK_STATUS)
	if (tp->speed & LINK_STATUS) {
		set_bit(RTL8152_SET_RX_MODE, &tp->flags);
		schedule_delayed_work(&tp->schedule, 0);
	}
}

static void _rtl8152_set_rx_mode(struct net_device *netdev)
@@ -1648,7 +1740,6 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
	r8152_mdio_write(tp, MII_BMCR, bmcr);

out:
	schedule_delayed_work(&tp->schedule, 5 * HZ);

	return ret;
}
@@ -1671,6 +1762,7 @@ static void set_carrier(struct r8152 *tp)
	struct net_device *netdev = tp->netdev;
	u8 speed;

	clear_bit(RTL8152_LINK_CHG, &tp->flags);
	speed = rtl8152_get_speed(tp);

	if (speed & LINK_STATUS) {
@@ -1700,13 +1792,12 @@ static void rtl_work_func_t(struct work_struct *work)
	if (test_bit(RTL8152_UNPLUG, &tp->flags))
		goto out1;

	if (test_bit(RTL8152_LINK_CHG, &tp->flags))
		set_carrier(tp);

	if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
		_rtl8152_set_rx_mode(tp->netdev);

	schedule_delayed_work(&tp->schedule, HZ);

out1:
	return;
}
@@ -1716,28 +1807,20 @@ static int rtl8152_open(struct net_device *netdev)
	struct r8152 *tp = netdev_priv(netdev);
	int res = 0;

	tp->speed = rtl8152_get_speed(tp);
	if (tp->speed & LINK_STATUS) {
		res = rtl8152_enable(tp);
	res = usb_submit_urb(tp->intr_urb, GFP_KERNEL);
	if (res) {
		if (res == -ENODEV)
			netif_device_detach(tp->netdev);

			netif_err(tp, ifup, netdev,
				  "rtl8152_open failed: %d\n", res);
		netif_warn(tp, ifup, netdev,
			"intr_urb submit failed: %d\n", res);
		return res;
	}

		netif_carrier_on(netdev);
	} else {
		netif_stop_queue(netdev);
		netif_carrier_off(netdev);
	}

	rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL);
	tp->speed = 0;
	netif_carrier_off(netdev);
	netif_start_queue(netdev);
	set_bit(WORK_ENABLE, &tp->flags);
	schedule_delayed_work(&tp->schedule, 0);

	return res;
}
@@ -1747,6 +1830,7 @@ static int rtl8152_close(struct net_device *netdev)
	struct r8152 *tp = netdev_priv(netdev);
	int res = 0;

	usb_kill_urb(tp->intr_urb);
	clear_bit(WORK_ENABLE, &tp->flags);
	cancel_delayed_work_sync(&tp->schedule);
	netif_stop_queue(netdev);
@@ -1872,6 +1956,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)

	if (netif_running(tp->netdev)) {
		clear_bit(WORK_ENABLE, &tp->flags);
		usb_kill_urb(tp->intr_urb);
		cancel_delayed_work_sync(&tp->schedule);
		tasklet_disable(&tp->tl);
	}
@@ -1888,10 +1973,11 @@ static int rtl8152_resume(struct usb_interface *intf)
	r8152b_init(tp);
	netif_device_attach(tp->netdev);
	if (netif_running(tp->netdev)) {
		rtl8152_enable(tp);
		rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL);
		tp->speed = 0;
		netif_carrier_off(tp->netdev);
		set_bit(WORK_ENABLE, &tp->flags);
		set_bit(RTL8152_SET_RX_MODE, &tp->flags);
		schedule_delayed_work(&tp->schedule, 0);
		usb_submit_urb(tp->intr_urb, GFP_KERNEL);
		tasklet_enable(&tp->tl);
	}

@@ -2027,13 +2113,13 @@ static int rtl8152_probe(struct usb_interface *intf,

	tp->udev = udev;
	tp->netdev = netdev;
	tp->intf = intf;
	netdev->netdev_ops = &rtl8152_netdev_ops;
	netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;

	netdev->features |= NETIF_F_IP_CSUM;
	netdev->hw_features = NETIF_F_IP_CSUM;
	SET_ETHTOOL_OPS(netdev, &ops);
	tp->speed = 0;

	tp->mii.dev = netdev;
	tp->mii.mdio_read = read_mii_word;