DM USB: xHCI: support multiple hubs in single layer

This patch is used to enable multiple hubs in single layer under
Flat Mode.

Tracked-On: #1434
Signed-off-by: Liang Yang <liang3.yang@intel.com>
Signed-off-by: Xiaoguang Wu <xiaoguang.wu@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Liang Yang 2018-10-08 19:22:01 +08:00 committed by Xie, Nanlin
parent 6886d3cdf8
commit f533a07af1
5 changed files with 222 additions and 22 deletions

View File

@ -571,6 +571,112 @@ pci_xhci_get_native_port_index_by_vport(struct pci_xhci_vdev *xdev,
return -1;
}
static void
pci_xhci_clr_native_port_assigned(struct pci_xhci_vdev *xdev,
struct usb_native_devinfo *info)
{
int i;
assert(xdev);
assert(info);
assert(xdev->native_ports);
i = pci_xhci_get_native_port_index_by_path(xdev, &info->path);
if (i >= 0) {
xdev->native_ports[i].state = VPORT_FREE;
xdev->native_ports[i].vport = 0;
}
}
static int
pci_xhci_assign_hub_ports(struct pci_xhci_vdev *xdev,
struct usb_native_devinfo *info)
{
int index;
uint8_t i;
struct usb_native_devinfo di;
struct usb_devpath *path;
if (!xdev || !info || info->type != USB_TYPE_EXTHUB)
return -1;
index = pci_xhci_get_native_port_index_by_path(xdev, &info->path);
if (index < 0) {
UPRINTF(LDBG, "cannot find hub %d-%s\r\n", info->path.bus,
usb_dev_path(&info->path));
return -1;
}
xdev->native_ports[index].info = *info;
UPRINTF(LDBG, "Found an USB hub %d-%s with %d port(s).\r\n",
info->path.bus, usb_dev_path(&info->path),
info->maxchild);
path = &di.path;
for (i = 1; i <= info->maxchild; i++) {
/* make a device path for hub ports */
memcpy(path->path, info->path.path, info->path.depth);
memcpy(path->path + info->path.depth, &i, sizeof(i));
memset(path->path + info->path.depth + 1, 0,
USB_MAX_TIERS - info->path.depth - 1);
path->depth = info->path.depth + 1;
path->bus = info->path.bus;
/* set the device path as assigned */
index = pci_xhci_set_native_port_assigned(xdev, &di);
if (index < 0) {
UPRINTF(LFTL, "too many USB devices\r\n");
return -1;
}
UPRINTF(LDBG, "Add %d-%s as assigned port\r\n",
path->bus, usb_dev_path(path));
}
return 0;
}
static int
pci_xhci_unassign_hub_ports(struct pci_xhci_vdev *xdev,
struct usb_native_devinfo *info)
{
uint8_t i, index;
struct usb_native_devinfo di, *oldinfo;
struct usb_devpath *path;
if (!xdev || !info || info->type != USB_TYPE_EXTHUB)
return -1;
index = pci_xhci_get_native_port_index_by_path(xdev, &info->path);
if (index < 0) {
UPRINTF(LFTL, "cannot find USB hub %d-%s\r\n",
info->path.bus, usb_dev_path(&info->path));
return -1;
}
oldinfo = &xdev->native_ports[index].info;
UPRINTF(LDBG, "Disconnect an USB hub %d-%s with %d port(s)\r\n",
oldinfo->path.bus, usb_dev_path(&oldinfo->path),
oldinfo->maxchild);
path = &di.path;
for (i = 1; i <= oldinfo->maxchild; i++) {
/* make a device path for hub ports */
memcpy(path->path, oldinfo->path.path, oldinfo->path.depth);
memcpy(path->path + oldinfo->path.depth, &i, sizeof(i));
memset(path->path + oldinfo->path.depth + 1, 0,
USB_MAX_TIERS - oldinfo->path.depth - 1);
path->depth = oldinfo->path.depth + 1;
path->bus = oldinfo->path.bus;
/* clear the device path as not assigned */
pci_xhci_clr_native_port_assigned(xdev, &di);
UPRINTF(LDBG, "Del %d-%s as assigned port\r\n",
path->bus, usb_dev_path(path));
}
return 0;
}
static int
pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
{
@ -579,6 +685,7 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
int vport;
int need_intr = 1;
int index;
int rc;
xdev = hci_data;
@ -600,6 +707,15 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
di->path.bus, usb_dev_path(&di->path));
return 0;
}
if (di->type == USB_TYPE_EXTHUB) {
rc = pci_xhci_assign_hub_ports(xdev, di);
if (rc < 0)
UPRINTF(LFTL, "fail to assign ports of hub %d-%s\r\n",
di->path.bus, usb_dev_path(&di->path));
return 0;
}
UPRINTF(LDBG, "%04x:%04x %d-%s belong to this vm.\r\n", di->vid,
di->pid, di->path.bus, usb_dev_path(&di->path));
@ -637,11 +753,12 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
{
struct pci_xhci_vdev *xdev;
struct pci_xhci_dev_emu *edev;
struct usb_native_devinfo di;
struct usb_native_devinfo *di;
uint8_t vport, slot;
uint16_t state;
int need_intr = 1;
int index;
int rc;
assert(hci_data);
assert(dev_data);
@ -649,20 +766,29 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
xdev = hci_data;
assert(xdev->devices);
di = *((struct usb_native_devinfo *)dev_data);
if (!pci_xhci_is_valid_portnum(ROOTHUB_PORT(di.path))) {
di = dev_data;
if (!pci_xhci_is_valid_portnum(ROOTHUB_PORT(di->path))) {
UPRINTF(LFTL, "invalid physical port %d\r\n",
ROOTHUB_PORT(di.path));
ROOTHUB_PORT(di->path));
return -1;
}
index = pci_xhci_get_native_port_index_by_path(xdev, &di.path);
index = pci_xhci_get_native_port_index_by_path(xdev, &di->path);
if (index < 0) {
UPRINTF(LFTL, "fail to find physical port %d\r\n",
ROOTHUB_PORT(di.path));
ROOTHUB_PORT(di->path));
return -1;
}
if (di->type == USB_TYPE_EXTHUB) {
rc = pci_xhci_unassign_hub_ports(xdev, di);
if (rc < 0)
UPRINTF(LFTL, "fail to unassign the ports of hub"
" %d-%s\r\n", di->path.bus,
usb_dev_path(&di->path));
return 0;
}
state = xdev->native_ports[index].state;
vport = xdev->native_ports[index].vport;
@ -674,8 +800,8 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
* cleared for future connecting.
*/
UPRINTF(LFTL, "disconnect VPORT_CONNECTED device: "
"%d-%s vport %d\r\n", di.path.bus,
usb_dev_path(&di.path), vport);
"%d-%s vport %d\r\n", di->path.bus,
usb_dev_path(&di->path), vport);
pci_xhci_disconnect_port(xdev, vport, 0);
xdev->native_ports[index].state = VPORT_ASSIGNED;
return 0;

View File

@ -46,6 +46,24 @@ usb_get_native_devinfo(struct libusb_device *ldev,
return false;
}
/* set device type */
if (ROOTHUB_PORT(info->path) == 0)
info->type = USB_TYPE_ROOTHUB;
else if (d.bDeviceClass == LIBUSB_CLASS_HUB)
info->type = USB_TYPE_EXTHUB;
else if (info->path.path[1] == 0)
info->type = USB_TYPE_ROOTHUB_SUBDEV;
else
info->type = USB_TYPE_EXTHUB_SUBDEV;
if (info->type == USB_TYPE_EXTHUB) {
info->maxchild = usb_get_hub_port_num(&info->path);
if (info->maxchild < 0)
UPRINTF(LFTL, "fail to get count of numbers of hub"
" %d-%s\r\n", info->path.bus,
usb_dev_path(&info->path));
}
info->pid = d.idProduct;
info->vid = d.idVendor;
info->bcd = d.bcdUSB;
@ -73,15 +91,36 @@ usb_dev_scan_dev()
if (num_devs < 0)
return -1;
/* first pass, process external hubs */
for (i = 0; i < num_devs; ++i) {
ldev = devlist[i];
ret = usb_get_native_devinfo(ldev, &di, &d);
if (ret == false)
continue;
if (ROOTHUB_PORT(di.path) == 0)
continue;
if (d.bDeviceClass == LIBUSB_CLASS_HUB)
if (di.type != USB_TYPE_EXTHUB)
continue;
if (g_ctx.conn_cb)
g_ctx.conn_cb(g_ctx.hci_data, &di);
}
/* second pass, process devices */
for (i = 0; i < num_devs; ++i) {
ldev = devlist[i];
ret = usb_get_native_devinfo(ldev, &di, &d);
if (ret == false)
continue;
if (ROOTHUB_PORT(di.path) == 0)
continue;
if (di.type == USB_TYPE_EXTHUB)
continue;
if (g_ctx.conn_cb)
@ -941,8 +980,8 @@ usb_dev_init(void *pdata, char *opt)
int ver;
assert(pdata);
di = pdata;
libusb_get_device_descriptor(di->priv_data, &desc);
UPRINTF(LINF, "Found USB device: %d-%s\r\nPID(0x%X), VID(0x%X) CLASS"
"(0x%X) SUBCLASS(0x%X) BCD(0x%X) SPEED(%d)\r\n",
@ -1088,7 +1127,6 @@ usb_dev_native_sys_conn_cb(struct libusb_context *ctx, struct libusb_device
*ldev, libusb_hotplug_event event, void *pdata)
{
struct usb_native_devinfo di;
struct libusb_device_descriptor d;
bool ret;
UPRINTF(LDBG, "connect event\r\n");
@ -1098,13 +1136,10 @@ usb_dev_native_sys_conn_cb(struct libusb_context *ctx, struct libusb_device
return -1;
}
ret = usb_get_native_devinfo(ldev, &di, &d);
ret = usb_get_native_devinfo(ldev, &di, NULL);
if (ret == false)
return 0;
if (d.bDeviceClass == LIBUSB_CLASS_HUB)
return 0;
if (g_ctx.conn_cb)
g_ctx.conn_cb(g_ctx.hci_data, &di);
@ -1116,7 +1151,6 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
*ldev, libusb_hotplug_event event, void *pdata)
{
struct usb_native_devinfo di;
struct libusb_device_descriptor d;
bool ret;
UPRINTF(LDBG, "disconnect event\r\n");
@ -1126,13 +1160,10 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
return -1;
}
ret = usb_get_native_devinfo(ldev, &di, &d);
ret = usb_get_native_devinfo(ldev, &di, NULL);
if (ret == false)
return 0;
if (d.bDeviceClass == LIBUSB_CLASS_HUB)
return 0;
if (g_ctx.disconn_cb)
g_ctx.disconn_cb(g_ctx.hci_data, &di);

View File

@ -264,3 +264,37 @@ usb_dev_path(struct usb_devpath *path)
return output;
}
int
usb_get_hub_port_num(struct usb_devpath *path)
{
int rc, fd;
char buf[128];
char cnt[8];
if (!usb_native_is_bus_existed(path->bus))
return -1;
snprintf(buf, sizeof(buf), "%s/%d-%s/maxchild", NATIVE_USBSYS_DEVDIR,
path->bus, usb_dev_path(path));
if (access(buf, R_OK)) {
UPRINTF(LWRN, "can't find maxchild file\r\n");
return -1;
}
fd = open(buf, O_RDONLY);
if (fd < 0) {
UPRINTF(LWRN, "fail to open maxchild file\r\n");
return -1;
}
rc = read(fd, &cnt, sizeof(cnt));
if (rc < 0) {
UPRINTF(LWRN, "fail to read maxchild file\r\n");
close(fd);
return -1;
}
close(fd);
return atoi(cnt);
}

View File

@ -84,6 +84,14 @@ enum usb_xfer_blk_stat {
USB_XFER_BLK_HANDLED
};
enum usb_native_devtype {
USB_TYPE_ROOTHUB,
USB_TYPE_EXTHUB,
USB_TYPE_ROOTHUB_SUBDEV,
USB_TYPE_EXTHUB_SUBDEV,
USB_TYPE_NONE
};
#define USB_MAX_TIERS 7
struct usb_hci;
@ -174,9 +182,11 @@ struct usb_devpath {
struct usb_native_devinfo {
int speed;
int maxchild;
uint16_t bcd;
uint16_t pid;
uint16_t vid;
enum usb_native_devtype type;
struct usb_devpath path;
void *priv_data;
};
@ -247,5 +257,6 @@ struct usb_data_xfer_block *usb_data_xfer_append(struct usb_data_xfer *xfer,
int blen,
void *hci_data,
int ccs);
int usb_get_hub_port_num(struct usb_devpath *path);
char *usb_dev_path(struct usb_devpath *path);
#endif /* _USB_CORE_H_ */

View File

@ -119,6 +119,4 @@ int usb_dev_info(void *pdata, int type, void *value, int size);
int usb_dev_request(void *pdata, struct usb_data_xfer *xfer);
int usb_dev_reset(void *pdata);
int usb_dev_data(void *pdata, struct usb_data_xfer *xfer, int dir, int epctx);
enum usb_native_dev_type usb_get_parent_dev_type(void *pdata, uint16_t *bus,
uint16_t *port);
#endif