From 220c2f0aeda0dd8fa75097c9dea453b4792097ae Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Sat, 3 Jun 2017 18:36:46 -0700 Subject: [PATCH 1/2] mhi: core: Add support for PCIe linkdown abort PCIe linkdown event can trigger anytime. During linkdown event abort any work MHI host doing that require PCIE link. CRs-Fixed: 2055975 Change-Id: Idba907c7977594dc08575e0020a7afa4868bc0e4 Signed-off-by: Sujeev Dias --- drivers/platform/msm/mhi/mhi_bhi.c | 20 +++++--- drivers/platform/msm/mhi/mhi_pm.c | 66 ++++++++++++++++++++------- drivers/platform/msm/mhi/mhi_states.c | 5 +- 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c index e1c50e1273ac..cff96a486e08 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.c +++ b/drivers/platform/msm/mhi/mhi_bhi.c @@ -439,7 +439,6 @@ void bhi_firmware_download(struct work_struct *work) struct bhi_ctxt_t *bhi_ctxt; struct bhie_mem_info mem_info; int ret; - long timeout; mhi_dev_ctxt = container_of(work, struct mhi_device_ctxt, bhi_ctxt.fw_load_work); @@ -448,7 +447,14 @@ void bhi_firmware_download(struct work_struct *work) mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enter\n"); wait_event_interruptible(*mhi_dev_ctxt->mhi_ev_wq.bhi_event, - mhi_dev_ctxt->mhi_state == MHI_STATE_BHI); + mhi_dev_ctxt->mhi_state == MHI_STATE_BHI || + mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT); + if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT || + mhi_dev_ctxt->mhi_state != MHI_STATE_BHI) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "MHI is not in valid state for firmware download\n"); + return; + } /* PBL image is the first segment in firmware vector table */ mem_info = *bhi_ctxt->fw_table.bhie_mem_info; @@ -462,10 +468,12 @@ void bhi_firmware_download(struct work_struct *work) mhi_init_state_transition(mhi_dev_ctxt, STATE_TRANSITION_RESET); - timeout = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.bhi_event, - mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_BHIE, - msecs_to_jiffies(bhi_ctxt->poll_timeout)); - if (!timeout) { + wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.bhi_event, + mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_BHIE || + mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT, + msecs_to_jiffies(bhi_ctxt->poll_timeout)); + if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT || + mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_BHIE) { mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to Enter EXEC_ENV_BHIE\n"); return; diff --git a/drivers/platform/msm/mhi/mhi_pm.c b/drivers/platform/msm/mhi/mhi_pm.c index caa34eadf8ea..fdaba493fc98 100644 --- a/drivers/platform/msm/mhi/mhi_pm.c +++ b/drivers/platform/msm/mhi/mhi_pm.c @@ -97,12 +97,14 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event, - mhi_dev_ctxt->mhi_state == MHI_STATE_M0 || - mhi_dev_ctxt->mhi_state == MHI_STATE_M1, - msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); - if (!r) { + mhi_dev_ctxt->mhi_state == MHI_STATE_M0 || + mhi_dev_ctxt->mhi_state == MHI_STATE_M1 || + mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT, + msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); + if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) { mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, - "Failed to get M0||M1 event, timeout, current state:%s\n", + "Failed to get M0||M1 event or LD pm_state:0x%x state:%s\n", + mhi_dev_ctxt->mhi_pm_state, TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); return -EIO; } @@ -122,9 +124,10 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt, write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Waiting for M3 completion.\n"); r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event, - mhi_dev_ctxt->mhi_state == MHI_STATE_M3, - msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT)); - if (!r) { + mhi_dev_ctxt->mhi_state == MHI_STATE_M3 || + mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT, + msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT)); + if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) { mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to get M3 event, timeout, current state:%s\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); @@ -158,12 +161,13 @@ static int mhi_pm_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt) mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M0); write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event, - mhi_dev_ctxt->mhi_state == MHI_STATE_M0 || - mhi_dev_ctxt->mhi_state == MHI_STATE_M1, - msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); - if (!r) { + mhi_dev_ctxt->mhi_state == MHI_STATE_M0 || + mhi_dev_ctxt->mhi_state == MHI_STATE_M1 || + mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT, + msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); + if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) { mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, - "Failed to get M0 event, timeout\n"); + "Failed to get M0 event, timeout or LD\n"); r = -EIO; } else r = 0; @@ -295,13 +299,16 @@ static int mhi_pm_slave_mode_power_on(struct mhi_device_ctxt *mhi_dev_ctxt) mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); read_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); - ret_val = wait_for_completion_timeout(&mhi_dev_ctxt->cmd_complete, - msecs_to_jiffies(timeout)); - if (!ret_val || mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_AMSS) + wait_for_completion_timeout(&mhi_dev_ctxt->cmd_complete, + msecs_to_jiffies(timeout)); + if (mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_AMSS) ret_val = -EIO; else ret_val = 0; + /* wait for firmware download to complete */ + flush_work(&mhi_dev_ctxt->bhi_ctxt.fw_load_work); + if (ret_val) { read_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); @@ -563,9 +570,28 @@ int mhi_pm_control_device(struct mhi_device *mhi_device, case MHI_DEV_CTRL_RDDM: return bhi_rddm(mhi_dev_ctxt, false); case MHI_DEV_CTRL_DE_INIT: - if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE) + if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE) { + enum MHI_PM_STATE cur_state; + /* + * If bus master calls DE_INIT before calling POWER_OFF + * means a critical failure occurred during POWER_ON + * state transition and external PCIe device may not + * respond to host. Force PM state to PCIe linkdown + * state prior to starting shutdown process to avoid + * accessing PCIe link. + */ + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, + MHI_PM_LD_ERR_FATAL_DETECT); + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + if (unlikely(cur_state != MHI_PM_LD_ERR_FATAL_DETECT)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to transition to state 0x%x from 0x%x\n", + MHI_PM_LD_ERR_FATAL_DETECT, cur_state); + } process_disable_transition(MHI_PM_SHUTDOWN_PROCESS, mhi_dev_ctxt); + } bhi_exit(mhi_dev_ctxt); break; case MHI_DEV_CTRL_NOTIFY_LINK_ERROR: @@ -580,6 +606,12 @@ int mhi_pm_control_device(struct mhi_device *mhi_device, mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Failed to transition to state 0x%x from 0x%x\n", MHI_PM_LD_ERR_FATAL_DETECT, cur_state); + + /* wake up all threads that's waiting for state change events */ + complete(&mhi_dev_ctxt->cmd_complete); + wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.bhi_event); + wake_up(mhi_dev_ctxt->mhi_ev_wq.m0_event); + wake_up(mhi_dev_ctxt->mhi_ev_wq.m3_event); break; } default: diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c index 2906393cbd5c..ea2a91bd2d06 100644 --- a/drivers/platform/msm/mhi/mhi_states.c +++ b/drivers/platform/msm/mhi/mhi_states.c @@ -147,7 +147,8 @@ void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt, * M1 -> M3_ENTER --> M3 * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR * L2: SHUTDOWN_PROCESS -> DISABLE -> SSR_PENDING (via SSR Notification only) - * L3: LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS + * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT + * LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS */ static const struct mhi_pm_transitions const mhi_state_transitions[] = { /* L0 States */ @@ -216,7 +217,7 @@ static const struct mhi_pm_transitions const mhi_state_transitions[] = { /* L3 States */ { MHI_PM_LD_ERR_FATAL_DETECT, - MHI_PM_SHUTDOWN_PROCESS + MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_PROCESS }, /* From SSR notification only */ { From 90bf661847845b2e3e9c52cdbb257ff3f707ca1c Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Tue, 16 May 2017 15:19:16 -0700 Subject: [PATCH 2/2] mhi: core: Add support for host triggered device ram dump Add support for bus master to trigger PCIe device into ram dump mode to collect device ram dump. RDDM capabilities are extended to support under kernel panic as well. CRs-Fixed: 2055981 Change-Id: I18f7d5784992df70aafc6e41d248ced3fac37181 Signed-off-by: Sujeev Dias --- drivers/platform/msm/mhi/mhi_bhi.c | 97 +++++++++++++++++++++++++++++- drivers/platform/msm/mhi/mhi_bhi.h | 1 + drivers/platform/msm/mhi/mhi_pm.c | 39 ++++++++++-- include/linux/msm_mhi.h | 2 + 4 files changed, 132 insertions(+), 7 deletions(-) diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c index cff96a486e08..4354b2600472 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.c +++ b/drivers/platform/msm/mhi/mhi_bhi.c @@ -249,6 +249,13 @@ int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic) { struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table; + struct bhie_mem_info *bhie_mem_info; + u32 rx_sequence, val, current_seq; + u32 timeout = (bhi_ctxt->poll_timeout * 1000) / BHIE_RDDM_DELAY_TIME_US; + int i; + u32 cur_exec, prev_exec = 0; + u32 state, prev_state = 0; + u32 rx_status, prev_status = 0; if (!rddm_table->bhie_mem_info) { mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "RDDM table == NULL\n"); @@ -258,9 +265,93 @@ int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic) if (!in_panic) return bhi_rddm_graceful(mhi_dev_ctxt); - mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, - "RDDM collection in panic not yet supported\n"); - return -EINVAL; + /* + * Below code should only be executed during kernel panic, + * we expect other cores to be shutting down while we're + * executing rddm transfer. After returning from this function, + * we expect device to reset. + */ + + /* Trigger device into RDDM */ + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "pm_state:0x%x mhi_state:%s\n", + mhi_dev_ctxt->mhi_pm_state, + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); + if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Register access not allowed\n"); + return -EIO; + } + + /* + * Normally we only set mhi_pm_state after grabbing pm_xfer_lock as a + * write, by function mhi_tryset_pm_state. Since we're in a kernel + * panic, we will set pm state w/o grabbing xfer lock. We're setting + * pm_state to LD as a safety precautions. If another core in middle + * of register access this should deter it. However, there is no + * no gurantee change will take effect. + */ + mhi_dev_ctxt->mhi_pm_state = MHI_PM_LD_ERR_FATAL_DETECT; + /* change should take effect immediately */ + smp_wmb(); + + bhie_mem_info = &rddm_table-> + bhie_mem_info[rddm_table->segment_count - 1]; + rx_sequence = rddm_table->sequence++; + + /* program the vector table */ + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Programming RXVEC table\n"); + val = HIGH_WORD(bhie_mem_info->phys_addr); + mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, + BHIE_RXVECADDR_HIGH_OFFS, val); + val = LOW_WORD(bhie_mem_info->phys_addr); + mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHIE_RXVECADDR_LOW_OFFS, + val); + val = (u32)bhie_mem_info->size; + mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHIE_RXVECSIZE_OFFS, + val); + mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHIE_RXVECDB_OFFS, + BHIE_TXVECDB_SEQNUM_BMSK, BHIE_TXVECDB_SEQNUM_SHFT, + rx_sequence); + + /* trigger device into rddm */ + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Triggering Device into RDDM mode\n"); + mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_SYS_ERR); + i = 0; + + while (timeout--) { + cur_exec = mhi_reg_read(bhi_ctxt->bhi_base, BHI_EXECENV); + state = mhi_get_m_state(mhi_dev_ctxt); + rx_status = mhi_reg_read(bhi_ctxt->bhi_base, + BHIE_RXVECSTATUS_OFFS); + /* if reg. values changed or each sec (udelay(1000)) log it */ + if (cur_exec != prev_exec || state != prev_state || + rx_status != prev_status || !(i & (SZ_1K - 1))) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "EXECENV:0x%x MHISTATE:0x%x RXSTATUS:0x%x\n", + cur_exec, state, rx_status); + prev_exec = cur_exec; + prev_state = state; + prev_status = rx_status; + }; + current_seq = (rx_status & BHIE_TXVECSTATUS_SEQNUM_BMSK) >> + BHIE_TXVECSTATUS_SEQNUM_SHFT; + rx_status = (rx_status & BHIE_TXVECSTATUS_STATUS_BMSK) >> + BHIE_TXVECSTATUS_STATUS_SHFT; + + if ((rx_status == BHIE_TXVECSTATUS_STATUS_XFER_COMPL) && + (current_seq == rx_sequence)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "rddm transfer completed\n"); + return 0; + } + udelay(BHIE_RDDM_DELAY_TIME_US); + i++; + } + + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "rddm transfer timeout\n"); + + return -EIO; } static int bhi_load_firmware(struct mhi_device_ctxt *mhi_dev_ctxt, diff --git a/drivers/platform/msm/mhi/mhi_bhi.h b/drivers/platform/msm/mhi/mhi_bhi.h index 8f7b3d69347c..8f9bc52bbbe0 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.h +++ b/drivers/platform/msm/mhi/mhi_bhi.h @@ -87,6 +87,7 @@ #define BHI_POLL_SLEEP_TIME_MS 100 #define BHI_POLL_TIMEOUT_MS 2000 +#define BHIE_RDDM_DELAY_TIME_US (1000) int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt); void bhi_firmware_download(struct work_struct *work); diff --git a/drivers/platform/msm/mhi/mhi_pm.c b/drivers/platform/msm/mhi/mhi_pm.c index fdaba493fc98..ad9a6fd6b278 100644 --- a/drivers/platform/msm/mhi/mhi_pm.c +++ b/drivers/platform/msm/mhi/mhi_pm.c @@ -22,6 +22,22 @@ #include "mhi_hwio.h" #include "mhi_bhi.h" +static const char *const mhi_dev_ctrl_str[MHI_DEV_CTRL_MAXCMD] = { + [MHI_DEV_CTRL_INIT] = "INIT", + [MHI_DEV_CTRL_DE_INIT] = "DE-INIT", + [MHI_DEV_CTRL_SUSPEND] = "SUSPEND", + [MHI_DEV_CTRL_RESUME] = "RESUME", + [MHI_DEV_CTRL_POWER_OFF] = "OFF", + [MHI_DEV_CTRL_POWER_ON] = "ON", + [MHI_DEV_CTRL_TRIGGER_RDDM] = "TRIGGER RDDM", + [MHI_DEV_CTRL_RDDM] = "RDDM", + [MHI_DEV_CTRL_RDDM_KERNEL_PANIC] = "RDDM IN PANIC", + [MHI_DEV_CTRL_NOTIFY_LINK_ERROR] = "LD", +}; + +#define TO_MHI_DEV_CTRL_STR(cmd) ((cmd >= MHI_DEV_CTRL_MAXCMD) ? "INVALID" : \ + mhi_dev_ctrl_str[cmd]) + /* Write only sysfs attributes */ static DEVICE_ATTR(MHI_M0, S_IWUSR, NULL, sysfs_init_m0); static DEVICE_ATTR(MHI_M3, S_IWUSR, NULL, sysfs_init_m3); @@ -544,16 +560,16 @@ void mhi_link_state_cb(struct msm_pcie_notify *notify) } } -int mhi_pm_control_device(struct mhi_device *mhi_device, - enum mhi_dev_ctrl ctrl) +int mhi_pm_control_device(struct mhi_device *mhi_device, enum mhi_dev_ctrl ctrl) { struct mhi_device_ctxt *mhi_dev_ctxt = mhi_device->mhi_dev_ctxt; + unsigned long flags; if (!mhi_dev_ctxt) return -EINVAL; - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Entered with cmd:%d\n", ctrl); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered with cmd:%s\n", + TO_MHI_DEV_CTRL_STR(ctrl)); switch (ctrl) { case MHI_DEV_CTRL_INIT: @@ -567,8 +583,23 @@ int mhi_pm_control_device(struct mhi_device *mhi_device, case MHI_DEV_CTRL_POWER_OFF: mhi_pm_slave_mode_power_off(mhi_dev_ctxt); break; + case MHI_DEV_CTRL_TRIGGER_RDDM: + write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); + if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { + write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, + flags); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "failed to trigger rddm, no register access in state:0x%x\n", + mhi_dev_ctxt->mhi_pm_state); + return -EIO; + } + mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_SYS_ERR); + write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); + break; case MHI_DEV_CTRL_RDDM: return bhi_rddm(mhi_dev_ctxt, false); + case MHI_DEV_CTRL_RDDM_KERNEL_PANIC: + return bhi_rddm(mhi_dev_ctxt, true); case MHI_DEV_CTRL_DE_INIT: if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE) { enum MHI_PM_STATE cur_state; diff --git a/include/linux/msm_mhi.h b/include/linux/msm_mhi.h index 01fe2e78b9d5..1704cb93e6a3 100644 --- a/include/linux/msm_mhi.h +++ b/include/linux/msm_mhi.h @@ -160,9 +160,11 @@ enum mhi_dev_ctrl { MHI_DEV_CTRL_RESUME, MHI_DEV_CTRL_POWER_OFF, MHI_DEV_CTRL_POWER_ON, + MHI_DEV_CTRL_TRIGGER_RDDM, MHI_DEV_CTRL_RDDM, MHI_DEV_CTRL_RDDM_KERNEL_PANIC, MHI_DEV_CTRL_NOTIFY_LINK_ERROR, + MHI_DEV_CTRL_MAXCMD, }; enum mhi_rddm_segment {