summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-04-03 13:56:03 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-04-03 13:56:03 +0200
commit68c6d134edbf085ce63038b630c63f056279225a (patch)
tree3e465784f9fa321f98f830efc7488bac45ccf8a3
parent94e731cbe84533a37701b4089b685d39e584fbea (diff)
parentac12b852b4ead4a586299c8f68cdcbcaf1bf6cbc (diff)
Merge tag 'mhi-for-v7.1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mani/mhi into char-misc-next
Manivannan writes: MHI Host -------- - Add support for Qualcomm SDX35 and Telit FE912C04 modems reusing the existing channel and event configurations. - Enable IP_SW and IP_ETH MHI channels for Qualcomm 5G DU X100 Accelerator device (QDU100). These channels are used to carry O-RAN specific M-Plane, S-Plane and Netconf packets. The drivers making use of these channels is being reviewed. - Add NMEA channels to Telit FN920C04 and FN990A modems for GPS/GNSS support - Switch to mhi_async_power_up() API in pci_generic driver to avoid boot delays as some Qcom modems take a while start. This API ensures that the pci_generic driver powers up the modem asynchronously and doesn't block the system boot. - Add pm_runtime_forbid() in remove callback to balance the pm_runtime_allow() call made during the Mission Mode transition. - Used kzalloc_flex() to simplify kzalloc() + kzalloc() calls MHI Endpoint ------------ - Test for non-zero return value 'if (ret)' in the endpoint stack where applicable to maintain code uniformity. * tag 'mhi-for-v7.1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mani/mhi: bus: mhi: host: pci_generic: Add Telit FE912C04 modem support bus: mhi: ep: Test for non-zero return value where applicable bus: mhi: host: Use kzalloc_flex bus: mhi: host: pci_generic: Add pm_runtime_forbid() in remove callback bus: mhi: host: pci_generic: Switch to async power up to avoid boot delays bus: mhi: host: pci_generic: Add NMEA channels to FN920C04 and FN990A bus: mhi: host: pci_generic: Enable IP_SW and IP_ETH channels for Qcom QDU100 device bus: mhi: host: pci_generic: Add Qualcomm SDX35 modem
-rw-r--r--drivers/bus/mhi/ep/main.c10
-rw-r--r--drivers/bus/mhi/ep/ring.c6
-rw-r--r--drivers/bus/mhi/host/boot.c22
-rw-r--r--drivers/bus/mhi/host/pci_generic.c40
-rw-r--r--include/linux/mhi.h34
5 files changed, 67 insertions, 45 deletions
diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index e3d0a3cbaf94..0277e1ab1198 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -367,7 +367,7 @@ static void mhi_ep_read_completion(struct mhi_ep_buf_info *buf_info)
ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
MHI_TRE_DATA_GET_LEN(el),
MHI_EV_CC_EOB);
- if (ret < 0) {
+ if (ret) {
dev_err(&mhi_chan->mhi_dev->dev,
"Error sending transfer compl. event\n");
goto err_free_tre_buf;
@@ -383,7 +383,7 @@ static void mhi_ep_read_completion(struct mhi_ep_buf_info *buf_info)
ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
MHI_TRE_DATA_GET_LEN(el),
MHI_EV_CC_EOT);
- if (ret < 0) {
+ if (ret) {
dev_err(&mhi_chan->mhi_dev->dev,
"Error sending transfer compl. event\n");
goto err_free_tre_buf;
@@ -449,7 +449,7 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
dev_dbg(dev, "Reading %zd bytes from channel (%u)\n", tr_len, ring->ch_id);
ret = mhi_cntrl->read_async(mhi_cntrl, &buf_info);
- if (ret < 0) {
+ if (ret) {
dev_err(&mhi_chan->mhi_dev->dev, "Error reading from channel\n");
goto err_free_buf_addr;
}
@@ -494,7 +494,7 @@ static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring)
} else {
/* UL channel */
ret = mhi_ep_read_channel(mhi_cntrl, ring);
- if (ret < 0) {
+ if (ret) {
dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n");
return ret;
}
@@ -591,7 +591,7 @@ int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb)
dev_dbg(dev, "Writing %zd bytes to channel (%u)\n", tr_len, ring->ch_id);
ret = mhi_cntrl->write_async(mhi_cntrl, &buf_info);
- if (ret < 0) {
+ if (ret) {
dev_err(dev, "Error writing to the channel\n");
goto err_exit;
}
diff --git a/drivers/bus/mhi/ep/ring.c b/drivers/bus/mhi/ep/ring.c
index 9375b16ff2a5..405ce16c02a8 100644
--- a/drivers/bus/mhi/ep/ring.c
+++ b/drivers/bus/mhi/ep/ring.c
@@ -49,7 +49,7 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end)
buf_info.dev_addr = &ring->ring_cache[start];
ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
- if (ret < 0)
+ if (ret)
return ret;
} else {
buf_info.size = (ring->ring_size - start) * sizeof(struct mhi_ring_element);
@@ -57,7 +57,7 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end)
buf_info.dev_addr = &ring->ring_cache[start];
ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
- if (ret < 0)
+ if (ret)
return ret;
if (end) {
@@ -66,7 +66,7 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end)
buf_info.size = end * sizeof(struct mhi_ring_element);
ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
- if (ret < 0)
+ if (ret)
return ret;
}
}
diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c
index f16a1e67a667..19c84913cfb9 100644
--- a/drivers/bus/mhi/host/boot.c
+++ b/drivers/bus/mhi/host/boot.c
@@ -308,7 +308,6 @@ static void mhi_free_bhi_buffer(struct mhi_controller *mhi_cntrl,
struct mhi_buf *mhi_buf = image_info->mhi_buf;
dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, mhi_buf->buf, mhi_buf->dma_addr);
- kfree(image_info->mhi_buf);
kfree(image_info);
}
@@ -322,7 +321,6 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl,
dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len,
mhi_buf->buf, mhi_buf->dma_addr);
- kfree(image_info->mhi_buf);
kfree(image_info);
}
@@ -333,15 +331,10 @@ static int mhi_alloc_bhi_buffer(struct mhi_controller *mhi_cntrl,
struct image_info *img_info;
struct mhi_buf *mhi_buf;
- img_info = kzalloc_obj(*img_info);
+ img_info = kzalloc_flex(*img_info, mhi_buf, 1);
if (!img_info)
return -ENOMEM;
- /* Allocate memory for entry */
- img_info->mhi_buf = kzalloc_obj(*img_info->mhi_buf);
- if (!img_info->mhi_buf)
- goto error_alloc_mhi_buf;
-
/* Allocate and populate vector table */
mhi_buf = img_info->mhi_buf;
@@ -358,8 +351,6 @@ static int mhi_alloc_bhi_buffer(struct mhi_controller *mhi_cntrl,
return 0;
error_alloc_segment:
- kfree(mhi_buf);
-error_alloc_mhi_buf:
kfree(img_info);
return -ENOMEM;
@@ -375,14 +366,11 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
struct image_info *img_info;
struct mhi_buf *mhi_buf;
- img_info = kzalloc_obj(*img_info);
+ img_info = kzalloc_flex(*img_info, mhi_buf, segments);
if (!img_info)
return -ENOMEM;
- /* Allocate memory for entries */
- img_info->mhi_buf = kzalloc_objs(*img_info->mhi_buf, segments);
- if (!img_info->mhi_buf)
- goto error_alloc_mhi_buf;
+ img_info->entries = segments;
/* Allocate and populate vector table */
mhi_buf = img_info->mhi_buf;
@@ -402,7 +390,6 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
}
img_info->bhi_vec = img_info->mhi_buf[segments - 1].buf;
- img_info->entries = segments;
*image_info = img_info;
return 0;
@@ -411,9 +398,6 @@ error_alloc_segment:
for (--i, --mhi_buf; i >= 0; i--, mhi_buf--)
dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len,
mhi_buf->buf, mhi_buf->dma_addr);
- kfree(img_info->mhi_buf);
-
-error_alloc_mhi_buf:
kfree(img_info);
return -ENOMEM;
diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c
index 0884a384b77f..750da3dbb4c6 100644
--- a/drivers/bus/mhi/host/pci_generic.c
+++ b/drivers/bus/mhi/host/pci_generic.c
@@ -253,6 +253,13 @@ static const struct mhi_channel_config mhi_qcom_qdu100_channels[] = {
MHI_CHANNEL_CONFIG_DL(41, "MHI_PHC", 32, 4),
MHI_CHANNEL_CONFIG_UL(46, "IP_SW0", 256, 5),
MHI_CHANNEL_CONFIG_DL(47, "IP_SW0", 256, 5),
+ MHI_CHANNEL_CONFIG_UL(48, "IP_SW1", 256, 6),
+ MHI_CHANNEL_CONFIG_DL(49, "IP_SW1", 256, 6),
+ MHI_CHANNEL_CONFIG_UL(50, "IP_ETH0", 256, 7),
+ MHI_CHANNEL_CONFIG_DL(51, "IP_ETH0", 256, 7),
+ MHI_CHANNEL_CONFIG_UL(52, "IP_ETH1", 256, 8),
+ MHI_CHANNEL_CONFIG_DL(53, "IP_ETH1", 256, 8),
+
};
static struct mhi_event_config mhi_qcom_qdu100_events[] = {
@@ -268,6 +275,7 @@ static struct mhi_event_config mhi_qcom_qdu100_events[] = {
MHI_EVENT_CONFIG_SW_DATA(5, 512),
MHI_EVENT_CONFIG_SW_DATA(6, 512),
MHI_EVENT_CONFIG_SW_DATA(7, 512),
+ MHI_EVENT_CONFIG_SW_DATA(8, 512),
};
static const struct mhi_controller_config mhi_qcom_qdu100_config = {
@@ -407,6 +415,16 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = {
.sideband_wake = false,
};
+static const struct mhi_pci_dev_info mhi_qcom_sdx35_info = {
+ .name = "qcom-sdx35m",
+ .config = &modem_qcom_v2_mhiv_config,
+ .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
+ .dma_data_width = 32,
+ .mru_default = 32768,
+ .sideband_wake = false,
+ .edl_trigger = true,
+};
+
static const struct mhi_pci_dev_info mhi_qcom_sdx24_info = {
.name = "qcom-sdx24",
.edl = "qcom/prog_firehose_sdx24.mbn",
@@ -788,6 +806,8 @@ static const struct mhi_channel_config mhi_telit_fn990_channels[] = {
MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0),
MHI_CHANNEL_CONFIG_UL(92, "DUN2", 32, 1),
MHI_CHANNEL_CONFIG_DL(93, "DUN2", 32, 1),
+ MHI_CHANNEL_CONFIG_UL(94, "NMEA", 32, 1),
+ MHI_CHANNEL_CONFIG_DL(95, "NMEA", 32, 1),
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2),
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3),
};
@@ -839,6 +859,8 @@ static const struct mhi_channel_config mhi_telit_fn920c04_channels[] = {
MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0),
MHI_CHANNEL_CONFIG_UL(92, "DUN2", 32, 1),
MHI_CHANNEL_CONFIG_DL(93, "DUN2", 32, 1),
+ MHI_CHANNEL_CONFIG_UL(94, "NMEA", 32, 1),
+ MHI_CHANNEL_CONFIG_DL(95, "NMEA", 32, 1),
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2),
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3),
};
@@ -882,6 +904,16 @@ static const struct mhi_pci_dev_info mhi_telit_fe990b40_info = {
.edl_trigger = true,
};
+static const struct mhi_pci_dev_info mhi_telit_fe912c04_info = {
+ .name = "telit-fe912c04",
+ .config = &modem_telit_fn920c04_config,
+ .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
+ .dma_data_width = 32,
+ .sideband_wake = false,
+ .mru_default = 32768,
+ .edl_trigger = true,
+};
+
static const struct mhi_pci_dev_info mhi_netprisma_lcur57_info = {
.name = "netprisma-lcur57",
.edl = "qcom/prog_firehose_sdx24.mbn",
@@ -909,6 +941,11 @@ static const struct pci_device_id mhi_pci_id_table[] = {
/* Telit FN920C04 (sdx35) */
{PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2020),
.driver_data = (kernel_ulong_t) &mhi_telit_fn920c04_info },
+ /* Telit FE912C04 (sdx35) */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2045),
+ .driver_data = (kernel_ulong_t) &mhi_telit_fe912c04_info },
+ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x011a),
+ .driver_data = (kernel_ulong_t) &mhi_qcom_sdx35_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304),
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c),
@@ -1393,7 +1430,7 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_unregister;
}
- err = mhi_sync_power_up(mhi_cntrl);
+ err = mhi_async_power_up(mhi_cntrl);
if (err) {
dev_err(&pdev->dev, "failed to power up MHI controller\n");
goto err_unprepare;
@@ -1428,6 +1465,7 @@ static void mhi_pci_remove(struct pci_dev *pdev)
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
+ pm_runtime_forbid(&pdev->dev);
pci_disable_sriov(pdev);
if (pdev->is_physfn)
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index 88ccb3e14f48..fb3ba639f4f8 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -86,16 +86,32 @@ enum mhi_ch_type {
};
/**
+ * struct mhi_buf - MHI Buffer description
+ * @buf: Virtual address of the buffer
+ * @name: Buffer label. For offload channel, configurations name must be:
+ * ECA - Event context array data
+ * CCA - Channel context array data
+ * @dma_addr: IOMMU address of the buffer
+ * @len: # of bytes
+ */
+struct mhi_buf {
+ void *buf;
+ const char *name;
+ dma_addr_t dma_addr;
+ size_t len;
+};
+
+/**
* struct image_info - Firmware and RDDM table
* @mhi_buf: Buffer for firmware and RDDM table
* @entries: # of entries in table
*/
struct image_info {
- struct mhi_buf *mhi_buf;
/* private: from internal.h */
struct bhi_vec_entry *bhi_vec;
/* public: */
u32 entries;
+ struct mhi_buf mhi_buf[] __counted_by(entries);
};
/**
@@ -489,22 +505,6 @@ struct mhi_result {
};
/**
- * struct mhi_buf - MHI Buffer description
- * @buf: Virtual address of the buffer
- * @name: Buffer label. For offload channel, configurations name must be:
- * ECA - Event context array data
- * CCA - Channel context array data
- * @dma_addr: IOMMU address of the buffer
- * @len: # of bytes
- */
-struct mhi_buf {
- void *buf;
- const char *name;
- dma_addr_t dma_addr;
- size_t len;
-};
-
-/**
* struct mhi_driver - Structure representing a MHI client driver
* @probe: CB function for client driver probe function
* @remove: CB function for client driver remove function