--------
 
 - Add support for loading dual ELF image format firmware to Qcom Trust
   Management Engine Lit (TME-L) supported devices like QCC2072, which require
   separate ELF header for SBL and WLAN firmware segments in a single firmware.
 
 - Remove the MHI auto_queue feature support. This feature was added to offload
   the queuing of buffers from the client drivers to the MHI stack, but it caused
   a lot of race over the time. So remove this feature from the QRTR client
   driver and also from the MHI stack/controller drivers.
 
 - Move the .probe() and .remove() callbacks from driver level to bus level.
 
 MHI Endpoint
 ------------
 
 - Move the .probe() and .remove() callbacks from driver level to bus level.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEZ6VDKoFIy9ikWCeXVZ8R5v6RzvUFAmlvHJAACgkQVZ8R5v6R
 zvUpogf+Leqm2ma1cORmVV0YgSQkC/DNpNw2wD8oYKRp0hlLdiQTVyJ1l0LZhK1v
 ud/0dDQ25HFlnICltm/eyzDlRp/kJz2OVh4becoDmnUqgqnfR4G1WP3DHhPhvODo
 5wFiKU463RW1Ba0GsJxhPjSNwbXQeMhyBFOIr2XuWNI9wLCT6c5BRXbM8X7fVTcY
 6pNONiEb8YMpclJAIoZwgMLlvHut+RmpKuVdYzOUfzL71os6AmRaDbKFVaBjTqDK
 aXUrh5WZZyVndKcxIPTHzrRiZSbqG8laQp8ES2Lfk5ogX5MUEVJVZ14m2Tx9inyH
 YYaOnYAyeW0/ZP33/p1odfqrJ6RX4w==
 =8oyK
 -----END PGP SIGNATURE-----

Merge tag 'mhi-for-v6.20' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mani/mhi into char-misc-next

Manivannan writes:

MHI Host
--------

- Add support for loading dual ELF image format firmware to Qcom Trust
  Management Engine Lit (TME-L) supported devices like QCC2072, which require
  separate ELF header for SBL and WLAN firmware segments in a single firmware.

- Remove the MHI auto_queue feature support. This feature was added to offload
  the queuing of buffers from the client drivers to the MHI stack, but it caused
  a lot of race over the time. So remove this feature from the QRTR client
  driver and also from the MHI stack/controller drivers.

- Move the .probe() and .remove() callbacks from driver level to bus level.

MHI Endpoint
------------

- Move the .probe() and .remove() callbacks from driver level to bus level.

* tag 'mhi-for-v6.20' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mani/mhi:
  bus: mhi: ep: Use bus callbacks for .probe() and .remove()
  bus: mhi: host: Use bus callbacks for .probe() and .remove()
  bus: mhi: host: Drop the auto_queue support
  net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels
  mhi: host: Add support for loading dual ELF image format
This commit is contained in:
Greg Kroah-Hartman 2026-01-20 16:40:49 +01:00
commit 740aeaf40f
11 changed files with 82 additions and 201 deletions

View File

@ -39,7 +39,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -55,7 +54,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -71,7 +69,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -87,7 +84,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -103,7 +99,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -119,7 +114,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -135,7 +129,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -151,7 +144,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -167,7 +159,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -183,7 +174,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -199,7 +189,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -215,7 +204,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -231,7 +219,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -247,7 +234,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -263,7 +249,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -279,7 +264,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -295,7 +279,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -311,7 +294,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -327,7 +309,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -343,7 +324,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -359,7 +339,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -375,7 +354,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -391,7 +369,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -407,7 +384,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -423,7 +399,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -439,7 +414,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
.wake_capable = false,
},
};
@ -458,7 +432,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -474,7 +447,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -490,7 +462,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -506,7 +477,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -522,7 +492,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -538,7 +507,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -554,7 +522,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -570,7 +537,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -586,7 +552,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -602,7 +567,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -618,7 +582,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -634,7 +597,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -650,7 +612,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -666,7 +627,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -682,7 +642,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -698,7 +657,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -714,7 +672,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
.wake_capable = false,
},
{
@ -730,7 +687,6 @@ static const struct mhi_channel_config aic200_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
.wake_capable = false,
},
};

View File

@ -1596,7 +1596,7 @@ void mhi_ep_unregister_controller(struct mhi_ep_cntrl *mhi_cntrl)
}
EXPORT_SYMBOL_GPL(mhi_ep_unregister_controller);
static int mhi_ep_driver_probe(struct device *dev)
static int mhi_ep_probe(struct device *dev)
{
struct mhi_ep_device *mhi_dev = to_mhi_ep_device(dev);
struct mhi_ep_driver *mhi_drv = to_mhi_ep_driver(dev->driver);
@ -1609,7 +1609,7 @@ static int mhi_ep_driver_probe(struct device *dev)
return mhi_drv->probe(mhi_dev, mhi_dev->id);
}
static int mhi_ep_driver_remove(struct device *dev)
static void mhi_ep_remove(struct device *dev)
{
struct mhi_ep_device *mhi_dev = to_mhi_ep_device(dev);
struct mhi_ep_driver *mhi_drv = to_mhi_ep_driver(dev->driver);
@ -1619,7 +1619,7 @@ static int mhi_ep_driver_remove(struct device *dev)
/* Skip if it is a controller device */
if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER)
return 0;
return;
/* Disconnect the channels associated with the driver */
for (dir = 0; dir < 2; dir++) {
@ -1643,8 +1643,6 @@ static int mhi_ep_driver_remove(struct device *dev)
/* Remove the client driver now */
mhi_drv->remove(mhi_dev);
return 0;
}
int __mhi_ep_driver_register(struct mhi_ep_driver *mhi_drv, struct module *owner)
@ -1660,8 +1658,6 @@ int __mhi_ep_driver_register(struct mhi_ep_driver *mhi_drv, struct module *owner
driver->bus = &mhi_ep_bus_type;
driver->owner = owner;
driver->probe = mhi_ep_driver_probe;
driver->remove = mhi_ep_driver_remove;
return driver_register(driver);
}
@ -1708,6 +1704,8 @@ const struct bus_type mhi_ep_bus_type = {
.dev_name = "mhi_ep",
.match = mhi_ep_match,
.uevent = mhi_ep_uevent,
.probe = mhi_ep_probe,
.remove = mhi_ep_remove,
};
static int __init mhi_ep_init(void)

View File

@ -584,6 +584,16 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
* device transitioning into MHI READY state
*/
if (fw_load_type == MHI_FW_LOAD_FBC) {
/*
* Some FW combine two separate ELF images (SBL + WLAN FW) in a single
* file. Hence, check for the existence of the second ELF header after
* SBL. If present, load the second image separately.
*/
if (!memcmp(fw_data + mhi_cntrl->sbl_size, ELFMAG, SELFMAG)) {
fw_data += mhi_cntrl->sbl_size;
fw_sz -= mhi_cntrl->sbl_size;
}
ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image, fw_sz);
if (ret) {
release_firmware(firmware);

View File

@ -841,18 +841,8 @@ static int parse_ch_cfg(struct mhi_controller *mhi_cntrl,
mhi_chan->lpm_notify = ch_cfg->lpm_notify;
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->wake_capable = ch_cfg->wake_capable;
/*
* If MHI host allocates buffers, then the channel direction
* should be DMA_FROM_DEVICE
*/
if (mhi_chan->pre_alloc && mhi_chan->dir != DMA_FROM_DEVICE) {
dev_err(dev, "Invalid channel configuration\n");
goto error_chan_cfg;
}
/*
* Bi-directional and direction less channel must be an
* offload channel
@ -1265,7 +1255,7 @@ struct mhi_device *mhi_alloc_device(struct mhi_controller *mhi_cntrl)
return mhi_dev;
}
static int mhi_driver_probe(struct device *dev)
static int mhi_probe(struct device *dev)
{
struct mhi_device *mhi_dev = to_mhi_device(dev);
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
@ -1341,7 +1331,7 @@ static int mhi_driver_probe(struct device *dev)
return ret;
}
static int mhi_driver_remove(struct device *dev)
static void mhi_remove(struct device *dev)
{
struct mhi_device *mhi_dev = to_mhi_device(dev);
struct mhi_driver *mhi_drv = to_mhi_driver(dev->driver);
@ -1355,7 +1345,7 @@ static int mhi_driver_remove(struct device *dev)
/* Skip if it is a controller device */
if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER)
return 0;
return;
/* Reset both channels */
for (dir = 0; dir < 2; dir++) {
@ -1407,8 +1397,6 @@ static int mhi_driver_remove(struct device *dev)
while (mhi_dev->dev_wake)
mhi_device_put(mhi_dev);
return 0;
}
int __mhi_driver_register(struct mhi_driver *mhi_drv, struct module *owner)
@ -1420,8 +1408,6 @@ int __mhi_driver_register(struct mhi_driver *mhi_drv, struct module *owner)
driver->bus = &mhi_bus_type;
driver->owner = owner;
driver->probe = mhi_driver_probe;
driver->remove = mhi_driver_remove;
return driver_register(driver);
}
@ -1468,6 +1454,8 @@ const struct bus_type mhi_bus_type = {
.dev_name = "mhi",
.match = mhi_match,
.uevent = mhi_uevent,
.probe = mhi_probe,
.remove = mhi_remove,
.dev_groups = mhi_dev_groups,
};

View File

@ -286,7 +286,6 @@ struct mhi_chan {
bool lpm_notify;
bool configured;
bool offload_ch;
bool pre_alloc;
bool wake_capable;
};
@ -389,8 +388,6 @@ int mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
struct image_info *img_info);
void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl);
/* Automatically allocate and queue inbound buffers */
#define MHI_CH_INBOUND_ALLOC_BUFS BIT(0)
int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl,
struct mhi_chan *mhi_chan);
void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,

View File

@ -664,23 +664,6 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
mhi_cntrl->runtime_put(mhi_cntrl);
}
/*
* Recycle the buffer if buffer is pre-allocated,
* if there is an error, not much we can do apart
* from dropping the packet
*/
if (mhi_chan->pre_alloc) {
if (mhi_queue_buf(mhi_chan->mhi_dev,
mhi_chan->dir,
buf_info->cb_buf,
buf_info->len, MHI_EOT)) {
dev_err(dev,
"Error recycling buffer for chan:%d\n",
mhi_chan->chan);
kfree(buf_info->cb_buf);
}
}
read_lock_bh(&mhi_chan->lock);
}
break;
@ -1177,17 +1160,12 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info,
int mhi_queue_skb(struct mhi_device *mhi_dev, enum dma_data_direction dir,
struct sk_buff *skb, size_t len, enum mhi_flags mflags)
{
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan :
mhi_dev->dl_chan;
struct mhi_buf_info buf_info = { };
buf_info.v_addr = skb->data;
buf_info.cb_buf = skb;
buf_info.len = len;
if (unlikely(mhi_chan->pre_alloc))
return -EINVAL;
return mhi_queue(mhi_dev, &buf_info, dir, mflags);
}
EXPORT_SYMBOL_GPL(mhi_queue_skb);
@ -1472,45 +1450,6 @@ static int mhi_prepare_channel(struct mhi_controller *mhi_cntrl,
if (ret)
goto error_pm_state;
if (mhi_chan->dir == DMA_FROM_DEVICE)
mhi_chan->pre_alloc = !!(flags & MHI_CH_INBOUND_ALLOC_BUFS);
/* Pre-allocate buffer for xfer ring */
if (mhi_chan->pre_alloc) {
int nr_el = get_nr_avail_ring_elements(mhi_cntrl,
&mhi_chan->tre_ring);
size_t len = mhi_cntrl->buffer_len;
while (nr_el--) {
void *buf;
struct mhi_buf_info info = { };
buf = kmalloc(len, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto error_pre_alloc;
}
/* Prepare transfer descriptors */
info.v_addr = buf;
info.cb_buf = buf;
info.len = len;
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, &info, MHI_EOT);
if (ret) {
kfree(buf);
goto error_pre_alloc;
}
}
read_lock_bh(&mhi_cntrl->pm_lock);
if (MHI_DB_ACCESS_VALID(mhi_cntrl)) {
read_lock_irq(&mhi_chan->lock);
mhi_ring_chan_db(mhi_cntrl, mhi_chan);
read_unlock_irq(&mhi_chan->lock);
}
read_unlock_bh(&mhi_cntrl->pm_lock);
}
mutex_unlock(&mhi_chan->mutex);
return 0;
@ -1522,12 +1461,6 @@ static int mhi_prepare_channel(struct mhi_controller *mhi_cntrl,
error_init_chan:
mutex_unlock(&mhi_chan->mutex);
return ret;
error_pre_alloc:
mutex_unlock(&mhi_chan->mutex);
mhi_unprepare_channel(mhi_cntrl, mhi_chan);
return ret;
}
@ -1600,12 +1533,8 @@ static void mhi_reset_data_chan(struct mhi_controller *mhi_cntrl,
mhi_del_ring_element(mhi_cntrl, buf_ring);
mhi_del_ring_element(mhi_cntrl, tre_ring);
if (mhi_chan->pre_alloc) {
kfree(buf_info->cb_buf);
} else {
result.buf_addr = buf_info->cb_buf;
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
}
result.buf_addr = buf_info->cb_buf;
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
}
}
@ -1666,12 +1595,6 @@ int mhi_prepare_for_transfer(struct mhi_device *mhi_dev)
}
EXPORT_SYMBOL_GPL(mhi_prepare_for_transfer);
int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev)
{
return __mhi_prepare_for_transfer(mhi_dev, MHI_CH_INBOUND_ALLOC_BUFS);
}
EXPORT_SYMBOL_GPL(mhi_prepare_for_transfer_autoqueue);
void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev)
{
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;

View File

@ -94,22 +94,6 @@ struct mhi_pci_dev_info {
.doorbell_mode_switch = false, \
}
#define MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(ch_num, ch_name, el_count, ev_ring) \
{ \
.num = ch_num, \
.name = ch_name, \
.num_elements = el_count, \
.event_ring = ev_ring, \
.dir = DMA_FROM_DEVICE, \
.ee_mask = BIT(MHI_EE_AMSS), \
.pollcfg = 0, \
.doorbell = MHI_DB_BRST_DISABLE, \
.lpm_notify = false, \
.offload_channel = false, \
.doorbell_mode_switch = false, \
.auto_queue = true, \
}
#define MHI_EVENT_CONFIG_CTRL(ev_ring, el_count) \
{ \
.num_elements = el_count, \
@ -329,7 +313,7 @@ static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = {
MHI_CHANNEL_CONFIG_UL(14, "QMI", 4, 0),
MHI_CHANNEL_CONFIG_DL(15, "QMI", 4, 0),
MHI_CHANNEL_CONFIG_UL(20, "IPCR", 8, 0),
MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 8, 0),
MHI_CHANNEL_CONFIG_DL(21, "IPCR", 8, 0),
MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0),
MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0),
MHI_CHANNEL_CONFIG_UL(46, "IP_SW0", 64, 2),
@ -762,7 +746,7 @@ static const struct mhi_channel_config mhi_telit_fn980_hw_v1_channels[] = {
MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0),
MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0),
MHI_CHANNEL_CONFIG_UL(20, "IPCR", 16, 0),
MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 16, 0),
MHI_CHANNEL_CONFIG_DL(21, "IPCR", 16, 0),
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 1),
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 2),
};

View File

@ -34,7 +34,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 21,
@ -48,7 +47,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
},
};
@ -99,7 +97,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 21,
@ -113,7 +110,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
},
};

View File

@ -31,7 +31,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 21,
@ -45,7 +44,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
},
};
@ -96,7 +94,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 21,
@ -110,7 +107,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
},
};

View File

@ -215,7 +215,6 @@ enum mhi_db_brst_mode {
* @lpm_notify: The channel master requires low power mode notifications
* @offload_channel: The client manages the channel completely
* @doorbell_mode_switch: Channel switches to doorbell mode on M0 transition
* @auto_queue: Framework will automatically queue buffers for DL traffic
* @wake-capable: Channel capable of waking up the system
*/
struct mhi_channel_config {
@ -232,7 +231,6 @@ struct mhi_channel_config {
bool lpm_notify;
bool offload_channel;
bool doorbell_mode_switch;
bool auto_queue;
bool wake_capable;
};
@ -743,18 +741,6 @@ void mhi_device_put(struct mhi_device *mhi_dev);
*/
int mhi_prepare_for_transfer(struct mhi_device *mhi_dev);
/**
* mhi_prepare_for_transfer_autoqueue - Setup UL and DL channels with auto queue
* buffers for DL traffic
* @mhi_dev: Device associated with the channels
*
* Allocate and initialize the channel context and also issue the START channel
* command to both channels. Channels can be started only if both host and
* device execution environments match and channels are in a DISABLED state.
* The MHI core will automatically allocate and queue buffers for the DL traffic.
*/
int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev);
/**
* mhi_unprepare_from_transfer - Reset UL and DL channels for data transfer.
* Issue the RESET channel command and let the

View File

@ -24,13 +24,25 @@ static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev,
struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
int rc;
if (!qdev || mhi_res->transaction_status)
if (!qdev || (mhi_res->transaction_status && mhi_res->transaction_status != -ENOTCONN))
return;
/* Channel got reset. So just free the buffer */
if (mhi_res->transaction_status == -ENOTCONN) {
devm_kfree(&mhi_dev->dev, mhi_res->buf_addr);
return;
}
rc = qrtr_endpoint_post(&qdev->ep, mhi_res->buf_addr,
mhi_res->bytes_xferd);
if (rc == -EINVAL)
dev_err(qdev->dev, "invalid ipcrouter packet\n");
/* Done with the buffer, now recycle it for future use */
rc = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, mhi_res->buf_addr,
mhi_dev->mhi_cntrl->buffer_len, MHI_EOT);
if (rc)
dev_err(&mhi_dev->dev, "Failed to recycle the buffer: %d\n", rc);
}
/* From QRTR to MHI */
@ -72,6 +84,29 @@ static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
return rc;
}
static int qcom_mhi_qrtr_queue_dl_buffers(struct mhi_device *mhi_dev)
{
u32 free_desc;
void *buf;
int ret;
free_desc = mhi_get_free_desc_count(mhi_dev, DMA_FROM_DEVICE);
while (free_desc--) {
buf = devm_kmalloc(&mhi_dev->dev, mhi_dev->mhi_cntrl->buffer_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, buf, mhi_dev->mhi_cntrl->buffer_len,
MHI_EOT);
if (ret) {
dev_err(&mhi_dev->dev, "Failed to queue buffer: %d\n", ret);
return ret;
}
}
return 0;
}
static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
const struct mhi_device_id *id)
{
@ -87,20 +122,30 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
qdev->ep.xmit = qcom_mhi_qrtr_send;
dev_set_drvdata(&mhi_dev->dev, qdev);
rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
/* start channels */
rc = mhi_prepare_for_transfer(mhi_dev);
if (rc)
return rc;
/* start channels */
rc = mhi_prepare_for_transfer_autoqueue(mhi_dev);
if (rc) {
qrtr_endpoint_unregister(&qdev->ep);
return rc;
}
rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
if (rc)
goto err_unprepare;
rc = qcom_mhi_qrtr_queue_dl_buffers(mhi_dev);
if (rc)
goto err_unregister;
dev_dbg(qdev->dev, "Qualcomm MHI QRTR driver probed\n");
return 0;
err_unregister:
qrtr_endpoint_unregister(&qdev->ep);
err_unprepare:
mhi_unprepare_from_transfer(mhi_dev);
return rc;
}
static void qcom_mhi_qrtr_remove(struct mhi_device *mhi_dev)
@ -151,11 +196,13 @@ static int __maybe_unused qcom_mhi_qrtr_pm_resume_early(struct device *dev)
if (state == MHI_STATE_M3)
return 0;
rc = mhi_prepare_for_transfer_autoqueue(mhi_dev);
if (rc)
rc = mhi_prepare_for_transfer(mhi_dev);
if (rc) {
dev_err(dev, "failed to prepare for autoqueue transfer %d\n", rc);
return rc;
}
return rc;
return qcom_mhi_qrtr_queue_dl_buffers(mhi_dev);
}
static const struct dev_pm_ops qcom_mhi_qrtr_pm_ops = {