Commit a19c2619 authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by David S. Miller
Browse files

net: usb: kaweth: Remove last user of kaweth_control()



kaweth_async_set_rx_mode() invokes kaweth_contol() and has two callers:

- kaweth_open() which is invoked from preemptible context
.
- kaweth_start_xmit() which holds a spinlock and has bottom halfs disabled.

If called from kaweth_start_xmit() kaweth_async_set_rx_mode() obviously
cannot block, which means it can't call kaweth_control(). This is detected
with an in_interrupt() check.

Replace the in_interrupt() check in kaweth_async_set_rx_mode() with an
argument which is set true by the caller if the context is safe to sleep,
otherwise false.

Now kaweth_control() is only called from preemptible context which means
there is no need for GFP_ATOMIC allocations anymore. Replace it with
usb_control_msg(). Cleanup the code a bit while at it.

Finally remove kaweth_control() since the last user is gone.

Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent af3563be
Loading
Loading
Loading
Loading
+17 −151
Original line number Diff line number Diff line
@@ -103,10 +103,6 @@ static int kaweth_probe(
		const struct usb_device_id *id	/* from id_table */
	);
static void kaweth_disconnect(struct usb_interface *intf);
static int kaweth_internal_control_msg(struct usb_device *usb_dev,
				       unsigned int pipe,
				       struct usb_ctrlrequest *cmd, void *data,
				       int len, int timeout);
static int kaweth_suspend(struct usb_interface *intf, pm_message_t message);
static int kaweth_resume(struct usb_interface *intf);

@@ -235,48 +231,6 @@ struct kaweth_device
	struct kaweth_ethernet_configuration configuration;
};

/****************************************************************
 *     kaweth_control
 ****************************************************************/
static int kaweth_control(struct kaweth_device *kaweth,
			  unsigned int pipe,
			  __u8 request,
			  __u8 requesttype,
			  __u16 value,
			  __u16 index,
			  void *data,
			  __u16 size,
			  int timeout)
{
	struct usb_ctrlrequest *dr;
	int retval;

	if(in_interrupt()) {
		netdev_dbg(kaweth->net, "in_interrupt()\n");
		return -EBUSY;
	}

	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
	if (!dr)
		return -ENOMEM;

	dr->bRequestType = requesttype;
	dr->bRequest = request;
	dr->wValue = cpu_to_le16(value);
	dr->wIndex = cpu_to_le16(index);
	dr->wLength = cpu_to_le16(size);

	retval = kaweth_internal_control_msg(kaweth->dev,
					     pipe,
					     dr,
					     data,
					     size,
					     timeout);

	kfree(dr);
	return retval;
}

/****************************************************************
 *     kaweth_read_configuration
 ****************************************************************/
@@ -531,7 +485,8 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
	return result;
}

static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth);
static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth,
				     bool may_sleep);

/****************************************************************
 *     kaweth_usb_receive
@@ -661,7 +616,7 @@ static int kaweth_open(struct net_device *net)

	netif_start_queue(net);

	kaweth_async_set_rx_mode(kaweth);
	kaweth_async_set_rx_mode(kaweth, true);
	return 0;

err_out:
@@ -749,7 +704,7 @@ static netdev_tx_t kaweth_start_xmit(struct sk_buff *skb,

	spin_lock_irq(&kaweth->device_lock);

	kaweth_async_set_rx_mode(kaweth);
	kaweth_async_set_rx_mode(kaweth, false);
	netif_stop_queue(net);
	if (IS_BLOCKED(kaweth->status)) {
		goto skip;
@@ -826,37 +781,32 @@ static void kaweth_set_rx_mode(struct net_device *net)
/****************************************************************
 *     kaweth_async_set_rx_mode
 ****************************************************************/
static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth,
				     bool may_sleep)
{
	int result;
	int ret;
	__u16 packet_filter_bitmap = kaweth->packet_filter_bitmap;

	kaweth->packet_filter_bitmap = 0;
	if (packet_filter_bitmap == 0)
		return;

	if (in_interrupt())
	if (!may_sleep)
		return;

	result = kaweth_control(kaweth,
				usb_sndctrlpipe(kaweth->dev, 0),
	ret = usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0),
			      KAWETH_COMMAND_SET_PACKET_FILTER,
			      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
				packet_filter_bitmap,
				0,
				(void *)&kaweth->scratch,
				0,
			      packet_filter_bitmap, 0,
			      &kaweth->scratch, 0,
			      KAWETH_CONTROL_TIMEOUT);

	if(result < 0) {
	if (ret < 0)
		dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n",
			result);
	}
	else {
			ret);
	else
		netdev_dbg(kaweth->net, "Set Rx mode to %d\n",
			   packet_filter_bitmap);
}
}

/****************************************************************
 *     kaweth_tx_timeout
@@ -1163,88 +1113,4 @@ static void kaweth_disconnect(struct usb_interface *intf)
}


// FIXME this completion stuff is a modified clone of
// an OLD version of some stuff in usb.c ...
struct usb_api_data {
	wait_queue_head_t wqh;
	int done;
};

/*-------------------------------------------------------------------*
 * completion handler for compatibility wrappers (sync control/bulk) *
 *-------------------------------------------------------------------*/
static void usb_api_blocking_completion(struct urb *urb)
{
        struct usb_api_data *awd = (struct usb_api_data *)urb->context;

	awd->done=1;
	wake_up(&awd->wqh);
}

/*-------------------------------------------------------------------*
 *                         COMPATIBILITY STUFF                       *
 *-------------------------------------------------------------------*/

// Starts urb and waits for completion or timeout
static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
{
	struct usb_api_data awd;
        int status;

        init_waitqueue_head(&awd.wqh);
        awd.done = 0;

        urb->context = &awd;
        status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status) {
                // something went wrong
                usb_free_urb(urb);
                return status;
        }

	if (!wait_event_timeout(awd.wqh, awd.done, timeout)) {
                // timeout
                dev_warn(&urb->dev->dev, "usb_control/bulk_msg: timeout\n");
                usb_kill_urb(urb);  // remove urb safely
                status = -ETIMEDOUT;
        }
	else {
                status = urb->status;
	}

        if (actual_length) {
                *actual_length = urb->actual_length;
	}

        usb_free_urb(urb);
        return status;
}

/*-------------------------------------------------------------------*/
// returns status (negative) or length (positive)
static int kaweth_internal_control_msg(struct usb_device *usb_dev,
				       unsigned int pipe,
				       struct usb_ctrlrequest *cmd, void *data,
				       int len, int timeout)
{
        struct urb *urb;
        int retv;
        int length = 0; /* shut up GCC */

	urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb)
                return -ENOMEM;

        usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data,
			 len, usb_api_blocking_completion, NULL);

        retv = usb_start_wait_urb(urb, timeout, &length);
        if (retv < 0) {
                return retv;
	}
        else {
                return length;
	}
}

module_usb_driver(kaweth_driver);