Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_xhci.c
Show First 20 Lines • Show All 2,653 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* pci.0.1.0 | * pci.0.1.0 | ||||
* .device="xhci" | * .device="xhci" | ||||
* .slot | * .slot | ||||
* .1 | * .1 | ||||
* .device="tablet" | * .device="tablet" | ||||
*/ | */ | ||||
static int | static int | ||||
pci_xhci_legacy_config(nvlist_t *nvl, const char *opts) | pci_xhci_legacy_config(config_node_t *node, const char *opts) | ||||
{ | { | ||||
char node_name[16]; | char node_name[16]; | ||||
nvlist_t *slots_nvl, *slot_nvl; | config_node_t *slots_node, *slot_node; | ||||
char *cp, *opt, *str, *tofree; | char *cp, *opt, *str, *tofree; | ||||
int slot; | int slot; | ||||
if (opts == NULL) | if (opts == NULL) | ||||
return (0); | return (0); | ||||
slots_nvl = create_relative_config_node(nvl, "slot"); | slots_node = create_relative_config_node(node, "slot"); | ||||
slot = 1; | slot = 1; | ||||
tofree = str = strdup(opts); | tofree = str = strdup(opts); | ||||
while ((opt = strsep(&str, ",")) != NULL) { | while ((opt = strsep(&str, ",")) != NULL) { | ||||
/* device[=<config>] */ | /* device[=<config>] */ | ||||
cp = strchr(opt, '='); | cp = strchr(opt, '='); | ||||
if (cp != NULL) { | if (cp != NULL) { | ||||
*cp = '\0'; | *cp = '\0'; | ||||
cp++; | cp++; | ||||
} | } | ||||
snprintf(node_name, sizeof(node_name), "%d", slot); | snprintf(node_name, sizeof(node_name), "%d", slot); | ||||
slot++; | slot++; | ||||
slot_nvl = create_relative_config_node(slots_nvl, node_name); | slot_node = create_relative_config_node(slots_node, node_name); | ||||
set_config_value_node(slot_nvl, "device", opt); | set_config_value_node(slot_node, "device", opt); | ||||
/* | /* | ||||
* NB: Given that we split on commas above, the legacy | * NB: Given that we split on commas above, the legacy | ||||
* format only supports a single option. | * format only supports a single option. | ||||
*/ | */ | ||||
if (cp != NULL && *cp != '\0') | if (cp != NULL && *cp != '\0') | ||||
pci_parse_legacy_config(slot_nvl, cp); | pci_parse_legacy_config(slot_node, cp); | ||||
} | } | ||||
free(tofree); | free(tofree); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
pci_xhci_parse_devices(struct pci_xhci_softc *sc, nvlist_t *nvl) | pci_xhci_parse_devices(struct pci_xhci_softc *sc, config_node_t *node) | ||||
{ | { | ||||
struct pci_xhci_dev_emu *dev; | struct pci_xhci_dev_emu *dev; | ||||
struct usb_devemu *ue; | struct usb_devemu *ue; | ||||
const nvlist_t *slots_nvl, *slot_nvl; | const config_node_t *slots_node, *slot_node; | ||||
const char *name, *device; | const char *name, *device; | ||||
char *cp; | char *cp; | ||||
void *devsc, *cookie; | void *devsc, *cookie; | ||||
long slot; | long slot; | ||||
int type, usb3_port, usb2_port, i, ndevices; | int type, usb3_port, usb2_port, i, ndevices; | ||||
usb3_port = sc->usb3_port_start; | usb3_port = sc->usb3_port_start; | ||||
usb2_port = sc->usb2_port_start; | usb2_port = sc->usb2_port_start; | ||||
sc->devices = calloc(XHCI_MAX_DEVS, sizeof(struct pci_xhci_dev_emu *)); | sc->devices = calloc(XHCI_MAX_DEVS, sizeof(struct pci_xhci_dev_emu *)); | ||||
sc->slots = calloc(XHCI_MAX_SLOTS, sizeof(struct pci_xhci_dev_emu *)); | sc->slots = calloc(XHCI_MAX_SLOTS, sizeof(struct pci_xhci_dev_emu *)); | ||||
/* port and slot numbering start from 1 */ | /* port and slot numbering start from 1 */ | ||||
sc->devices--; | sc->devices--; | ||||
sc->slots--; | sc->slots--; | ||||
ndevices = 0; | ndevices = 0; | ||||
slots_nvl = find_relative_config_node(nvl, "slot"); | slots_node = find_relative_config_node(node, "slot"); | ||||
if (slots_nvl == NULL) | if (slots_node == NULL) | ||||
goto portsfinal; | goto portsfinal; | ||||
cookie = NULL; | cookie = NULL; | ||||
while ((name = nvlist_next(slots_nvl, &type, &cookie)) != NULL) { | while ((name = config_node_next(slots_node, &type, &cookie)) != NULL) { | ||||
if (usb2_port == ((sc->usb2_port_start) + XHCI_MAX_DEVS/2) || | if (usb2_port == ((sc->usb2_port_start) + XHCI_MAX_DEVS/2) || | ||||
usb3_port == ((sc->usb3_port_start) + XHCI_MAX_DEVS/2)) { | usb3_port == ((sc->usb3_port_start) + XHCI_MAX_DEVS/2)) { | ||||
WPRINTF(("pci_xhci max number of USB 2 or 3 " | WPRINTF(("pci_xhci max number of USB 2 or 3 " | ||||
"devices reached, max %d", XHCI_MAX_DEVS/2)); | "devices reached, max %d", XHCI_MAX_DEVS/2)); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
if (type != NV_TYPE_NVLIST) { | if (type != NODE_TYPE_NODE) { | ||||
EPRINTLN( | EPRINTLN( | ||||
"pci_xhci: config variable '%s' under slot node", | "pci_xhci: config variable '%s' under slot node", | ||||
name); | name); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
slot = strtol(name, &cp, 0); | slot = strtol(name, &cp, 0); | ||||
if (*cp != '\0' || slot <= 0 || slot > XHCI_MAX_SLOTS) { | if (*cp != '\0' || slot <= 0 || slot > XHCI_MAX_SLOTS) { | ||||
EPRINTLN("pci_xhci: invalid slot '%s'", name); | EPRINTLN("pci_xhci: invalid slot '%s'", name); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
if (XHCI_SLOTDEV_PTR(sc, slot) != NULL) { | if (XHCI_SLOTDEV_PTR(sc, slot) != NULL) { | ||||
EPRINTLN("pci_xhci: duplicate slot '%s'", name); | EPRINTLN("pci_xhci: duplicate slot '%s'", name); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
slot_nvl = nvlist_get_nvlist(slots_nvl, name); | slot_node = find_relative_config_node(slots_node, name); | ||||
device = get_config_value_node(slot_nvl, "device"); | device = get_config_value_node(slot_node, "device"); | ||||
if (device == NULL) { | if (device == NULL) { | ||||
EPRINTLN( | EPRINTLN( | ||||
"pci_xhci: missing \"device\" value for slot '%s'", | "pci_xhci: missing \"device\" value for slot '%s'", | ||||
name); | name); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
ue = usb_emu_finddev(device); | ue = usb_emu_finddev(device); | ||||
Show All 28 Lines | if (ue->ue_usbver == 2) { | ||||
goto bad; | goto bad; | ||||
} | } | ||||
dev->hci.hci_port = usb3_port; | dev->hci.hci_port = usb3_port; | ||||
usb3_port++; | usb3_port++; | ||||
} | } | ||||
XHCI_DEVINST_PTR(sc, dev->hci.hci_port) = dev; | XHCI_DEVINST_PTR(sc, dev->hci.hci_port) = dev; | ||||
dev->hci.hci_address = 0; | dev->hci.hci_address = 0; | ||||
devsc = ue->ue_init(&dev->hci, nvl); | devsc = ue->ue_init(&dev->hci, node); | ||||
if (devsc == NULL) { | if (devsc == NULL) { | ||||
goto bad; | goto bad; | ||||
} | } | ||||
dev->dev_ue = ue; | dev->dev_ue = ue; | ||||
dev->dev_sc = devsc; | dev->dev_sc = devsc; | ||||
XHCI_SLOTDEV_PTR(sc, slot) = dev; | XHCI_SLOTDEV_PTR(sc, slot) = dev; | ||||
Show All 20 Lines | bad: | ||||
free(sc->devices + 1); | free(sc->devices + 1); | ||||
free(sc->slots + 1); | free(sc->slots + 1); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
static int | static int | ||||
pci_xhci_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | pci_xhci_init(struct vmctx *ctx, struct pci_devinst *pi, config_node_t *node) | ||||
{ | { | ||||
struct pci_xhci_softc *sc; | struct pci_xhci_softc *sc; | ||||
int error; | int error; | ||||
if (xhci_in_use) { | if (xhci_in_use) { | ||||
WPRINTF(("pci_xhci controller already defined")); | WPRINTF(("pci_xhci controller already defined")); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
xhci_in_use = 1; | xhci_in_use = 1; | ||||
sc = calloc(1, sizeof(struct pci_xhci_softc)); | sc = calloc(1, sizeof(struct pci_xhci_softc)); | ||||
pi->pi_arg = sc; | pi->pi_arg = sc; | ||||
sc->xsc_pi = pi; | sc->xsc_pi = pi; | ||||
sc->usb2_port_start = (XHCI_MAX_DEVS/2) + 1; | sc->usb2_port_start = (XHCI_MAX_DEVS/2) + 1; | ||||
sc->usb3_port_start = 1; | sc->usb3_port_start = 1; | ||||
/* discover devices */ | /* discover devices */ | ||||
error = pci_xhci_parse_devices(sc, nvl); | error = pci_xhci_parse_devices(sc, node); | ||||
if (error < 0) | if (error < 0) | ||||
goto done; | goto done; | ||||
else | else | ||||
error = 0; | error = 0; | ||||
sc->caplength = XHCI_SET_CAPLEN(XHCI_CAPLEN) | | sc->caplength = XHCI_SET_CAPLEN(XHCI_CAPLEN) | | ||||
XHCI_SET_HCIVERSION(0x0100); | XHCI_SET_HCIVERSION(0x0100); | ||||
sc->hcsparams1 = XHCI_SET_HCSP1_MAXPORTS(XHCI_MAX_DEVS) | | sc->hcsparams1 = XHCI_SET_HCSP1_MAXPORTS(XHCI_MAX_DEVS) | | ||||
▲ Show 20 Lines • Show All 329 Lines • Show Last 20 Lines |