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

Commit d8a7e3a7 authored by Azhar Shaikh's avatar Azhar Shaikh
Browse files

net: usbnet: Do not wait for ipa_ready_callback



Commit 8c949509 ("net: usbnet: Perform IPA initialization
after IPA is ready") waits for IPA ready call back to unblock
usbnet_probe and then initialize the odu bridge. But while booting
up in HOST mode with device connected, the IPA is not ready by
the time USB is ready and it gets blocked at the wait instead of
continuing further. This leads to usbnet_probe failure since the
wait for ipa ready callback is timedout.
So instead of waiting for the ipa_ready_callback, in usbnet_probe()
just continue with probe and do odu_bridge_init() whenever
ipa is ready. Schedule a work for odu_bridge_init() to avoid
inter-locking of IPA functions.

Change-Id: I439643d61814e59c7a87eca2195b72471bface2b
Signed-off-by: default avatarAzhar Shaikh <azhars@codeaurora.org>
parent 0ce8ed27
Loading
Loading
Loading
Loading
+38 −44
Original line number Diff line number Diff line
@@ -2008,14 +2008,42 @@ static void usbnet_ipa_send_routine(struct work_struct *work)
	spin_unlock(&dev->ipa_pendq.lock);
}

static void usbnet_odu_bridge_init(struct work_struct *work)
{
	struct usbnet *dev = container_of(work, struct usbnet, odu_bridge_init);
	struct odu_bridge_params params;
	int status;

	/* Initialize the ODU bridge driver */
	params.netdev_name      = dev->net->name;
	params.priv             = dev;
	params.tx_dp_notify     = usbnet_ipa_tx_dp_cb;
	params.send_dl_skb      = (void *)&usbnet_ipa_tx_dl;
	params.ipa_desc_size    = (dev->ipa_high_watermark + 1) *
					sizeof(struct sps_iovec);
	memcpy(params.device_ethaddr, dev->net->dev_addr, 6);

	status = odu_bridge_init(&params);
	if (status) {
		pr_err("Couldnt initialize ODU_Bridge Driver\n");
		return;
	}

	status = odu_bridge_connect();
	if (!status) {
		usbnet_ipa_set_perf_level(dev);
	} else {
		pr_err("Could not connect to ODU bridge %d\n", status);
		return;
	}
}

static void usbnet_ipa_ready_callback(void *user_data)
{
	struct usbnet *dev = user_data;

	pr_info("%s: ipa is ready\n", __func__);
	dev->ipa_ready = true;

	wake_up_interruptible(&dev->wait_for_ipa_ready);
	queue_work(usbnet_wq, &dev->odu_bridge_init);
}

int
@@ -2030,9 +2058,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
	const char			*name;
	struct usb_driver 	*driver = to_usb_driver(udev->dev.driver);
	struct usbnet_ipa_ctx *usbnet_ipa = NULL;
	struct odu_bridge_params *params_ptr, params;

	params_ptr = &params;

	/* usbnet already took usb runtime pm, so have to enable the feature
	 * for usb interface, otherwise usb_autopm_get_interface may return
@@ -2070,7 +2095,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
	dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
				| NETIF_MSG_PROBE | NETIF_MSG_LINK);
	init_waitqueue_head(&dev->wait);
	init_waitqueue_head(&dev->wait_for_ipa_ready);
	skb_queue_head_init (&dev->rxq);
	skb_queue_head_init (&dev->txq);
	skb_queue_head_init (&dev->done);
@@ -2200,6 +2224,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
		/* Initialize flow control variables */
		skb_queue_head_init(&dev->ipa_pendq);
		INIT_WORK(&dev->ipa_send_task, usbnet_ipa_send_routine);
		INIT_WORK(&dev->odu_bridge_init, usbnet_odu_bridge_init);

		status = usbnet_ipa_setup_rm(dev);
		if (status) {
@@ -2211,34 +2236,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
		if (status)
			pr_err("USBNET: Debugfs Init Failed\n");

		/* Initialize the ODU bridge driver now: odu_bridge_init()*/
		params_ptr->netdev_name = net->name;
		params_ptr->priv = dev;
		params.tx_dp_notify = usbnet_ipa_tx_dp_cb;
		params_ptr->send_dl_skb = (void *)&usbnet_ipa_tx_dl;
		memcpy(params_ptr->device_ethaddr, net->dev_addr, 6);
		params_ptr->ipa_desc_size = (dev->ipa_high_watermark + 1) *
					sizeof(struct sps_iovec);

		status = odu_bridge_init(params_ptr);
		if (status) {
			pr_err("Couldnt initialize ODU_Bridge Driver\n");
			goto ipa_cleanup;
		}

		status = ipa_register_ipa_ready_cb(usbnet_ipa_ready_callback,
						   dev);
		if (!status) {
			pr_info("%s: ipa is not ready\n", __func__);
			status = wait_event_interruptible_timeout(
					dev->wait_for_ipa_ready, dev->ipa_ready,
					msecs_to_jiffies
						(USBNET_IPA_READY_TIMEOUT));
			if (!status) {
				pr_err("%s: ipa ready timeout\n", __func__);
				status = -ETIMEDOUT;
				goto ipa_cleanup;
			}
		} else if (status == -EEXIST) {
			pr_debug("USBNET: IPA is ready\n");
			usbnet_odu_bridge_init(&dev->odu_bridge_init);
		} else {
			pr_err("USBNET: error in ipa register cb\n");
			goto free_ipa;
		}
	}

@@ -2250,21 +2257,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
	if (dev->driver_info->flags & FLAG_LINK_INTR)
		usbnet_link_change(dev, 0, 0);

	if (enable_ipa_bridge) {
		status = odu_bridge_connect();
		if (status) {
			pr_err("Could not connect to ODU bridge %d\n",
			       status);
			goto ipa_cleanup;
		} else {
			usbnet_ipa_set_perf_level(dev);
		}
	}

	return 0;

ipa_cleanup:
	usbnet_ipa_cleanup_rm(dev);
free_ipa:
	kfree(usbnet_ipa);
unreg_netdev:
+2 −3
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@
#define USBNET_IPA_SYS_PIPE_MAX_PKTS_DESC 200
#define USBNET_IPA_SYS_PIPE_MIN_PKTS_DESC 5
#define USBNET_IPA_SYS_PIPE_DNE_PKTS (USBNET_IPA_SYS_PIPE_MAX_PKTS_DESC*2)
#define USBNET_IPA_READY_TIMEOUT 5000

struct usbnet_ipa_stats {
	/* RX Side */
@@ -119,8 +118,8 @@ struct usbnet {
	struct sk_buff_head	ipa_pendq;
	/* work to send pending packets to ipa */
	struct work_struct ipa_send_task;
	bool	ipa_ready;
	wait_queue_head_t wait_for_ipa_ready;
	/* work for odu bridge initialization */
	struct work_struct odu_bridge_init;
};

static inline struct usb_driver *driver_of(struct usb_interface *intf)