Merge tag 'mhi-for-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Apr 2023 13:06:11 +0000 (15:06 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Apr 2023 13:06:11 +0000 (15:06 +0200)
Manivannan writes:

MHI Host
========

Core
----

- Removed the "mhi_poll()" API as there are no in-kernel users available at the
  moment.

- Added range check for the CHDBOFF and ERDBOFF registers in case the device
  reports bad values.

- Fixed the errno for the rest of the range checks to use -ERANGE.

- Modified the event ring handlers to ring the doorbell only if there are
  any pending elements in the ring to process for the device.

- Removed the check for EE (Execution Environment) while processing the SYS_ERR
  transition as it creates device recovery issues when SBL (Secondary
  Bootloader) crashes early.

- Used mhi_tryset_pm_state() API to set the error state instead of open coding
  if the firmware loading fails. This avoids the race with other pm_state
  updates.

pci_generic
-----------

- Dropped the dedundant pci_{enable/disable}_pcie_error_reporting() calls from
  driver probe's error path as the PCI core itself takes care of that now.

- Revered the commit 2d5253a096c6 ("bus: mhi: host: pci_generic: Add a secondary
  AT port to Telit FN990") as it turned out to be erroneous. This happened due
  to the patch adding secondary AT port for FN990 getting applied through NET
  and MHI trees and this caused two commits for the same functionality but one
  of them ended up wrong.

- Added support for Foxconn T99W510 modem based on SDX24 chipset from Qualcomm.

MHI Endpoint
============

- Demoted the channel not supported error log to debug as not all devices will
  support all channels defined in MHI spec and this may spam users.

* tag 'mhi-for-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi:
  bus: mhi: host: Use mhi_tryset_pm_state() for setting fw error state
  bus: mhi: host: Remove duplicate ee check for syserr
  bus: mhi: host: Avoid ringing EV DB if there are no elements to process
  bus: mhi: pci_generic: Add Foxconn T99W510
  bus: mhi: host: Use ERANGE for BHIOFF/BHIEOFF range check
  bus: mhi: host: Range check CHDBOFF and ERDBOFF
  bus: mhi: host: pci_generic: Revert "Add a secondary AT port to Telit FN990"
  bus: mhi: host: pci_generic: Drop redundant pci_enable_pcie_error_reporting()
  bus: mhi: ep: Demote unsupported channel error log to debug
  bus: mhi: host: Remove mhi_poll() API

drivers/bus/mhi/ep/main.c
drivers/bus/mhi/host/boot.c
drivers/bus/mhi/host/init.c
drivers/bus/mhi/host/main.c
drivers/bus/mhi/host/pci_generic.c
include/linux/mhi.h

index a6a48e5154784f133f66122d3faaf2bb0aea9551..600881808982aa5686636ccd2bf9a19892a25177 100644 (file)
@@ -126,7 +126,7 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele
 
        /* Check if the channel is supported by the controller */
        if ((ch_id >= mhi_cntrl->max_chan) || !mhi_cntrl->mhi_chan[ch_id].name) {
-               dev_err(dev, "Channel (%u) not supported!\n", ch_id);
+               dev_dbg(dev, "Channel (%u) not supported!\n", ch_id);
                return -ENODEV;
        }
 
@@ -702,7 +702,7 @@ static void mhi_ep_cmd_ring_worker(struct work_struct *work)
                el = &ring->ring_cache[ring->rd_offset];
 
                ret = mhi_ep_process_cmd_ring(ring, el);
-               if (ret)
+               if (ret && ret != -ENODEV)
                        dev_err(dev, "Error processing cmd ring element: %zu\n", ring->rd_offset);
 
                mhi_ep_ring_inc_index(ring);
index 1c69feee1703005db11c911d86e7dff0d4cb3a7a..d2a19b07ccb885fbeeb996a9cb8216ae55d1803b 100644 (file)
@@ -391,6 +391,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
 {
        const struct firmware *firmware = NULL;
        struct device *dev = &mhi_cntrl->mhi_dev->dev;
+       enum mhi_pm_state new_state;
        const char *fw_name;
        void *buf;
        dma_addr_t dma_addr;
@@ -508,14 +509,18 @@ error_ready_state:
        }
 
 error_fw_load:
-       mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR;
-       wake_up_all(&mhi_cntrl->state_event);
+       write_lock_irq(&mhi_cntrl->pm_lock);
+       new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_FW_DL_ERR);
+       write_unlock_irq(&mhi_cntrl->pm_lock);
+       if (new_state == MHI_PM_FW_DL_ERR)
+               wake_up_all(&mhi_cntrl->state_event);
 }
 
 int mhi_download_amss_image(struct mhi_controller *mhi_cntrl)
 {
        struct image_info *image_info = mhi_cntrl->fbc_image;
        struct device *dev = &mhi_cntrl->mhi_dev->dev;
+       enum mhi_pm_state new_state;
        int ret;
 
        if (!image_info)
@@ -526,8 +531,11 @@ int mhi_download_amss_image(struct mhi_controller *mhi_cntrl)
                               &image_info->mhi_buf[image_info->entries - 1]);
        if (ret) {
                dev_err(dev, "MHI did not load AMSS, ret:%d\n", ret);
-               mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR;
-               wake_up_all(&mhi_cntrl->state_event);
+               write_lock_irq(&mhi_cntrl->pm_lock);
+               new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_FW_DL_ERR);
+               write_unlock_irq(&mhi_cntrl->pm_lock);
+               if (new_state == MHI_PM_FW_DL_ERR)
+                       wake_up_all(&mhi_cntrl->state_event);
        }
 
        return ret;
index 3d779ee6396d556e9f41a1cd5f773ca4f2bc08c3..f72fcb66f408a6cf589c7039322ea2064a6ad6a3 100644 (file)
@@ -516,6 +516,12 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
                return -EIO;
        }
 
+       if (val >= mhi_cntrl->reg_len - (8 * MHI_DEV_WAKE_DB)) {
+               dev_err(dev, "CHDB offset: 0x%x is out of range: 0x%zx\n",
+                       val, mhi_cntrl->reg_len - (8 * MHI_DEV_WAKE_DB));
+               return -ERANGE;
+       }
+
        /* Setup wake db */
        mhi_cntrl->wake_db = base + val + (8 * MHI_DEV_WAKE_DB);
        mhi_cntrl->wake_set = false;
@@ -532,6 +538,12 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
                return -EIO;
        }
 
+       if (val >= mhi_cntrl->reg_len - (8 * mhi_cntrl->total_ev_rings)) {
+               dev_err(dev, "ERDB offset: 0x%x is out of range: 0x%zx\n",
+                       val, mhi_cntrl->reg_len - (8 * mhi_cntrl->total_ev_rings));
+               return -ERANGE;
+       }
+
        /* Setup event db address for each ev_ring */
        mhi_event = mhi_cntrl->mhi_event;
        for (i = 0; i < mhi_cntrl->total_ev_rings; i++, val += 8, mhi_event++) {
@@ -1100,7 +1112,7 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
        if (bhi_off >= mhi_cntrl->reg_len) {
                dev_err(dev, "BHI offset: 0x%x is out of range: 0x%zx\n",
                        bhi_off, mhi_cntrl->reg_len);
-               ret = -EINVAL;
+               ret = -ERANGE;
                goto error_reg_offset;
        }
        mhi_cntrl->bhi = mhi_cntrl->regs + bhi_off;
@@ -1117,7 +1129,7 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
                        dev_err(dev,
                                "BHIe offset: 0x%x is out of range: 0x%zx\n",
                                bhie_off, mhi_cntrl->reg_len);
-                       ret = -EINVAL;
+                       ret = -ERANGE;
                        goto error_reg_offset;
                }
                mhi_cntrl->bhie = mhi_cntrl->regs + bhie_off;
index df0fbfee7b78b093387a7c24aa223ceed17846a7..74a75439c713054dbf59aa39ae17d43c46feb824 100644 (file)
@@ -503,7 +503,7 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv)
        }
        write_unlock_irq(&mhi_cntrl->pm_lock);
 
-       if (pm_state != MHI_PM_SYS_ERR_DETECT || ee == mhi_cntrl->ee)
+       if (pm_state != MHI_PM_SYS_ERR_DETECT)
                goto exit_intvec;
 
        switch (ee) {
@@ -961,7 +961,9 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
        }
 
        read_lock_bh(&mhi_cntrl->pm_lock);
-       if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)))
+
+       /* Ring EV DB only if there is any pending element to process */
+       if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)) && count)
                mhi_ring_er_db(mhi_event);
        read_unlock_bh(&mhi_cntrl->pm_lock);
 
@@ -1031,7 +1033,9 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl,
                count++;
        }
        read_lock_bh(&mhi_cntrl->pm_lock);
-       if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)))
+
+       /* Ring EV DB only if there is any pending element to process */
+       if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)) && count)
                mhi_ring_er_db(mhi_event);
        read_unlock_bh(&mhi_cntrl->pm_lock);
 
@@ -1679,18 +1683,3 @@ void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev)
        }
 }
 EXPORT_SYMBOL_GPL(mhi_unprepare_from_transfer);
-
-int mhi_poll(struct mhi_device *mhi_dev, u32 budget)
-{
-       struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
-       struct mhi_chan *mhi_chan = mhi_dev->dl_chan;
-       struct mhi_event *mhi_event = &mhi_cntrl->mhi_event[mhi_chan->er_index];
-       int ret;
-
-       spin_lock_bh(&mhi_event->lock);
-       ret = mhi_event->process_event(mhi_cntrl, mhi_event, budget);
-       spin_unlock_bh(&mhi_event->lock);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(mhi_poll);
index f39657f71483cb9d814a62bdbb51a1a3a489af08..db0a0b062d8e07df9ddbafaab2a6dd37ab932aff 100644 (file)
@@ -8,7 +8,6 @@
  * Copyright (C) 2020 Linaro Ltd <loic.poulain@linaro.org>
  */
 
-#include <linux/aer.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/mhi.h>
@@ -344,8 +343,6 @@ static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = {
        MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0),
        MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0),
        MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0),
-       MHI_CHANNEL_CONFIG_UL(92, "DUN2", 32, 1),
-       MHI_CHANNEL_CONFIG_DL(93, "DUN2", 32, 1),
        MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2),
        MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3),
 };
@@ -366,6 +363,15 @@ static const struct mhi_controller_config modem_foxconn_sdx55_config = {
        .event_cfg = mhi_foxconn_sdx55_events,
 };
 
+static const struct mhi_pci_dev_info mhi_foxconn_sdx24_info = {
+       .name = "foxconn-sdx24",
+       .config = &modem_foxconn_sdx55_config,
+       .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
+       .dma_data_width = 32,
+       .mru_default = 32768,
+       .sideband_wake = false,
+};
+
 static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = {
        .name = "foxconn-sdx55",
        .fw = "qcom/sdx55m/sbl1.mbn",
@@ -590,6 +596,15 @@ static const struct pci_device_id mhi_pci_id_table[] = {
        /* T99W373 (sdx62) */
        { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0d9),
                .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info },
+       /* T99W510 (sdx24), variant 1 */
+       { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f0),
+               .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info },
+       /* T99W510 (sdx24), variant 2 */
+       { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f1),
+               .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info },
+       /* T99W510 (sdx24), variant 3 */
+       { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f2),
+               .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info },
        /* MV31-W (Cinterion) */
        { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b3),
                .driver_data = (kernel_ulong_t) &mhi_mv31_info },
@@ -903,11 +918,9 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        mhi_pdev->pci_state = pci_store_saved_state(pdev);
        pci_load_saved_state(pdev, NULL);
 
-       pci_enable_pcie_error_reporting(pdev);
-
        err = mhi_register_controller(mhi_cntrl, mhi_cntrl_config);
        if (err)
-               goto err_disable_reporting;
+               return err;
 
        /* MHI bus does not power up the controller by default */
        err = mhi_prepare_for_power_up(mhi_cntrl);
@@ -941,8 +954,6 @@ err_unprepare:
        mhi_unprepare_after_power_down(mhi_cntrl);
 err_unregister:
        mhi_unregister_controller(mhi_cntrl);
-err_disable_reporting:
-       pci_disable_pcie_error_reporting(pdev);
 
        return err;
 }
@@ -965,7 +976,6 @@ static void mhi_pci_remove(struct pci_dev *pdev)
                pm_runtime_get_noresume(&pdev->dev);
 
        mhi_unregister_controller(mhi_cntrl);
-       pci_disable_pcie_error_reporting(pdev);
 }
 
 static void mhi_pci_shutdown(struct pci_dev *pdev)
index a5441ad33c74a9b4c87f326e5dab10efa547d463..f6de4b6ecfc74e359874a22cd810252974f673fe 100644 (file)
@@ -765,13 +765,6 @@ int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev);
  */
 void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev);
 
-/**
- * mhi_poll - Poll for any available data in DL direction
- * @mhi_dev: Device associated with the channels
- * @budget: # of events to process
- */
-int mhi_poll(struct mhi_device *mhi_dev, u32 budget);
-
 /**
  * mhi_queue_dma - Send or receive DMA mapped buffers from client device
  *                 over MHI channel