mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
Merge tag 'mhi-for-v7.3' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mani/mhi into char-misc-next
Manivannan writes: MHI Host -------- - Add SAHARA channel support in the pci_generic driver for Foxconn products. This allows capturing crashdump (ramdump) using the in-kernel sahara client driver. - Add support for devices with no M3 state. Some devices do not support the M3 power state due to hardware issues. For those devices, MHI bus will now run the full host-side suspend/resume sequence but skip the device-side M3/M0 handshake, so any transfer queued by clients during suspend is deferred until resume. - Set 'mhi_cntrl->no_m3' flag in the pci_generic driver for the QDU100 device so that the MHI bus also skips the M3 transition during system suspend. Earlier, the flag was only used to disable runtime PM, but the system suspend path was still transitioning the device to M3. - Fix sys error transition latency by polling for the state transition in mhi_pm_sys_error_transition() instead of waiting up to 24 seconds for an interrupt from the device. Since a device that has been reset (e.g., via AT!RESET) is not guaranteed to raise one. - Flush the posted write after writing to MHI_SOC_RESET_REQ_OFFSET in mhi_soc_reset() so that the reset actually reaches the device before the caller's post-reset delay begins. - Fix controller cleanup on EDL sysfs failure in mhi_register_controller(). The error path was leaving the device registered when sysfs_create_file() failed. MHI Endpoint ------------ - Add mhi_cntrl->flush_async() callback to drain the in-flight async DMA read/write operations issued through the MHI controller driver. This is used by the MHI EP stack before disconnect to avoid UAF where a late DMA completion could invoke a now-invalid xfer_cb(). - Implement the flush_async() callback in the PCI EPF MHI controller driver by waiting for the in-flight DMA operations to complete and then flushing the DMA workqueue. Since I'm the maintainer for this PCI EPF driver, I'm taking this patch through MHI tree due to dependency. - Flush the in-flight async transfers before notifying disconnect in mhi_ep_abort_transfer() to fix a UAF, where a success callback delivered after the -ENOTCONN notification could reference resources already freed by the client. - Fix device refcount leak in the error path of mhi_ep_create_device() when dev_set_name() or device_add() fails. Common ------ - Clean up kernel-doc warnings in include/linux/mhi.h. - Add Jeff Hugo as the Reviewer of MHI bus. * tag 'mhi-for-v7.3' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mani/mhi: PCI: epf-mhi: Implement mhi_cntrl->flush_async() to flush DMA read/write bus: mhi: ep: Flush async transfers before notifying disconnect in mhi_ep_abort_transfer() bus: mhi: ep: Add mhi_cntrl->flush_async() callback to flush the async read/write bus: mhi: Clean up some kernel-doc warnings bus: mhi: host: Fix controller cleanup on EDL sysfs failure bus: mhi: pci_generic: Add SAHARA channel support for Foxconn products bus: mhi: host: pci_generic: Set 'mhi_cntrl->no_m3' flag bus: mhi: host: Add support for devices with no M3 state bus: mhi: host: Flush the posted write after writing to MHI_SOC_RESET_REQ_OFFSET MAINTAINERS: Add Jeff Hugo as the Reviewer of MHI bus bus: mhi: ep: Fix device refcount leak in the error path of MHI device creation bus: mhi: core: Fix sys error transition latency
This commit is contained in:
@@ -17477,6 +17477,7 @@ F: arch/arm64/boot/dts/marvell/armada-3720-uDPU.*
|
||||
|
||||
MHI BUS
|
||||
M: Manivannan Sadhasivam <mani@kernel.org>
|
||||
R: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
|
||||
L: mhi@lists.linux.dev
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
+44
-12
@@ -1026,26 +1026,37 @@ static void mhi_ep_abort_transfer(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
struct mhi_ep_chan *mhi_chan;
|
||||
int i;
|
||||
|
||||
/* Stop all the channels */
|
||||
/* Disable all the channels to prevent new transfers */
|
||||
for (i = 0; i < mhi_cntrl->max_chan; i++) {
|
||||
mhi_chan = &mhi_cntrl->mhi_chan[i];
|
||||
if (!mhi_chan->ring.started)
|
||||
continue;
|
||||
|
||||
mutex_lock(&mhi_chan->lock);
|
||||
mhi_chan->state = MHI_CH_STATE_DISABLED;
|
||||
mutex_unlock(&mhi_chan->lock);
|
||||
}
|
||||
|
||||
/* Drain ring workers and in-flight transfers before notifying disconnect */
|
||||
flush_workqueue(mhi_cntrl->wq);
|
||||
if (mhi_cntrl->flush_async)
|
||||
mhi_cntrl->flush_async(mhi_cntrl);
|
||||
|
||||
/* Send channel disconnect status to client drivers */
|
||||
for (i = 0; i < mhi_cntrl->max_chan; i++) {
|
||||
mhi_chan = &mhi_cntrl->mhi_chan[i];
|
||||
if (!mhi_chan->ring.started)
|
||||
continue;
|
||||
|
||||
mutex_lock(&mhi_chan->lock);
|
||||
/* Send channel disconnect status to client drivers */
|
||||
if (mhi_chan->xfer_cb) {
|
||||
result.transaction_status = -ENOTCONN;
|
||||
result.bytes_xferd = 0;
|
||||
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
|
||||
}
|
||||
|
||||
mhi_chan->state = MHI_CH_STATE_DISABLED;
|
||||
mutex_unlock(&mhi_chan->lock);
|
||||
}
|
||||
|
||||
flush_workqueue(mhi_cntrl->wq);
|
||||
|
||||
/* Destroy devices associated with all channels */
|
||||
device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_ep_destroy_device);
|
||||
|
||||
@@ -1340,14 +1351,19 @@ static int mhi_ep_create_device(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id)
|
||||
ret = dev_set_name(&mhi_dev->dev, "%s_%s",
|
||||
dev_name(&mhi_cntrl->mhi_dev->dev),
|
||||
mhi_dev->name);
|
||||
if (ret) {
|
||||
put_device(&mhi_dev->dev);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err_put_channels;
|
||||
|
||||
ret = device_add(&mhi_dev->dev);
|
||||
if (ret)
|
||||
put_device(&mhi_dev->dev);
|
||||
goto err_put_channels;
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_channels:
|
||||
put_device(&mhi_dev->dev); /* DL channel reference */
|
||||
put_device(&mhi_dev->dev); /* UL channel reference */
|
||||
put_device(&mhi_dev->dev); /* device_initialize() reference */
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1614,6 +1630,7 @@ 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);
|
||||
struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
struct mhi_result result = {};
|
||||
struct mhi_ep_chan *mhi_chan;
|
||||
int dir;
|
||||
@@ -1622,6 +1639,22 @@ static void mhi_ep_remove(struct device *dev)
|
||||
if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER)
|
||||
return;
|
||||
|
||||
/* Disable the channels to prevent new transfers */
|
||||
for (dir = 0; dir < 2; dir++) {
|
||||
mhi_chan = dir ? mhi_dev->ul_chan : mhi_dev->dl_chan;
|
||||
|
||||
if (!mhi_chan)
|
||||
continue;
|
||||
|
||||
mutex_lock(&mhi_chan->lock);
|
||||
mhi_chan->state = MHI_CH_STATE_DISABLED;
|
||||
mutex_unlock(&mhi_chan->lock);
|
||||
}
|
||||
|
||||
/* Flush in-flight transfers before notifying disconnect */
|
||||
if (mhi_cntrl->flush_async)
|
||||
mhi_cntrl->flush_async(mhi_cntrl);
|
||||
|
||||
/* Disconnect the channels associated with the driver */
|
||||
for (dir = 0; dir < 2; dir++) {
|
||||
mhi_chan = dir ? mhi_dev->ul_chan : mhi_dev->dl_chan;
|
||||
@@ -1637,7 +1670,6 @@ static void mhi_ep_remove(struct device *dev)
|
||||
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
|
||||
}
|
||||
|
||||
mhi_chan->state = MHI_CH_STATE_DISABLED;
|
||||
mhi_chan->xfer_cb = NULL;
|
||||
mutex_unlock(&mhi_chan->lock);
|
||||
}
|
||||
|
||||
@@ -1029,7 +1029,7 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
|
||||
if (mhi_cntrl->edl_trigger) {
|
||||
ret = sysfs_create_file(&mhi_dev->dev.kobj, &dev_attr_trigger_edl.attr);
|
||||
if (ret)
|
||||
goto err_release_dev;
|
||||
goto err_del_dev;
|
||||
}
|
||||
|
||||
mhi_cntrl->mhi_dev = mhi_dev;
|
||||
@@ -1038,6 +1038,8 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
|
||||
|
||||
return 0;
|
||||
|
||||
err_del_dev:
|
||||
device_del(&mhi_dev->dev);
|
||||
err_release_dev:
|
||||
put_device(&mhi_dev->dev);
|
||||
error_setup_irq:
|
||||
|
||||
@@ -170,6 +170,9 @@ EXPORT_SYMBOL_GPL(mhi_get_mhi_state);
|
||||
|
||||
void mhi_soc_reset(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
int __maybe_unused ret;
|
||||
u32 tmp;
|
||||
|
||||
if (mhi_cntrl->reset) {
|
||||
mhi_cntrl->reset(mhi_cntrl);
|
||||
return;
|
||||
@@ -178,6 +181,9 @@ void mhi_soc_reset(struct mhi_controller *mhi_cntrl)
|
||||
/* Generic MHI SoC reset */
|
||||
mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, MHI_SOC_RESET_REQ_OFFSET,
|
||||
MHI_SOC_RESET_REQ);
|
||||
/* Flush the posted write to the device (ignore return value) */
|
||||
ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, MHI_SOC_RESET_REQ_OFFSET,
|
||||
&tmp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mhi_soc_reset);
|
||||
|
||||
|
||||
@@ -491,6 +491,8 @@ static const struct mhi_pci_dev_info mhi_quectel_rm5xx_info = {
|
||||
static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = {
|
||||
MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 1),
|
||||
MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 1),
|
||||
MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0),
|
||||
@@ -506,6 +508,8 @@ static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = {
|
||||
static const struct mhi_channel_config mhi_foxconn_sdx61_channels[] = {
|
||||
MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 1),
|
||||
MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 1),
|
||||
MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0),
|
||||
@@ -1395,6 +1399,7 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
mhi_cntrl->iova_stop = (dma_addr_t)DMA_BIT_MASK(dma_data_width);
|
||||
mhi_cntrl->fw_image = info->fw;
|
||||
mhi_cntrl->edl_image = info->edl;
|
||||
mhi_cntrl->no_m3 = info->no_m3;
|
||||
|
||||
mhi_cntrl->read_reg = mhi_pci_read_reg;
|
||||
mhi_cntrl->write_reg = mhi_pci_write_reg;
|
||||
|
||||
+45
-26
@@ -651,21 +651,13 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl)
|
||||
|
||||
/* Trigger MHI RESET so that the device will not access host memory */
|
||||
if (reset_device) {
|
||||
u32 in_reset = -1;
|
||||
unsigned long timeout = msecs_to_jiffies(mhi_cntrl->timeout_ms);
|
||||
|
||||
dev_dbg(dev, "Triggering MHI Reset in device\n");
|
||||
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
|
||||
|
||||
/* Wait for the reset bit to be cleared by the device */
|
||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||
mhi_read_reg_field(mhi_cntrl,
|
||||
mhi_cntrl->regs,
|
||||
MHICTRL,
|
||||
MHICTRL_RESET_MASK,
|
||||
&in_reset) ||
|
||||
!in_reset, timeout);
|
||||
if (!ret || in_reset) {
|
||||
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
|
||||
MHICTRL_RESET_MASK, 0, 25000, mhi_cntrl->timeout_ms);
|
||||
if (ret) {
|
||||
dev_err(dev, "Device failed to exit MHI Reset state\n");
|
||||
write_lock_irq(&mhi_cntrl->pm_lock);
|
||||
cur_state = mhi_tryset_pm_state(mhi_cntrl,
|
||||
@@ -922,22 +914,39 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Set MHI to M3 and wait for completion */
|
||||
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_M3);
|
||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
||||
dev_dbg(dev, "Waiting for M3 completion\n");
|
||||
/*
|
||||
* For devices without M3 support, just set the host state to M3. This
|
||||
* host transition is needed to prevent the client drivers from
|
||||
* accessing the device during suspend.
|
||||
*/
|
||||
if (mhi_cntrl->no_m3) {
|
||||
new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_M3);
|
||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
||||
if (new_state != MHI_PM_M3) {
|
||||
dev_err(dev,
|
||||
"Error setting to PM state: %s from: %s\n",
|
||||
to_mhi_pm_state_str(MHI_PM_M3),
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state));
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
/* Set MHI to M3 and wait for completion */
|
||||
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_M3);
|
||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
||||
dev_dbg(dev, "Waiting for M3 completion\n");
|
||||
|
||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||
mhi_cntrl->dev_state == MHI_STATE_M3 ||
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||
mhi_cntrl->dev_state == MHI_STATE_M3 ||
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
|
||||
if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
|
||||
dev_err(dev,
|
||||
"Did not enter M3 state, MHI state: %s, PM state: %s\n",
|
||||
mhi_state_str(mhi_cntrl->dev_state),
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state));
|
||||
return -EIO;
|
||||
if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
|
||||
dev_err(dev,
|
||||
"Did not enter M3 state, MHI state: %s, PM state: %s\n",
|
||||
mhi_state_str(mhi_cntrl->dev_state),
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state));
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify clients about entering LPM */
|
||||
@@ -969,7 +978,8 @@ static int __mhi_pm_resume(struct mhi_controller *mhi_cntrl, bool force)
|
||||
if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))
|
||||
return -EIO;
|
||||
|
||||
if (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3) {
|
||||
if (!mhi_cntrl->no_m3 &&
|
||||
mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3) {
|
||||
dev_warn(dev, "Resuming from non M3 state (%s)\n",
|
||||
mhi_state_str(mhi_get_mhi_state(mhi_cntrl)));
|
||||
if (!force)
|
||||
@@ -995,6 +1005,15 @@ static int __mhi_pm_resume(struct mhi_controller *mhi_cntrl, bool force)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* For devices without M3 support, just move the host back to M0
|
||||
* directly.
|
||||
*/
|
||||
if (mhi_cntrl->no_m3) {
|
||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
||||
return mhi_pm_m0_transition(mhi_cntrl);
|
||||
}
|
||||
|
||||
/* Set MHI to M0 and wait for completion */
|
||||
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_M0);
|
||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
||||
|
||||
@@ -644,6 +644,15 @@ err_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pci_epf_mhi_edma_flush_async(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl);
|
||||
|
||||
dmaengine_synchronize(epf_mhi->dma_chan_rx);
|
||||
dmaengine_synchronize(epf_mhi->dma_chan_tx);
|
||||
flush_workqueue(epf_mhi->dma_wq);
|
||||
}
|
||||
|
||||
struct epf_dma_filter {
|
||||
struct device *dev;
|
||||
u32 dma_mask;
|
||||
@@ -812,6 +821,7 @@ static int pci_epf_mhi_link_up(struct pci_epf *epf)
|
||||
mhi_cntrl->write_sync = pci_epf_mhi_edma_write;
|
||||
mhi_cntrl->read_async = pci_epf_mhi_edma_read_async;
|
||||
mhi_cntrl->write_async = pci_epf_mhi_edma_write_async;
|
||||
mhi_cntrl->flush_async = pci_epf_mhi_edma_flush_async;
|
||||
}
|
||||
|
||||
/* Register the MHI EP controller */
|
||||
|
||||
+12
-5
@@ -117,8 +117,8 @@ struct image_info {
|
||||
|
||||
/**
|
||||
* struct mhi_link_info - BW requirement
|
||||
* target_link_speed - Link speed as defined by TLS bits in LinkControl reg
|
||||
* target_link_width - Link width as defined by NLW bits in LinkStatus reg
|
||||
* @target_link_speed: Link speed as defined by TLS bits in LinkControl reg
|
||||
* @target_link_width: Link width as defined by NLW bits in LinkStatus reg
|
||||
*/
|
||||
struct mhi_link_info {
|
||||
unsigned int target_link_speed;
|
||||
@@ -173,6 +173,7 @@ enum mhi_state {
|
||||
MHI_STATE_M3_FAST = 0x6,
|
||||
MHI_STATE_BHI = 0x7,
|
||||
MHI_STATE_SYS_ERR = 0xFF,
|
||||
/* private: */
|
||||
MHI_STATE_MAX,
|
||||
};
|
||||
|
||||
@@ -227,12 +228,12 @@ enum mhi_db_brst_mode {
|
||||
* @type: Channel type
|
||||
* @ee_mask: Execution Environment mask for this channel
|
||||
* @pollcfg: Polling configuration for burst mode. 0 is default. milliseconds
|
||||
for UL channels, multiple of 8 ring elements for DL channels
|
||||
* for UL channels, multiple of 8 ring elements for DL channels
|
||||
* @doorbell: Doorbell 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
|
||||
* @wake-capable: Channel capable of waking up the system
|
||||
* @wake_capable: Channel capable of waking up the system
|
||||
*/
|
||||
struct mhi_channel_config {
|
||||
char *name;
|
||||
@@ -350,7 +351,9 @@ struct mhi_controller_config {
|
||||
* @dev_state: MHI device state
|
||||
* @dev_wake: Device wakeup count
|
||||
* @pending_pkts: Pending packets for the controller
|
||||
* @M0, M2, M3: Counters to track number of device MHI state changes
|
||||
* @M0: Counter to track number of device MHI state changes
|
||||
* @M2: Counter to track number of device MHI state changes
|
||||
* @M3: Counter to track number of device MHI state changes
|
||||
* @transition_list: List of MHI state transitions
|
||||
* @transition_lock: Lock for protecting MHI state transition list
|
||||
* @wlock: Lock for protecting device wakeup
|
||||
@@ -375,6 +378,7 @@ struct mhi_controller_config {
|
||||
* @bounce_buf: Use of bounce buffer
|
||||
* @fbc_download: MHI host needs to do complete image transfer (optional)
|
||||
* @wake_set: Device wakeup set flag
|
||||
* @no_m3: Device doesn't support M3 state
|
||||
* @irq_flags: irq flags passed to request_irq (optional)
|
||||
* @mru: the default MRU for the MHI device
|
||||
*
|
||||
@@ -460,6 +464,7 @@ struct mhi_controller {
|
||||
bool bounce_buf;
|
||||
bool fbc_download;
|
||||
bool wake_set;
|
||||
bool no_m3;
|
||||
unsigned long irq_flags;
|
||||
u32 mru;
|
||||
};
|
||||
@@ -507,6 +512,7 @@ struct mhi_result {
|
||||
|
||||
/**
|
||||
* struct mhi_driver - Structure representing a MHI client driver
|
||||
* @id_table: table of MHI channel names that a driver supports
|
||||
* @probe: CB function for client driver probe function
|
||||
* @remove: CB function for client driver remove function
|
||||
* @ul_xfer_cb: CB function for UL data transfer
|
||||
@@ -538,6 +544,7 @@ struct mhi_controller *mhi_alloc_controller(void);
|
||||
|
||||
/**
|
||||
* mhi_free_controller - Free the MHI Controller structure
|
||||
* @mhi_cntrl: MHI controller to free
|
||||
* Free the mhi_controller structure which was previously allocated
|
||||
*/
|
||||
void mhi_free_controller(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
@@ -107,6 +107,7 @@ struct mhi_ep_buf_info {
|
||||
* @write_sync: CB function for writing to host memory synchronously
|
||||
* @read_async: CB function for reading from host memory asynchronously
|
||||
* @write_async: CB function for writing to host memory asynchronously
|
||||
* @flush_async: CB function for flushing asynchronous read/writes
|
||||
* @mhi_state: MHI Endpoint state
|
||||
* @max_chan: Maximum channels supported by the endpoint controller
|
||||
* @mru: MRU (Maximum Receive Unit) value of the endpoint controller
|
||||
@@ -164,6 +165,7 @@ struct mhi_ep_cntrl {
|
||||
int (*write_sync)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
|
||||
int (*read_async)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
|
||||
int (*write_async)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
|
||||
void (*flush_async)(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
|
||||
enum mhi_state mhi_state;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user