Skip to content

Commit c2df4a8

Browse files
xiaoguangwuwenlingz
authored andcommitted
DM USB: xHCI: no wait logic implementation for S3
On Intel Apllo Lake platform, the VBus will drop after the SOC suspended, hence during the SOS resuming process, there will be a disconnecting event and a connecting event sent to each native USB device in order. This patch will use new strategy for S3 resuming emultion. 1. The DM set PORTSC register to 'no device attached' state when S3 suspending started, 2. SOS resuming starts and do nothing for device disconnecting event, 3. 'Cache' device connecting event and don't report it to UOS, 4. UOS believe no device attached due to PORTSC register state and begin to clear the resource allocated for the device before S3 suspending, 5. DM receives the Disable Slot command from UOS and report the 'cached' device connecting event to UOS, hence trigger the emulation behavior for the device. The purpose of this strategy is to let UOS resuming proceed as quickly as possible, which means the UI will be turned on quickly to user. Tracked-On: #1893 Signed-off-by: Xiaoguang Wu <xiaoguang.wu@intel.com> Reviewed-by: Liang Yang <liang3.yang@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
1 parent 8265983 commit c2df4a8

File tree

1 file changed

+174
-29
lines changed

1 file changed

+174
-29
lines changed

devicemodel/hw/pci/xhci.c

Lines changed: 174 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
#include <unistd.h>
8585
#include <fcntl.h>
8686
#include <ctype.h>
87+
#include <semaphore.h>
8788
#include "usb.h"
8889
#include "usbdi.h"
8990
#include "xhcireg.h"
@@ -253,6 +254,13 @@ struct pci_xhci_rtsregs {
253254
uint32_t event_pcs; /* producer cycle state flag */
254255
};
255256

257+
/* this is used to describe the VBus Drop state */
258+
enum pci_xhci_vbdp_state {
259+
S3_VBDP_NONE = 0,
260+
S3_VBDP_START,
261+
S3_VBDP_END
262+
};
263+
256264
struct pci_xhci_excap_ptr {
257265
uint8_t cap_id;
258266
uint8_t cap_ptr;
@@ -351,6 +359,13 @@ struct pci_xhci_native_port {
351359
uint8_t state;
352360
};
353361

362+
/* This is used to describe the VBus Drop state */
363+
struct pci_xhci_vbdp_dev_state {
364+
struct usb_devpath path;
365+
uint8_t vport;
366+
uint8_t state;
367+
};
368+
354369
struct pci_xhci_vdev {
355370
struct pci_vdev *dev;
356371
pthread_mutex_t mtx;
@@ -384,6 +399,12 @@ struct pci_xhci_vdev {
384399
int usb2_port_start;
385400
int usb3_port_start;
386401

402+
pthread_t vbdp_thread;
403+
sem_t vbdp_sem;
404+
bool vbdp_polling;
405+
int vbdp_dev_num;
406+
struct pci_xhci_vbdp_dev_state vbdp_devs[XHCI_MAX_VIRT_PORTS];
407+
387408
/*
388409
* native_ports uses for record the command line assigned native root
389410
* hub ports and its child external hub ports.
@@ -491,7 +512,7 @@ pci_xhci_get_free_vport(struct pci_xhci_vdev *xdev,
491512
struct usb_native_devinfo *di)
492513
{
493514
int ports, porte;
494-
int i, j;
515+
int i, j, k;
495516

496517
assert(xdev);
497518
assert(di);
@@ -504,10 +525,15 @@ pci_xhci_get_free_vport(struct pci_xhci_vdev *xdev,
504525
porte = ports + (XHCI_MAX_DEVS / 2);
505526

506527
for (i = ports; i <= porte; i++) {
507-
for (j = 0; j < XHCI_MAX_VIRT_PORTS; j++)
528+
for (j = 0; j < XHCI_MAX_VIRT_PORTS; j++) {
508529
if (xdev->native_ports[j].vport == i)
509530
break;
510531

532+
k = xdev->vbdp_dev_num;
533+
if (k > 0 && xdev->vbdp_devs[j].state == S3_VBDP_START
534+
&& xdev->vbdp_devs[j].vport == i)
535+
break;
536+
}
511537
if (j >= XHCI_MAX_VIRT_PORTS)
512538
return i;
513539
}
@@ -673,15 +699,54 @@ pci_xhci_unassign_hub_ports(struct pci_xhci_vdev *xdev,
673699
return 0;
674700
}
675701

702+
703+
static void *
704+
xhci_vbdp_thread(void *data)
705+
{
706+
int i, j;
707+
int speed;
708+
struct pci_xhci_vdev *xdev;
709+
struct pci_xhci_native_port *p;
710+
711+
xdev = data;
712+
assert(xdev);
713+
714+
while (xdev->vbdp_polling) {
715+
716+
sem_wait(&xdev->vbdp_sem);
717+
for (i = 0; i < XHCI_MAX_VIRT_PORTS; ++i)
718+
if (xdev->vbdp_devs[i].state == S3_VBDP_END) {
719+
xdev->vbdp_devs[i].state = S3_VBDP_NONE;
720+
break;
721+
}
722+
723+
j = pci_xhci_get_native_port_index_by_path(xdev,
724+
&xdev->vbdp_devs[i].path);
725+
if (j < 0)
726+
continue;
727+
728+
p = &xdev->native_ports[j];
729+
if (p->state != VPORT_CONNECTED)
730+
continue;
731+
732+
speed = pci_xhci_convert_speed(p->info.speed);
733+
pci_xhci_connect_port(xdev, p->vport, speed, 1);
734+
UPRINTF(LINF, "change portsc for %d-%s\r\n", p->info.path.bus,
735+
usb_dev_path(&p->info.path));
736+
}
737+
return NULL;
738+
}
739+
676740
static int
677741
pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
678742
{
679743
struct pci_xhci_vdev *xdev;
680744
struct usb_native_devinfo *di;
681-
int vport;
745+
int vport = -1;
682746
int index;
683747
int rc;
684-
int speed;
748+
int i;
749+
int s3_conn = 0;
685750

686751
xdev = hci_data;
687752

@@ -715,7 +780,23 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
715780
UPRINTF(LDBG, "%04x:%04x %d-%s belong to this vm.\r\n", di->vid,
716781
di->pid, di->path.bus, usb_dev_path(&di->path));
717782

718-
vport = pci_xhci_get_free_vport(xdev, di);
783+
for (i = 0; xdev->vbdp_dev_num && i < XHCI_MAX_VIRT_PORTS; ++i) {
784+
if (xdev->vbdp_devs[i].state != S3_VBDP_START)
785+
continue;
786+
787+
if (!usb_dev_path_cmp(&di->path, &xdev->vbdp_devs[i].path))
788+
continue;
789+
790+
s3_conn = 1;
791+
vport = xdev->vbdp_devs[i].vport;
792+
UPRINTF(LINF, "Skip and cache connect event for %d-%s\r\n",
793+
di->path.bus, usb_dev_path(&di->path));
794+
break;
795+
}
796+
797+
if (vport <= 0)
798+
vport = pci_xhci_get_free_vport(xdev, di);
799+
719800
if (vport <= 0) {
720801
UPRINTF(LFTL, "no free virtual port for native device %d-%s"
721802
"\r\n", di->path.bus,
@@ -731,15 +812,11 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
731812
di->vid, di->pid, di->path.bus,
732813
usb_dev_path(&di->path), vport);
733814

734-
/* TODO: should revisit in deeper level */
735-
if (XHCI_PS_PLS_GET(XHCI_PORTREG_PTR(xdev, vport)->portsc) ==
736-
UPS_PORT_LS_U3) {
737-
speed = pci_xhci_convert_speed(di->speed);
738-
XHCI_PORTREG_PTR(xdev, vport)->portsc |= (XHCI_PS_CCS |
739-
XHCI_PS_PP | XHCI_PS_CSC |
740-
XHCI_PS_SPEED_SET(speed));
815+
/* we will report connecting event in xhci_vbdp_thread for
816+
* device that hasn't complete the S3 process
817+
*/
818+
if (s3_conn)
741819
return 0;
742-
}
743820

744821
/* Trigger port change event for the arriving device */
745822
if (pci_xhci_connect_port(xdev, vport, di->speed, 1))
@@ -761,6 +838,7 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
761838
int need_intr = 1;
762839
int index;
763840
int rc;
841+
int i;
764842

765843
assert(hci_data);
766844
assert(dev_data);
@@ -814,25 +892,24 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
814892
if (xdev->slots[slot] == edev)
815893
break;
816894

817-
assert(state == VPORT_EMULATED || state == VPORT_CONNECTED);
818-
xdev->native_ports[index].state = VPORT_ASSIGNED;
819-
xdev->native_ports[index].vport = 0;
895+
for (i = 0; xdev->vbdp_dev_num && i < XHCI_MAX_VIRT_PORTS; ++i) {
896+
if (xdev->vbdp_devs[i].state != S3_VBDP_START)
897+
continue;
820898

821-
/* TODO: should revisit in deeper level */
822-
if (XHCI_PS_PLS_GET(XHCI_PORTREG_PTR(xdev, vport)->portsc) ==
823-
UPS_PORT_LS_U3) {
899+
if (!usb_dev_path_cmp(&xdev->vbdp_devs[i].path, &di->path))
900+
continue;
824901

825-
XHCI_PORTREG_PTR(xdev, vport)->portsc &= ~(XHCI_PS_CSC |
826-
XHCI_PS_CCS | XHCI_PS_PED | XHCI_PS_PP);
827-
edev->dev_slotstate = XHCI_ST_DISABLED;
828-
xdev->devices[vport] = NULL;
829-
xdev->slots[slot] = NULL;
830-
xdev->slot_allocated[slot] = false;
831-
pci_xhci_dev_destroy(edev);
832-
need_intr = 0;
902+
/*
903+
* we do nothing here for device that is in the middle of
904+
* S3 resuming process.
905+
*/
833906
return 0;
834907
}
835908

909+
assert(state == VPORT_EMULATED || state == VPORT_CONNECTED);
910+
xdev->native_ports[index].state = VPORT_ASSIGNED;
911+
xdev->native_ports[index].vport = 0;
912+
836913
UPRINTF(LDBG, "report virtual port %d status %d\r\n", vport, state);
837914
if (pci_xhci_disconnect_port(xdev, vport, need_intr)) {
838915
UPRINTF(LFTL, "fail to report event\r\n");
@@ -1107,6 +1184,9 @@ pci_xhci_reset(struct pci_xhci_vdev *xdev)
11071184
static uint32_t
11081185
pci_xhci_usbcmd_write(struct pci_xhci_vdev *xdev, uint32_t cmd)
11091186
{
1187+
int i, j;
1188+
struct pci_xhci_native_port *p;
1189+
11101190
if (cmd & XHCI_CMD_RS) {
11111191
xdev->opregs.usbcmd |= XHCI_CMD_RS;
11121192
xdev->opregs.usbsts &= ~XHCI_STS_HCH;
@@ -1126,6 +1206,37 @@ pci_xhci_usbcmd_write(struct pci_xhci_vdev *xdev, uint32_t cmd)
11261206
cmd &= ~XHCI_CMD_HCRST;
11271207
}
11281208

1209+
if (cmd & XHCI_CMD_CSS) {
1210+
/* TODO: should think about what happen if system S3 fail
1211+
* and under that situation, the vbdp_devs and se_dev_num
1212+
* should also need to be cleared
1213+
*/
1214+
xdev->vbdp_dev_num = 0;
1215+
memset(xdev->vbdp_devs, 0, sizeof(xdev->vbdp_devs));
1216+
1217+
for (i = 0; i < XHCI_MAX_VIRT_PORTS; ++i) {
1218+
p = &xdev->native_ports[i];
1219+
if (xdev->native_ports[i].state == VPORT_EMULATED) {
1220+
/* save the device state before suspending */
1221+
j = xdev->vbdp_dev_num;
1222+
xdev->vbdp_devs[j].path = p->info.path;
1223+
xdev->vbdp_devs[j].vport = p->vport;
1224+
xdev->vbdp_devs[j].state = S3_VBDP_START;
1225+
xdev->vbdp_dev_num++;
1226+
1227+
/* clear PORTSC register */
1228+
pci_xhci_init_port(xdev, p->vport);
1229+
1230+
/* clear other information for this device*/
1231+
p->vport = 0;
1232+
p->state = VPORT_ASSIGNED;
1233+
UPRINTF(LINF, "s3: save %d-%s state\r\n",
1234+
p->info.path.bus,
1235+
usb_dev_path(&p->info.path));
1236+
}
1237+
}
1238+
}
1239+
11291240
cmd &= ~(XHCI_CMD_CSS | XHCI_CMD_CRS);
11301241
return cmd;
11311242
}
@@ -1631,9 +1742,10 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_vdev *xdev, uint32_t slot)
16311742
{
16321743
struct pci_xhci_dev_emu *dev;
16331744
struct usb_dev *udev;
1634-
struct usb_native_devinfo *di;
1745+
struct usb_native_devinfo *di = NULL;
1746+
struct usb_devpath *path;
16351747
uint32_t cmderr;
1636-
int i, index;
1748+
int i, j, index;
16371749

16381750
UPRINTF(LDBG, "pci_xhci disable slot %u\r\n", slot);
16391751

@@ -1678,11 +1790,31 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_vdev *xdev, uint32_t slot)
16781790
di = &udev->info;
16791791
index = pci_xhci_get_native_port_index_by_path(xdev, &di->path);
16801792
if (index < 0) {
1793+
/*
1794+
* one possible reason for failing to find the device is
1795+
* it is plugged out during the resuming process. we
1796+
* should give the xhci_vbdp_thread an opportunity to
1797+
* try.
1798+
*/
1799+
sem_post(&xdev->vbdp_sem);
16811800
cmderr = XHCI_TRB_ERROR_SLOT_NOT_ON;
16821801
goto done;
16831802
}
16841803

16851804
pci_xhci_dev_destroy(dev);
1805+
1806+
for (j = 0; j < XHCI_MAX_VIRT_PORTS; ++j) {
1807+
path = &xdev->vbdp_devs[j].path;
1808+
1809+
if (!usb_dev_path_cmp(path, &di->path))
1810+
continue;
1811+
1812+
xdev->vbdp_devs[j].state = S3_VBDP_END;
1813+
xdev->vbdp_dev_num--;
1814+
sem_post(&xdev->vbdp_sem);
1815+
UPRINTF(LINF, "signal device %d-%s to connect\r\n",
1816+
di->path.bus, usb_dev_path(&di->path));
1817+
}
16861818
UPRINTF(LINF, "disable slot %d for native device %d-%s"
16871819
"\r\n", slot, di->path.bus,
16881820
usb_dev_path(&di->path));
@@ -4018,6 +4150,14 @@ pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
40184150

40194151
pthread_mutex_init(&xdev->mtx, NULL);
40204152

4153+
/* create vbdp_thread */
4154+
xdev->vbdp_polling = true;
4155+
sem_init(&xdev->vbdp_sem, 0, 0);
4156+
error = pthread_create(&xdev->vbdp_thread, NULL, xhci_vbdp_thread,
4157+
xdev);
4158+
if (error)
4159+
goto done;
4160+
40214161
xhci_in_use = 1;
40224162
done:
40234163
if (error) {
@@ -4057,6 +4197,11 @@ pci_xhci_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
40574197

40584198
usb_dev_sys_deinit();
40594199

4200+
xdev->vbdp_polling = false;
4201+
sem_post(&xdev->vbdp_sem);
4202+
pthread_join(xdev->vbdp_thread, NULL);
4203+
sem_close(&xdev->vbdp_sem);
4204+
40604205
pthread_mutex_destroy(&xdev->mtx);
40614206
free(xdev);
40624207
xhci_in_use = 0;

0 commit comments

Comments
 (0)