mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-25 15:02:13 +00:00
DM USB: xHCI: introduce get/set function for PORTSC register
Port Status and Control (PORTSC) register is one of the most frequently accessed regiseter according the xHCI spec. This patch implement a pair of set/get function to access PORTS and it gives a clear code structure and help a lot for debugging work. Tracked-On: #2576 Signed-off-by: Conghui Chen <conghui.chen@intel.com> Signed-off-by: Xiaoguang Wu <xiaoguang.wu@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
parent
b7f5614387
commit
5f36580190
@ -508,6 +508,34 @@ static struct pci_xhci_option_elem xhci_option_table[] = {
|
||||
{"cap", pci_xhci_parse_extcap}
|
||||
};
|
||||
|
||||
static inline uint32_t pci_xhci_access_portsc(struct pci_xhci_vdev *xdev,
|
||||
uint32_t portnum, uint32_t value, int read)
|
||||
{
|
||||
if (!xdev || !xdev->portregs) {
|
||||
UPRINTF(LDBG, "fail to set portsc (port %d)\r\n", portnum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (read)
|
||||
return xdev->portregs[portnum].portsc;
|
||||
|
||||
xdev->portregs[portnum].portsc = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_xhci_set_portsc(struct pci_xhci_vdev *xdev, uint32_t portnum,
|
||||
uint32_t value)
|
||||
{
|
||||
UPRINTF(LDBG, "set portsc (port %d) %08x\r\n", portnum, value);
|
||||
pci_xhci_access_portsc(xdev, portnum, value, 0);
|
||||
}
|
||||
|
||||
static uint32_t pci_xhci_get_portsc(struct pci_xhci_vdev *xdev,
|
||||
uint32_t portnum)
|
||||
{
|
||||
return pci_xhci_access_portsc(xdev, portnum, 0, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
pci_xhci_get_free_vport(struct pci_xhci_vdev *xdev,
|
||||
struct usb_native_devinfo *di)
|
||||
@ -1113,19 +1141,21 @@ pci_xhci_change_port(struct pci_xhci_vdev *xdev, int port, int usb_speed,
|
||||
{
|
||||
int speed, error;
|
||||
struct xhci_trb evtrb;
|
||||
struct pci_xhci_portregs *reg;
|
||||
uint32_t value;
|
||||
|
||||
assert(xdev != NULL);
|
||||
|
||||
reg = XHCI_PORTREG_PTR(xdev, port);
|
||||
if (conn == 0) {
|
||||
reg->portsc &= ~(XHCI_PS_CCS | XHCI_PS_PED);
|
||||
reg->portsc |= (XHCI_PS_CSC |
|
||||
XHCI_PS_PLS_SET(UPS_PORT_LS_RX_DET));
|
||||
value = pci_xhci_get_portsc(xdev, port);
|
||||
value &= ~(XHCI_PS_CCS | XHCI_PS_PED);
|
||||
value |= (XHCI_PS_CSC | XHCI_PS_PLS_SET(UPS_PORT_LS_RX_DET));
|
||||
pci_xhci_set_portsc(xdev, port, value);
|
||||
|
||||
} else {
|
||||
speed = pci_xhci_convert_speed(usb_speed);
|
||||
reg->portsc = XHCI_PS_CCS | XHCI_PS_PP | XHCI_PS_CSC;
|
||||
reg->portsc |= XHCI_PS_SPEED_SET(speed);
|
||||
value = XHCI_PS_CCS | XHCI_PS_PP | XHCI_PS_CSC;
|
||||
value |= XHCI_PS_SPEED_SET(speed);
|
||||
pci_xhci_set_portsc(xdev, port, value);
|
||||
}
|
||||
|
||||
if (!need_intr)
|
||||
@ -1148,7 +1178,8 @@ pci_xhci_change_port(struct pci_xhci_vdev *xdev, int port, int usb_speed,
|
||||
if (error != XHCI_TRB_ERROR_SUCCESS)
|
||||
UPRINTF(LWRN, "fail to report port change\r\n");
|
||||
|
||||
UPRINTF(LDBG, "%s: port %d:%08X\r\n", __func__, port, reg->portsc);
|
||||
UPRINTF(LDBG, "%s: portsc (port %d) to %08x\r\n", __func__, port,
|
||||
pci_xhci_get_portsc(xdev, port));
|
||||
return (error == XHCI_TRB_ERROR_SUCCESS) ? 0 : -1;
|
||||
}
|
||||
|
||||
@ -1258,6 +1289,7 @@ pci_xhci_portregs_write(struct pci_xhci_vdev *xdev,
|
||||
struct pci_xhci_portregs *p;
|
||||
int port;
|
||||
uint32_t oldpls, newpls;
|
||||
uint32_t portsc;
|
||||
|
||||
if (xdev->portregs == NULL)
|
||||
return;
|
||||
@ -1282,6 +1314,7 @@ pci_xhci_portregs_write(struct pci_xhci_vdev *xdev,
|
||||
}
|
||||
|
||||
p = XHCI_PORTREG_PTR(xdev, port);
|
||||
portsc = pci_xhci_get_portsc(xdev, port);
|
||||
switch (offset) {
|
||||
case 0:
|
||||
/* port reset or warm reset */
|
||||
@ -1290,23 +1323,23 @@ pci_xhci_portregs_write(struct pci_xhci_vdev *xdev,
|
||||
break;
|
||||
}
|
||||
|
||||
if ((p->portsc & XHCI_PS_PP) == 0) {
|
||||
if ((portsc & XHCI_PS_PP) == 0) {
|
||||
UPRINTF(LWRN, "portregs_write to unpowered "
|
||||
"port %d\r\n", port);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Port status and control register */
|
||||
oldpls = XHCI_PS_PLS_GET(p->portsc);
|
||||
oldpls = XHCI_PS_PLS_GET(portsc);
|
||||
newpls = XHCI_PS_PLS_GET(value);
|
||||
|
||||
p->portsc &= XHCI_PS_PED | XHCI_PS_PLS_MASK |
|
||||
portsc &= XHCI_PS_PED | XHCI_PS_PLS_MASK |
|
||||
XHCI_PS_SPEED_MASK | XHCI_PS_PIC_MASK;
|
||||
|
||||
if (XHCI_DEVINST_PTR(xdev, port))
|
||||
p->portsc |= XHCI_PS_CCS;
|
||||
|
||||
p->portsc |= (value &
|
||||
portsc |= (value &
|
||||
~(XHCI_PS_OCA |
|
||||
XHCI_PS_PR |
|
||||
XHCI_PS_PED |
|
||||
@ -1316,7 +1349,7 @@ pci_xhci_portregs_write(struct pci_xhci_vdev *xdev,
|
||||
XHCI_PS_LWS | XHCI_PS_DR | XHCI_PS_WPR));
|
||||
|
||||
/* clear control bits */
|
||||
p->portsc &= ~(value &
|
||||
portsc &= ~(value &
|
||||
(XHCI_PS_CSC |
|
||||
XHCI_PS_PEC |
|
||||
XHCI_PS_WRC |
|
||||
@ -1330,16 +1363,18 @@ pci_xhci_portregs_write(struct pci_xhci_vdev *xdev,
|
||||
if (value & XHCI_PS_PED)
|
||||
UPRINTF(LDBG, "Disable port %d request\r\n", port);
|
||||
|
||||
if (!(value & XHCI_PS_LWS))
|
||||
if (!(value & XHCI_PS_LWS)) {
|
||||
pci_xhci_set_portsc(xdev, port, portsc);
|
||||
break;
|
||||
}
|
||||
|
||||
UPRINTF(LDBG, "Port new PLS: %d\r\n", newpls);
|
||||
switch (newpls) {
|
||||
case 0: /* U0 */
|
||||
case 3: /* U3 */
|
||||
if (oldpls != newpls) {
|
||||
p->portsc &= ~XHCI_PS_PLS_MASK;
|
||||
p->portsc |= XHCI_PS_PLS_SET(newpls);
|
||||
portsc &= ~XHCI_PS_PLS_MASK;
|
||||
portsc |= XHCI_PS_PLS_SET(newpls);
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
@ -1347,8 +1382,9 @@ pci_xhci_portregs_write(struct pci_xhci_vdev *xdev,
|
||||
* consistent with xHCI spec.
|
||||
*/
|
||||
if (newpls == 0)
|
||||
p->portsc |= XHCI_PS_PLC;
|
||||
portsc |= XHCI_PS_PLC;
|
||||
|
||||
pci_xhci_set_portsc(xdev, port, portsc);
|
||||
if (oldpls != 0 && newpls == 0) {
|
||||
pci_xhci_set_evtrb(&evtrb, port,
|
||||
XHCI_TRB_ERROR_SUCCESS,
|
||||
@ -3610,17 +3646,16 @@ pci_xhci_read(struct vmctx *ctx,
|
||||
static void
|
||||
pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
|
||||
{
|
||||
struct pci_xhci_portregs *port;
|
||||
struct xhci_trb evtrb;
|
||||
struct usb_native_devinfo *di;
|
||||
int speed, error;
|
||||
int index;
|
||||
uint32_t portsc;
|
||||
|
||||
assert(portn <= XHCI_MAX_DEVS);
|
||||
|
||||
UPRINTF(LINF, "reset port %d\r\n", portn);
|
||||
|
||||
port = XHCI_PORTREG_PTR(xdev, portn);
|
||||
index = pci_xhci_get_native_port_index_by_vport(xdev, portn);
|
||||
if (index < 0) {
|
||||
UPRINTF(LWRN, "fail to reset port %d\r\n", portn);
|
||||
@ -3628,15 +3663,17 @@ pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
|
||||
}
|
||||
di = &xdev->native_ports[index].info;
|
||||
|
||||
portsc = pci_xhci_get_portsc(xdev, portn);
|
||||
speed = pci_xhci_convert_speed(di->speed);
|
||||
port->portsc &= ~(XHCI_PS_PLS_MASK | XHCI_PS_PR | XHCI_PS_PRC);
|
||||
port->portsc |= XHCI_PS_PED | XHCI_PS_SPEED_SET(speed);
|
||||
portsc &= ~(XHCI_PS_PLS_MASK | XHCI_PS_PR | XHCI_PS_PRC);
|
||||
portsc |= XHCI_PS_PED | XHCI_PS_SPEED_SET(speed);
|
||||
|
||||
if (warm && di->bcd >= 0x300)
|
||||
port->portsc |= XHCI_PS_WRC;
|
||||
portsc |= XHCI_PS_WRC;
|
||||
|
||||
if ((port->portsc & XHCI_PS_PRC) == 0) {
|
||||
port->portsc |= XHCI_PS_PRC;
|
||||
if ((portsc & XHCI_PS_PRC) == 0) {
|
||||
portsc |= XHCI_PS_PRC;
|
||||
pci_xhci_set_portsc(xdev, portn, portsc);
|
||||
|
||||
pci_xhci_set_evtrb(&evtrb, portn,
|
||||
XHCI_TRB_ERROR_SUCCESS,
|
||||
@ -3645,14 +3682,15 @@ pci_xhci_reset_port(struct pci_xhci_vdev *xdev, int portn, int warm)
|
||||
if (error != XHCI_TRB_ERROR_SUCCESS)
|
||||
UPRINTF(LWRN, "reset port insert event "
|
||||
"failed\n");
|
||||
}
|
||||
} else
|
||||
pci_xhci_set_portsc(xdev, portn, portsc);
|
||||
}
|
||||
|
||||
static void
|
||||
pci_xhci_init_port(struct pci_xhci_vdev *xdev, int portn)
|
||||
{
|
||||
XHCI_PORTREG_PTR(xdev, portn)->portsc =
|
||||
XHCI_PS_PLS_SET(UPS_PORT_LS_RX_DET) | XHCI_PS_PP;
|
||||
pci_xhci_set_portsc(xdev, portn, XHCI_PS_PLS_SET(UPS_PORT_LS_RX_DET)
|
||||
| XHCI_PS_PP);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -3662,11 +3700,11 @@ pci_xhci_dev_intr(struct usb_hci *hci, int epctx)
|
||||
struct xhci_dev_ctx *dev_ctx;
|
||||
struct xhci_trb evtrb;
|
||||
struct pci_xhci_vdev *xdev;
|
||||
struct pci_xhci_portregs *p;
|
||||
struct xhci_endp_ctx *ep_ctx;
|
||||
int error = 0;
|
||||
int dir_in;
|
||||
int epid;
|
||||
uint32_t portsc;
|
||||
|
||||
dir_in = epctx & 0x80;
|
||||
epid = epctx & ~0x80;
|
||||
@ -3685,16 +3723,19 @@ pci_xhci_dev_intr(struct usb_hci *hci, int epctx)
|
||||
dev->dev_ctx == NULL)
|
||||
return 0;
|
||||
|
||||
p = XHCI_PORTREG_PTR(xdev, hci->hci_port);
|
||||
portsc = pci_xhci_get_portsc(xdev, hci->hci_port);
|
||||
|
||||
/* raise event if link U3 (suspended) state */
|
||||
if (XHCI_PS_PLS_GET(p->portsc) == 3) {
|
||||
p->portsc &= ~XHCI_PS_PLS_MASK;
|
||||
p->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_RESUME);
|
||||
if ((p->portsc & XHCI_PS_PLC) != 0)
|
||||
if (XHCI_PS_PLS_GET(portsc) == 3) {
|
||||
portsc &= ~XHCI_PS_PLS_MASK;
|
||||
portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_RESUME);
|
||||
if ((portsc & XHCI_PS_PLC) != 0) {
|
||||
pci_xhci_set_portsc(xdev, hci->hci_port, portsc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->portsc |= XHCI_PS_PLC;
|
||||
portsc |= XHCI_PS_PLC;
|
||||
pci_xhci_set_portsc(xdev, hci->hci_port, portsc);
|
||||
|
||||
pci_xhci_set_evtrb(&evtrb, hci->hci_port,
|
||||
XHCI_TRB_ERROR_SUCCESS,
|
||||
|
Loading…
Reference in New Issue
Block a user