Skip to content

Commit 55f6ac4

Browse files
committed
Merge patch series "mei: connect to card in D3cold"
Alexander Usyskin <[email protected]> says: When discrete graphic card enters D3cold th CSC engine is powered down. On wakeup from the D3cold full HECI link reset is required. The driver should detect that firmware requests link reset and initiate the link reset flow. In the usual flow the connect IOCTL will trigger the wake from D3cold and corresponding link reset. The MEI driver invalidates all open handles on link reset including the one that triggered the wake rendering this connection unusable. To break this loop make connect detect that it is interrupted by link reset and retry connect attempt after reset was completed. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
2 parents 68be6c4 + f9deb46 commit 55f6ac4

File tree

6 files changed

+62
-77
lines changed

6 files changed

+62
-77
lines changed

drivers/misc/mei/bus.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ int mei_cldev_enable(struct mei_cl_device *cldev)
814814

815815
ret = mei_cl_connect(cl, cldev->me_cl, NULL);
816816
if (ret < 0) {
817-
dev_err(&cldev->dev, "cannot connect\n");
817+
dev_dbg(&cldev->dev, "cannot connect\n");
818818
mei_cl_bus_vtag_free(cldev);
819819
}
820820

drivers/misc/mei/hw-me.c

Lines changed: 17 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -493,43 +493,6 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
493493
return 0;
494494
}
495495

496-
/**
497-
* mei_me_check_fw_reset - check for the firmware reset error and exception conditions
498-
*
499-
* @dev: mei device
500-
*/
501-
static void mei_me_check_fw_reset(struct mei_device *dev)
502-
{
503-
struct mei_fw_status fw_status;
504-
char fw_sts_str[MEI_FW_STATUS_STR_SZ] = {0};
505-
int ret;
506-
u32 fw_pm_event = 0;
507-
508-
if (!dev->saved_fw_status_flag)
509-
goto end;
510-
511-
if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) {
512-
ret = mei_fw_status(dev, &fw_status);
513-
if (!ret) {
514-
fw_pm_event = fw_status.status[1] & PCI_CFG_HFS_2_PM_EVENT_MASK;
515-
if (fw_pm_event != PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR &&
516-
fw_pm_event != PCI_CFG_HFS_2_PM_CM_RESET_ERROR)
517-
goto end;
518-
} else {
519-
dev_err(&dev->dev, "failed to read firmware status: %d\n", ret);
520-
}
521-
}
522-
523-
mei_fw_status2str(&dev->saved_fw_status, fw_sts_str, sizeof(fw_sts_str));
524-
dev_warn(&dev->dev, "unexpected reset: fw_pm_event = 0x%x, dev_state = %u fw status = %s\n",
525-
fw_pm_event, dev->saved_dev_state, fw_sts_str);
526-
527-
end:
528-
if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED)
529-
dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DONE;
530-
dev->saved_fw_status_flag = false;
531-
}
532-
533496
/**
534497
* mei_me_hw_start - hw start routine
535498
*
@@ -540,8 +503,9 @@ static int mei_me_hw_start(struct mei_device *dev)
540503
{
541504
int ret = mei_me_hw_ready_wait(dev);
542505

543-
if (kind_is_gsc(dev) || kind_is_gscfi(dev))
544-
mei_me_check_fw_reset(dev);
506+
if ((kind_is_gsc(dev) || kind_is_gscfi(dev)) &&
507+
dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED)
508+
dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DONE;
545509
if (ret)
546510
return ret;
547511
dev_dbg(&dev->dev, "hw is ready\n");
@@ -1373,9 +1337,20 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
13731337
/* check if we need to start the dev */
13741338
if (!mei_host_is_ready(dev)) {
13751339
if (mei_hw_is_ready(dev)) {
1376-
dev_dbg(&dev->dev, "we need to start the dev.\n");
1377-
dev->recvd_hw_ready = true;
1378-
wake_up(&dev->wait_hw_ready);
1340+
/* synchronized by dev mutex */
1341+
if (waitqueue_active(&dev->wait_hw_ready)) {
1342+
dev_dbg(&dev->dev, "we need to start the dev.\n");
1343+
dev->recvd_hw_ready = true;
1344+
wake_up(&dev->wait_hw_ready);
1345+
} else if (dev->dev_state != MEI_DEV_UNINITIALIZED &&
1346+
dev->dev_state != MEI_DEV_POWERING_DOWN &&
1347+
dev->dev_state != MEI_DEV_POWER_DOWN) {
1348+
dev_dbg(&dev->dev, "Force link reset.\n");
1349+
schedule_work(&dev->reset_work);
1350+
} else {
1351+
dev_dbg(&dev->dev, "Ignore this interrupt in state = %d\n",
1352+
dev->dev_state);
1353+
}
13791354
} else {
13801355
dev_dbg(&dev->dev, "Spurious Interrupt\n");
13811356
}

drivers/misc/mei/hw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#define MKHI_RCV_TIMEOUT 500 /* receive timeout in msec */
2828
#define MKHI_RCV_TIMEOUT_SLOW 10000 /* receive timeout in msec, slow FW */
2929

30+
#define MEI_LINK_RESET_WAIT_TIMEOUT_MSEC 500 /* Max wait timeout for link reset, in msec */
31+
3032
/*
3133
* FW page size for DMA allocations
3234
*/

drivers/misc/mei/init.c

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -89,22 +89,6 @@ void mei_cancel_work(struct mei_device *dev)
8989
}
9090
EXPORT_SYMBOL_GPL(mei_cancel_work);
9191

92-
static void mei_save_fw_status(struct mei_device *dev)
93-
{
94-
struct mei_fw_status fw_status;
95-
int ret;
96-
97-
ret = mei_fw_status(dev, &fw_status);
98-
if (ret) {
99-
dev_err(&dev->dev, "failed to read firmware status: %d\n", ret);
100-
return;
101-
}
102-
103-
dev->saved_dev_state = dev->dev_state;
104-
dev->saved_fw_status_flag = true;
105-
memcpy(&dev->saved_fw_status, &fw_status, sizeof(fw_status));
106-
}
107-
10892
/**
10993
* mei_reset - resets host and fw.
11094
*
@@ -128,7 +112,6 @@ int mei_reset(struct mei_device *dev)
128112
if (kind_is_gsc(dev) || kind_is_gscfi(dev)) {
129113
dev_dbg(&dev->dev, "unexpected reset: dev_state = %s fw status = %s\n",
130114
mei_dev_state_str(state), fw_sts_str);
131-
mei_save_fw_status(dev);
132115
} else {
133116
dev_warn(&dev->dev, "unexpected reset: dev_state = %s fw status = %s\n",
134117
mei_dev_state_str(state), fw_sts_str);
@@ -399,7 +382,8 @@ void mei_device_init(struct mei_device *dev,
399382
init_waitqueue_head(&dev->wait_hw_ready);
400383
init_waitqueue_head(&dev->wait_pg);
401384
init_waitqueue_head(&dev->wait_hbm_start);
402-
dev->dev_state = MEI_DEV_INITIALIZING;
385+
dev->dev_state = MEI_DEV_UNINITIALIZED;
386+
init_waitqueue_head(&dev->wait_dev_state);
403387
dev->reset_count = 0;
404388

405389
INIT_LIST_HEAD(&dev->write_list);
@@ -442,5 +426,6 @@ void mei_device_init(struct mei_device *dev,
442426
dev->timeouts.hbm = mei_secs_to_jiffies(MEI_HBM_TIMEOUT);
443427
dev->timeouts.mkhi_recv = msecs_to_jiffies(MKHI_RCV_TIMEOUT);
444428
}
429+
dev->timeouts.link_reset_wait = msecs_to_jiffies(MEI_LINK_RESET_WAIT_TIMEOUT_MSEC);
445430
}
446431
EXPORT_SYMBOL_GPL(mei_device_init);

drivers/misc/mei/main.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ static int mei_ioctl_connect_client(struct file *file,
423423
cl->state != MEI_FILE_DISCONNECTED)
424424
return -EBUSY;
425425

426+
retry:
426427
/* find ME client we're trying to connect to */
427428
me_cl = mei_me_cl_by_uuid(dev, in_client_uuid);
428429
if (!me_cl) {
@@ -454,6 +455,28 @@ static int mei_ioctl_connect_client(struct file *file,
454455

455456
rets = mei_cl_connect(cl, me_cl, file);
456457

458+
if (rets && cl->status == -EFAULT &&
459+
(dev->dev_state == MEI_DEV_RESETTING ||
460+
dev->dev_state == MEI_DEV_INIT_CLIENTS)) {
461+
/* in link reset, wait for it completion */
462+
mutex_unlock(&dev->device_lock);
463+
rets = wait_event_interruptible_timeout(dev->wait_dev_state,
464+
dev->dev_state == MEI_DEV_ENABLED,
465+
dev->timeouts.link_reset_wait);
466+
mutex_lock(&dev->device_lock);
467+
if (rets < 0) {
468+
if (signal_pending(current))
469+
rets = -EINTR;
470+
goto end;
471+
}
472+
if (dev->dev_state != MEI_DEV_ENABLED) {
473+
rets = -ETIME;
474+
goto end;
475+
}
476+
mei_me_cl_put(me_cl);
477+
goto retry;
478+
}
479+
457480
end:
458481
mei_me_cl_put(me_cl);
459482
return rets;
@@ -646,7 +669,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
646669
struct mei_cl *cl = file->private_data;
647670
struct mei_connect_client_data conn;
648671
struct mei_connect_client_data_vtag conn_vtag;
649-
const uuid_le *cl_uuid;
672+
uuid_le cl_uuid;
650673
struct mei_client *props;
651674
u8 vtag;
652675
u32 notify_get, notify_req;
@@ -674,18 +697,18 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
674697
rets = -EFAULT;
675698
goto out;
676699
}
677-
cl_uuid = &conn.in_client_uuid;
700+
cl_uuid = conn.in_client_uuid;
678701
props = &conn.out_client_properties;
679702
vtag = 0;
680703

681-
rets = mei_vt_support_check(dev, cl_uuid);
704+
rets = mei_vt_support_check(dev, &cl_uuid);
682705
if (rets == -ENOTTY)
683706
goto out;
684707
if (!rets)
685-
rets = mei_ioctl_connect_vtag(file, cl_uuid, props,
708+
rets = mei_ioctl_connect_vtag(file, &cl_uuid, props,
686709
vtag);
687710
else
688-
rets = mei_ioctl_connect_client(file, cl_uuid, props);
711+
rets = mei_ioctl_connect_client(file, &cl_uuid, props);
689712
if (rets)
690713
goto out;
691714

@@ -707,14 +730,14 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
707730
goto out;
708731
}
709732

710-
cl_uuid = &conn_vtag.connect.in_client_uuid;
733+
cl_uuid = conn_vtag.connect.in_client_uuid;
711734
props = &conn_vtag.out_client_properties;
712735
vtag = conn_vtag.connect.vtag;
713736

714-
rets = mei_vt_support_check(dev, cl_uuid);
737+
rets = mei_vt_support_check(dev, &cl_uuid);
715738
if (rets == -EOPNOTSUPP)
716739
cl_dbg(dev, cl, "FW Client %pUl does not support vtags\n",
717-
cl_uuid);
740+
&cl_uuid);
718741
if (rets)
719742
goto out;
720743

@@ -724,7 +747,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
724747
goto out;
725748
}
726749

727-
rets = mei_ioctl_connect_vtag(file, cl_uuid, props, vtag);
750+
rets = mei_ioctl_connect_vtag(file, &cl_uuid, props, vtag);
728751
if (rets)
729752
goto out;
730753

@@ -1120,6 +1143,8 @@ void mei_set_devstate(struct mei_device *dev, enum mei_dev_state state)
11201143

11211144
dev->dev_state = state;
11221145

1146+
wake_up_interruptible_all(&dev->wait_dev_state);
1147+
11231148
if (!dev->cdev)
11241149
return;
11251150

drivers/misc/mei/mei_dev.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ enum file_state {
5757

5858
/* MEI device states */
5959
enum mei_dev_state {
60-
MEI_DEV_INITIALIZING = 0,
60+
MEI_DEV_UNINITIALIZED = 0,
61+
MEI_DEV_INITIALIZING,
6162
MEI_DEV_INIT_CLIENTS,
6263
MEI_DEV_ENABLED,
6364
MEI_DEV_RESETTING,
@@ -465,6 +466,7 @@ struct mei_dev_timeouts {
465466
unsigned int d0i3; /* D0i3 set/unset max response time, in jiffies */
466467
unsigned long hbm; /* HBM operation timeout, in jiffies */
467468
unsigned long mkhi_recv; /* receive timeout, in jiffies */
469+
unsigned long link_reset_wait; /* link reset wait timeout, in jiffies */
468470
};
469471

470472
/**
@@ -495,6 +497,7 @@ struct mei_dev_timeouts {
495497
*
496498
* @reset_count : number of consecutive resets
497499
* @dev_state : device state
500+
* @wait_dev_state: wait queue for device state change
498501
* @hbm_state : state of host bus message protocol
499502
* @pxp_mode : PXP device mode
500503
* @init_clients_timer : HBM init handshake timeout
@@ -548,9 +551,6 @@ struct mei_dev_timeouts {
548551
*
549552
* @dbgfs_dir : debugfs mei root directory
550553
*
551-
* @saved_fw_status : saved firmware status
552-
* @saved_dev_state : saved device state
553-
* @saved_fw_status_flag : flag indicating that firmware status was saved
554554
* @gsc_reset_to_pxp : state of reset to the PXP mode
555555
*
556556
* @ops: : hw specific operations
@@ -587,6 +587,7 @@ struct mei_device {
587587
*/
588588
unsigned long reset_count;
589589
enum mei_dev_state dev_state;
590+
wait_queue_head_t wait_dev_state;
590591
enum mei_hbm_state hbm_state;
591592
enum mei_dev_pxp_mode pxp_mode;
592593
u16 init_clients_timer;
@@ -650,9 +651,6 @@ struct mei_device {
650651
struct dentry *dbgfs_dir;
651652
#endif /* CONFIG_DEBUG_FS */
652653

653-
struct mei_fw_status saved_fw_status;
654-
enum mei_dev_state saved_dev_state;
655-
bool saved_fw_status_flag;
656654
enum mei_dev_reset_to_pxp gsc_reset_to_pxp;
657655

658656
const struct mei_hw_ops *ops;

0 commit comments

Comments
 (0)