Skip to content

Commit d943fa6

Browse files
committed
Merge tag 'mhi-for-v6.18' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mani/mhi into char-misc-next
Manivannan writes: MHI Host ======== - Add support for all Foxconn T99W696 SKU variants - Fix accessing the uninitialized 'dev' pointer in mhi_init_irq_setup() - Notify the MHI Execution Environment (EE) change to userspace using uevent - Add support for Virtual Functions (VFs) in SR-IOV capable QDU100 device from Qualcomm. For adding SR-IOV support, MHI pci_generic driver has been modified to apply different configurations for PFs and VFs. MHI Endpoint ============ - Fix the handling of chained transfers in EP MHI driver that leads to reading past the host transfer buffers causing IOMMU faults in the host and other issues. * tag 'mhi-for-v6.18' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mani/mhi: bus: mhi: host: pci_generic: Set DMA mask for VFs bus: mhi: core: Improve mhi_sync_power_up handling for SYS_ERR state bus: mhi: host: pci_generic: Reset QDU100 while the MHI driver is removed bus: mhi: host: pci_generic: Add SRIOV support bus: mhi: host: pci_generic: Read SUBSYSTEM_VENDOR_ID for VF's to check status bus: mhi: host: Add support for separate controller configurations for VF and PF bus: mhi: ep: Fix chained transfer handling in read path bus: mhi: host: Notify EE change via uevent bus: mhi: host: Do not use uninitialized 'dev' pointer in mhi_init_irq_setup() bus: mhi: host: pci_generic: Add support for all Foxconn T99W696 SKU variants
2 parents fc3e44e + 54c6774 commit d943fa6

File tree

6 files changed

+103
-57
lines changed

6 files changed

+103
-57
lines changed

drivers/bus/mhi/ep/main.c

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -403,17 +403,13 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
403403
{
404404
struct mhi_ep_chan *mhi_chan = &mhi_cntrl->mhi_chan[ring->ch_id];
405405
struct device *dev = &mhi_cntrl->mhi_dev->dev;
406-
size_t tr_len, read_offset, write_offset;
406+
size_t tr_len, read_offset;
407407
struct mhi_ep_buf_info buf_info = {};
408408
u32 len = MHI_EP_DEFAULT_MTU;
409409
struct mhi_ring_element *el;
410-
bool tr_done = false;
411410
void *buf_addr;
412-
u32 buf_left;
413411
int ret;
414412

415-
buf_left = len;
416-
417413
do {
418414
/* Don't process the transfer ring if the channel is not in RUNNING state */
419415
if (mhi_chan->state != MHI_CH_STATE_RUNNING) {
@@ -426,24 +422,23 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
426422
/* Check if there is data pending to be read from previous read operation */
427423
if (mhi_chan->tre_bytes_left) {
428424
dev_dbg(dev, "TRE bytes remaining: %u\n", mhi_chan->tre_bytes_left);
429-
tr_len = min(buf_left, mhi_chan->tre_bytes_left);
425+
tr_len = min(len, mhi_chan->tre_bytes_left);
430426
} else {
431427
mhi_chan->tre_loc = MHI_TRE_DATA_GET_PTR(el);
432428
mhi_chan->tre_size = MHI_TRE_DATA_GET_LEN(el);
433429
mhi_chan->tre_bytes_left = mhi_chan->tre_size;
434430

435-
tr_len = min(buf_left, mhi_chan->tre_size);
431+
tr_len = min(len, mhi_chan->tre_size);
436432
}
437433

438434
read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left;
439-
write_offset = len - buf_left;
440435

441436
buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL);
442437
if (!buf_addr)
443438
return -ENOMEM;
444439

445440
buf_info.host_addr = mhi_chan->tre_loc + read_offset;
446-
buf_info.dev_addr = buf_addr + write_offset;
441+
buf_info.dev_addr = buf_addr;
447442
buf_info.size = tr_len;
448443
buf_info.cb = mhi_ep_read_completion;
449444
buf_info.cb_buf = buf_addr;
@@ -459,16 +454,12 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
459454
goto err_free_buf_addr;
460455
}
461456

462-
buf_left -= tr_len;
463457
mhi_chan->tre_bytes_left -= tr_len;
464458

465-
if (!mhi_chan->tre_bytes_left) {
466-
if (MHI_TRE_DATA_GET_IEOT(el))
467-
tr_done = true;
468-
459+
if (!mhi_chan->tre_bytes_left)
469460
mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size;
470-
}
471-
} while (buf_left && !tr_done);
461+
/* Read until the some buffer is left or the ring becomes not empty */
462+
} while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE));
472463

473464
return 0;
474465

@@ -502,15 +493,11 @@ static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring)
502493
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
503494
} else {
504495
/* UL channel */
505-
do {
506-
ret = mhi_ep_read_channel(mhi_cntrl, ring);
507-
if (ret < 0) {
508-
dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n");
509-
return ret;
510-
}
511-
512-
/* Read until the ring becomes empty */
513-
} while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE));
496+
ret = mhi_ep_read_channel(mhi_cntrl, ring);
497+
if (ret < 0) {
498+
dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n");
499+
return ret;
500+
}
514501
}
515502

516503
return 0;

drivers/bus/mhi/host/init.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,6 @@ static void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl)
194194
static int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
195195
{
196196
struct mhi_event *mhi_event = mhi_cntrl->mhi_event;
197-
struct device *dev = &mhi_cntrl->mhi_dev->dev;
198197
unsigned long irq_flags = IRQF_SHARED | IRQF_NO_SUSPEND;
199198
int i, ret;
200199

@@ -221,7 +220,7 @@ static int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
221220
continue;
222221

223222
if (mhi_event->irq >= mhi_cntrl->nr_irqs) {
224-
dev_err(dev, "irq %d not available for event ring\n",
223+
dev_err(mhi_cntrl->cntrl_dev, "irq %d not available for event ring\n",
225224
mhi_event->irq);
226225
ret = -EINVAL;
227226
goto error_request;
@@ -232,7 +231,7 @@ static int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
232231
irq_flags,
233232
"mhi", mhi_event);
234233
if (ret) {
235-
dev_err(dev, "Error requesting irq:%d for ev:%d\n",
234+
dev_err(mhi_cntrl->cntrl_dev, "Error requesting irq:%d for ev:%d\n",
236235
mhi_cntrl->irq[mhi_event->irq], i);
237236
goto error_request;
238237
}

drivers/bus/mhi/host/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ enum mhi_pm_state {
170170
MHI_PM_IN_ERROR_STATE(pm_state))
171171
#define MHI_PM_IN_SUSPEND_STATE(pm_state) (pm_state & \
172172
(MHI_PM_M3_ENTER | MHI_PM_M3))
173+
#define MHI_PM_FATAL_ERROR(pm_state) ((pm_state == MHI_PM_FW_DL_ERR) || \
174+
(pm_state >= MHI_PM_SYS_ERR_FAIL))
173175

174176
#define NR_OF_CMD_RINGS 1
175177
#define CMD_EL_PER_RING 128
@@ -403,6 +405,7 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl,
403405
struct mhi_event *mhi_event, u32 event_quota);
404406
int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
405407
struct mhi_event *mhi_event, u32 event_quota);
408+
void mhi_uevent_notify(struct mhi_controller *mhi_cntrl, enum mhi_ee_type ee);
406409

407410
/* ISR handlers */
408411
irqreturn_t mhi_irq_handler(int irq_number, void *dev);

drivers/bus/mhi/host/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,7 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv)
512512
if (mhi_cntrl->rddm_image && mhi_is_active(mhi_cntrl)) {
513513
mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_RDDM);
514514
mhi_cntrl->ee = ee;
515+
mhi_uevent_notify(mhi_cntrl, mhi_cntrl->ee);
515516
wake_up_all(&mhi_cntrl->state_event);
516517
}
517518
break;

drivers/bus/mhi/host/pci_generic.c

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,34 @@
3434
/**
3535
* struct mhi_pci_dev_info - MHI PCI device specific information
3636
* @config: MHI controller configuration
37+
* @vf_config: MHI controller configuration for Virtual function (optional)
3738
* @name: name of the PCI module
3839
* @fw: firmware path (if any)
3940
* @edl: emergency download mode firmware path (if any)
4041
* @edl_trigger: capable of triggering EDL mode in the device (if supported)
4142
* @bar_num: PCI base address register to use for MHI MMIO register space
4243
* @dma_data_width: DMA transfer word size (32 or 64 bits)
44+
* @vf_dma_data_width: DMA transfer word size for VF's (optional)
4345
* @mru_default: default MRU size for MBIM network packets
4446
* @sideband_wake: Devices using dedicated sideband GPIO for wakeup instead
4547
* of inband wake support (such as sdx24)
4648
* @no_m3: M3 not supported
49+
* @reset_on_remove: Set true for devices that require SoC during driver removal
4750
*/
4851
struct mhi_pci_dev_info {
4952
const struct mhi_controller_config *config;
53+
const struct mhi_controller_config *vf_config;
5054
const char *name;
5155
const char *fw;
5256
const char *edl;
5357
bool edl_trigger;
5458
unsigned int bar_num;
5559
unsigned int dma_data_width;
60+
unsigned int vf_dma_data_width;
5661
unsigned int mru_default;
5762
bool sideband_wake;
5863
bool no_m3;
64+
bool reset_on_remove;
5965
};
6066

6167
#define MHI_CHANNEL_CONFIG_UL(ch_num, ch_name, el_count, ev_ring) \
@@ -296,8 +302,10 @@ static const struct mhi_pci_dev_info mhi_qcom_qdu100_info = {
296302
.config = &mhi_qcom_qdu100_config,
297303
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
298304
.dma_data_width = 32,
305+
.vf_dma_data_width = 40,
299306
.sideband_wake = false,
300307
.no_m3 = true,
308+
.reset_on_remove = true,
301309
};
302310

303311
static const struct mhi_channel_config mhi_qcom_sa8775p_channels[] = {
@@ -917,20 +925,8 @@ static const struct pci_device_id mhi_pci_id_table[] = {
917925
/* Telit FE990A */
918926
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2015),
919927
.driver_data = (kernel_ulong_t) &mhi_telit_fe990a_info },
920-
/* Foxconn T99W696.01, Lenovo Generic SKU */
921-
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe142),
922-
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
923-
/* Foxconn T99W696.02, Lenovo X1 Carbon SKU */
924-
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe143),
925-
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
926-
/* Foxconn T99W696.03, Lenovo X1 2in1 SKU */
927-
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe144),
928-
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
929-
/* Foxconn T99W696.04, Lenovo PRC SKU */
930-
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe145),
931-
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
932-
/* Foxconn T99W696.00, Foxconn SKU */
933-
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe146),
928+
/* Foxconn T99W696, all variants */
929+
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, PCI_ANY_ID),
934930
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
935931
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308),
936932
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info },
@@ -1037,6 +1033,7 @@ struct mhi_pci_device {
10371033
struct work_struct recovery_work;
10381034
struct timer_list health_check_timer;
10391035
unsigned long status;
1036+
bool reset_on_remove;
10401037
};
10411038

10421039
static int mhi_pci_read_reg(struct mhi_controller *mhi_cntrl,
@@ -1092,7 +1089,7 @@ static bool mhi_pci_is_alive(struct mhi_controller *mhi_cntrl)
10921089
struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
10931090
u16 vendor = 0;
10941091

1095-
if (pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor))
1092+
if (pci_read_config_word(pci_physfn(pdev), PCI_VENDOR_ID, &vendor))
10961093
return false;
10971094

10981095
if (vendor == (u16) ~0 || vendor == 0)
@@ -1203,7 +1200,9 @@ static void mhi_pci_recovery_work(struct work_struct *work)
12031200

12041201
dev_warn(&pdev->dev, "device recovery started\n");
12051202

1206-
timer_delete(&mhi_pdev->health_check_timer);
1203+
if (pdev->is_physfn)
1204+
timer_delete(&mhi_pdev->health_check_timer);
1205+
12071206
pm_runtime_forbid(&pdev->dev);
12081207

12091208
/* Clean up MHI state */
@@ -1230,7 +1229,10 @@ static void mhi_pci_recovery_work(struct work_struct *work)
12301229
dev_dbg(&pdev->dev, "Recovery completed\n");
12311230

12321231
set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
1233-
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
1232+
1233+
if (pdev->is_physfn)
1234+
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
1235+
12341236
return;
12351237

12361238
err_unprepare:
@@ -1301,6 +1303,7 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
13011303
const struct mhi_controller_config *mhi_cntrl_config;
13021304
struct mhi_pci_device *mhi_pdev;
13031305
struct mhi_controller *mhi_cntrl;
1306+
unsigned int dma_data_width;
13041307
int err;
13051308

13061309
dev_info(&pdev->dev, "MHI PCI device found: %s\n", info->name);
@@ -1311,14 +1314,24 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
13111314
return -ENOMEM;
13121315

13131316
INIT_WORK(&mhi_pdev->recovery_work, mhi_pci_recovery_work);
1314-
timer_setup(&mhi_pdev->health_check_timer, health_check, 0);
13151317

1316-
mhi_cntrl_config = info->config;
1318+
if (pdev->is_virtfn && info->vf_config)
1319+
mhi_cntrl_config = info->vf_config;
1320+
else
1321+
mhi_cntrl_config = info->config;
1322+
1323+
/* Initialize health check monitor only for Physical functions */
1324+
if (pdev->is_physfn)
1325+
timer_setup(&mhi_pdev->health_check_timer, health_check, 0);
1326+
13171327
mhi_cntrl = &mhi_pdev->mhi_cntrl;
13181328

1329+
dma_data_width = (pdev->is_virtfn && info->vf_dma_data_width) ?
1330+
info->vf_dma_data_width : info->dma_data_width;
1331+
13191332
mhi_cntrl->cntrl_dev = &pdev->dev;
13201333
mhi_cntrl->iova_start = 0;
1321-
mhi_cntrl->iova_stop = (dma_addr_t)DMA_BIT_MASK(info->dma_data_width);
1334+
mhi_cntrl->iova_stop = (dma_addr_t)DMA_BIT_MASK(dma_data_width);
13221335
mhi_cntrl->fw_image = info->fw;
13231336
mhi_cntrl->edl_image = info->edl;
13241337

@@ -1330,6 +1343,9 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
13301343
mhi_cntrl->mru = info->mru_default;
13311344
mhi_cntrl->name = info->name;
13321345

1346+
if (pdev->is_physfn)
1347+
mhi_pdev->reset_on_remove = info->reset_on_remove;
1348+
13331349
if (info->edl_trigger)
13341350
mhi_cntrl->edl_trigger = mhi_pci_generic_edl_trigger;
13351351

@@ -1339,7 +1355,7 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
13391355
mhi_cntrl->wake_toggle = mhi_pci_wake_toggle_nop;
13401356
}
13411357

1342-
err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(info->dma_data_width));
1358+
err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(dma_data_width));
13431359
if (err)
13441360
return err;
13451361

@@ -1376,7 +1392,8 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
13761392
set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
13771393

13781394
/* start health check */
1379-
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
1395+
if (pdev->is_physfn)
1396+
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
13801397

13811398
/* Allow runtime suspend only if both PME from D3Hot and M3 are supported */
13821399
if (pci_pme_capable(pdev, PCI_D3hot) && !(info->no_m3)) {
@@ -1401,7 +1418,10 @@ static void mhi_pci_remove(struct pci_dev *pdev)
14011418
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
14021419
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
14031420

1404-
timer_delete_sync(&mhi_pdev->health_check_timer);
1421+
pci_disable_sriov(pdev);
1422+
1423+
if (pdev->is_physfn)
1424+
timer_delete_sync(&mhi_pdev->health_check_timer);
14051425
cancel_work_sync(&mhi_pdev->recovery_work);
14061426

14071427
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
@@ -1413,6 +1433,9 @@ static void mhi_pci_remove(struct pci_dev *pdev)
14131433
if (pci_pme_capable(pdev, PCI_D3hot))
14141434
pm_runtime_get_noresume(&pdev->dev);
14151435

1436+
if (mhi_pdev->reset_on_remove)
1437+
mhi_soc_reset(mhi_cntrl);
1438+
14161439
mhi_unregister_controller(mhi_cntrl);
14171440
}
14181441

@@ -1429,7 +1452,8 @@ static void mhi_pci_reset_prepare(struct pci_dev *pdev)
14291452

14301453
dev_info(&pdev->dev, "reset\n");
14311454

1432-
timer_delete(&mhi_pdev->health_check_timer);
1455+
if (pdev->is_physfn)
1456+
timer_delete(&mhi_pdev->health_check_timer);
14331457

14341458
/* Clean up MHI state */
14351459
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
@@ -1474,7 +1498,8 @@ static void mhi_pci_reset_done(struct pci_dev *pdev)
14741498
}
14751499

14761500
set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
1477-
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
1501+
if (pdev->is_physfn)
1502+
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
14781503
}
14791504

14801505
static pci_ers_result_t mhi_pci_error_detected(struct pci_dev *pdev,
@@ -1539,7 +1564,9 @@ static int __maybe_unused mhi_pci_runtime_suspend(struct device *dev)
15391564
if (test_and_set_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status))
15401565
return 0;
15411566

1542-
timer_delete(&mhi_pdev->health_check_timer);
1567+
if (pdev->is_physfn)
1568+
timer_delete(&mhi_pdev->health_check_timer);
1569+
15431570
cancel_work_sync(&mhi_pdev->recovery_work);
15441571

15451572
if (!test_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status) ||
@@ -1590,7 +1617,8 @@ static int __maybe_unused mhi_pci_runtime_resume(struct device *dev)
15901617
}
15911618

15921619
/* Resume health check */
1593-
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
1620+
if (pdev->is_physfn)
1621+
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
15941622

15951623
/* It can be a remote wakeup (no mhi runtime_get), update access time */
15961624
pm_runtime_mark_last_busy(dev);
@@ -1676,7 +1704,8 @@ static struct pci_driver mhi_pci_driver = {
16761704
.remove = mhi_pci_remove,
16771705
.shutdown = mhi_pci_shutdown,
16781706
.err_handler = &mhi_pci_err_handler,
1679-
.driver.pm = &mhi_pci_pm_ops
1707+
.driver.pm = &mhi_pci_pm_ops,
1708+
.sriov_configure = pci_sriov_configure_simple,
16801709
};
16811710
module_pci_driver(mhi_pci_driver);
16821711

0 commit comments

Comments
 (0)