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

Commit 44dc2017 authored by Jinesh K. Jayakumar's avatar Jinesh K. Jayakumar
Browse files

msm: ipa: Use work queue for refreshing offload devices



Performing offload init from uC ready callbacks can cause dead locks when
commands need to be sent to IPA uC since the callbacks are executed from
uC response handler itself. Use work queue in the offload sub-system for
performing offload device refreshes.

CRs-Fixed: 2438237
Change-Id: I15b3c088349088cbbf42892835175b74ef42849f
Signed-off-by: default avatarJinesh K. Jayakumar <jineshk@codeaurora.org>
parent 76d0fd8b
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -166,6 +166,15 @@ config IPA_ETH_NOAUTO
	  to enable offloading. This feature is meant only for debugging.
	  If unsure, say N.

config IPA_ETH_DEBUG
	bool "Enable addtional debug logging in the offload sub-system"
	depends on IPA_ETH
	help
	  Enabling this option increases the number of messages logged by the offload
	  sub-system for aiding debugging. Additional debug messages are logged into
	  IPC log as well as kernel log using dynamic debug.
	  If unsure, say N.

source "drivers/platform/msm/ipa/ipa_v3/ethernet/aquantia/Kconfig"

config RMNET_IPA3
+180 −73
Original line number Diff line number Diff line
@@ -18,9 +18,14 @@

#include "ipa_eth_i.h"

static bool ipa_eth_is_ready;
static bool ipa_eth_ipa_is_ready;
static bool ipa_eth_ipa_uc_is_ready;
enum ipa_eth_states {
	IPA_ETH_ST_READY,
	IPA_ETH_ST_UC_READY,
	IPA_ETH_ST_IPA_READY,
	IPA_ETH_ST_MAX,
};

static unsigned long ipa_eth_state;

static struct dentry *ipa_eth_debugfs;
static struct dentry *ipa_eth_drivers_debugfs;
@@ -38,54 +43,67 @@ static bool ipa_eth_ipc_logdbg = IPA_ETH_IPC_LOGDBG_DEFAULT;
module_param(ipa_eth_ipc_logdbg, bool, 0444);
MODULE_PARM_DESC(ipa_eth_ipc_logdbg, "Log debug IPC messages");

static struct workqueue_struct *ipa_eth_wq;

static inline bool ipa_eth_ready(void)
{
	return ipa_eth_is_ready &&
		ipa_eth_ipa_is_ready &&
		ipa_eth_ipa_uc_is_ready;
	return test_bit(IPA_ETH_ST_READY, &ipa_eth_state) &&
		test_bit(IPA_ETH_ST_UC_READY, &ipa_eth_state) &&
		test_bit(IPA_ETH_ST_IPA_READY, &ipa_eth_state);
}

static inline bool initable(struct ipa_eth_device *eth_dev)
{
	return eth_dev->init;
}

static inline bool startable(struct ipa_eth_device *eth_dev)
{
	return eth_dev->init && eth_dev->start &&
		test_bit(IPA_ETH_IF_ST_LOWER_UP, &eth_dev->if_state);
}

static int ipa_eth_init_device(struct ipa_eth_device *eth_dev)
{
	int rc;

	if (eth_dev->state == IPA_ETH_ST_INITED)
	if (eth_dev->of_state == IPA_ETH_OF_ST_INITED)
		return 0;

	if (eth_dev->state != IPA_ETH_ST_DEINITED)
	if (eth_dev->of_state != IPA_ETH_OF_ST_DEINITED)
		return -EFAULT;

	rc = ipa_eth_ep_init_headers(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to init EP headers");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	rc = ipa_eth_pm_register(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to register with IPA PM");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	rc = ipa_eth_offload_init(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to init offload");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	rc = ipa_eth_ep_register_interface(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to register EP interface");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	ipa_eth_dev_log(eth_dev, "Initialized device");

	eth_dev->state = IPA_ETH_ST_INITED;
	eth_dev->of_state = IPA_ETH_OF_ST_INITED;

	return 0;
}
@@ -94,36 +112,36 @@ static int ipa_eth_deinit_device(struct ipa_eth_device *eth_dev)
{
	int rc;

	if (eth_dev->state == IPA_ETH_ST_DEINITED)
	if (eth_dev->of_state == IPA_ETH_OF_ST_DEINITED)
		return 0;

	if (eth_dev->state != IPA_ETH_ST_INITED)
	if (eth_dev->of_state != IPA_ETH_OF_ST_INITED)
		return -EFAULT;

	rc = ipa_eth_ep_unregister_interface(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to unregister IPA interface");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	rc = ipa_eth_offload_deinit(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to deinit offload");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	rc = ipa_eth_pm_unregister(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to unregister with IPA PM");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	ipa_eth_dev_log(eth_dev, "Deinitialized device");

	eth_dev->state = IPA_ETH_ST_DEINITED;
	eth_dev->of_state = IPA_ETH_OF_ST_DEINITED;

	return 0;
}
@@ -132,29 +150,29 @@ static int ipa_eth_start_device(struct ipa_eth_device *eth_dev)
{
	int rc;

	if (eth_dev->state == IPA_ETH_ST_STARTED)
	if (eth_dev->of_state == IPA_ETH_OF_ST_STARTED)
		return 0;

	if (eth_dev->state != IPA_ETH_ST_INITED)
	if (eth_dev->of_state != IPA_ETH_OF_ST_INITED)
		return -EFAULT;

	rc = ipa_eth_pm_activate(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to activate device PM");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	rc = ipa_eth_offload_start(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to start offload");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	ipa_eth_dev_log(eth_dev, "Started device");

	eth_dev->state = IPA_ETH_ST_STARTED;
	eth_dev->of_state = IPA_ETH_OF_ST_STARTED;

	return 0;
}
@@ -163,48 +181,56 @@ static int ipa_eth_stop_device(struct ipa_eth_device *eth_dev)
{
	int rc;

	if (eth_dev->state == IPA_ETH_ST_DEINITED)
	if (eth_dev->of_state == IPA_ETH_OF_ST_DEINITED)
		return 0;

	if (eth_dev->state != IPA_ETH_ST_STARTED)
	if (eth_dev->of_state != IPA_ETH_OF_ST_STARTED)
		return -EFAULT;

	rc = ipa_eth_offload_stop(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to stop offload");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	rc = ipa_eth_pm_deactivate(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to deactivate device PM");
		eth_dev->state = IPA_ETH_ST_ERROR;
		eth_dev->of_state = IPA_ETH_OF_ST_ERROR;
		return rc;
	}

	ipa_eth_dev_log(eth_dev, "Stopped device");

	eth_dev->state = IPA_ETH_ST_INITED;
	eth_dev->of_state = IPA_ETH_OF_ST_INITED;

	return 0;
}

static void __ipa_eth_refresh_device(struct ipa_eth_device *eth_dev)
static void __ipa_eth_refresh_device(struct work_struct *work)
{
	struct ipa_eth_device *eth_dev = container_of(work,
				struct ipa_eth_device, refresh);

	ipa_eth_dev_log(eth_dev, "Refreshing offload state for device");

	if (eth_dev->state == IPA_ETH_ST_ERROR) {
	if (!ipa_eth_offload_device_paired(eth_dev)) {
		ipa_eth_dev_log(eth_dev, "Device is not paired. Skipping.");
		return;
	}

	if (eth_dev->of_state == IPA_ETH_OF_ST_ERROR) {
		ipa_eth_dev_err(eth_dev,
				"Device in ERROR state, skipping refresh");
		return;
	}

	if (eth_dev->init) {
		if (eth_dev->state == IPA_ETH_ST_DEINITED) {
	if (initable(eth_dev)) {
		if (eth_dev->of_state == IPA_ETH_OF_ST_DEINITED) {
			(void) ipa_eth_init_device(eth_dev);

			if (eth_dev->state != IPA_ETH_ST_INITED) {
			if (eth_dev->of_state != IPA_ETH_OF_ST_INITED) {
				ipa_eth_dev_err(eth_dev,
						"Failed to init device");
				return;
@@ -212,11 +238,10 @@ static void __ipa_eth_refresh_device(struct ipa_eth_device *eth_dev)
		}
	}


	if (eth_dev->init && eth_dev->start && eth_dev->link_up) {
	if (startable(eth_dev)) {
		(void) ipa_eth_start_device(eth_dev);

		if (eth_dev->state != IPA_ETH_ST_STARTED) {
		if (eth_dev->of_state != IPA_ETH_OF_ST_STARTED) {
			ipa_eth_dev_err(eth_dev, "Failed to start device");
			return;
		}
@@ -227,10 +252,10 @@ static void __ipa_eth_refresh_device(struct ipa_eth_device *eth_dev)
	} else {
		ipa_eth_dev_log(eth_dev, "Start is disallowed for the device");

		if (eth_dev->state == IPA_ETH_ST_STARTED) {
		if (eth_dev->of_state == IPA_ETH_OF_ST_STARTED) {
			ipa_eth_stop_device(eth_dev);

			if (eth_dev->state != IPA_ETH_ST_INITED) {
			if (eth_dev->of_state != IPA_ETH_OF_ST_INITED) {
				ipa_eth_dev_err(eth_dev,
						"Failed to stop device");
				return;
@@ -238,12 +263,12 @@ static void __ipa_eth_refresh_device(struct ipa_eth_device *eth_dev)
		}
	}

	if (!eth_dev->init) {
	if (!initable(eth_dev)) {
		ipa_eth_dev_log(eth_dev, "Init is disallowed for the device");

		ipa_eth_deinit_device(eth_dev);

		if (eth_dev->state != IPA_ETH_ST_DEINITED) {
		if (eth_dev->of_state != IPA_ETH_OF_ST_DEINITED) {
			ipa_eth_dev_err(eth_dev, "Failed to deinit device");
			return;
		}
@@ -252,29 +277,46 @@ static void __ipa_eth_refresh_device(struct ipa_eth_device *eth_dev)

static void ipa_eth_refresh_device(struct ipa_eth_device *eth_dev)
{
	mutex_lock(&ipa_eth_devices_lock);

	if (ipa_eth_ready())
		__ipa_eth_refresh_device(eth_dev);

	mutex_unlock(&ipa_eth_devices_lock);
		queue_work(ipa_eth_wq, &eth_dev->refresh);
}

static void ipa_eth_refresh_devices(void)
static void __ipa_eth_refresh_devices(struct work_struct *work)
{
	struct ipa_eth_device *eth_dev;

	ipa_eth_log("Performing global refresh");

	mutex_lock(&ipa_eth_devices_lock);

	if (ipa_eth_ready()) {
		list_for_each_entry(eth_dev, &ipa_eth_devices, device_list) {
			__ipa_eth_refresh_device(eth_dev);
			ipa_eth_refresh_device(eth_dev);
		}
	}

	mutex_unlock(&ipa_eth_devices_lock);
}

static DECLARE_WORK(global_refresh, __ipa_eth_refresh_devices);

static void ipa_eth_refresh_devices(void)
{
	queue_work(ipa_eth_wq, &global_refresh);
}

static int ipa_eth_netdev_event_change(struct ipa_eth_device *eth_dev)
{
	bool refresh_needed = netif_carrier_ok(eth_dev->net_dev) ?
		!test_and_set_bit(IPA_ETH_IF_ST_LOWER_UP, &eth_dev->if_state) :
		test_and_clear_bit(IPA_ETH_IF_ST_LOWER_UP, &eth_dev->if_state);

	if (refresh_needed)
		ipa_eth_refresh_device(eth_dev);

	return NOTIFY_DONE;
}

static int ipa_eth_netdev_event(struct notifier_block *nb,
	unsigned long event, void *ptr)
{
@@ -288,11 +330,12 @@ static int ipa_eth_netdev_event(struct notifier_block *nb,

	ipa_eth_dev_log(eth_dev, "Received netdev event %lu", event);

	if (event == NETDEV_CHANGE) {
		eth_dev->link_up =
			!test_bit(__LINK_STATE_NOCARRIER, &net_dev->state);

		ipa_eth_refresh_device(eth_dev);
	switch (event) {
	case NETDEV_CHANGE:
		return ipa_eth_netdev_event_change(eth_dev);
	default:
		/* Ignore other events */
		break;
	}

	return NOTIFY_DONE;
@@ -303,7 +346,7 @@ static int ipa_eth_uc_ready_cb(struct notifier_block *nb,
{
	ipa_eth_log("IPA uC is ready");

	ipa_eth_ipa_uc_is_ready = true;
	set_bit(IPA_ETH_ST_UC_READY, &ipa_eth_state);

	ipa_eth_refresh_devices();

@@ -318,7 +361,7 @@ static void ipa_eth_ipa_ready_cb(void *data)
{
	ipa_eth_log("IPA is ready");

	ipa_eth_ipa_is_ready = true;
	set_bit(IPA_ETH_ST_IPA_READY, &ipa_eth_state);

	ipa_eth_refresh_devices();
}
@@ -437,15 +480,15 @@ static ssize_t eth_dev_stats_print(char *buf, const size_t size,
static ssize_t eth_dev_stats_read(struct file *file, char __user *user_buf,
				  size_t count, loff_t *ppos)
{
	ssize_t n;
	ssize_t n = 0, size = 2048;
	char *buf = NULL;
	struct ipa_eth_device *eth_dev = file->private_data;

	buf = kzalloc(2048, GFP_KERNEL);
	buf = kzalloc(size, GFP_KERNEL);
	if (buf == NULL)
		return 0;

	n = eth_dev_stats_print(buf, sizeof(buf), eth_dev);
	n = eth_dev_stats_print(buf, size, eth_dev);
	n = simple_read_from_buffer(user_buf, count, ppos, buf, n);

	kfree(buf);
@@ -531,7 +574,9 @@ static void __ipa_eth_unpair_device(struct ipa_eth_device *eth_dev)

	eth_dev->init = eth_dev->start = false;

	__ipa_eth_refresh_device(eth_dev);
	ipa_eth_refresh_device(eth_dev);
	flush_work(&eth_dev->refresh);
	cancel_work_sync(&eth_dev->refresh);

	unregister_netdevice_notifier(&eth_dev->netdevice_nb);
	ipa_eth_offload_unpair_device(eth_dev);
@@ -565,8 +610,19 @@ static void ipa_eth_unpair_devices(struct ipa_eth_offload_driver *od)

int ipa_eth_register_device(struct ipa_eth_device *eth_dev)
{
	eth_dev->state = IPA_ETH_ST_DEINITED;
	if (!eth_dev->dev) {
		ipa_eth_dev_err(eth_dev, "Device is NULL");
		return -EINVAL;
	}

	if (!eth_dev->nd) {
		ipa_eth_dev_err(eth_dev, "Network driver is NULL");
		return -EINVAL;
	}

	eth_dev->of_state = IPA_ETH_OF_ST_DEINITED;
	eth_dev->pm_handle = IPA_PM_MAX_CLIENTS;
	INIT_WORK(&eth_dev->refresh, __ipa_eth_refresh_device);

	eth_dev->init = eth_dev->start = !ipa_eth_noauto;

@@ -800,6 +856,44 @@ static void ipa_eth_debugfs_cleanup(void)
	debugfs_remove_recursive(ipa_eth_debugfs);
}

static ssize_t eth_dev_ready_read(struct file *file, char __user *user_buf,
				  size_t count, loff_t *ppos)
{
	char *buf;
	ssize_t n = 0, size = 128;

	buf = kzalloc(size, GFP_KERNEL);
	if (buf == NULL)
		return 0;

	n += scnprintf(&buf[n], size - n, "Offload Sub-system: %s\n",
		test_bit(IPA_ETH_ST_READY, &ipa_eth_state) ?
			"Ready" : "Not Ready");

	n += scnprintf(&buf[n], size - n, "uC: %s\n",
		test_bit(IPA_ETH_ST_UC_READY, &ipa_eth_state) ?
			"Ready" : "Not Ready");

	n += scnprintf(&buf[n], size - n, "IPA: %s\n",
		test_bit(IPA_ETH_ST_IPA_READY, &ipa_eth_state) ?
			"Ready" : "Not Ready");

	n += scnprintf(&buf[n], size - n, "ALL: %s\n",
		ipa_eth_ready() ? "Ready" : "Not Ready");

	n = simple_read_from_buffer(user_buf, count, ppos, buf, n);

	kfree(buf);

	return n;
}

static const struct file_operations fops_eth_dev_ready = {
	.read = eth_dev_ready_read,
	.open = simple_open,
	.llseek = default_llseek,
};

static int ipa_eth_debugfs_init(void)
{
	int rc = 0;
@@ -837,14 +931,8 @@ static int ipa_eth_debugfs_init(void)
		goto err_exit;
	}

	(void) debugfs_create_bool("ready", 0444,
				   ipa_eth_debugfs, &ipa_eth_is_ready);

	(void) debugfs_create_bool("ipa_ready", 0444,
				   ipa_eth_debugfs, &ipa_eth_ipa_is_ready);

	(void) debugfs_create_bool("uc_ready", 0444,
				   ipa_eth_debugfs, &ipa_eth_ipa_uc_is_ready);
	(void) debugfs_create_file("ready", 0644, ipa_eth_debugfs, NULL,
			    &fops_eth_dev_ready);

	(void) debugfs_create_bool("no_auto", 0644,
				   ipa_eth_debugfs, &ipa_eth_noauto);
@@ -852,6 +940,8 @@ static int ipa_eth_debugfs_init(void)
	(void) debugfs_create_bool("ipc_logdbg", 0644,
				   ipa_eth_debugfs, &ipa_eth_ipc_logdbg);

	ipa_eth_log("Debugfs root is initialized");

	return 0;

err_exit:
@@ -898,20 +988,26 @@ int ipa_eth_init(void)
{
	int rc;

	ipa_eth_dbg("Initializing IPA Ethernet Offload Sub-System");

	rc = ipa_eth_ipc_log_init();
	if (rc) {
		ipa_eth_err("Failed to initialize IPC logging");
		goto err_ipclog;
	}

	ipa_eth_dbg("Initializing IPA Ethernet Offload Sub-System");

	rc = ipa_eth_debugfs_init();
	if (rc) {
		ipa_eth_err("Failed to initialize debugfs");
		goto err_dbgfs;
	}

	ipa_eth_wq = alloc_workqueue("ipa_eth", WQ_UNBOUND, 0);
	if (!ipa_eth_wq) {
		ipa_eth_err("Failed to alloc workqueue");
		goto err_wq;
	}

	rc = ipa_eth_bus_modinit(ipa_eth_drivers_debugfs);
	if (rc) {
		ipa_eth_err("Failed to initialize bus");
@@ -932,13 +1028,17 @@ int ipa_eth_init(void)

	rc = ipa_register_ipa_ready_cb(ipa_eth_ipa_ready_cb, NULL);
	if (rc == -EEXIST) {
		ipa_eth_ipa_is_ready = true;
		set_bit(IPA_ETH_ST_IPA_READY, &ipa_eth_state);
	} else if (rc) {
		ipa_eth_err("Failed to register for IPA ready cb");
		goto err_ipa;
	}

	ipa_eth_is_ready = true;
	set_bit(IPA_ETH_ST_READY, &ipa_eth_state);

	ipa_eth_log("Offload sub-system init is complete");

	ipa_eth_refresh_devices();

	return 0;

@@ -949,6 +1049,9 @@ int ipa_eth_init(void)
err_offload:
	ipa_eth_bus_modexit();
err_bus:
	destroy_workqueue(ipa_eth_wq);
	ipa_eth_wq = NULL;
err_wq:
	ipa_eth_debugfs_cleanup();
err_dbgfs:
	ipa_eth_ipc_log_cleanup();
@@ -960,13 +1063,17 @@ void ipa_eth_exit(void)
{
	ipa_eth_dbg("De-initializing IPA Ethernet Offload Sub-System");

	ipa_eth_is_ready = false;
	clear_bit(IPA_ETH_ST_READY, &ipa_eth_state);

	// IPA ready CB can not be unregistered; just unregister uC ready CB
	ipa3_uc_unregister_ready_cb(&uc_ready_cb);

	ipa_eth_offload_modexit();
	ipa_eth_bus_modexit();

	destroy_workqueue(ipa_eth_wq);
	ipa_eth_wq = NULL;

	ipa_eth_debugfs_cleanup();
	ipa_eth_ipc_log_cleanup();
}
+4 −0
Original line number Diff line number Diff line
@@ -112,6 +112,8 @@ int ipa_eth_bus_modinit(struct dentry *dbgfs_root)

	ipa_eth_bus_is_ready = true;

	ipa_eth_log("Offload sub-system bus module init is complete");

	return 0;

err_init:
@@ -127,6 +129,8 @@ void ipa_eth_bus_modexit(void)
{
	struct ipa_eth_bus_map *map;

	ipa_eth_log("De-initing offload sub-system bus module");

	if (!ipa_eth_bus_is_ready)
		return;

+22 −9
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@
#define IPA_ETH_NOAUTO_DEFAULT false
#endif

#ifdef DEBUG
#ifdef CONFIG_IPA_ETH_DEBUG
#define IPA_ETH_IPC_LOGDBG_DEFAULT true
#else
#define IPA_ETH_IPC_LOGDBG_DEFAULT false
@@ -41,6 +41,12 @@
		ipa_eth_ipc_log("ERROR: " fmt, ## args); \
	} while (0)

#define ipa_eth_bug(fmt, args...) \
	do { \
		ipa_eth_err("BUG: " fmt, ## args); \
		dump_stack(); \
	} while (0)

#define ipa_eth_log(fmt, args...) \
	do { \
		dev_dbg(IPA_ETH_PFDEV, \
@@ -54,21 +60,28 @@
		dev_dbg(IPA_ETH_PFDEV, \
			IPA_ETH_SUBSYS " %s:%d " fmt "\n", \
			__func__, __LINE__, ## args); \
		ipa_eth_ipc_dbg("ERROR: " fmt, ## args); \
		ipa_eth_ipc_dbg("DEBUG: " fmt, ## args); \
	} while (0)

#define ipa_eth_dev_err(edev, fmt, args...) \
	ipa_eth_err("(%s) " fmt, \
		(edev->net_dev ? edev->net_dev->name : "<unpaired>"), ## args)
	ipa_eth_err("(%s) " fmt, ((edev && edev->net_dev) ? \
		edev->net_dev->name : "<unpaired>"), \
		## args)

#define ipa_eth_dev_bug(edev, fmt, args...) \
	ipa_eth_bug("(%s) " fmt, ((edev && edev->net_dev) ? \
		edev->net_dev->name : "<unpaired>"), \
		## args)

#define ipa_eth_dev_dbg(edev, fmt, args...) \
	ipa_eth_dbg("(%s) " fmt, \
		(edev->net_dev ? edev->net_dev->name : "<unpaired>"), ## args)
	ipa_eth_dbg("(%s) " fmt, ((edev && edev->net_dev) ? \
		edev->net_dev->name : "<unpaired>"), \
		## args)

#define ipa_eth_dev_log(edev, fmt, args...) \
	ipa_eth_log("(%s) " fmt, \
		(edev->net_dev ? edev->net_dev->name : "<unpaired>"), ## args)

	ipa_eth_log("(%s) " fmt, ((edev && edev->net_dev) ? \
		edev->net_dev->name : "<unpaired>"), \
		## args)

struct ipa_eth_bus {
	struct list_head bus_list;
+50 −18
Original line number Diff line number Diff line
@@ -109,39 +109,55 @@ int ipa_eth_offload_stop(struct ipa_eth_device *eth_dev)
	return rc_rx || rc_tx;
}

static int try_pair_device(struct ipa_eth_device *eth_dev,
static int __try_pair_device(struct ipa_eth_device *eth_dev,
			   struct ipa_eth_offload_driver *od)
{
	if (od->bus && od->bus != eth_dev->dev->bus) {
	int rc = od->bus_ops->probe(eth_dev);

	if (rc) {
		ipa_eth_dev_dbg(eth_dev,
			"Offload driver %s is not a bus match for %s",
			"Offload driver %s passed up paring with %s",
			od->name, eth_dev->nd->name);

		return -ENOTSUPP;
		return rc;
	}

	if (od->bus_ops->probe) {
		int rc = od->bus_ops->probe(eth_dev);
	ipa_eth_dev_log(eth_dev,
		"Offload driver %s successfully probed device from %s",
		od->name, eth_dev->nd->name);

		if (!rc) {
			eth_dev->od = od;
			return 0;
	if (!eth_dev->net_dev) {
		ipa_eth_dev_err(eth_dev,
			"Offload driver %s did not fill net_dev field",
			od->name);

		od->bus_ops->remove(eth_dev);

		return -EFAULT;
	}

		ipa_eth_dev_dbg(eth_dev,
			"Offload driver %s passed up paring with %s",
	eth_dev->od = od;

	ipa_eth_dev_log(eth_dev,
		"Offload driver %s successfully paired with device from %s",
		od->name, eth_dev->nd->name);

		return rc;
	return 0;
}

static int try_pair_device(struct ipa_eth_device *eth_dev,
			   struct ipa_eth_offload_driver *od)
{
	if (od->bus != eth_dev->dev->bus) {
		ipa_eth_dev_dbg(eth_dev,
		"Bus probe is unsupported by the offload driver %s",
		od->name);
			"Offload driver %s is not a bus match for %s",
			od->name, eth_dev->nd->name);

		return -ENOTSUPP;
	}

	return __try_pair_device(eth_dev, od);
}

int ipa_eth_offload_pair_device(struct ipa_eth_device *eth_dev)
{
	struct ipa_eth_offload_driver *od;
@@ -181,6 +197,11 @@ int ipa_eth_offload_register_driver(struct ipa_eth_offload_driver *od)
		return -EINVAL;
	}

	if (!od->bus_ops || !od->bus_ops->probe || !od->bus_ops->remove) {
		ipa_eth_err("Bus ops missing for offload driver %s", od->name);
		return -EINVAL;
	}

	if (!od->debugfs && ipa_eth_offload_debugfs) {
		od->debugfs =
			debugfs_create_dir(od->name, ipa_eth_offload_debugfs);
@@ -208,10 +229,21 @@ void ipa_eth_offload_unregister_driver(struct ipa_eth_offload_driver *od)

int ipa_eth_offload_modinit(struct dentry *dbgfs_root)
{
	return ipa_eth_offload_debugfs_init(dbgfs_root);
	int rc;

	rc = ipa_eth_offload_debugfs_init(dbgfs_root);
	if (rc) {
		ipa_eth_err("Failed to init offload module debugfs");
		return rc;
	}

	ipa_eth_log("Offload sub-system offload module init is complete");

	return 0;
}

void ipa_eth_offload_modexit(void)
{
	ipa_eth_log("De-initing offload sub-system offload module");
	ipa_eth_offload_debugfs_cleanup();
}
Loading