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

Commit 3a0abfea authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mhi: mhi_uci: Create char dev only after PCIe device ID is known"

parents 92fe0179 a7d01c02
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ Main node properties:
  Definition: "qcom,mhi"

- qcom,pci-dev_id
  Usage: required
  Usage: optional
  Value type: <u32>
  Definition: Device id reported by modem

+28 −21
Original line number Diff line number Diff line
@@ -153,16 +153,19 @@ static int mhi_pci_probe(struct pci_dev *pcie_device,
	u32 slot = PCI_SLOT(pcie_device->devfn);
	unsigned long msi_requested, msi_required;
	struct msm_pcie_register_event *mhi_pci_link_event;
	struct pcie_core_info *core;
	int i;
	char node[32];

	/* Find correct device context based on bdf & dev_id */
	mutex_lock(&mhi_device_drv->lock);
	list_for_each_entry(itr, &mhi_device_drv->head, node) {
		struct pcie_core_info *core = &itr->core;

		if (core->domain == domain &&
		    core->bus == bus &&
		    core->dev_id == dev_id &&
		core = &itr->core;
		if (core->domain == domain && core->bus == bus &&
		    (core->dev_id == PCI_ANY_ID || (core->dev_id == dev_id)) &&
		    core->slot == slot) {
			/* change default dev_id to actual dev_id */
			core->dev_id = dev_id;
			mhi_dev_ctxt = itr;
			break;
		}
@@ -171,6 +174,11 @@ static int mhi_pci_probe(struct pci_dev *pcie_device,
	if (!mhi_dev_ctxt)
		return -EPROBE_DEFER;

	snprintf(node, sizeof(node), "mhi_%04x_%02u.%02u.%02u",
		 core->dev_id, core->domain, core->bus, core->slot);
	mhi_dev_ctxt->mhi_ipc_log =
		ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0);

	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
		"Processing Domain:%02u Bus:%04u dev:0x%04x slot:%04u\n",
		domain, bus, dev_id, slot);
@@ -280,9 +288,22 @@ static int mhi_pci_probe(struct pci_dev *pcie_device,
	mutex_lock(&mhi_dev_ctxt->pm_lock);
	write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
	mhi_dev_ctxt->mhi_pm_state = MHI_PM_POR;
	ret_val = set_mhi_base_state(mhi_dev_ctxt);
	write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);

	/* notify all registered clients we probed */
	for (i = 0; i < MHI_MAX_CHANNELS; i++) {
		struct mhi_client_handle *client_handle =
			mhi_dev_ctxt->client_handle_list[i];

		if (!client_handle)
			continue;
		client_handle->dev_id = core->dev_id;
		mhi_notify_client(client_handle, MHI_CB_MHI_PROBED);
	}
	write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
	ret_val = set_mhi_base_state(mhi_dev_ctxt);
	write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);

	if (ret_val) {
		mhi_log(mhi_dev_ctxt,
			MHI_MSG_ERROR,
@@ -344,7 +365,6 @@ static int mhi_plat_probe(struct platform_device *pdev)
	int r = 0, len;
	struct mhi_device_ctxt *mhi_dev_ctxt;
	struct pcie_core_info *core;
	char node[32];
	struct device_node *of_node = pdev->dev.of_node;
	u64 address_window[2];

@@ -377,7 +397,7 @@ static int mhi_plat_probe(struct platform_device *pdev)
	core = &mhi_dev_ctxt->core;
	r = of_property_read_u32(of_node, "qcom,pci-dev_id", &core->dev_id);
	if (r)
		return r;
		core->dev_id = PCI_ANY_ID;

	r = of_property_read_u32(of_node, "qcom,pci-slot", &core->slot);
	if (r)
@@ -391,14 +411,6 @@ static int mhi_plat_probe(struct platform_device *pdev)
	if (r)
		return r;

	snprintf(node, sizeof(node),
		 "mhi_%04x_%02u.%02u.%02u",
		 core->dev_id, core->domain, core->bus, core->slot);
	mhi_dev_ctxt->mhi_ipc_log =
		ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0);
	if (!mhi_dev_ctxt->mhi_ipc_log)
		pr_err("%s: Error creating ipc_log buffer\n", __func__);

	r = of_property_read_u32(of_node, "qcom,mhi-ready-timeout",
				 &mhi_dev_ctxt->poll_reset_timeout_ms);
	if (r)
@@ -407,10 +419,6 @@ static int mhi_plat_probe(struct platform_device *pdev)

	mhi_dev_ctxt->dev_space.start_win_addr = address_window[0];
	mhi_dev_ctxt->dev_space.end_win_addr = address_window[1];
	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
		"Start Addr:0x%llx End_Addr:0x%llx\n",
		mhi_dev_ctxt->dev_space.start_win_addr,
		mhi_dev_ctxt->dev_space.end_win_addr);

	r = of_property_read_u32(of_node, "qcom,bhi-alignment",
				 &mhi_dev_ctxt->bhi_ctxt.alignment);
@@ -471,7 +479,6 @@ static int mhi_plat_probe(struct platform_device *pdev)
	mutex_lock(&mhi_device_drv->lock);
	list_add_tail(&mhi_dev_ctxt->node, &mhi_device_drv->head);
	mutex_unlock(&mhi_device_drv->lock);
	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n");

	return 0;
}
+27 −11
Original line number Diff line number Diff line
@@ -563,6 +563,7 @@ int mhi_register_channel(struct mhi_client_handle **client_handle,
	(*client_handle)->domain = mhi_dev_ctxt->core.domain;
	(*client_handle)->bus = mhi_dev_ctxt->core.bus;
	(*client_handle)->slot = mhi_dev_ctxt->core.slot;
	(*client_handle)->enabled = false;
	client_config = (*client_handle)->client_config;
	client_config->mhi_dev_ctxt = mhi_dev_ctxt;
	client_config->user_data = client_info->user_data;
@@ -589,11 +590,8 @@ int mhi_register_channel(struct mhi_client_handle **client_handle,
	}

	if (mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_AMSS &&
	    mhi_dev_ctxt->flags.mhi_initialized) {
		mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
			"Exec env is AMSS notify client now chan:%u\n", chan);
		mhi_notify_client(*client_handle, MHI_CB_MHI_ENABLED);
	}
	    mhi_dev_ctxt->flags.mhi_initialized)
		(*client_handle)->enabled = true;

	mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE,
		"Successfuly registered chan:%u\n", chan);
@@ -1790,6 +1788,8 @@ int mhi_register_device(struct mhi_device *mhi_device,
	u32 dev_id = pci_dev->device;
	u32 slot = PCI_SLOT(pci_dev->devfn);
	int ret, i;
	char node[32];
	struct pcie_core_info *core;

	of_node = of_parse_phandle(mhi_device->dev->of_node, node_name, 0);
	if (!of_node)
@@ -1802,13 +1802,13 @@ int mhi_register_device(struct mhi_device *mhi_device,
	mutex_lock(&mhi_device_drv->lock);
	list_for_each_entry(itr, &mhi_device_drv->head, node) {
		struct platform_device *pdev = itr->plat_dev;
		struct pcie_core_info *core = &itr->core;

		if (pdev->dev.of_node == of_node &&
		    core->domain == domain &&
		    core->bus == bus &&
		    core->dev_id == dev_id &&
		    core->slot == slot) {
		core = &itr->core;
		if (pdev->dev.of_node == of_node && core->domain == domain &&
		    core->bus == bus && core->slot == slot &&
		    (core->dev_id == PCI_ANY_ID || (core->dev_id == dev_id))) {
			/* change default dev_id to current dev_id */
			core->dev_id = dev_id;
			mhi_dev_ctxt = itr;
			break;
		}
@@ -1819,6 +1819,11 @@ int mhi_register_device(struct mhi_device *mhi_device,
	if (!mhi_dev_ctxt)
		return -EPROBE_DEFER;

	snprintf(node, sizeof(node), "mhi_%04x_%02u.%02u.%02u",
		 core->dev_id, core->domain, core->bus, core->slot);
	mhi_dev_ctxt->mhi_ipc_log =
		ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0);

	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
		"Registering Domain:%02u Bus:%04u dev:0x%04x slot:%04u\n",
		domain, bus, dev_id, slot);
@@ -1900,6 +1905,17 @@ int mhi_register_device(struct mhi_device *mhi_device,
			mhi_dev_ctxt->bhi_ctxt.rddm_size);
	}

	/* notify all the registered clients we probed */
	for (i = 0; i < MHI_MAX_CHANNELS; i++) {
		struct mhi_client_handle *client_handle =
			mhi_dev_ctxt->client_handle_list[i];

		if (!client_handle)
			continue;
		client_handle->dev_id = core->dev_id;
		mhi_notify_client(client_handle, MHI_CB_MHI_PROBED);
	}

	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit success\n");
	return 0;
}
+11 −11
Original line number Diff line number Diff line
@@ -593,24 +593,24 @@ static void enable_clients(struct mhi_device_ctxt *mhi_dev_ctxt,
			   enum MHI_EXEC_ENV exec_env)
{
	struct mhi_client_handle *client_handle = NULL;
	struct mhi_cb_info cb_info;
	int i = 0, r = 0;
	struct mhi_chan_info chan_info;

	cb_info.cb_reason = MHI_CB_MHI_ENABLED;
	struct mhi_chan_info *chan_info;
	int i = 0;

	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
		"Enabling Clients, exec env %d.\n", exec_env);

	for (i = 0; i < MHI_MAX_CHANNELS; ++i) {
		if (!VALID_CHAN_NR(i))
		if (!mhi_dev_ctxt->client_handle_list[i])
			continue;

		client_handle = mhi_dev_ctxt->client_handle_list[i];
		r = get_chan_props(mhi_dev_ctxt, i, &chan_info);
		if (!r && client_handle &&
		    exec_env == GET_CHAN_PROPS(CHAN_BRINGUP_STAGE,
						chan_info.flags))
		chan_info = &client_handle->client_config->chan_info;
		if (exec_env == GET_CHAN_PROPS(CHAN_BRINGUP_STAGE,
					       chan_info->flags)) {
			client_handle->enabled = true;
			mhi_notify_client(client_handle, MHI_CB_MHI_ENABLED);
		}
	}

	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Done.\n");
}
+98 −102
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@ struct uci_client {
	atomic_t out_pkt_pend_ack;
	atomic_t completion_ack;
	struct mhi_uci_ctxt_t *uci_ctxt;
	struct cdev cdev;
	bool enabled;
	void *uci_ipc_log;
};
@@ -132,7 +133,6 @@ struct mhi_uci_ctxt_t {
	struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT];
	dev_t dev_t;
	struct mutex ctrl_mutex;
	struct cdev cdev[MHI_SOFTWARE_CLIENT_LIMIT];
	struct uci_client *ctrl_client;
};

@@ -246,6 +246,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait);
static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd,
					unsigned long arg);
static int mhi_uci_create_device(struct uci_client *uci_client);

static struct mhi_uci_drv_ctxt mhi_uci_drv_ctxt;

@@ -1174,6 +1175,14 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info)

	uci_handle = cb_info->result->user_data;
	switch (cb_info->cb_reason) {
	case MHI_CB_MHI_PROBED:
		/* If it's outbound channel create the node */
		mutex_lock(&uci_handle->client_lock);
		if (!uci_handle->dev &&
		    cb_info->chan == uci_handle->out_attr.chan_id)
			mhi_uci_create_device(uci_handle);
		mutex_unlock(&uci_handle->client_lock);
		break;
	case MHI_CB_MHI_ENABLED:
		uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
			"MHI enabled CB received for chan %d\n",
@@ -1295,17 +1304,65 @@ static const struct file_operations mhi_uci_client_fops = {
	.unlocked_ioctl = mhi_uci_ctl_ioctl,
};

static int mhi_uci_create_device(struct uci_client *uci_client)
{
	struct mhi_uci_ctxt_t *uci_ctxt = uci_client->uci_ctxt;
	char node_name[32];
	int index = uci_client - uci_ctxt->client_handles;
	int ret;

	uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO,
		"Creating dev node %04x_%02u.%02u.%02u_pipe%d\n",
		uci_client->out_attr.mhi_handle->dev_id,
		uci_client->out_attr.mhi_handle->domain,
		uci_client->out_attr.mhi_handle->bus,
		uci_client->out_attr.mhi_handle->slot,
		uci_client->out_attr.chan_id);

	cdev_init(&uci_client->cdev, &mhi_uci_client_fops);
	uci_client->cdev.owner = THIS_MODULE;
	ret = cdev_add(&uci_client->cdev, uci_ctxt->dev_t + index, 1);
	if (ret) {
		uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
			"Failed to add cdev %d, ret:%d\n", index, ret);
		return ret;
	}
	uci_client->dev = device_create(mhi_uci_drv_ctxt.mhi_uci_class, NULL,
					uci_ctxt->dev_t + index, NULL,
					DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d",
					uci_client->out_attr.mhi_handle->dev_id,
					uci_client->out_attr.mhi_handle->domain,
					uci_client->out_attr.mhi_handle->bus,
					uci_client->out_attr.mhi_handle->slot,
					"_pipe_",
					uci_client->out_attr.chan_id);
	if (IS_ERR(uci_client->dev)) {
		uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
			"Failed to add cdev %d\n", IS_ERR(uci_client->dev));
		cdev_del(&uci_client->cdev);
		return -EIO;
	}

	/* dev node created successfully, create logging buffer */
	snprintf(node_name, sizeof(node_name), "mhi_uci_%04x_%02u.%02u.%02u_%d",
		 uci_client->out_attr.mhi_handle->dev_id,
		 uci_client->out_attr.mhi_handle->domain,
		 uci_client->out_attr.mhi_handle->bus,
		 uci_client->out_attr.mhi_handle->slot,
		 uci_client->out_attr.chan_id);
	uci_client->uci_ipc_log = ipc_log_context_create(MHI_UCI_IPC_LOG_PAGES,
							 node_name, 0);

	return 0;
}

static int mhi_uci_probe(struct platform_device *pdev)
{
	struct mhi_uci_ctxt_t *uci_ctxt;
	int ret_val;
	int i;
	char node_name[32];

	uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
		UCI_DBG_INFO,
		"Entered with pdev:%p\n",
		pdev);
	uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO, "Entered\n");

	if (mhi_is_device_ready(&pdev->dev, "qcom,mhi") == false)
		return -EPROBE_DEFER;
@@ -1326,128 +1383,67 @@ static int mhi_uci_probe(struct platform_device *pdev)
	uci_ctxt->pdev = pdev;
	mutex_init(&uci_ctxt->ctrl_mutex);

	uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
		UCI_DBG_INFO,
	uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO,
		"Setting up channel attributes\n");
	ret_val = uci_init_client_attributes(uci_ctxt,
					     pdev->dev.of_node);
	if (ret_val) {
		uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
			UCI_DBG_ERROR,
		uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
			"Failed to init client attributes\n");
		return -EIO;
	}

	uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
		UCI_DBG_INFO,
	uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO,
		"Allocating char devices\n");
	ret_val = alloc_chrdev_region(&uci_ctxt->dev_t, 0,
				      MHI_SOFTWARE_CLIENT_LIMIT,
				      DEVICE_NAME);
	if (IS_ERR_VALUE(ret_val)) {
		uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
			"Failed to alloc char devs, ret 0x%x\n", ret_val);
		return ret_val;
	}

	uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO,
		"Registering for MHI events\n");
	for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; ++i) {
		struct uci_client *uci_client = &uci_ctxt->client_handles[i];

		uci_client->uci_ctxt = uci_ctxt;
		mutex_init(&uci_client->client_lock);
		if (uci_client->in_attr.uci_ownership) {
			ret_val = mhi_register_client(uci_client,
						      &pdev->dev);
		if (!uci_client->in_attr.uci_ownership)
			continue;
		ret_val = mhi_register_client(uci_client, &pdev->dev);
		if (ret_val) {
			uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
				UCI_DBG_CRITICAL,
				"Failed to reg client %d ret %d\n",
					ret_val,
					i);

				ret_val, i);
				return -EIO;
		}
			snprintf(node_name,
				 sizeof(node_name),
				 "mhi_uci_%04x_%02u.%02u.%02u_%d",
				 uci_client->out_attr.mhi_handle->dev_id,
				 uci_client->out_attr.mhi_handle->domain,
				 uci_client->out_attr.mhi_handle->bus,
				 uci_client->out_attr.mhi_handle->slot,
				 uci_client->out_attr.chan_id);
			uci_client->uci_ipc_log = ipc_log_context_create
				(MHI_UCI_IPC_LOG_PAGES,
				 node_name,
				 0);
		}
	}

	uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
		UCI_DBG_INFO,
		"Allocating char devices\n");
	ret_val = alloc_chrdev_region(&uci_ctxt->dev_t,
				      0,
				      MHI_SOFTWARE_CLIENT_LIMIT,
				      DEVICE_NAME);
	if (IS_ERR_VALUE(ret_val)) {
		uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
			UCI_DBG_ERROR,
			"Failed to alloc char devs, ret 0x%x\n", ret_val);
		goto failed_char_alloc;
	}

		mutex_lock(&uci_client->client_lock);
		/* If we have device id, create the node now */
		if (uci_client->out_attr.mhi_handle->dev_id != PCI_ANY_ID) {
			ret_val = mhi_uci_create_device(uci_client);
			if (ret_val) {
				uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
		UCI_DBG_INFO,
		"Setting up device nodes. for dev_t: 0x%x major:0x%x\n",
		uci_ctxt->dev_t,
		MAJOR(uci_ctxt->dev_t));
	for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; ++i) {
		struct uci_client *uci_client = &uci_ctxt->client_handles[i];

		if (uci_client->in_attr.uci_ownership) {
			cdev_init(&uci_ctxt->cdev[i], &mhi_uci_client_fops);
			uci_ctxt->cdev[i].owner = THIS_MODULE;
			ret_val = cdev_add(&uci_ctxt->cdev[i],
					   uci_ctxt->dev_t + i , 1);
			if (IS_ERR_VALUE(ret_val)) {
				uci_log(uci_client->uci_ipc_log,
					UCI_DBG_ERROR,
					"Failed to add cdev %d, ret 0x%x\n",
					i, ret_val);
				goto failed_char_add;
			}
			uci_client->dev =
				device_create(mhi_uci_drv_ctxt.mhi_uci_class,
					NULL,
					uci_ctxt->dev_t + i,
					NULL,
					DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d",
					uci_client->out_attr.mhi_handle->dev_id,
					uci_client->out_attr.mhi_handle->domain,
					uci_client->out_attr.mhi_handle->bus,
					uci_client->out_attr.mhi_handle->slot,
					"_pipe_",
					uci_client->out_attr.chan_id);
			if (IS_ERR(uci_client->dev)) {
				uci_log(uci_client->uci_ipc_log,
					UCI_DBG_ERROR,
					"Failed to add cdev %d\n", i);
				cdev_del(&uci_ctxt->cdev[i]);
				ret_val = -EIO;
				goto failed_device_create;
					UCI_DBG_CRITICAL,
					"Failed to create device node, ret:%d\n",
					ret_val);
				mutex_unlock(&uci_client->client_lock);
				return -EIO;
			}
		}
		mutex_unlock(&uci_client->client_lock);
	}

	platform_set_drvdata(pdev, uci_ctxt);
	mutex_lock(&mhi_uci_drv_ctxt.list_lock);
	list_add_tail(&uci_ctxt->node, &mhi_uci_drv_ctxt.head);
	mutex_unlock(&mhi_uci_drv_ctxt.list_lock);
	return 0;

failed_char_add:
failed_device_create:
	while (--i >= 0) {
		cdev_del(&uci_ctxt->cdev[i]);
		device_destroy(mhi_uci_drv_ctxt.mhi_uci_class,
			       MKDEV(MAJOR(uci_ctxt->dev_t), i));
	};

	unregister_chrdev_region(MAJOR(uci_ctxt->dev_t),
				 MHI_SOFTWARE_CLIENT_LIMIT);
failed_char_alloc:

	return ret_val;
	return 0;
};

static int mhi_uci_remove(struct platform_device *pdev)
@@ -1462,7 +1458,7 @@ static int mhi_uci_remove(struct platform_device *pdev)
		if (uci_client->in_attr.uci_ownership) {
			mhi_deregister_channel(uci_client->out_attr.mhi_handle);
			mhi_deregister_channel(uci_client->in_attr.mhi_handle);
			cdev_del(&uci_ctxt->cdev[i]);
			cdev_del(&uci_client->cdev);
			device_destroy(mhi_uci_drv_ctxt.mhi_uci_class,
				       MKDEV(MAJOR(uci_ctxt->dev_t), i));
		}
Loading