Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/pci/pci_iov.c
Show First 20 Lines • Show All 660 Lines • ▼ Show 20 Lines | if (error != 0) { | ||||
device_printf(dev, "Failed to add VF %d\n", i); | device_printf(dev, "Failed to add VF %d\n", i); | ||||
device_delete_child(bus, vf); | device_delete_child(bus, vf); | ||||
} | } | ||||
} | } | ||||
bus_generic_attach(bus); | bus_generic_attach(bus); | ||||
} | } | ||||
static bool | |||||
pci_iov_vf_bus_in_range(device_t bus, uint8_t vf_bus) | |||||
{ | |||||
device_t pdev; | |||||
uint8_t secbus, subbus; | |||||
struct pci_devinfo *pdinfo; | |||||
pdev = bus; | |||||
while (pdev != NULL) { | |||||
pdinfo = (struct pci_devinfo *)device_get_ivars(pdev); | |||||
if ((pdinfo != NULL) && | |||||
((pdinfo->cfg.hdrtype & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE)) { | |||||
secbus = pdinfo->cfg.bridge.br_secbus; | |||||
subbus = pdinfo->cfg.bridge.br_subbus; | |||||
if (vf_bus >= secbus && vf_bus <= subbus) | |||||
return (true); | |||||
else if (device_get_parent(pdev) == NULL) { | |||||
device_printf(pdev, "%d is not in allocated bus range: %u-%u\n", | |||||
vf_bus, secbus, subbus); | |||||
break; | |||||
} | |||||
} | |||||
pdev = device_get_parent(pdev); | |||||
} | |||||
return (false); | |||||
} | |||||
static int | static int | ||||
pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg) | pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg) | ||||
{ | { | ||||
device_t bus, dev; | device_t bus, dev; | ||||
struct pci_devinfo *dinfo; | struct pci_devinfo *dinfo; | ||||
struct pcicfg_iov *iov; | struct pcicfg_iov *iov; | ||||
nvlist_t *config; | nvlist_t *config; | ||||
int i, error; | int i, error; | ||||
Show All 36 Lines | pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg) | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
error = pci_iov_init(dev, num_vfs, config); | error = pci_iov_init(dev, num_vfs, config); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
iov_inited = 1; | iov_inited = 1; | ||||
IOV_WRITE(dinfo, PCIR_SRIOV_NUM_VFS, num_vfs, 2); | |||||
rid_off = IOV_READ(dinfo, PCIR_SRIOV_VF_OFF, 2); | rid_off = IOV_READ(dinfo, PCIR_SRIOV_VF_OFF, 2); | ||||
rid_stride = IOV_READ(dinfo, PCIR_SRIOV_VF_STRIDE, 2); | rid_stride = IOV_READ(dinfo, PCIR_SRIOV_VF_STRIDE, 2); | ||||
first_rid = pci_get_rid(dev) + rid_off; | first_rid = pci_get_rid(dev) + rid_off; | ||||
last_rid = first_rid + (num_vfs - 1) * rid_stride; | last_rid = first_rid + (num_vfs - 1) * rid_stride; | ||||
/* We don't yet support allocating extra bus numbers for VFs. */ | /* TODO: Check parent PCI bridges to see if the current VF bus number | ||||
if (pci_get_bus(dev) != PCI_RID2BUS(last_rid)) { | * has already been allocated; we don't yet support allocating extra | ||||
* bus numbers for VFs. | |||||
*/ | |||||
if (!pci_iov_vf_bus_in_range(bus, PCI_RID2BUS(last_rid))) { | |||||
error = ENOSPC; | error = ENOSPC; | ||||
goto out; | goto out; | ||||
} | } | ||||
iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2); | iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2); | ||||
iov_ctl &= ~(PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE); | iov_ctl &= ~(PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE); | ||||
IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2); | IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2); | ||||
error = pci_iov_init_rman(dev, iov); | error = pci_iov_init_rman(dev, iov); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
iov->iov_num_vfs = num_vfs; | iov->iov_num_vfs = num_vfs; | ||||
error = pci_iov_setup_bars(dinfo); | error = pci_iov_setup_bars(dinfo); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2); | iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2); | ||||
iov_ctl |= PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE; | iov_ctl |= PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE; | ||||
IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2); | IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2); | ||||
IOV_WRITE(dinfo, PCIR_SRIOV_NUM_VFS, num_vfs, 2); | |||||
/* Per specification, we must wait 100ms before accessing VFs. */ | /* Per specification, we must wait 100ms before accessing VFs. */ | ||||
pause("iov", roundup(hz, 10)); | pause("iov", roundup(hz, 10)); | ||||
pci_iov_enumerate_vfs(dinfo, config, first_rid, rid_stride); | pci_iov_enumerate_vfs(dinfo, config, first_rid, rid_stride); | ||||
nvlist_destroy(config); | nvlist_destroy(config); | ||||
iov->iov_flags &= ~IOV_BUSY; | iov->iov_flags &= ~IOV_BUSY; | ||||
mtx_unlock(&Giant); | mtx_unlock(&Giant); | ||||
▲ Show 20 Lines • Show All 305 Lines • Show Last 20 Lines |