Hello,
This series adds initial support for the Qualcomm specific Modem Host Interface
(MHI) bus in endpoint devices like SDX55 modems. The MHI bus in endpoint devices
communicates with the MHI bus in host machines like x86 over any physical bus
like PCIe. The MHI host support is already in mainline [1] and been used by PCIe
based modems and WLAN devices running vendor code (downstream).
Overview
========
This series aims at adding the MHI support in the endpoint devices with the goal
of getting data connectivity using the mainline kernel running on the modems.
Modems here refer to the combination of an APPS processor (Cortex A grade) and
a baseband processor (DSP). The MHI bus is located in the APPS processor and it
transfers data packets from the baseband processor to the host machine.
The MHI Endpoint (MHI EP) stack proposed here is inspired by the downstream
code written by Qualcomm. But the complete stack is mostly re-written to adapt
to the "bus" framework and made it modular so that it can work with the upstream
subsystems like "PCI Endpoint". The code structure of the MHI endpoint stack
follows the MHI host stack to maintain uniformity.
With this initial MHI EP stack (along with few other drivers), we can establish
the network interface between host and endpoint over the MHI software channels
(IP_SW0) and can do things like IP forwarding, SSH, etc...
Stack Organization
==================
The MHI EP stack has the concept of controller and device drivers as like the
MHI host stack. The MHI EP controller driver can be a PCI Endpoint Function
driver and the MHI device driver can be a MHI EP Networking driver or QRTR
driver. The MHI EP controller driver is tied to the PCI Endpoint subsystem and
handles all bus related activities like mapping the host memory, raising IRQ,
passing link specific events etc... The MHI EP networking driver is tied to the
Networking stack and handles all networking related activities like
sending/receiving the SKBs from netdev, statistics collection etc...
This series only contains the MHI EP code, whereas the PCIe EPF driver and MHI
EP Networking drivers are not yet submitted and can be found here [2]. Though
the MHI EP stack doesn't have the build time dependency, it cannot function
without them.
Test setup
==========
This series has been tested on Telit FN980 TLB board powered by Qualcomm SDX55
(a.k.a X55 modem) and Qualcomm SM8450 based dev board.
For testing the stability and performance, networking tools such as iperf, ssh
and ping are used.
Limitations
===========
We are not _yet_ there to get the data packets from the modem as that involves
the Qualcomm IP Accelerator (IPA) integration with MHI endpoint stack. But we
are planning to add support for it in the coming days.
References
==========
MHI bus: https://www.kernel.org/doc/html/latest/mhi/mhi.html
Linaro connect presentation around this topic: https://connect.linaro.org/resources/lvc21f/lvc21f-222/
Thanks,
Mani
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/bus/mhi
[2] https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/log/?h=tracking-qcomlt-sdx55-drivers
Changes in v4:
* Collected reviews from Hemant and Alex.
* Removed the A7 suffix from register names and functions.
* Added a couple of cleanup patches.
* Reworked the mhi_ep_queue_skb() API.
* Switched to separate workers for command and transfer rings.
* Used a common workqueue for state and ring management.
* Reworked the channel ring management.
* Other misc changes as per review from Alex.
Changes in v3:
* Splitted the patch 20/23 into two.
* Fixed the error handling in patch 21/23.
* Removed spurious change in patch 01/23.
* Added check for xfer callbacks in client driver probe.
Changes in v2:
v2 mostly addresses the issues seen while testing the stack on SM8450 that is a
SMP platform and also incorporates the review comments from Alex.
Major changes are:
* Added a cleanup patch for getting rid of SHIFT macros and used the bitfield
operations.
* Added the endianess patches that were submitted to MHI list and used the
endianess conversion in EP patches also.
* Added support for multiple event rings.
* Fixed the MSI generation based on the event ring index.
* Fixed the doorbell list handling by making use of list splice and not locking
the entire list manipulation.
* Added new APIs for wrapping the reading and writing to host memory (Dmitry).
* Optimized the read_channel and queue_skb function logics.
* Added Hemant's R-o-b tag.
Manivannan Sadhasivam (25):
bus: mhi: Move host MHI code to "host" directory
bus: mhi: Use bitfield operations for register read and write
bus: mhi: Use bitfield operations for handling DWORDs of ring elements
bus: mhi: Cleanup the register definitions used in headers
bus: mhi: host: Rename "struct mhi_tre" to "struct mhi_ring_element"
bus: mhi: Move common MHI definitions out of host directory
bus: mhi: Make mhi_state_str[] array static inline and move to
common.h
bus: mhi: ep: Add support for registering MHI endpoint controllers
bus: mhi: ep: Add support for registering MHI endpoint client drivers
bus: mhi: ep: Add support for creating and destroying MHI EP devices
bus: mhi: ep: Add support for managing MMIO registers
bus: mhi: ep: Add support for ring management
bus: mhi: ep: Add support for sending events to the host
bus: mhi: ep: Add support for managing MHI state machine
bus: mhi: ep: Add support for processing MHI endpoint interrupts
bus: mhi: ep: Add support for powering up the MHI endpoint stack
bus: mhi: ep: Add support for powering down the MHI endpoint stack
bus: mhi: ep: Add support for handling MHI_RESET
bus: mhi: ep: Add support for handling SYS_ERR condition
bus: mhi: ep: Add support for processing command rings
bus: mhi: ep: Add support for reading from the host
bus: mhi: ep: Add support for processing channel rings
bus: mhi: ep: Add support for queueing SKBs to the host
bus: mhi: ep: Add support for suspending and resuming channels
bus: mhi: ep: Add uevent support for module autoloading
Paul Davey (2):
bus: mhi: Fix pm_state conversion to string
bus: mhi: Fix MHI DMA structure endianness
drivers/bus/Makefile | 2 +-
drivers/bus/mhi/Kconfig | 28 +-
drivers/bus/mhi/Makefile | 9 +-
drivers/bus/mhi/common.h | 326 +++++
drivers/bus/mhi/core/internal.h | 722 ----------
drivers/bus/mhi/ep/Kconfig | 10 +
drivers/bus/mhi/ep/Makefile | 2 +
drivers/bus/mhi/ep/internal.h | 222 +++
drivers/bus/mhi/ep/main.c | 1623 ++++++++++++++++++++++
drivers/bus/mhi/ep/mmio.c | 272 ++++
drivers/bus/mhi/ep/ring.c | 197 +++
drivers/bus/mhi/ep/sm.c | 148 ++
drivers/bus/mhi/host/Kconfig | 31 +
drivers/bus/mhi/{core => host}/Makefile | 4 +-
drivers/bus/mhi/{core => host}/boot.c | 17 +-
drivers/bus/mhi/{core => host}/debugfs.c | 40 +-
drivers/bus/mhi/{core => host}/init.c | 131 +-
drivers/bus/mhi/host/internal.h | 382 +++++
drivers/bus/mhi/{core => host}/main.c | 66 +-
drivers/bus/mhi/{ => host}/pci_generic.c | 0
drivers/bus/mhi/{core => host}/pm.c | 36 +-
include/linux/mhi_ep.h | 284 ++++
include/linux/mod_devicetable.h | 2 +
scripts/mod/file2alias.c | 10 +
24 files changed, 3649 insertions(+), 915 deletions(-)
create mode 100644 drivers/bus/mhi/common.h
delete mode 100644 drivers/bus/mhi/core/internal.h
create mode 100644 drivers/bus/mhi/ep/Kconfig
create mode 100644 drivers/bus/mhi/ep/Makefile
create mode 100644 drivers/bus/mhi/ep/internal.h
create mode 100644 drivers/bus/mhi/ep/main.c
create mode 100644 drivers/bus/mhi/ep/mmio.c
create mode 100644 drivers/bus/mhi/ep/ring.c
create mode 100644 drivers/bus/mhi/ep/sm.c
create mode 100644 drivers/bus/mhi/host/Kconfig
rename drivers/bus/mhi/{core => host}/Makefile (54%)
rename drivers/bus/mhi/{core => host}/boot.c (96%)
rename drivers/bus/mhi/{core => host}/debugfs.c (90%)
rename drivers/bus/mhi/{core => host}/init.c (92%)
create mode 100644 drivers/bus/mhi/host/internal.h
rename drivers/bus/mhi/{core => host}/main.c (97%)
rename drivers/bus/mhi/{ => host}/pci_generic.c (100%)
rename drivers/bus/mhi/{core => host}/pm.c (97%)
create mode 100644 include/linux/mhi_ep.h
--
2.25.1
Move the common MHI definitions in host "internal.h" to "common.h" so
that the endpoint code can make use of them. This also avoids
duplicating the definitions in the endpoint stack.
Reviewed-by: Hemant Kumar <[email protected]>
Reviewed-by: Alex Elder <[email protected]>
Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
drivers/bus/mhi/common.h | 283 ++++++++++++++++++++++++++++++++
drivers/bus/mhi/host/internal.h | 264 +----------------------------
2 files changed, 284 insertions(+), 263 deletions(-)
create mode 100644 drivers/bus/mhi/common.h
diff --git a/drivers/bus/mhi/common.h b/drivers/bus/mhi/common.h
new file mode 100644
index 000000000000..f2690bf11c99
--- /dev/null
+++ b/drivers/bus/mhi/common.h
@@ -0,0 +1,283 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022, Linaro Ltd.
+ *
+ */
+
+#ifndef _MHI_COMMON_H
+#define _MHI_COMMON_H
+
+#include <linux/bitfield.h>
+#include <linux/mhi.h>
+
+/* MHI registers */
+#define MHIREGLEN 0x00
+#define MHIVER 0x08
+#define MHICFG 0x10
+#define CHDBOFF 0x18
+#define ERDBOFF 0x20
+#define BHIOFF 0x28
+#define BHIEOFF 0x2c
+#define DEBUGOFF 0x30
+#define MHICTRL 0x38
+#define MHISTATUS 0x48
+#define CCABAP_LOWER 0x58
+#define CCABAP_HIGHER 0x5c
+#define ECABAP_LOWER 0x60
+#define ECABAP_HIGHER 0x64
+#define CRCBAP_LOWER 0x68
+#define CRCBAP_HIGHER 0x6c
+#define CRDB_LOWER 0x70
+#define CRDB_HIGHER 0x74
+#define MHICTRLBASE_LOWER 0x80
+#define MHICTRLBASE_HIGHER 0x84
+#define MHICTRLLIMIT_LOWER 0x88
+#define MHICTRLLIMIT_HIGHER 0x8c
+#define MHIDATABASE_LOWER 0x98
+#define MHIDATABASE_HIGHER 0x9c
+#define MHIDATALIMIT_LOWER 0xa0
+#define MHIDATALIMIT_HIGHER 0xa4
+
+/* MHI BHI registers */
+#define BHI_BHIVERSION_MINOR 0x00
+#define BHI_BHIVERSION_MAJOR 0x04
+#define BHI_IMGADDR_LOW 0x08
+#define BHI_IMGADDR_HIGH 0x0c
+#define BHI_IMGSIZE 0x10
+#define BHI_RSVD1 0x14
+#define BHI_IMGTXDB 0x18
+#define BHI_RSVD2 0x1c
+#define BHI_INTVEC 0x20
+#define BHI_RSVD3 0x24
+#define BHI_EXECENV 0x28
+#define BHI_STATUS 0x2c
+#define BHI_ERRCODE 0x30
+#define BHI_ERRDBG1 0x34
+#define BHI_ERRDBG2 0x38
+#define BHI_ERRDBG3 0x3c
+#define BHI_SERIALNU 0x40
+#define BHI_SBLANTIROLLVER 0x44
+#define BHI_NUMSEG 0x48
+#define BHI_MSMHWID(n) (0x4c + (0x4 * (n)))
+#define BHI_OEMPKHASH(n) (0x64 + (0x4 * (n)))
+#define BHI_RSVD5 0xc4
+
+/* BHI register bits */
+#define BHI_TXDB_SEQNUM_BMSK GENMASK(29, 0)
+#define BHI_TXDB_SEQNUM_SHFT 0
+#define BHI_STATUS_MASK GENMASK(31, 30)
+#define BHI_STATUS_ERROR 0x03
+#define BHI_STATUS_SUCCESS 0x02
+#define BHI_STATUS_RESET 0x00
+
+/* MHI BHIE registers */
+#define BHIE_MSMSOCID_OFFS 0x00
+#define BHIE_TXVECADDR_LOW_OFFS 0x2c
+#define BHIE_TXVECADDR_HIGH_OFFS 0x30
+#define BHIE_TXVECSIZE_OFFS 0x34
+#define BHIE_TXVECDB_OFFS 0x3c
+#define BHIE_TXVECSTATUS_OFFS 0x44
+#define BHIE_RXVECADDR_LOW_OFFS 0x60
+#define BHIE_RXVECADDR_HIGH_OFFS 0x64
+#define BHIE_RXVECSIZE_OFFS 0x68
+#define BHIE_RXVECDB_OFFS 0x70
+#define BHIE_RXVECSTATUS_OFFS 0x78
+
+/* BHIE register bits */
+#define BHIE_TXVECDB_SEQNUM_BMSK GENMASK(29, 0)
+#define BHIE_TXVECDB_SEQNUM_SHFT 0
+#define BHIE_TXVECSTATUS_SEQNUM_BMSK GENMASK(29, 0)
+#define BHIE_TXVECSTATUS_SEQNUM_SHFT 0
+#define BHIE_TXVECSTATUS_STATUS_BMSK GENMASK(31, 30)
+#define BHIE_TXVECSTATUS_STATUS_SHFT 30
+#define BHIE_TXVECSTATUS_STATUS_RESET 0x00
+#define BHIE_TXVECSTATUS_STATUS_XFER_COMPL 0x02
+#define BHIE_TXVECSTATUS_STATUS_ERROR 0x03
+#define BHIE_RXVECDB_SEQNUM_BMSK GENMASK(29, 0)
+#define BHIE_RXVECDB_SEQNUM_SHFT 0
+#define BHIE_RXVECSTATUS_SEQNUM_BMSK GENMASK(29, 0)
+#define BHIE_RXVECSTATUS_SEQNUM_SHFT 0
+#define BHIE_RXVECSTATUS_STATUS_BMSK GENMASK(31, 30)
+#define BHIE_RXVECSTATUS_STATUS_SHFT 30
+#define BHIE_RXVECSTATUS_STATUS_RESET 0x00
+#define BHIE_RXVECSTATUS_STATUS_XFER_COMPL 0x02
+#define BHIE_RXVECSTATUS_STATUS_ERROR 0x03
+
+/* MHI register bits */
+#define MHICFG_NHWER_MASK GENMASK(31, 24)
+#define MHICFG_NER_MASK GENMASK(23, 16)
+#define MHICFG_NHWCH_MASK GENMASK(15, 8)
+#define MHICFG_NCH_MASK GENMASK(7, 0)
+#define MHICTRL_MHISTATE_MASK GENMASK(15, 8)
+#define MHICTRL_RESET_MASK BIT(1)
+#define MHISTATUS_MHISTATE_MASK GENMASK(15, 8)
+#define MHISTATUS_SYSERR_MASK BIT(2)
+#define MHISTATUS_READY_MASK BIT(0)
+
+/* Command Ring Element macros */
+/* No operation command */
+#define MHI_TRE_CMD_NOOP_PTR 0
+#define MHI_TRE_CMD_NOOP_DWORD0 0
+#define MHI_TRE_CMD_NOOP_DWORD1 cpu_to_le32(FIELD_PREP(GENMASK(23, 16), MHI_CMD_NOP))
+
+/* Channel reset command */
+#define MHI_TRE_CMD_RESET_PTR 0
+#define MHI_TRE_CMD_RESET_DWORD0 0
+#define MHI_TRE_CMD_RESET_DWORD1(chid) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), chid) | \
+ FIELD_PREP(GENMASK(23, 16), \
+ MHI_CMD_RESET_CHAN))
+
+/* Channel stop command */
+#define MHI_TRE_CMD_STOP_PTR 0
+#define MHI_TRE_CMD_STOP_DWORD0 0
+#define MHI_TRE_CMD_STOP_DWORD1(chid) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), chid) | \
+ FIELD_PREP(GENMASK(23, 16), \
+ MHI_CMD_STOP_CHAN))
+
+/* Channel start command */
+#define MHI_TRE_CMD_START_PTR 0
+#define MHI_TRE_CMD_START_DWORD0 0
+#define MHI_TRE_CMD_START_DWORD1(chid) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), chid) | \
+ FIELD_PREP(GENMASK(23, 16), \
+ MHI_CMD_START_CHAN))
+
+#define MHI_TRE_GET_DWORD(tre, word) le32_to_cpu((tre)->dword[(word)])
+#define MHI_TRE_GET_CMD_CHID(tre) FIELD_GET(GENMASK(31, 24), MHI_TRE_GET_DWORD(tre, 1))
+#define MHI_TRE_GET_CMD_TYPE(tre) FIELD_GET(GENMASK(23, 16), MHI_TRE_GET_DWORD(tre, 1))
+
+/* Event descriptor macros */
+#define MHI_TRE_EV_PTR(ptr) cpu_to_le64(ptr)
+#define MHI_TRE_EV_DWORD0(code, len) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), code) | \
+ FIELD_PREP(GENMASK(15, 0), len))
+#define MHI_TRE_EV_DWORD1(chid, type) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), chid) | \
+ FIELD_PREP(GENMASK(23, 16), type))
+#define MHI_TRE_GET_EV_PTR(tre) le64_to_cpu((tre)->ptr)
+#define MHI_TRE_GET_EV_CODE(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
+#define MHI_TRE_GET_EV_LEN(tre) FIELD_GET(GENMASK(15, 0), (MHI_TRE_GET_DWORD(tre, 0)))
+#define MHI_TRE_GET_EV_CHID(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 1)))
+#define MHI_TRE_GET_EV_TYPE(tre) FIELD_GET(GENMASK(23, 16), (MHI_TRE_GET_DWORD(tre, 1)))
+#define MHI_TRE_GET_EV_STATE(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
+#define MHI_TRE_GET_EV_EXECENV(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
+#define MHI_TRE_GET_EV_SEQ(tre) MHI_TRE_GET_DWORD(tre, 0)
+#define MHI_TRE_GET_EV_TIME(tre) MHI_TRE_GET_EV_PTR(tre)
+#define MHI_TRE_GET_EV_COOKIE(tre) lower_32_bits(MHI_TRE_GET_EV_PTR(tre))
+#define MHI_TRE_GET_EV_VEID(tre) FIELD_GET(GENMASK(23, 16), (MHI_TRE_GET_DWORD(tre, 0)))
+#define MHI_TRE_GET_EV_LINKSPEED(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 1)))
+#define MHI_TRE_GET_EV_LINKWIDTH(tre) FIELD_GET(GENMASK(7, 0), (MHI_TRE_GET_DWORD(tre, 0)))
+
+/* Transfer descriptor macros */
+#define MHI_TRE_DATA_PTR(ptr) cpu_to_le64(ptr)
+#define MHI_TRE_DATA_DWORD0(len) cpu_to_le32(FIELD_PREP(GENMASK(15, 0), len))
+#define MHI_TRE_TYPE_TRANSFER 2
+#define MHI_TRE_DATA_DWORD1(bei, ieot, ieob, chain) cpu_to_le32(FIELD_PREP(GENMASK(23, 16), \
+ MHI_TRE_TYPE_TRANSFER) | \
+ FIELD_PREP(BIT(10), bei) | \
+ FIELD_PREP(BIT(9), ieot) | \
+ FIELD_PREP(BIT(8), ieob) | \
+ FIELD_PREP(BIT(0), chain))
+
+/* RSC transfer descriptor macros */
+#define MHI_RSCTRE_DATA_PTR(ptr, len) cpu_to_le64(FIELD_PREP(GENMASK(64, 48), len) | ptr)
+#define MHI_RSCTRE_DATA_DWORD0(cookie) cpu_to_le32(cookie)
+#define MHI_RSCTRE_DATA_DWORD1 cpu_to_le32(FIELD_PREP(GENMASK(23, 16), \
+ MHI_PKT_TYPE_COALESCING))
+
+enum mhi_pkt_type {
+ MHI_PKT_TYPE_INVALID = 0x0,
+ MHI_PKT_TYPE_NOOP_CMD = 0x1,
+ MHI_PKT_TYPE_TRANSFER = 0x2,
+ MHI_PKT_TYPE_COALESCING = 0x8,
+ MHI_PKT_TYPE_RESET_CHAN_CMD = 0x10,
+ MHI_PKT_TYPE_STOP_CHAN_CMD = 0x11,
+ MHI_PKT_TYPE_START_CHAN_CMD = 0x12,
+ MHI_PKT_TYPE_STATE_CHANGE_EVENT = 0x20,
+ MHI_PKT_TYPE_CMD_COMPLETION_EVENT = 0x21,
+ MHI_PKT_TYPE_TX_EVENT = 0x22,
+ MHI_PKT_TYPE_RSC_TX_EVENT = 0x28,
+ MHI_PKT_TYPE_EE_EVENT = 0x40,
+ MHI_PKT_TYPE_TSYNC_EVENT = 0x48,
+ MHI_PKT_TYPE_BW_REQ_EVENT = 0x50,
+ MHI_PKT_TYPE_STALE_EVENT, /* internal event */
+};
+
+/* MHI transfer completion events */
+enum mhi_ev_ccs {
+ MHI_EV_CC_INVALID = 0x0,
+ MHI_EV_CC_SUCCESS = 0x1,
+ MHI_EV_CC_EOT = 0x2, /* End of transfer event */
+ MHI_EV_CC_OVERFLOW = 0x3,
+ MHI_EV_CC_EOB = 0x4, /* End of block event */
+ MHI_EV_CC_OOB = 0x5, /* Out of block event */
+ MHI_EV_CC_DB_MODE = 0x6,
+ MHI_EV_CC_UNDEFINED_ERR = 0x10,
+ MHI_EV_CC_BAD_TRE = 0x11,
+};
+
+/* Channel state */
+enum mhi_ch_state {
+ MHI_CH_STATE_DISABLED,
+ MHI_CH_STATE_ENABLED,
+ MHI_CH_STATE_RUNNING,
+ MHI_CH_STATE_SUSPENDED,
+ MHI_CH_STATE_STOP,
+ MHI_CH_STATE_ERROR,
+};
+
+enum mhi_cmd_type {
+ MHI_CMD_NOP = 1,
+ MHI_CMD_RESET_CHAN = 16,
+ MHI_CMD_STOP_CHAN = 17,
+ MHI_CMD_START_CHAN = 18,
+};
+
+#define EV_CTX_RESERVED_MASK GENMASK(7, 0)
+#define EV_CTX_INTMODC_MASK GENMASK(15, 8)
+#define EV_CTX_INTMODT_MASK GENMASK(31, 16)
+struct mhi_event_ctxt {
+ __le32 intmod;
+ __le32 ertype;
+ __le32 msivec;
+
+ __le64 rbase __packed __aligned(4);
+ __le64 rlen __packed __aligned(4);
+ __le64 rp __packed __aligned(4);
+ __le64 wp __packed __aligned(4);
+};
+
+#define CHAN_CTX_CHSTATE_MASK GENMASK(7, 0)
+#define CHAN_CTX_BRSTMODE_MASK GENMASK(9, 8)
+#define CHAN_CTX_POLLCFG_MASK GENMASK(15, 10)
+#define CHAN_CTX_RESERVED_MASK GENMASK(31, 16)
+struct mhi_chan_ctxt {
+ __le32 chcfg;
+ __le32 chtype;
+ __le32 erindex;
+
+ __le64 rbase __packed __aligned(4);
+ __le64 rlen __packed __aligned(4);
+ __le64 rp __packed __aligned(4);
+ __le64 wp __packed __aligned(4);
+};
+
+struct mhi_cmd_ctxt {
+ __le32 reserved0;
+ __le32 reserved1;
+ __le32 reserved2;
+
+ __le64 rbase __packed __aligned(4);
+ __le64 rlen __packed __aligned(4);
+ __le64 rp __packed __aligned(4);
+ __le64 wp __packed __aligned(4);
+};
+
+struct mhi_ring_element {
+ __le64 ptr;
+ __le32 dword[2];
+};
+
+extern const char * const mhi_state_str[MHI_STATE_MAX];
+#define TO_MHI_STATE_STR(state) ((state >= MHI_STATE_MAX || \
+ !mhi_state_str[state]) ? \
+ "INVALID_STATE" : mhi_state_str[state])
+
+#endif /* _MHI_COMMON_H */
diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
index 5860cd326db6..b47d8ef2624a 100644
--- a/drivers/bus/mhi/host/internal.h
+++ b/drivers/bus/mhi/host/internal.h
@@ -7,158 +7,20 @@
#ifndef _MHI_INT_H
#define _MHI_INT_H
-#include <linux/bitfield.h>
-#include <linux/mhi.h>
+#include "../common.h"
extern struct bus_type mhi_bus_type;
-/* MHI registers */
-#define MHIREGLEN 0x00
-#define MHIVER 0x08
-#define MHICFG 0x10
-#define CHDBOFF 0x18
-#define ERDBOFF 0x20
-#define BHIOFF 0x28
-#define BHIEOFF 0x2c
-#define DEBUGOFF 0x30
-#define MHICTRL 0x38
-#define MHISTATUS 0x48
-#define CCABAP_LOWER 0x58
-#define CCABAP_HIGHER 0x5c
-#define ECABAP_LOWER 0x60
-#define ECABAP_HIGHER 0x64
-#define CRCBAP_LOWER 0x68
-#define CRCBAP_HIGHER 0x6c
-#define CRDB_LOWER 0x70
-#define CRDB_HIGHER 0x74
-#define MHICTRLBASE_LOWER 0x80
-#define MHICTRLBASE_HIGHER 0x84
-#define MHICTRLLIMIT_LOWER 0x88
-#define MHICTRLLIMIT_HIGHER 0x8c
-#define MHIDATABASE_LOWER 0x98
-#define MHIDATABASE_HIGHER 0x9c
-#define MHIDATALIMIT_LOWER 0xa0
-#define MHIDATALIMIT_HIGHER 0xa4
-
/* Host request register */
#define MHI_SOC_RESET_REQ_OFFSET 0xb0
#define MHI_SOC_RESET_REQ BIT(0)
-/* MHI register bits */
-#define MHICFG_NHWER_MASK GENMASK(31, 24)
-#define MHICFG_NER_MASK GENMASK(23, 16)
-#define MHICFG_NHWCH_MASK GENMASK(15, 8)
-#define MHICFG_NCH_MASK GENMASK(7, 0)
-#define MHICTRL_MHISTATE_MASK GENMASK(15, 8)
-#define MHICTRL_RESET_MASK BIT(1)
-#define MHISTATUS_MHISTATE_MASK GENMASK(15, 8)
-#define MHISTATUS_SYSERR_MASK BIT(2)
-#define MHISTATUS_READY_MASK BIT(0)
-
-/* MHI BHI registers */
-#define BHI_BHIVERSION_MINOR 0x00
-#define BHI_BHIVERSION_MAJOR 0x04
-#define BHI_IMGADDR_LOW 0x08
-#define BHI_IMGADDR_HIGH 0x0c
-#define BHI_IMGSIZE 0x10
-#define BHI_RSVD1 0x14
-#define BHI_IMGTXDB 0x18
-#define BHI_RSVD2 0x1c
-#define BHI_INTVEC 0x20
-#define BHI_RSVD3 0x24
-#define BHI_EXECENV 0x28
-#define BHI_STATUS 0x2c
-#define BHI_ERRCODE 0x30
-#define BHI_ERRDBG1 0x34
-#define BHI_ERRDBG2 0x38
-#define BHI_ERRDBG3 0x3c
-#define BHI_SERIALNU 0x40
-#define BHI_SBLANTIROLLVER 0x44
-#define BHI_NUMSEG 0x48
-#define BHI_MSMHWID(n) (0x4c + (0x4 * (n)))
-#define BHI_OEMPKHASH(n) (0x64 + (0x4 * (n)))
-#define BHI_RSVD5 0xc4
-
-/* BHI register bits */
-#define BHI_TXDB_SEQNUM_BMSK GENMASK(29, 0)
-#define BHI_STATUS_MASK GENMASK(31, 30)
-#define BHI_STATUS_ERROR 0x03
-#define BHI_STATUS_SUCCESS 0x02
-#define BHI_STATUS_RESET 0x00
-
-/* MHI BHIE registers */
-#define BHIE_MSMSOCID_OFFS 0x00
-#define BHIE_TXVECADDR_LOW_OFFS 0x2c
-#define BHIE_TXVECADDR_HIGH_OFFS 0x30
-#define BHIE_TXVECSIZE_OFFS 0x34
-#define BHIE_TXVECDB_OFFS 0x3c
-#define BHIE_TXVECSTATUS_OFFS 0x44
-#define BHIE_RXVECADDR_LOW_OFFS 0x60
-#define BHIE_RXVECADDR_HIGH_OFFS 0x64
-#define BHIE_RXVECSIZE_OFFS 0x68
-#define BHIE_RXVECDB_OFFS 0x70
-#define BHIE_RXVECSTATUS_OFFS 0x78
-
-/* BHIE register bits */
-#define BHIE_TXVECDB_SEQNUM_BMSK GENMASK(29, 0)
-#define BHIE_TXVECSTATUS_SEQNUM_BMSK GENMASK(29, 0)
-#define BHIE_TXVECSTATUS_STATUS_BMSK GENMASK(31, 30)
-#define BHIE_TXVECSTATUS_STATUS_RESET 0x00
-#define BHIE_TXVECSTATUS_STATUS_XFER_COMPL 0x02
-#define BHIE_TXVECSTATUS_STATUS_ERROR 0x03
-#define BHIE_RXVECDB_SEQNUM_BMSK GENMASK(29, 0)
-#define BHIE_RXVECSTATUS_SEQNUM_BMSK GENMASK(29, 0)
-#define BHIE_RXVECSTATUS_STATUS_BMSK GENMASK(31, 30)
-#define BHIE_RXVECSTATUS_STATUS_RESET 0x00
-#define BHIE_RXVECSTATUS_STATUS_XFER_COMPL 0x02
-#define BHIE_RXVECSTATUS_STATUS_ERROR 0x03
-
#define SOC_HW_VERSION_OFFS 0x224
#define SOC_HW_VERSION_FAM_NUM_BMSK GENMASK(31, 28)
#define SOC_HW_VERSION_DEV_NUM_BMSK GENMASK(27, 16)
#define SOC_HW_VERSION_MAJOR_VER_BMSK GENMASK(15, 8)
#define SOC_HW_VERSION_MINOR_VER_BMSK GENMASK(7, 0)
-#define EV_CTX_RESERVED_MASK GENMASK(7, 0)
-#define EV_CTX_INTMODC_MASK GENMASK(15, 8)
-#define EV_CTX_INTMODT_MASK GENMASK(31, 16)
-struct mhi_event_ctxt {
- __le32 intmod;
- __le32 ertype;
- __le32 msivec;
-
- __le64 rbase __packed __aligned(4);
- __le64 rlen __packed __aligned(4);
- __le64 rp __packed __aligned(4);
- __le64 wp __packed __aligned(4);
-};
-
-#define CHAN_CTX_CHSTATE_MASK GENMASK(7, 0)
-#define CHAN_CTX_BRSTMODE_MASK GENMASK(9, 8)
-#define CHAN_CTX_POLLCFG_MASK GENMASK(15, 10)
-#define CHAN_CTX_RESERVED_MASK GENMASK(31, 16)
-struct mhi_chan_ctxt {
- __le32 chcfg;
- __le32 chtype;
- __le32 erindex;
-
- __le64 rbase __packed __aligned(4);
- __le64 rlen __packed __aligned(4);
- __le64 rp __packed __aligned(4);
- __le64 wp __packed __aligned(4);
-};
-
-struct mhi_cmd_ctxt {
- __le32 reserved0;
- __le32 reserved1;
- __le32 reserved2;
-
- __le64 rbase __packed __aligned(4);
- __le64 rlen __packed __aligned(4);
- __le64 rp __packed __aligned(4);
- __le64 wp __packed __aligned(4);
-};
-
struct mhi_ctxt {
struct mhi_event_ctxt *er_ctxt;
struct mhi_chan_ctxt *chan_ctxt;
@@ -168,130 +30,11 @@ struct mhi_ctxt {
dma_addr_t cmd_ctxt_addr;
};
-struct mhi_ring_element {
- __le64 ptr;
- __le32 dword[2];
-};
-
struct bhi_vec_entry {
u64 dma_addr;
u64 size;
};
-enum mhi_cmd_type {
- MHI_CMD_NOP = 1,
- MHI_CMD_RESET_CHAN = 16,
- MHI_CMD_STOP_CHAN = 17,
- MHI_CMD_START_CHAN = 18,
-};
-
-/* No operation command */
-#define MHI_TRE_CMD_NOOP_PTR 0
-#define MHI_TRE_CMD_NOOP_DWORD0 0
-#define MHI_TRE_CMD_NOOP_DWORD1 cpu_to_le32(FIELD_PREP(GENMASK(23, 16), MHI_CMD_NOP))
-
-/* Channel reset command */
-#define MHI_TRE_CMD_RESET_PTR 0
-#define MHI_TRE_CMD_RESET_DWORD0 0
-#define MHI_TRE_CMD_RESET_DWORD1(chid) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), chid) | \
- FIELD_PREP(GENMASK(23, 16), \
- MHI_CMD_RESET_CHAN))
-
-/* Channel stop command */
-#define MHI_TRE_CMD_STOP_PTR 0
-#define MHI_TRE_CMD_STOP_DWORD0 0
-#define MHI_TRE_CMD_STOP_DWORD1(chid) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), chid) | \
- FIELD_PREP(GENMASK(23, 16), \
- MHI_CMD_STOP_CHAN))
-
-/* Channel start command */
-#define MHI_TRE_CMD_START_PTR 0
-#define MHI_TRE_CMD_START_DWORD0 0
-#define MHI_TRE_CMD_START_DWORD1(chid) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), chid) | \
- FIELD_PREP(GENMASK(23, 16), \
- MHI_CMD_START_CHAN))
-
-#define MHI_TRE_GET_DWORD(tre, word) le32_to_cpu((tre)->dword[(word)])
-#define MHI_TRE_GET_CMD_CHID(tre) FIELD_GET(GENMASK(31, 24), MHI_TRE_GET_DWORD(tre, 1))
-#define MHI_TRE_GET_CMD_TYPE(tre) FIELD_GET(GENMASK(23, 16), MHI_TRE_GET_DWORD(tre, 1))
-
-/* Event descriptor macros */
-#define MHI_TRE_EV_PTR(ptr) cpu_to_le64(ptr)
-#define MHI_TRE_EV_DWORD0(code, len) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), code | \
- FIELD_PREP(GENMASK(15, 0), len)))
-#define MHI_TRE_EV_DWORD1(chid, type) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), chid | \
- FIELD_PREP(GENMASK(23, 16), type)))
-#define MHI_TRE_GET_EV_PTR(tre) le64_to_cpu((tre)->ptr)
-#define MHI_TRE_GET_EV_CODE(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
-#define MHI_TRE_GET_EV_LEN(tre) FIELD_GET(GENMASK(15, 0), (MHI_TRE_GET_DWORD(tre, 0)))
-#define MHI_TRE_GET_EV_CHID(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 1)))
-#define MHI_TRE_GET_EV_TYPE(tre) FIELD_GET(GENMASK(23, 16), (MHI_TRE_GET_DWORD(tre, 1)))
-#define MHI_TRE_GET_EV_STATE(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
-#define MHI_TRE_GET_EV_EXECENV(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
-#define MHI_TRE_GET_EV_SEQ(tre) MHI_TRE_GET_DWORD(tre, 0)
-#define MHI_TRE_GET_EV_TIME(tre) MHI_TRE_GET_EV_PTR(tre)
-#define MHI_TRE_GET_EV_COOKIE(tre) lower_32_bits(MHI_TRE_GET_EV_PTR(tre))
-#define MHI_TRE_GET_EV_VEID(tre) FIELD_GET(GENMASK(23, 16), (MHI_TRE_GET_DWORD(tre, 0)))
-#define MHI_TRE_GET_EV_LINKSPEED(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 1)))
-#define MHI_TRE_GET_EV_LINKWIDTH(tre) FIELD_GET(GENMASK(7, 0), (MHI_TRE_GET_DWORD(tre, 0)))
-
-/* Transfer descriptor macros */
-#define MHI_TRE_DATA_PTR(ptr) cpu_to_le64(ptr)
-#define MHI_TRE_DATA_DWORD0(len) cpu_to_le32(FIELD_PREP(GENMASK(15, 0), len))
-#define MHI_TRE_TYPE_TRANSFER 2
-#define MHI_TRE_DATA_DWORD1(bei, ieot, ieob, chain) cpu_to_le32(FIELD_PREP(GENMASK(23, 16), \
- MHI_TRE_TYPE_TRANSFER) | \
- FIELD_PREP(BIT(10), bei) | \
- FIELD_PREP(BIT(9), ieot) | \
- FIELD_PREP(BIT(8), ieob) | \
- FIELD_PREP(BIT(0), chain))
-
-/* RSC transfer descriptor macros */
-#define MHI_RSCTRE_DATA_PTR(ptr, len) cpu_to_le64(FIELD_PREP(GENMASK(64, 48), len) | ptr)
-#define MHI_RSCTRE_DATA_DWORD0(cookie) cpu_to_le32(cookie)
-#define MHI_RSCTRE_DATA_DWORD1 cpu_to_le32(FIELD_PREP(GENMASK(23, 16), \
- MHI_PKT_TYPE_COALESCING))
-
-enum mhi_pkt_type {
- MHI_PKT_TYPE_INVALID = 0x0,
- MHI_PKT_TYPE_NOOP_CMD = 0x1,
- MHI_PKT_TYPE_TRANSFER = 0x2,
- MHI_PKT_TYPE_COALESCING = 0x8,
- MHI_PKT_TYPE_RESET_CHAN_CMD = 0x10,
- MHI_PKT_TYPE_STOP_CHAN_CMD = 0x11,
- MHI_PKT_TYPE_START_CHAN_CMD = 0x12,
- MHI_PKT_TYPE_STATE_CHANGE_EVENT = 0x20,
- MHI_PKT_TYPE_CMD_COMPLETION_EVENT = 0x21,
- MHI_PKT_TYPE_TX_EVENT = 0x22,
- MHI_PKT_TYPE_RSC_TX_EVENT = 0x28,
- MHI_PKT_TYPE_EE_EVENT = 0x40,
- MHI_PKT_TYPE_TSYNC_EVENT = 0x48,
- MHI_PKT_TYPE_BW_REQ_EVENT = 0x50,
- MHI_PKT_TYPE_STALE_EVENT, /* internal event */
-};
-
-/* MHI transfer completion events */
-enum mhi_ev_ccs {
- MHI_EV_CC_INVALID = 0x0,
- MHI_EV_CC_SUCCESS = 0x1,
- MHI_EV_CC_EOT = 0x2, /* End of transfer event */
- MHI_EV_CC_OVERFLOW = 0x3,
- MHI_EV_CC_EOB = 0x4, /* End of block event */
- MHI_EV_CC_OOB = 0x5, /* Out of block event */
- MHI_EV_CC_DB_MODE = 0x6,
- MHI_EV_CC_UNDEFINED_ERR = 0x10,
- MHI_EV_CC_BAD_TRE = 0x11,
-};
-
-enum mhi_ch_state {
- MHI_CH_STATE_DISABLED = 0x0,
- MHI_CH_STATE_ENABLED = 0x1,
- MHI_CH_STATE_RUNNING = 0x2,
- MHI_CH_STATE_SUSPENDED = 0x3,
- MHI_CH_STATE_STOP = 0x4,
- MHI_CH_STATE_ERROR = 0x5,
-};
-
enum mhi_ch_state_type {
MHI_CH_STATE_TYPE_RESET,
MHI_CH_STATE_TYPE_STOP,
@@ -333,11 +76,6 @@ extern const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX];
#define TO_DEV_STATE_TRANS_STR(state) (((state) >= DEV_ST_TRANSITION_MAX) ? \
"INVALID_STATE" : dev_state_tran_str[state])
-extern const char * const mhi_state_str[MHI_STATE_MAX];
-#define TO_MHI_STATE_STR(state) ((state >= MHI_STATE_MAX || \
- !mhi_state_str[state]) ? \
- "INVALID_STATE" : mhi_state_str[state])
-
/* internal power states */
enum mhi_pm_state {
MHI_PM_STATE_DISABLE,
--
2.25.1
On 2/28/22 6:43 AM, Manivannan Sadhasivam wrote:
> Hello,
>
> This series adds initial support for the Qualcomm specific Modem Host Interface
> (MHI) bus in endpoint devices like SDX55 modems. The MHI bus in endpoint devices
> communicates with the MHI bus in host machines like x86 over any physical bus
> like PCIe. The MHI host support is already in mainline [1] and been used by PCIe
> based modems and WLAN devices running vendor code (downstream).
I believe I have provided a "Reviewed-by" tag for all patches in
this series. I've made a few minor suggestions, but nothing I
saw deserves issuing a new version of the series. The only
"big thing" is whether you want to rework the stuff that David
Laight commented on in patch 5 (and 15 too). I agree with him
that the code there isn't very pretty and could be improved,
but as I said in my review, my preference would be to get this
accepted with a promise from you to revisit that. Improving
that would improve readability and maintainability, and that's
important. But there's too much *other* code in this series
and I hate to see its acceptance delayed further.
So anyway, I'm done reviewing this, and in general I trust that
you will tell me (and drop my Reviewed-by tag) if you change
anything substantive in a new version of the series.
-Alex
>
> Overview
> ========
>
> This series aims at adding the MHI support in the endpoint devices with the goal
> of getting data connectivity using the mainline kernel running on the modems.
> Modems here refer to the combination of an APPS processor (Cortex A grade) and
> a baseband processor (DSP). The MHI bus is located in the APPS processor and it
> transfers data packets from the baseband processor to the host machine.
>
> The MHI Endpoint (MHI EP) stack proposed here is inspired by the downstream
> code written by Qualcomm. But the complete stack is mostly re-written to adapt
> to the "bus" framework and made it modular so that it can work with the upstream
> subsystems like "PCI Endpoint". The code structure of the MHI endpoint stack
> follows the MHI host stack to maintain uniformity.
>
> With this initial MHI EP stack (along with few other drivers), we can establish
> the network interface between host and endpoint over the MHI software channels
> (IP_SW0) and can do things like IP forwarding, SSH, etc...
>
> Stack Organization
> ==================
>
> The MHI EP stack has the concept of controller and device drivers as like the
> MHI host stack. The MHI EP controller driver can be a PCI Endpoint Function
> driver and the MHI device driver can be a MHI EP Networking driver or QRTR
> driver. The MHI EP controller driver is tied to the PCI Endpoint subsystem and
> handles all bus related activities like mapping the host memory, raising IRQ,
> passing link specific events etc... The MHI EP networking driver is tied to the
> Networking stack and handles all networking related activities like
> sending/receiving the SKBs from netdev, statistics collection etc...
>
> This series only contains the MHI EP code, whereas the PCIe EPF driver and MHI
> EP Networking drivers are not yet submitted and can be found here [2]. Though
> the MHI EP stack doesn't have the build time dependency, it cannot function
> without them.
>
> Test setup
> ==========
>
> This series has been tested on Telit FN980 TLB board powered by Qualcomm SDX55
> (a.k.a X55 modem) and Qualcomm SM8450 based dev board.
>
> For testing the stability and performance, networking tools such as iperf, ssh
> and ping are used.
>
> Limitations
> ===========
>
> We are not _yet_ there to get the data packets from the modem as that involves
> the Qualcomm IP Accelerator (IPA) integration with MHI endpoint stack. But we
> are planning to add support for it in the coming days.
>
> References
> ==========
>
> MHI bus: https://www.kernel.org/doc/html/latest/mhi/mhi.html
> Linaro connect presentation around this topic: https://connect.linaro.org/resources/lvc21f/lvc21f-222/
>
> Thanks,
> Mani
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/bus/mhi
> [2] https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/log/?h=tracking-qcomlt-sdx55-drivers
>
> Changes in v4:
>
> * Collected reviews from Hemant and Alex.
> * Removed the A7 suffix from register names and functions.
> * Added a couple of cleanup patches.
> * Reworked the mhi_ep_queue_skb() API.
> * Switched to separate workers for command and transfer rings.
> * Used a common workqueue for state and ring management.
> * Reworked the channel ring management.
> * Other misc changes as per review from Alex.
>
> Changes in v3:
>
> * Splitted the patch 20/23 into two.
> * Fixed the error handling in patch 21/23.
> * Removed spurious change in patch 01/23.
> * Added check for xfer callbacks in client driver probe.
>
> Changes in v2:
>
> v2 mostly addresses the issues seen while testing the stack on SM8450 that is a
> SMP platform and also incorporates the review comments from Alex.
>
> Major changes are:
>
> * Added a cleanup patch for getting rid of SHIFT macros and used the bitfield
> operations.
> * Added the endianess patches that were submitted to MHI list and used the
> endianess conversion in EP patches also.
> * Added support for multiple event rings.
> * Fixed the MSI generation based on the event ring index.
> * Fixed the doorbell list handling by making use of list splice and not locking
> the entire list manipulation.
> * Added new APIs for wrapping the reading and writing to host memory (Dmitry).
> * Optimized the read_channel and queue_skb function logics.
> * Added Hemant's R-o-b tag.
>
> Manivannan Sadhasivam (25):
> bus: mhi: Move host MHI code to "host" directory
> bus: mhi: Use bitfield operations for register read and write
> bus: mhi: Use bitfield operations for handling DWORDs of ring elements
> bus: mhi: Cleanup the register definitions used in headers
> bus: mhi: host: Rename "struct mhi_tre" to "struct mhi_ring_element"
> bus: mhi: Move common MHI definitions out of host directory
> bus: mhi: Make mhi_state_str[] array static inline and move to
> common.h
> bus: mhi: ep: Add support for registering MHI endpoint controllers
> bus: mhi: ep: Add support for registering MHI endpoint client drivers
> bus: mhi: ep: Add support for creating and destroying MHI EP devices
> bus: mhi: ep: Add support for managing MMIO registers
> bus: mhi: ep: Add support for ring management
> bus: mhi: ep: Add support for sending events to the host
> bus: mhi: ep: Add support for managing MHI state machine
> bus: mhi: ep: Add support for processing MHI endpoint interrupts
> bus: mhi: ep: Add support for powering up the MHI endpoint stack
> bus: mhi: ep: Add support for powering down the MHI endpoint stack
> bus: mhi: ep: Add support for handling MHI_RESET
> bus: mhi: ep: Add support for handling SYS_ERR condition
> bus: mhi: ep: Add support for processing command rings
> bus: mhi: ep: Add support for reading from the host
> bus: mhi: ep: Add support for processing channel rings
> bus: mhi: ep: Add support for queueing SKBs to the host
> bus: mhi: ep: Add support for suspending and resuming channels
> bus: mhi: ep: Add uevent support for module autoloading
>
> Paul Davey (2):
> bus: mhi: Fix pm_state conversion to string
> bus: mhi: Fix MHI DMA structure endianness
>
> drivers/bus/Makefile | 2 +-
> drivers/bus/mhi/Kconfig | 28 +-
> drivers/bus/mhi/Makefile | 9 +-
> drivers/bus/mhi/common.h | 326 +++++
> drivers/bus/mhi/core/internal.h | 722 ----------
> drivers/bus/mhi/ep/Kconfig | 10 +
> drivers/bus/mhi/ep/Makefile | 2 +
> drivers/bus/mhi/ep/internal.h | 222 +++
> drivers/bus/mhi/ep/main.c | 1623 ++++++++++++++++++++++
> drivers/bus/mhi/ep/mmio.c | 272 ++++
> drivers/bus/mhi/ep/ring.c | 197 +++
> drivers/bus/mhi/ep/sm.c | 148 ++
> drivers/bus/mhi/host/Kconfig | 31 +
> drivers/bus/mhi/{core => host}/Makefile | 4 +-
> drivers/bus/mhi/{core => host}/boot.c | 17 +-
> drivers/bus/mhi/{core => host}/debugfs.c | 40 +-
> drivers/bus/mhi/{core => host}/init.c | 131 +-
> drivers/bus/mhi/host/internal.h | 382 +++++
> drivers/bus/mhi/{core => host}/main.c | 66 +-
> drivers/bus/mhi/{ => host}/pci_generic.c | 0
> drivers/bus/mhi/{core => host}/pm.c | 36 +-
> include/linux/mhi_ep.h | 284 ++++
> include/linux/mod_devicetable.h | 2 +
> scripts/mod/file2alias.c | 10 +
> 24 files changed, 3649 insertions(+), 915 deletions(-)
> create mode 100644 drivers/bus/mhi/common.h
> delete mode 100644 drivers/bus/mhi/core/internal.h
> create mode 100644 drivers/bus/mhi/ep/Kconfig
> create mode 100644 drivers/bus/mhi/ep/Makefile
> create mode 100644 drivers/bus/mhi/ep/internal.h
> create mode 100644 drivers/bus/mhi/ep/main.c
> create mode 100644 drivers/bus/mhi/ep/mmio.c
> create mode 100644 drivers/bus/mhi/ep/ring.c
> create mode 100644 drivers/bus/mhi/ep/sm.c
> create mode 100644 drivers/bus/mhi/host/Kconfig
> rename drivers/bus/mhi/{core => host}/Makefile (54%)
> rename drivers/bus/mhi/{core => host}/boot.c (96%)
> rename drivers/bus/mhi/{core => host}/debugfs.c (90%)
> rename drivers/bus/mhi/{core => host}/init.c (92%)
> create mode 100644 drivers/bus/mhi/host/internal.h
> rename drivers/bus/mhi/{core => host}/main.c (97%)
> rename drivers/bus/mhi/{ => host}/pci_generic.c (100%)
> rename drivers/bus/mhi/{core => host}/pm.c (97%)
> create mode 100644 include/linux/mhi_ep.h
>
Add support for processing the channel rings from host. For the channel
ring associated with DL channel, the xfer callback will simply invoked.
For the case of UL channel, the ring elements will be read in a buffer
till the write pointer and later passed to the client driver using the
xfer callback.
The client drivers should provide the callbacks for both UL and DL
channels during registration.
Reviewed-by: Alex Elder <[email protected]>
Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
drivers/bus/mhi/ep/main.c | 108 ++++++++++++++++++++++++++++++++++++++
include/linux/mhi_ep.h | 2 +
2 files changed, 110 insertions(+)
diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index e7c0ef9f281b..63e14d55aa06 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -420,6 +420,57 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
return 0;
}
+int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring, struct mhi_ring_element *el)
+{
+ struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
+ struct mhi_result result = {};
+ u32 len = MHI_EP_DEFAULT_MTU;
+ struct mhi_ep_chan *mhi_chan;
+ int ret;
+
+ mhi_chan = &mhi_cntrl->mhi_chan[ring->ch_id];
+
+ /*
+ * Bail out if transfer callback is not registered for the channel.
+ * This is most likely due to the client driver not loaded at this point.
+ */
+ if (!mhi_chan->xfer_cb) {
+ dev_err(&mhi_chan->mhi_dev->dev, "Client driver not available\n");
+ return -ENODEV;
+ }
+
+ if (ring->ch_id % 2) {
+ /* DL channel */
+ result.dir = mhi_chan->dir;
+ mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
+ } else {
+ /* UL channel */
+ result.buf_addr = kzalloc(len, GFP_KERNEL);
+ if (!result.buf_addr)
+ return -ENOMEM;
+
+ do {
+ ret = mhi_ep_read_channel(mhi_cntrl, ring, &result, len);
+ if (ret < 0) {
+ dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n");
+ kfree(result.buf_addr);
+ return ret;
+ }
+
+ result.dir = mhi_chan->dir;
+ mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
+ result.bytes_xferd = 0;
+ memset(result.buf_addr, 0, len);
+
+ /* Read until the ring becomes empty */
+ } while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE));
+
+ kfree(result.buf_addr);
+ }
+
+ return 0;
+}
+
static int mhi_ep_cache_host_cfg(struct mhi_ep_cntrl *mhi_cntrl)
{
size_t cmd_ctx_host_size, ch_ctx_host_size, ev_ctx_host_size;
@@ -597,6 +648,60 @@ static void mhi_ep_cmd_ring_worker(struct work_struct *work)
}
}
+static void mhi_ep_ch_ring_worker(struct work_struct *work)
+{
+ struct mhi_ep_cntrl *mhi_cntrl = container_of(work, struct mhi_ep_cntrl, ch_ring_work);
+ struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ struct mhi_ep_ring_item *itr, *tmp;
+ struct mhi_ring_element *el;
+ struct mhi_ep_ring *ring;
+ struct mhi_ep_chan *chan;
+ unsigned long flags;
+ LIST_HEAD(head);
+ int ret;
+
+ spin_lock_irqsave(&mhi_cntrl->list_lock, flags);
+ list_splice_tail_init(&mhi_cntrl->ch_db_list, &head);
+ spin_unlock_irqrestore(&mhi_cntrl->list_lock, flags);
+
+ /* Process each queued channel ring. In case of an error, just process next element. */
+ list_for_each_entry_safe(itr, tmp, &head, node) {
+ list_del(&itr->node);
+ ring = itr->ring;
+
+ /* Update the write offset for the ring */
+ ret = mhi_ep_update_wr_offset(ring);
+ if (ret) {
+ dev_err(dev, "Error updating write offset for ring\n");
+ kfree(itr);
+ continue;
+ }
+
+ /* Sanity check to make sure there are elements in the ring */
+ if (ring->rd_offset == ring->wr_offset) {
+ kfree(itr);
+ continue;
+ }
+
+ el = &ring->ring_cache[ring->rd_offset];
+ chan = &mhi_cntrl->mhi_chan[ring->ch_id];
+
+ mutex_lock(&chan->lock);
+ dev_dbg(dev, "Processing the ring for channel (%u)\n", ring->ch_id);
+ ret = mhi_ep_process_ch_ring(ring, el);
+ if (ret) {
+ dev_err(dev, "Error processing ring for channel (%u): %d\n",
+ ring->ch_id, ret);
+ mutex_unlock(&chan->lock);
+ kfree(itr);
+ continue;
+ }
+
+ mutex_unlock(&chan->lock);
+ kfree(itr);
+ }
+}
+
static void mhi_ep_state_worker(struct work_struct *work)
{
struct mhi_ep_cntrl *mhi_cntrl = container_of(work, struct mhi_ep_cntrl, state_work);
@@ -662,6 +767,8 @@ static void mhi_ep_queue_channel_db(struct mhi_ep_cntrl *mhi_cntrl, unsigned lon
spin_lock(&mhi_cntrl->list_lock);
list_splice_tail_init(&head, &mhi_cntrl->ch_db_list);
spin_unlock(&mhi_cntrl->list_lock);
+
+ queue_work(mhi_cntrl->wq, &mhi_cntrl->ch_ring_work);
}
}
@@ -1152,6 +1259,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
INIT_WORK(&mhi_cntrl->state_work, mhi_ep_state_worker);
INIT_WORK(&mhi_cntrl->reset_work, mhi_ep_reset_worker);
INIT_WORK(&mhi_cntrl->cmd_ring_work, mhi_ep_cmd_ring_worker);
+ INIT_WORK(&mhi_cntrl->ch_ring_work, mhi_ep_ch_ring_worker);
mhi_cntrl->wq = alloc_workqueue("mhi_ep_wq", 0, 0);
if (!mhi_cntrl->wq) {
diff --git a/include/linux/mhi_ep.h b/include/linux/mhi_ep.h
index 45d12a55b435..74170dad09f6 100644
--- a/include/linux/mhi_ep.h
+++ b/include/linux/mhi_ep.h
@@ -78,6 +78,7 @@ struct mhi_ep_db_info {
* @state_work: State transition worker
* @reset_work: Worker for MHI Endpoint reset
* @cmd_ring_work: Worker for processing command rings
+ * @ch_ring_work: Worker for processing channel rings
* @raise_irq: CB function for raising IRQ to the host
* @alloc_addr: CB function for allocating memory in endpoint for storing host context
* @map_addr: CB function for mapping host context to endpoint
@@ -128,6 +129,7 @@ struct mhi_ep_cntrl {
struct work_struct state_work;
struct work_struct reset_work;
struct work_struct cmd_ring_work;
+ struct work_struct ch_ring_work;
void (*raise_irq)(struct mhi_ep_cntrl *mhi_cntrl, u32 vector);
void __iomem *(*alloc_addr)(struct mhi_ep_cntrl *mhi_cntrl, phys_addr_t *phys_addr,
--
2.25.1
Add support for managing the MHI ring. The MHI ring is a circular queue
of data structures used to pass the information between host and the
endpoint.
MHI support 3 types of rings:
1. Transfer ring
2. Event ring
3. Command ring
All rings reside inside the host memory and the MHI EP device maps it to
the device memory using blocks like PCIe iATU. The mapping is handled in
the MHI EP controller driver itself.
Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
drivers/bus/mhi/ep/Makefile | 2 +-
drivers/bus/mhi/ep/internal.h | 18 ++++
drivers/bus/mhi/ep/ring.c | 197 ++++++++++++++++++++++++++++++++++
3 files changed, 216 insertions(+), 1 deletion(-)
create mode 100644 drivers/bus/mhi/ep/ring.c
diff --git a/drivers/bus/mhi/ep/Makefile b/drivers/bus/mhi/ep/Makefile
index a1555ae287ad..7ba0e04801eb 100644
--- a/drivers/bus/mhi/ep/Makefile
+++ b/drivers/bus/mhi/ep/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_MHI_BUS_EP) += mhi_ep.o
-mhi_ep-y := main.o mmio.o
+mhi_ep-y := main.o mmio.o ring.o
diff --git a/drivers/bus/mhi/ep/internal.h b/drivers/bus/mhi/ep/internal.h
index 139e939fcf57..b3b8770f2f4e 100644
--- a/drivers/bus/mhi/ep/internal.h
+++ b/drivers/bus/mhi/ep/internal.h
@@ -114,6 +114,11 @@ union mhi_ep_ring_ctx {
struct mhi_generic_ctx generic;
};
+struct mhi_ep_ring_item {
+ struct list_head node;
+ struct mhi_ep_ring *ring;
+};
+
struct mhi_ep_ring {
struct mhi_ep_cntrl *mhi_cntrl;
union mhi_ep_ring_ctx *ring_ctx;
@@ -126,6 +131,9 @@ struct mhi_ep_ring {
u32 db_offset_h;
u32 db_offset_l;
u32 ch_id;
+ u32 er_index;
+ u32 irq_vector;
+ bool started;
};
struct mhi_ep_cmd {
@@ -151,6 +159,16 @@ struct mhi_ep_chan {
bool skip_td;
};
+/* MHI Ring related functions */
+void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id);
+void mhi_ep_ring_reset(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring);
+int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
+ union mhi_ep_ring_ctx *ctx);
+size_t mhi_ep_ring_addr2offset(struct mhi_ep_ring *ring, u64 ptr);
+int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *element);
+void mhi_ep_ring_inc_index(struct mhi_ep_ring *ring);
+int mhi_ep_update_wr_offset(struct mhi_ep_ring *ring);
+
/* MMIO related functions */
u32 mhi_ep_mmio_read(struct mhi_ep_cntrl *mhi_cntrl, u32 offset);
void mhi_ep_mmio_write(struct mhi_ep_cntrl *mhi_cntrl, u32 offset, u32 val);
diff --git a/drivers/bus/mhi/ep/ring.c b/drivers/bus/mhi/ep/ring.c
new file mode 100644
index 000000000000..1029eed2cc28
--- /dev/null
+++ b/drivers/bus/mhi/ep/ring.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <[email protected]>
+ */
+
+#include <linux/mhi_ep.h>
+#include "internal.h"
+
+size_t mhi_ep_ring_addr2offset(struct mhi_ep_ring *ring, u64 ptr)
+{
+ return (ptr - ring->rbase) / sizeof(struct mhi_ring_element);
+}
+
+static u32 mhi_ep_ring_num_elems(struct mhi_ep_ring *ring)
+{
+ return le64_to_cpu(ring->ring_ctx->generic.rlen) / sizeof(struct mhi_ring_element);
+}
+
+void mhi_ep_ring_inc_index(struct mhi_ep_ring *ring)
+{
+ ring->rd_offset = (ring->rd_offset + 1) % ring->ring_size;
+}
+
+static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end)
+{
+ struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
+ struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ size_t start, copy_size;
+ int ret;
+
+ /* Don't proceed in the case of event ring. This happens during mhi_ep_ring_start(). */
+ if (ring->type == RING_TYPE_ER)
+ return 0;
+
+ /* No need to cache the ring if write pointer is unmodified */
+ if (ring->wr_offset == end)
+ return 0;
+
+ start = ring->wr_offset;
+ if (start < end) {
+ copy_size = (end - start) * sizeof(struct mhi_ring_element);
+ ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase +
+ (start * sizeof(struct mhi_ring_element)),
+ &ring->ring_cache[start], copy_size);
+ if (ret < 0)
+ return ret;
+ } else {
+ copy_size = (ring->ring_size - start) * sizeof(struct mhi_ring_element);
+ ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase +
+ (start * sizeof(struct mhi_ring_element)),
+ &ring->ring_cache[start], copy_size);
+ if (ret < 0)
+ return ret;
+
+ if (end) {
+ ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase,
+ &ring->ring_cache[0],
+ end * sizeof(struct mhi_ring_element));
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, copy_size);
+
+ return 0;
+}
+
+static int mhi_ep_cache_ring(struct mhi_ep_ring *ring, u64 wr_ptr)
+{
+ size_t wr_offset;
+ int ret;
+
+ wr_offset = mhi_ep_ring_addr2offset(ring, wr_ptr);
+
+ /* Cache the host ring till write offset */
+ ret = __mhi_ep_cache_ring(ring, wr_offset);
+ if (ret)
+ return ret;
+
+ ring->wr_offset = wr_offset;
+
+ return 0;
+}
+
+int mhi_ep_update_wr_offset(struct mhi_ep_ring *ring)
+{
+ u64 wr_ptr;
+
+ wr_ptr = mhi_ep_mmio_get_db(ring);
+
+ return mhi_ep_cache_ring(ring, wr_ptr);
+}
+
+/* TODO: Support for adding multiple ring elements to the ring */
+int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *el)
+{
+ struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
+ struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ size_t old_offset = 0;
+ u32 num_free_elem;
+ int ret;
+
+ ret = mhi_ep_update_wr_offset(ring);
+ if (ret) {
+ dev_err(dev, "Error updating write pointer\n");
+ return ret;
+ }
+
+ if (ring->rd_offset < ring->wr_offset)
+ num_free_elem = (ring->wr_offset - ring->rd_offset) - 1;
+ else
+ num_free_elem = ((ring->ring_size - ring->rd_offset) + ring->wr_offset) - 1;
+
+ /* Check if there is space in ring for adding at least an element */
+ if (!num_free_elem) {
+ dev_err(dev, "No space left in the ring\n");
+ return -ENOSPC;
+ }
+
+ old_offset = ring->rd_offset;
+ mhi_ep_ring_inc_index(ring);
+
+ dev_dbg(dev, "Adding an element to ring at offset (%zu)\n", ring->rd_offset);
+
+ /* Update rp in ring context */
+ ring->ring_ctx->generic.rp = cpu_to_le64((ring->rd_offset * sizeof(*el)) + ring->rbase);
+
+ ret = mhi_cntrl->write_to_host(mhi_cntrl, el, ring->rbase + (old_offset * sizeof(*el)),
+ sizeof(*el));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id)
+{
+ ring->type = type;
+ if (ring->type == RING_TYPE_CMD) {
+ ring->db_offset_h = EP_CRDB_HIGHER;
+ ring->db_offset_l = EP_CRDB_LOWER;
+ } else if (ring->type == RING_TYPE_CH) {
+ ring->db_offset_h = CHDB_HIGHER_n(id);
+ ring->db_offset_l = CHDB_LOWER_n(id);
+ ring->ch_id = id;
+ } else {
+ ring->db_offset_h = ERDB_HIGHER_n(id);
+ ring->db_offset_l = ERDB_LOWER_n(id);
+ }
+}
+
+int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
+ union mhi_ep_ring_ctx *ctx)
+{
+ struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ int ret;
+
+ ring->mhi_cntrl = mhi_cntrl;
+ ring->ring_ctx = ctx;
+ ring->ring_size = mhi_ep_ring_num_elems(ring);
+ ring->rbase = le64_to_cpu(ring->ring_ctx->generic.rbase);
+
+ if (ring->type == RING_TYPE_CH)
+ ring->er_index = le32_to_cpu(ring->ring_ctx->ch.erindex);
+
+ if (ring->type == RING_TYPE_ER)
+ ring->irq_vector = le32_to_cpu(ring->ring_ctx->ev.msivec);
+
+ /* During ring init, both rp and wp are equal */
+ ring->rd_offset = mhi_ep_ring_addr2offset(ring, le64_to_cpu(ring->ring_ctx->generic.rp));
+ ring->wr_offset = mhi_ep_ring_addr2offset(ring, le64_to_cpu(ring->ring_ctx->generic.rp));
+
+ /* Allocate ring cache memory for holding the copy of host ring */
+ ring->ring_cache = kcalloc(ring->ring_size, sizeof(struct mhi_ring_element), GFP_KERNEL);
+ if (!ring->ring_cache)
+ return -ENOMEM;
+
+ ret = mhi_ep_cache_ring(ring, le64_to_cpu(ring->ring_ctx->generic.wp));
+ if (ret) {
+ dev_err(dev, "Failed to cache ring\n");
+ kfree(ring->ring_cache);
+ return ret;
+ }
+
+ ring->started = true;
+
+ return 0;
+}
+
+void mhi_ep_ring_reset(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring)
+{
+ ring->started = false;
+ kfree(ring->ring_cache);
+ ring->ring_cache = NULL;
+}
--
2.25.1
This commit adds support for registering MHI endpoint client drivers
with the MHI endpoint stack. MHI endpoint client drivers bind to one
or more MHI endpoint devices inorder to send and receive the upper-layer
protocol packets like IP packets, modem control messages, and
diagnostics messages over MHI bus.
Reviewed-by: Hemant Kumar <[email protected]>
Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
drivers/bus/mhi/ep/main.c | 85 +++++++++++++++++++++++++++++++++++++++
include/linux/mhi_ep.h | 57 +++++++++++++++++++++++++-
2 files changed, 140 insertions(+), 2 deletions(-)
diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index 87ca42c7b067..2bdcf1657479 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -198,9 +198,88 @@ 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)
+{
+ 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_chan *ul_chan = mhi_dev->ul_chan;
+ struct mhi_ep_chan *dl_chan = mhi_dev->dl_chan;
+
+ ul_chan->xfer_cb = mhi_drv->ul_xfer_cb;
+ dl_chan->xfer_cb = mhi_drv->dl_xfer_cb;
+
+ return mhi_drv->probe(mhi_dev, mhi_dev->id);
+}
+
+static int mhi_ep_driver_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_result result = {};
+ struct mhi_ep_chan *mhi_chan;
+ int dir;
+
+ /* Skip if it is a controller device */
+ if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER)
+ return 0;
+
+ /* Disconnect the channels associated with the driver */
+ 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);
+ /* Send channel disconnect status to the client driver */
+ 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;
+ mhi_chan->xfer_cb = NULL;
+ mutex_unlock(&mhi_chan->lock);
+ }
+
+ /* 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)
+{
+ struct device_driver *driver = &mhi_drv->driver;
+
+ if (!mhi_drv->probe || !mhi_drv->remove)
+ return -EINVAL;
+
+ /* Client drivers should have callbacks defined for both channels */
+ if (!mhi_drv->ul_xfer_cb || !mhi_drv->dl_xfer_cb)
+ return -EINVAL;
+
+ 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);
+}
+EXPORT_SYMBOL_GPL(__mhi_ep_driver_register);
+
+void mhi_ep_driver_unregister(struct mhi_ep_driver *mhi_drv)
+{
+ driver_unregister(&mhi_drv->driver);
+}
+EXPORT_SYMBOL_GPL(mhi_ep_driver_unregister);
+
static int mhi_ep_match(struct device *dev, struct device_driver *drv)
{
struct mhi_ep_device *mhi_dev = to_mhi_ep_device(dev);
+ struct mhi_ep_driver *mhi_drv = to_mhi_ep_driver(drv);
+ const struct mhi_device_id *id;
/*
* If the device is a controller type then there is no client driver
@@ -209,6 +288,12 @@ static int mhi_ep_match(struct device *dev, struct device_driver *drv)
if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER)
return 0;
+ for (id = mhi_drv->id_table; id->chan[0]; id++)
+ if (!strcmp(mhi_dev->name, id->chan)) {
+ mhi_dev->id = id;
+ return 1;
+ }
+
return 0;
};
diff --git a/include/linux/mhi_ep.h b/include/linux/mhi_ep.h
index 9c58938371e2..efcbdc51464f 100644
--- a/include/linux/mhi_ep.h
+++ b/include/linux/mhi_ep.h
@@ -108,8 +108,8 @@ struct mhi_ep_cntrl {
* @mhi_cntrl: Controller the device belongs to
* @id: Pointer to MHI Endpoint device ID struct
* @name: Name of the associated MHI Endpoint device
- * @ul_chan: UL channel for the device
- * @dl_chan: DL channel for the device
+ * @ul_chan: UL (from host to endpoint) channel for the device
+ * @dl_chan: DL (from endpoint to host) channel for the device
* @dev_type: MHI device type
*/
struct mhi_ep_device {
@@ -122,7 +122,60 @@ struct mhi_ep_device {
enum mhi_device_type dev_type;
};
+/**
+ * struct mhi_ep_driver - Structure representing a MHI Endpoint client driver
+ * @id_table: Pointer to MHI Endpoint device ID table
+ * @driver: Device driver model driver
+ * @probe: CB function for client driver probe function
+ * @remove: CB function for client driver remove function
+ * @ul_xfer_cb: CB function for UL (from host to endpoint) data transfer
+ * @dl_xfer_cb: CB function for DL (from endpoint to host) data transfer
+ */
+struct mhi_ep_driver {
+ const struct mhi_device_id *id_table;
+ struct device_driver driver;
+ int (*probe)(struct mhi_ep_device *mhi_ep,
+ const struct mhi_device_id *id);
+ void (*remove)(struct mhi_ep_device *mhi_ep);
+ void (*ul_xfer_cb)(struct mhi_ep_device *mhi_dev,
+ struct mhi_result *result);
+ void (*dl_xfer_cb)(struct mhi_ep_device *mhi_dev,
+ struct mhi_result *result);
+};
+
#define to_mhi_ep_device(dev) container_of(dev, struct mhi_ep_device, dev)
+#define to_mhi_ep_driver(drv) container_of(drv, struct mhi_ep_driver, driver)
+
+/*
+ * module_mhi_ep_driver() - Helper macro for drivers that don't do
+ * anything special other than using default mhi_ep_driver_register() and
+ * mhi_ep_driver_unregister(). This eliminates a lot of boilerplate.
+ * Each module may only use this macro once.
+ */
+#define module_mhi_ep_driver(mhi_drv) \
+ module_driver(mhi_drv, mhi_ep_driver_register, \
+ mhi_ep_driver_unregister)
+
+/*
+ * Macro to avoid include chaining to get THIS_MODULE
+ */
+#define mhi_ep_driver_register(mhi_drv) \
+ __mhi_ep_driver_register(mhi_drv, THIS_MODULE)
+
+/**
+ * __mhi_ep_driver_register - Register a driver with MHI Endpoint bus
+ * @mhi_drv: Driver to be associated with the device
+ * @owner: The module owner
+ *
+ * Return: 0 if driver registrations succeeds, a negative error code otherwise.
+ */
+int __mhi_ep_driver_register(struct mhi_ep_driver *mhi_drv, struct module *owner);
+
+/**
+ * mhi_ep_driver_unregister - Unregister a driver from MHI Endpoint bus
+ * @mhi_drv: Driver associated with the device
+ */
+void mhi_ep_driver_unregister(struct mhi_ep_driver *mhi_drv);
/**
* mhi_ep_register_controller - Register MHI Endpoint controller
--
2.25.1
On Mon, Feb 28, 2022 at 10:57:48AM -0600, Alex Elder wrote:
> On 2/28/22 6:43 AM, Manivannan Sadhasivam wrote:
> > Hello,
> >
> > This series adds initial support for the Qualcomm specific Modem Host Interface
> > (MHI) bus in endpoint devices like SDX55 modems. The MHI bus in endpoint devices
> > communicates with the MHI bus in host machines like x86 over any physical bus
> > like PCIe. The MHI host support is already in mainline [1] and been used by PCIe
> > based modems and WLAN devices running vendor code (downstream).
>
> I believe I have provided a "Reviewed-by" tag for all patches in
> this series. I've made a few minor suggestions, but nothing I
> saw deserves issuing a new version of the series.
Thanks a lot for your time, Alex! Much appreciated.
> The only "big thing" is whether you want to rework the stuff that David
> Laight commented on in patch 5 (and 15 too). I agree with him
> that the code there isn't very pretty and could be improved,
> but as I said in my review, my preference would be to get this
> accepted with a promise from you to revisit that. Improving
> that would improve readability and maintainability, and that's
> important. But there's too much *other* code in this series
> and I hate to see its acceptance delayed further.
>
As I replied to you during v3 review, the ring element structure changes
between command, transfer and event rings. Even with command ring, we
got different structure for each command. This makes the definition
a bit hard.
Anyway, I'll take another look once this series gets merged.
> So anyway, I'm done reviewing this, and in general I trust that
> you will tell me (and drop my Reviewed-by tag) if you change
> anything substantive in a new version of the series.
>
Sure.
Thanks,
Mani
> -Alex
>
> >
> > Overview
> > ========
> >
> > This series aims at adding the MHI support in the endpoint devices with the goal
> > of getting data connectivity using the mainline kernel running on the modems.
> > Modems here refer to the combination of an APPS processor (Cortex A grade) and
> > a baseband processor (DSP). The MHI bus is located in the APPS processor and it
> > transfers data packets from the baseband processor to the host machine.
> >
> > The MHI Endpoint (MHI EP) stack proposed here is inspired by the downstream
> > code written by Qualcomm. But the complete stack is mostly re-written to adapt
> > to the "bus" framework and made it modular so that it can work with the upstream
> > subsystems like "PCI Endpoint". The code structure of the MHI endpoint stack
> > follows the MHI host stack to maintain uniformity.
> >
> > With this initial MHI EP stack (along with few other drivers), we can establish
> > the network interface between host and endpoint over the MHI software channels
> > (IP_SW0) and can do things like IP forwarding, SSH, etc...
> >
> > Stack Organization
> > ==================
> >
> > The MHI EP stack has the concept of controller and device drivers as like the
> > MHI host stack. The MHI EP controller driver can be a PCI Endpoint Function
> > driver and the MHI device driver can be a MHI EP Networking driver or QRTR
> > driver. The MHI EP controller driver is tied to the PCI Endpoint subsystem and
> > handles all bus related activities like mapping the host memory, raising IRQ,
> > passing link specific events etc... The MHI EP networking driver is tied to the
> > Networking stack and handles all networking related activities like
> > sending/receiving the SKBs from netdev, statistics collection etc...
> >
> > This series only contains the MHI EP code, whereas the PCIe EPF driver and MHI
> > EP Networking drivers are not yet submitted and can be found here [2]. Though
> > the MHI EP stack doesn't have the build time dependency, it cannot function
> > without them.
> >
> > Test setup
> > ==========
> >
> > This series has been tested on Telit FN980 TLB board powered by Qualcomm SDX55
> > (a.k.a X55 modem) and Qualcomm SM8450 based dev board.
> >
> > For testing the stability and performance, networking tools such as iperf, ssh
> > and ping are used.
> >
> > Limitations
> > ===========
> >
> > We are not _yet_ there to get the data packets from the modem as that involves
> > the Qualcomm IP Accelerator (IPA) integration with MHI endpoint stack. But we
> > are planning to add support for it in the coming days.
> >
> > References
> > ==========
> >
> > MHI bus: https://www.kernel.org/doc/html/latest/mhi/mhi.html
> > Linaro connect presentation around this topic: https://connect.linaro.org/resources/lvc21f/lvc21f-222/
> >
> > Thanks,
> > Mani
> >
> > [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/bus/mhi
> > [2] https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/log/?h=tracking-qcomlt-sdx55-drivers
> >
> > Changes in v4:
> >
> > * Collected reviews from Hemant and Alex.
> > * Removed the A7 suffix from register names and functions.
> > * Added a couple of cleanup patches.
> > * Reworked the mhi_ep_queue_skb() API.
> > * Switched to separate workers for command and transfer rings.
> > * Used a common workqueue for state and ring management.
> > * Reworked the channel ring management.
> > * Other misc changes as per review from Alex.
> >
> > Changes in v3:
> >
> > * Splitted the patch 20/23 into two.
> > * Fixed the error handling in patch 21/23.
> > * Removed spurious change in patch 01/23.
> > * Added check for xfer callbacks in client driver probe.
> >
> > Changes in v2:
> >
> > v2 mostly addresses the issues seen while testing the stack on SM8450 that is a
> > SMP platform and also incorporates the review comments from Alex.
> >
> > Major changes are:
> >
> > * Added a cleanup patch for getting rid of SHIFT macros and used the bitfield
> > operations.
> > * Added the endianess patches that were submitted to MHI list and used the
> > endianess conversion in EP patches also.
> > * Added support for multiple event rings.
> > * Fixed the MSI generation based on the event ring index.
> > * Fixed the doorbell list handling by making use of list splice and not locking
> > the entire list manipulation.
> > * Added new APIs for wrapping the reading and writing to host memory (Dmitry).
> > * Optimized the read_channel and queue_skb function logics.
> > * Added Hemant's R-o-b tag.
> >
> > Manivannan Sadhasivam (25):
> > bus: mhi: Move host MHI code to "host" directory
> > bus: mhi: Use bitfield operations for register read and write
> > bus: mhi: Use bitfield operations for handling DWORDs of ring elements
> > bus: mhi: Cleanup the register definitions used in headers
> > bus: mhi: host: Rename "struct mhi_tre" to "struct mhi_ring_element"
> > bus: mhi: Move common MHI definitions out of host directory
> > bus: mhi: Make mhi_state_str[] array static inline and move to
> > common.h
> > bus: mhi: ep: Add support for registering MHI endpoint controllers
> > bus: mhi: ep: Add support for registering MHI endpoint client drivers
> > bus: mhi: ep: Add support for creating and destroying MHI EP devices
> > bus: mhi: ep: Add support for managing MMIO registers
> > bus: mhi: ep: Add support for ring management
> > bus: mhi: ep: Add support for sending events to the host
> > bus: mhi: ep: Add support for managing MHI state machine
> > bus: mhi: ep: Add support for processing MHI endpoint interrupts
> > bus: mhi: ep: Add support for powering up the MHI endpoint stack
> > bus: mhi: ep: Add support for powering down the MHI endpoint stack
> > bus: mhi: ep: Add support for handling MHI_RESET
> > bus: mhi: ep: Add support for handling SYS_ERR condition
> > bus: mhi: ep: Add support for processing command rings
> > bus: mhi: ep: Add support for reading from the host
> > bus: mhi: ep: Add support for processing channel rings
> > bus: mhi: ep: Add support for queueing SKBs to the host
> > bus: mhi: ep: Add support for suspending and resuming channels
> > bus: mhi: ep: Add uevent support for module autoloading
> >
> > Paul Davey (2):
> > bus: mhi: Fix pm_state conversion to string
> > bus: mhi: Fix MHI DMA structure endianness
> >
> > drivers/bus/Makefile | 2 +-
> > drivers/bus/mhi/Kconfig | 28 +-
> > drivers/bus/mhi/Makefile | 9 +-
> > drivers/bus/mhi/common.h | 326 +++++
> > drivers/bus/mhi/core/internal.h | 722 ----------
> > drivers/bus/mhi/ep/Kconfig | 10 +
> > drivers/bus/mhi/ep/Makefile | 2 +
> > drivers/bus/mhi/ep/internal.h | 222 +++
> > drivers/bus/mhi/ep/main.c | 1623 ++++++++++++++++++++++
> > drivers/bus/mhi/ep/mmio.c | 272 ++++
> > drivers/bus/mhi/ep/ring.c | 197 +++
> > drivers/bus/mhi/ep/sm.c | 148 ++
> > drivers/bus/mhi/host/Kconfig | 31 +
> > drivers/bus/mhi/{core => host}/Makefile | 4 +-
> > drivers/bus/mhi/{core => host}/boot.c | 17 +-
> > drivers/bus/mhi/{core => host}/debugfs.c | 40 +-
> > drivers/bus/mhi/{core => host}/init.c | 131 +-
> > drivers/bus/mhi/host/internal.h | 382 +++++
> > drivers/bus/mhi/{core => host}/main.c | 66 +-
> > drivers/bus/mhi/{ => host}/pci_generic.c | 0
> > drivers/bus/mhi/{core => host}/pm.c | 36 +-
> > include/linux/mhi_ep.h | 284 ++++
> > include/linux/mod_devicetable.h | 2 +
> > scripts/mod/file2alias.c | 10 +
> > 24 files changed, 3649 insertions(+), 915 deletions(-)
> > create mode 100644 drivers/bus/mhi/common.h
> > delete mode 100644 drivers/bus/mhi/core/internal.h
> > create mode 100644 drivers/bus/mhi/ep/Kconfig
> > create mode 100644 drivers/bus/mhi/ep/Makefile
> > create mode 100644 drivers/bus/mhi/ep/internal.h
> > create mode 100644 drivers/bus/mhi/ep/main.c
> > create mode 100644 drivers/bus/mhi/ep/mmio.c
> > create mode 100644 drivers/bus/mhi/ep/ring.c
> > create mode 100644 drivers/bus/mhi/ep/sm.c
> > create mode 100644 drivers/bus/mhi/host/Kconfig
> > rename drivers/bus/mhi/{core => host}/Makefile (54%)
> > rename drivers/bus/mhi/{core => host}/boot.c (96%)
> > rename drivers/bus/mhi/{core => host}/debugfs.c (90%)
> > rename drivers/bus/mhi/{core => host}/init.c (92%)
> > create mode 100644 drivers/bus/mhi/host/internal.h
> > rename drivers/bus/mhi/{core => host}/main.c (97%)
> > rename drivers/bus/mhi/{ => host}/pci_generic.c (100%)
> > rename drivers/bus/mhi/{core => host}/pm.c (97%)
> > create mode 100644 include/linux/mhi_ep.h
> >
>
On Mon, Feb 28, 2022 at 06:13:17PM +0530, Manivannan Sadhasivam wrote:
> Hello,
>
> This series adds initial support for the Qualcomm specific Modem Host Interface
> (MHI) bus in endpoint devices like SDX55 modems. The MHI bus in endpoint devices
> communicates with the MHI bus in host machines like x86 over any physical bus
> like PCIe. The MHI host support is already in mainline [1] and been used by PCIe
> based modems and WLAN devices running vendor code (downstream).
>
Series applied to mhi-next with Alex's Reviewed-by tag. Also incorporated few
suggestions by Alex.
Thanks,
Mani
> Overview
> ========
>
> This series aims at adding the MHI support in the endpoint devices with the goal
> of getting data connectivity using the mainline kernel running on the modems.
> Modems here refer to the combination of an APPS processor (Cortex A grade) and
> a baseband processor (DSP). The MHI bus is located in the APPS processor and it
> transfers data packets from the baseband processor to the host machine.
>
> The MHI Endpoint (MHI EP) stack proposed here is inspired by the downstream
> code written by Qualcomm. But the complete stack is mostly re-written to adapt
> to the "bus" framework and made it modular so that it can work with the upstream
> subsystems like "PCI Endpoint". The code structure of the MHI endpoint stack
> follows the MHI host stack to maintain uniformity.
>
> With this initial MHI EP stack (along with few other drivers), we can establish
> the network interface between host and endpoint over the MHI software channels
> (IP_SW0) and can do things like IP forwarding, SSH, etc...
>
> Stack Organization
> ==================
>
> The MHI EP stack has the concept of controller and device drivers as like the
> MHI host stack. The MHI EP controller driver can be a PCI Endpoint Function
> driver and the MHI device driver can be a MHI EP Networking driver or QRTR
> driver. The MHI EP controller driver is tied to the PCI Endpoint subsystem and
> handles all bus related activities like mapping the host memory, raising IRQ,
> passing link specific events etc... The MHI EP networking driver is tied to the
> Networking stack and handles all networking related activities like
> sending/receiving the SKBs from netdev, statistics collection etc...
>
> This series only contains the MHI EP code, whereas the PCIe EPF driver and MHI
> EP Networking drivers are not yet submitted and can be found here [2]. Though
> the MHI EP stack doesn't have the build time dependency, it cannot function
> without them.
>
> Test setup
> ==========
>
> This series has been tested on Telit FN980 TLB board powered by Qualcomm SDX55
> (a.k.a X55 modem) and Qualcomm SM8450 based dev board.
>
> For testing the stability and performance, networking tools such as iperf, ssh
> and ping are used.
>
> Limitations
> ===========
>
> We are not _yet_ there to get the data packets from the modem as that involves
> the Qualcomm IP Accelerator (IPA) integration with MHI endpoint stack. But we
> are planning to add support for it in the coming days.
>
> References
> ==========
>
> MHI bus: https://www.kernel.org/doc/html/latest/mhi/mhi.html
> Linaro connect presentation around this topic: https://connect.linaro.org/resources/lvc21f/lvc21f-222/
>
> Thanks,
> Mani
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/bus/mhi
> [2] https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/log/?h=tracking-qcomlt-sdx55-drivers
>
> Changes in v4:
>
> * Collected reviews from Hemant and Alex.
> * Removed the A7 suffix from register names and functions.
> * Added a couple of cleanup patches.
> * Reworked the mhi_ep_queue_skb() API.
> * Switched to separate workers for command and transfer rings.
> * Used a common workqueue for state and ring management.
> * Reworked the channel ring management.
> * Other misc changes as per review from Alex.
>
> Changes in v3:
>
> * Splitted the patch 20/23 into two.
> * Fixed the error handling in patch 21/23.
> * Removed spurious change in patch 01/23.
> * Added check for xfer callbacks in client driver probe.
>
> Changes in v2:
>
> v2 mostly addresses the issues seen while testing the stack on SM8450 that is a
> SMP platform and also incorporates the review comments from Alex.
>
> Major changes are:
>
> * Added a cleanup patch for getting rid of SHIFT macros and used the bitfield
> operations.
> * Added the endianess patches that were submitted to MHI list and used the
> endianess conversion in EP patches also.
> * Added support for multiple event rings.
> * Fixed the MSI generation based on the event ring index.
> * Fixed the doorbell list handling by making use of list splice and not locking
> the entire list manipulation.
> * Added new APIs for wrapping the reading and writing to host memory (Dmitry).
> * Optimized the read_channel and queue_skb function logics.
> * Added Hemant's R-o-b tag.
>
> Manivannan Sadhasivam (25):
> bus: mhi: Move host MHI code to "host" directory
> bus: mhi: Use bitfield operations for register read and write
> bus: mhi: Use bitfield operations for handling DWORDs of ring elements
> bus: mhi: Cleanup the register definitions used in headers
> bus: mhi: host: Rename "struct mhi_tre" to "struct mhi_ring_element"
> bus: mhi: Move common MHI definitions out of host directory
> bus: mhi: Make mhi_state_str[] array static inline and move to
> common.h
> bus: mhi: ep: Add support for registering MHI endpoint controllers
> bus: mhi: ep: Add support for registering MHI endpoint client drivers
> bus: mhi: ep: Add support for creating and destroying MHI EP devices
> bus: mhi: ep: Add support for managing MMIO registers
> bus: mhi: ep: Add support for ring management
> bus: mhi: ep: Add support for sending events to the host
> bus: mhi: ep: Add support for managing MHI state machine
> bus: mhi: ep: Add support for processing MHI endpoint interrupts
> bus: mhi: ep: Add support for powering up the MHI endpoint stack
> bus: mhi: ep: Add support for powering down the MHI endpoint stack
> bus: mhi: ep: Add support for handling MHI_RESET
> bus: mhi: ep: Add support for handling SYS_ERR condition
> bus: mhi: ep: Add support for processing command rings
> bus: mhi: ep: Add support for reading from the host
> bus: mhi: ep: Add support for processing channel rings
> bus: mhi: ep: Add support for queueing SKBs to the host
> bus: mhi: ep: Add support for suspending and resuming channels
> bus: mhi: ep: Add uevent support for module autoloading
>
> Paul Davey (2):
> bus: mhi: Fix pm_state conversion to string
> bus: mhi: Fix MHI DMA structure endianness
>
> drivers/bus/Makefile | 2 +-
> drivers/bus/mhi/Kconfig | 28 +-
> drivers/bus/mhi/Makefile | 9 +-
> drivers/bus/mhi/common.h | 326 +++++
> drivers/bus/mhi/core/internal.h | 722 ----------
> drivers/bus/mhi/ep/Kconfig | 10 +
> drivers/bus/mhi/ep/Makefile | 2 +
> drivers/bus/mhi/ep/internal.h | 222 +++
> drivers/bus/mhi/ep/main.c | 1623 ++++++++++++++++++++++
> drivers/bus/mhi/ep/mmio.c | 272 ++++
> drivers/bus/mhi/ep/ring.c | 197 +++
> drivers/bus/mhi/ep/sm.c | 148 ++
> drivers/bus/mhi/host/Kconfig | 31 +
> drivers/bus/mhi/{core => host}/Makefile | 4 +-
> drivers/bus/mhi/{core => host}/boot.c | 17 +-
> drivers/bus/mhi/{core => host}/debugfs.c | 40 +-
> drivers/bus/mhi/{core => host}/init.c | 131 +-
> drivers/bus/mhi/host/internal.h | 382 +++++
> drivers/bus/mhi/{core => host}/main.c | 66 +-
> drivers/bus/mhi/{ => host}/pci_generic.c | 0
> drivers/bus/mhi/{core => host}/pm.c | 36 +-
> include/linux/mhi_ep.h | 284 ++++
> include/linux/mod_devicetable.h | 2 +
> scripts/mod/file2alias.c | 10 +
> 24 files changed, 3649 insertions(+), 915 deletions(-)
> create mode 100644 drivers/bus/mhi/common.h
> delete mode 100644 drivers/bus/mhi/core/internal.h
> create mode 100644 drivers/bus/mhi/ep/Kconfig
> create mode 100644 drivers/bus/mhi/ep/Makefile
> create mode 100644 drivers/bus/mhi/ep/internal.h
> create mode 100644 drivers/bus/mhi/ep/main.c
> create mode 100644 drivers/bus/mhi/ep/mmio.c
> create mode 100644 drivers/bus/mhi/ep/ring.c
> create mode 100644 drivers/bus/mhi/ep/sm.c
> create mode 100644 drivers/bus/mhi/host/Kconfig
> rename drivers/bus/mhi/{core => host}/Makefile (54%)
> rename drivers/bus/mhi/{core => host}/boot.c (96%)
> rename drivers/bus/mhi/{core => host}/debugfs.c (90%)
> rename drivers/bus/mhi/{core => host}/init.c (92%)
> create mode 100644 drivers/bus/mhi/host/internal.h
> rename drivers/bus/mhi/{core => host}/main.c (97%)
> rename drivers/bus/mhi/{ => host}/pci_generic.c (100%)
> rename drivers/bus/mhi/{core => host}/pm.c (97%)
> create mode 100644 include/linux/mhi_ep.h
>
> --
> 2.25.1
>