Commit 888982a8 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'mhi-for-v5.11' of...

Merge tag 'mhi-for-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi into char-misc-next

Manivannan writes:

MHI patches for v5.11

Here is the MHI patch set for v5.11. Most of the patches are cleanups and fixes
but there are some noticeable changes too:

1. Loic finally removed the auto-start option from the channel parameters of the
MHI controller. It is the duty of the client drivers like qrtr to start/stop the
channels when required, so we decided to remove this option. As a side effect,
we changed the qrtr driver to start the channels during its probe and removed
the auto-start option from ath11k controller.

**NOTE** Since these changes spawns both MHI and networking trees, the patches
are maintained in an immutable branch [1] and pulled into both mhi-next and
ath11k-next branches. The networking patches got acks from ath11k and networking
maintainers as well.

2. Loic added a generic MHI pci controller driver. This driver will be used by
the PCI based Qualcomm modems like SDX55 and exposes channels such as QMI,
IP_HW0, IPCR etc...

3. Loic fixed the MHI device hierarchy by maintaining the correct parent child
relationships. Earlier all MHI devices lived in the same level under the parent
device like PCIe. But now, the MHI devices belonging to channels will become the
children of controller MHI device.

4. Finally Loic also improved the MHI device naming by using indexed names such
as mhi0, mhi1, etc... This will break the userspace applications depending on
the old naming convention but since the only one user so far is Jeff Hugo's AI
accelerator apps, we decided to make this change now itself with his agreement.

5. Bhaumik fixed the qrtr driver by stopping the channels during remove. This
patch also got ack from networking maintainer and we decided to take it through
MHI tree (via immutable branch) since we already had a qrtr change.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi.git/log/?h=mhi-ath11k-immutable

* tag 'mhi-for-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi: (30 commits)
  mhi: pci_generic: Fix implicit conversion warning
  bus: mhi: core: Fix error handling in mhi_register_controller()
  bus: mhi: core: Fix device hierarchy
  bus: mhi: core: Indexed MHI controller name
  net: qrtr: Unprepare MHI channels during remove
  bus: mhi: core: Remove MHI event ring IRQ handlers when powering down
  bus: mhi: core: Mark and maintain device states early on after power down
  bus: mhi: core: Separate system error and power down handling
  bus: mhi: core: Check for IRQ availability during registration
  bus: mhi: core: Move to an error state on mission mode failure
  bus: mhi: core: Use appropriate label in firmware load handler API
  bus: mhi: core: Move to an error state on any firmware load failure
  bus: mhi: core: Prevent sending multiple RDDM entry callbacks
  bus: mhi: core: Move to SYS_ERROR regardless of RDDM capability
  bus: mhi: core: Skip device wake in error or shutdown states
  bus: mhi: core: Move to using high priority workqueue
  bus: mhi: core: Use appropriate names for firmware load functions
  bus: mhi: core: Skip RDDM download for unknown execution environment
  bus: mhi: core: Rename RDDM download function to use proper words
  bus: mhi: core: Remove unused mhi_fw_load_worker() declaration
  ...
parents 9fb3b4ca 4ea6fa2c
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -20,3 +20,12 @@ config MHI_BUS_DEBUG
	  Enable debugfs support for use with the MHI transport. Allows
	  reading and/or modifying some values within the MHI controller
	  for debug and test purposes.

config MHI_BUS_PCI_GENERIC
	tristate "MHI PCI controller driver"
	depends on MHI_BUS
	depends on PCI
	help
	  This driver provides MHI PCI controller driver for devices such as
	  Qualcomm SDX55 based PCIe modems.
+4 −0
Original line number Diff line number Diff line
# core layer
obj-y += core/

obj-$(CONFIG_MHI_BUS_PCI_GENERIC) += mhi_pci_generic.o
mhi_pci_generic-y += pci_generic.o
+42 −33
Original line number Diff line number Diff line
@@ -92,6 +92,9 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl)
	 * image download completion.
	 */
	ee = mhi_get_exec_env(mhi_cntrl);
	if (ee == MHI_EE_MAX)
		goto error_exit_rddm;

	if (ee != MHI_EE_RDDM) {
		dev_dbg(dev, "Trigger device into RDDM mode using SYS ERR\n");
		mhi_set_mhi_state(mhi_cntrl, MHI_STATE_SYS_ERR);
@@ -139,15 +142,17 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl)
	ee = mhi_get_exec_env(mhi_cntrl);
	ret = mhi_read_reg(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, &rx_status);

	dev_err(dev, "Did not complete RDDM transfer\n");
	dev_err(dev, "Current EE: %s\n", TO_MHI_EXEC_STR(ee));
	dev_err(dev, "RXVEC_STATUS: 0x%x\n", rx_status);

error_exit_rddm:
	dev_err(dev, "RDDM transfer failed. Current EE: %s\n",
		TO_MHI_EXEC_STR(ee));

	return -EIO;
}

/* Download RDDM image from device */
int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic)
int mhi_download_rddm_image(struct mhi_controller *mhi_cntrl, bool in_panic)
{
	void __iomem *base = mhi_cntrl->bhie;
	struct device *dev = &mhi_cntrl->mhi_dev->dev;
@@ -169,9 +174,9 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic)

	return (rx_status == BHIE_RXVECSTATUS_STATUS_XFER_COMPL) ? 0 : -EIO;
}
EXPORT_SYMBOL_GPL(mhi_download_rddm_img);
EXPORT_SYMBOL_GPL(mhi_download_rddm_image);

static int mhi_fw_load_amss(struct mhi_controller *mhi_cntrl,
static int mhi_fw_load_bhie(struct mhi_controller *mhi_cntrl,
			    const struct mhi_buf *mhi_buf)
{
	void __iomem *base = mhi_cntrl->bhie;
@@ -187,7 +192,7 @@ static int mhi_fw_load_amss(struct mhi_controller *mhi_cntrl,
	}

	sequence_id = MHI_RANDOM_U32_NONZERO(BHIE_TXVECSTATUS_SEQNUM_BMSK);
	dev_dbg(dev, "Starting AMSS download via BHIe. Sequence ID:%u\n",
	dev_dbg(dev, "Starting image download via BHIe. Sequence ID: %u\n",
		sequence_id);
	mhi_write_reg(mhi_cntrl, base, BHIE_TXVECADDR_HIGH_OFFS,
		      upper_32_bits(mhi_buf->dma_addr));
@@ -218,7 +223,7 @@ static int mhi_fw_load_amss(struct mhi_controller *mhi_cntrl,
	return (!ret) ? -ETIMEDOUT : 0;
}

static int mhi_fw_load_sbl(struct mhi_controller *mhi_cntrl,
static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl,
			   dma_addr_t dma_addr,
			   size_t size)
{
@@ -245,7 +250,7 @@ static int mhi_fw_load_sbl(struct mhi_controller *mhi_cntrl,
	}

	session_id = MHI_RANDOM_U32_NONZERO(BHI_TXDB_SEQNUM_BMSK);
	dev_dbg(dev, "Starting SBL download via BHI. Session ID:%u\n",
	dev_dbg(dev, "Starting image download via BHI. Session ID: %u\n",
		session_id);
	mhi_write_reg(mhi_cntrl, base, BHI_STATUS, 0);
	mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_HIGH,
@@ -365,7 +370,6 @@ static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl,
	size_t remainder = firmware->size;
	size_t to_cpy;
	const u8 *buf = firmware->data;
	int i = 0;
	struct mhi_buf *mhi_buf = img_info->mhi_buf;
	struct bhi_vec_entry *bhi_vec = img_info->bhi_vec;

@@ -377,7 +381,6 @@ static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl,

		buf += to_cpy;
		remainder -= to_cpy;
		i++;
		bhi_vec++;
		mhi_buf++;
	}
@@ -425,13 +428,13 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
						     !mhi_cntrl->seg_len))) {
		dev_err(dev,
			"No firmware image defined or !sbl_size || !seg_len\n");
		return;
		goto error_fw_load;
	}

	ret = request_firmware(&firmware, fw_name, dev);
	if (ret) {
		dev_err(dev, "Error loading firmware: %d\n", ret);
		return;
		goto error_fw_load;
	}

	size = (mhi_cntrl->fbc_download) ? mhi_cntrl->sbl_size : firmware->size;
@@ -443,25 +446,25 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
	buf = mhi_alloc_coherent(mhi_cntrl, size, &dma_addr, GFP_KERNEL);
	if (!buf) {
		release_firmware(firmware);
		return;
		goto error_fw_load;
	}

	/* Download SBL image */
	/* Download image using BHI */
	memcpy(buf, firmware->data, size);
	ret = mhi_fw_load_sbl(mhi_cntrl, dma_addr, size);
	ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size);
	mhi_free_coherent(mhi_cntrl, size, buf, dma_addr);

	if (!mhi_cntrl->fbc_download || ret || mhi_cntrl->ee == MHI_EE_EDL)
		release_firmware(firmware);

	/* Error or in EDL mode, we're done */
	if (ret) {
		dev_err(dev, "MHI did not load SBL, ret:%d\n", ret);
		return;
		dev_err(dev, "MHI did not load image over BHI, ret: %d\n", ret);
		release_firmware(firmware);
		goto error_fw_load;
	}

	if (mhi_cntrl->ee == MHI_EE_EDL)
	if (mhi_cntrl->ee == MHI_EE_EDL) {
		release_firmware(firmware);
		return;
	}

	write_lock_irq(&mhi_cntrl->pm_lock);
	mhi_cntrl->dev_state = MHI_STATE_RESET;
@@ -474,13 +477,17 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
	if (mhi_cntrl->fbc_download) {
		ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image,
					   firmware->size);
		if (ret)
			goto error_alloc_fw_table;
		if (ret) {
			release_firmware(firmware);
			goto error_fw_load;
		}

		/* Load the firmware into BHIE vec table */
		mhi_firmware_copy(mhi_cntrl, firmware, mhi_cntrl->fbc_image);
	}

	release_firmware(firmware);

fw_load_ee_pthru:
	/* Transitioning into MHI RESET->READY state */
	ret = mhi_ready_state_transition(mhi_cntrl);
@@ -490,7 +497,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)

	if (ret) {
		dev_err(dev, "MHI did not enter READY state\n");
		goto error_read;
		goto error_ready_state;
	}

	/* Wait for the SBL event */
@@ -501,25 +508,27 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)

	if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
		dev_err(dev, "MHI did not enter SBL\n");
		goto error_read;
		goto error_ready_state;
	}

	/* Start full firmware image download */
	image_info = mhi_cntrl->fbc_image;
	ret = mhi_fw_load_amss(mhi_cntrl,
	ret = mhi_fw_load_bhie(mhi_cntrl,
			       /* Vector table is the last entry */
			       &image_info->mhi_buf[image_info->entries - 1]);
	if (ret)
		dev_err(dev, "MHI did not load AMSS, ret:%d\n", ret);

	release_firmware(firmware);
	if (ret) {
		dev_err(dev, "MHI did not load image over BHIe, ret: %d\n",
			ret);
		goto error_fw_load;
	}

	return;

error_read:
error_ready_state:
	mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image);
	mhi_cntrl->fbc_image = NULL;

error_alloc_fw_table:
	release_firmware(firmware);
error_fw_load:
	mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR;
	wake_up_all(&mhi_cntrl->state_event);
}
+3 −1
Original line number Diff line number Diff line
@@ -159,7 +159,9 @@ static int mhi_debugfs_devices_show(struct seq_file *m, void *d)
		return -ENODEV;
	}

	device_for_each_child(mhi_cntrl->cntrl_dev, m, mhi_device_info_show);
	/* Show controller and client(s) info */
	mhi_device_info_show(&mhi_cntrl->mhi_dev->dev, m);
	device_for_each_child(&mhi_cntrl->mhi_dev->dev, m, mhi_device_info_show);

	return 0;
}
+46 −27
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/device.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/mhi.h>
@@ -18,6 +19,8 @@
#include <linux/wait.h>
#include "internal.h"

static DEFINE_IDA(mhi_controller_ida);

const char * const mhi_ee_str[MHI_EE_MAX] = {
	[MHI_EE_PBL] = "PBL",
	[MHI_EE_SBL] = "SBL",
@@ -610,7 +613,7 @@ static int parse_ev_cfg(struct mhi_controller *mhi_cntrl,
{
	struct mhi_event *mhi_event;
	const struct mhi_event_config *event_cfg;
	struct device *dev = &mhi_cntrl->mhi_dev->dev;
	struct device *dev = mhi_cntrl->cntrl_dev;
	int i, num;

	num = config->num_events;
@@ -692,7 +695,7 @@ static int parse_ch_cfg(struct mhi_controller *mhi_cntrl,
			const struct mhi_controller_config *config)
{
	const struct mhi_channel_config *ch_cfg;
	struct device *dev = &mhi_cntrl->mhi_dev->dev;
	struct device *dev = mhi_cntrl->cntrl_dev;
	int i;
	u32 chan;

@@ -758,7 +761,6 @@ static int parse_ch_cfg(struct mhi_controller *mhi_cntrl,
		mhi_chan->offload_ch = ch_cfg->offload_channel;
		mhi_chan->db_cfg.reset_req = ch_cfg->doorbell_mode_switch;
		mhi_chan->pre_alloc = ch_cfg->auto_queue;
		mhi_chan->auto_start = ch_cfg->auto_start;

		/*
		 * If MHI host allocates buffers, then the channel direction
@@ -858,7 +860,7 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,

	if (!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put ||
	    !mhi_cntrl->status_cb || !mhi_cntrl->read_reg ||
	    !mhi_cntrl->write_reg)
	    !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs)
		return -EINVAL;

	ret = parse_config(mhi_cntrl, config);
@@ -869,7 +871,7 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
				     sizeof(*mhi_cntrl->mhi_cmd), GFP_KERNEL);
	if (!mhi_cntrl->mhi_cmd) {
		ret = -ENOMEM;
		goto error_alloc_cmd;
		goto err_free_event;
	}

	INIT_LIST_HEAD(&mhi_cntrl->transition_list);
@@ -880,6 +882,14 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
	INIT_WORK(&mhi_cntrl->st_worker, mhi_pm_st_worker);
	init_waitqueue_head(&mhi_cntrl->state_event);

	mhi_cntrl->hiprio_wq = alloc_ordered_workqueue
				("mhi_hiprio_wq", WQ_MEM_RECLAIM | WQ_HIGHPRI);
	if (!mhi_cntrl->hiprio_wq) {
		dev_err(mhi_cntrl->cntrl_dev, "Failed to allocate workqueue\n");
		ret = -ENOMEM;
		goto err_free_cmd;
	}

	mhi_cmd = mhi_cntrl->mhi_cmd;
	for (i = 0; i < NR_OF_CMD_RINGS; i++, mhi_cmd++)
		spin_lock_init(&mhi_cmd->lock);
@@ -923,7 +933,7 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
	ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs,
			   SOC_HW_VERSION_OFFS, &soc_info);
	if (ret)
		goto error_alloc_dev;
		goto err_destroy_wq;

	mhi_cntrl->family_number = (soc_info & SOC_HW_VERSION_FAM_NUM_BMSK) >>
					SOC_HW_VERSION_FAM_NUM_SHFT;
@@ -934,25 +944,31 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
	mhi_cntrl->minor_version = (soc_info & SOC_HW_VERSION_MINOR_VER_BMSK) >>
					SOC_HW_VERSION_MINOR_VER_SHFT;

	mhi_cntrl->index = ida_alloc(&mhi_controller_ida, GFP_KERNEL);
	if (mhi_cntrl->index < 0) {
		ret = mhi_cntrl->index;
		goto err_destroy_wq;
	}

	/* Register controller with MHI bus */
	mhi_dev = mhi_alloc_device(mhi_cntrl);
	if (IS_ERR(mhi_dev)) {
		dev_err(mhi_cntrl->cntrl_dev, "Failed to allocate MHI device\n");
		ret = PTR_ERR(mhi_dev);
		goto error_alloc_dev;
		goto err_ida_free;
	}

	mhi_dev->dev_type = MHI_DEVICE_CONTROLLER;
	mhi_dev->mhi_cntrl = mhi_cntrl;
	dev_set_name(&mhi_dev->dev, "%s", dev_name(mhi_cntrl->cntrl_dev));
	mhi_dev->name = dev_name(mhi_cntrl->cntrl_dev);
	dev_set_name(&mhi_dev->dev, "mhi%d", mhi_cntrl->index);
	mhi_dev->name = dev_name(&mhi_dev->dev);

	/* Init wakeup source */
	device_init_wakeup(&mhi_dev->dev, true);

	ret = device_add(&mhi_dev->dev);
	if (ret)
		goto error_add_dev;
		goto err_release_dev;

	mhi_cntrl->mhi_dev = mhi_dev;

@@ -960,15 +976,17 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,

	return 0;

error_add_dev:
err_release_dev:
	put_device(&mhi_dev->dev);

error_alloc_dev:
err_ida_free:
	ida_free(&mhi_controller_ida, mhi_cntrl->index);
err_destroy_wq:
	destroy_workqueue(mhi_cntrl->hiprio_wq);
err_free_cmd:
	kfree(mhi_cntrl->mhi_cmd);

error_alloc_cmd:
	vfree(mhi_cntrl->mhi_chan);
err_free_event:
	kfree(mhi_cntrl->mhi_event);
	vfree(mhi_cntrl->mhi_chan);

	return ret;
}
@@ -982,6 +1000,7 @@ void mhi_unregister_controller(struct mhi_controller *mhi_cntrl)

	mhi_destroy_debugfs(mhi_cntrl);

	destroy_workqueue(mhi_cntrl->hiprio_wq);
	kfree(mhi_cntrl->mhi_cmd);
	kfree(mhi_cntrl->mhi_event);

@@ -996,6 +1015,8 @@ void mhi_unregister_controller(struct mhi_controller *mhi_cntrl)

	device_del(&mhi_dev->dev);
	put_device(&mhi_dev->dev);

	ida_free(&mhi_controller_ida, mhi_cntrl->index);
}
EXPORT_SYMBOL_GPL(mhi_unregister_controller);

@@ -1122,7 +1143,15 @@ struct mhi_device *mhi_alloc_device(struct mhi_controller *mhi_cntrl)
	device_initialize(dev);
	dev->bus = &mhi_bus_type;
	dev->release = mhi_release_device;

	if (mhi_cntrl->mhi_dev) {
		/* for MHI client devices, parent is the MHI controller device */
		dev->parent = &mhi_cntrl->mhi_dev->dev;
	} else {
		/* for MHI controller device, parent is the bus device (e.g. pci device) */
		dev->parent = mhi_cntrl->cntrl_dev;
	}

	mhi_dev->mhi_cntrl = mhi_cntrl;
	mhi_dev->dev_wake = 0;

@@ -1160,11 +1189,6 @@ static int mhi_driver_probe(struct device *dev)
			goto exit_probe;

		ul_chan->xfer_cb = mhi_drv->ul_xfer_cb;
		if (ul_chan->auto_start) {
			ret = mhi_prepare_channel(mhi_cntrl, ul_chan);
			if (ret)
				goto exit_probe;
		}
	}

	ret = -EINVAL;
@@ -1198,9 +1222,6 @@ static int mhi_driver_probe(struct device *dev)
	if (ret)
		goto exit_probe;

	if (dl_chan && dl_chan->auto_start)
		mhi_prepare_channel(mhi_cntrl, dl_chan);

	mhi_device_put(mhi_dev);

	return ret;
@@ -1276,10 +1297,8 @@ static int mhi_driver_remove(struct device *dev)
		mutex_unlock(&mhi_chan->mutex);
	}

	read_lock_bh(&mhi_cntrl->pm_lock);
	while (mhi_dev->dev_wake)
		mhi_device_put(mhi_dev);
	read_unlock_bh(&mhi_cntrl->pm_lock);

	return 0;
}
Loading