Expand the MSI/MSI-X API to address some deficiencies in the MSI-X support.
- First off, device drivers really do need to know if they are allocating MSI or MSI-X messages. MSI requires allocating powerof2() messages for example where MSI-X does not. To address this, split out the MSI-X support from pci_msi_count() and pci_alloc_msi() into new driver-visible functions pci_msix_count() and pci_alloc_msix(). As a result, pci_msi_count() now just returns a count of the max supported MSI messages for the device, and pci_alloc_msi() only tries to allocate MSI messages. To get a count of the max supported MSI-X messages, use pci_msix_count(). To allocate MSI-X messages, use pci_alloc_msix(). pci_release_msi() still handles both MSI and MSI-X messages, however. As a result of this change, drivers using the existing API will only use MSI messages and will no longer try to use MSI-X messages. - Because MSI-X allows for each message to have its own data and address values (and thus does not require all of the messages to have their MD vectors allocated as a group), some devices allow for "sparse" use of MSI-X message slots. For example, if a device supports 8 messages but the OS is only able to allocate 2 messages, the device may make the best use of 2 IRQs if it enables the messages at slots 1 and 4 rather than default of using the first N slots (or indicies) at 1 and 2. To support this, add a new pci_remap_msix() function that a driver may call after a successful pci_alloc_msix() (but before allocating any of the SYS_RES_IRQ resources) to allow the allocated IRQ resources to be assigned to different message indices. For example, from the earlier example, after pci_alloc_msix() returned a value of 2, the driver would call pci_remap_msix() passing in array of integers { 1, 4 } as the new message indices to use. The rid's for the SYS_RES_IRQ resources will always match the message indices. Thus, after the call to pci_remap_msix() the driver would be able to access the first message in slot 1 at SYS_RES_IRQ rid 1, and the second message at slot 4 at SYS_RES_IRQ rid 4. Note that the message slots/indices are 1-based rather than 0-based so that they will always correspond to the rid values (SYS_RES_IRQ rid 0 is reserved for the legacy INTx interrupt). To support this API, a new PCIB_REMAP_MSIX() method was added to the pcib interface to change the message index for a single IRQ. Tested by: scottl
This commit is contained in:
parent
7c32173ba8
commit
5fe82bca57
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=166176
@ -120,6 +120,7 @@ static device_method_t mptable_hostb_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, mptable_hostb_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, mptable_hostb_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{ 0, 0 }
|
||||
@ -176,6 +177,7 @@ static device_method_t mptable_pcib_pci_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{0, 0}
|
||||
|
@ -479,6 +479,30 @@ msix_alloc(device_t dev, int index, int *irq, int *new)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
msix_remap(int index, int irq)
|
||||
{
|
||||
struct msi_intsrc *msi;
|
||||
|
||||
sx_xlock(&msi_sx);
|
||||
msi = (struct msi_intsrc *)intr_lookup_source(irq);
|
||||
if (msi == NULL) {
|
||||
sx_xunlock(&msi_sx);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
/* Make sure this is an MSI-X message. */
|
||||
if (!msi->msi_msix) {
|
||||
sx_xunlock(&msi_sx);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
KASSERT(msi->msi_dev != NULL, ("unowned message"));
|
||||
msi->msi_index = index;
|
||||
sx_xunlock(&msi_sx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
msix_release(int irq)
|
||||
{
|
||||
|
@ -105,6 +105,7 @@ static void nexus_delete_resource(device_t, device_t, int, int);
|
||||
static int nexus_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs);
|
||||
static int nexus_release_msi(device_t pcib, device_t dev, int count, int *irqs);
|
||||
static int nexus_alloc_msix(device_t pcib, device_t dev, int index, int *irq);
|
||||
static int nexus_remap_msix(device_t pcib, device_t dev, int index, int irq);
|
||||
static int nexus_release_msix(device_t pcib, device_t dev, int irq);
|
||||
|
||||
static device_method_t nexus_methods[] = {
|
||||
@ -135,6 +136,7 @@ static device_method_t nexus_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, nexus_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, nexus_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, nexus_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, nexus_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, nexus_release_msix),
|
||||
|
||||
{ 0, 0 }
|
||||
@ -509,6 +511,13 @@ nexus_alloc_msix(device_t pcib, device_t dev, int index, int *irq)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_remap_msix(device_t pcib, device_t dev, int index, int irq)
|
||||
{
|
||||
|
||||
return (msix_remap(index, irq));
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_release_msix(device_t pcib, device_t dev, int irq)
|
||||
{
|
||||
|
@ -152,6 +152,7 @@ int msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
|
||||
void msi_init(void);
|
||||
int msi_release(int *irqs, int count);
|
||||
int msix_alloc(device_t dev, int index, int *irq, int *new);
|
||||
int msix_remap(int index, int irq);
|
||||
int msix_release(int irq);
|
||||
|
||||
#endif /* !LOCORE */
|
||||
|
@ -347,6 +347,7 @@ static device_method_t legacy_pcib_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{ 0, 0 }
|
||||
|
@ -110,6 +110,7 @@ static device_method_t acpi_pcib_acpi_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, acpi_pcib_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, acpi_pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{0, 0}
|
||||
|
@ -96,6 +96,7 @@ static device_method_t acpi_pcib_pci_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{0, 0}
|
||||
|
@ -101,6 +101,7 @@ static void pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg,
|
||||
int reg, uint32_t data);
|
||||
#endif
|
||||
static void pci_read_vpd(device_t pcib, pcicfgregs *cfg);
|
||||
static int pci_msi_blacklisted(void);
|
||||
|
||||
static device_method_t pci_methods[] = {
|
||||
/* Device interface */
|
||||
@ -145,8 +146,11 @@ static device_method_t pci_methods[] = {
|
||||
DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method),
|
||||
DEVMETHOD(pci_find_extcap, pci_find_extcap_method),
|
||||
DEVMETHOD(pci_alloc_msi, pci_alloc_msi_method),
|
||||
DEVMETHOD(pci_alloc_msix, pci_alloc_msix_method),
|
||||
DEVMETHOD(pci_remap_msix, pci_remap_msix_method),
|
||||
DEVMETHOD(pci_release_msi, pci_release_msi_method),
|
||||
DEVMETHOD(pci_msi_count, pci_msi_count_method),
|
||||
DEVMETHOD(pci_msix_count, pci_msix_count_method),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
@ -1024,14 +1028,36 @@ pci_pending_msix(device_t dev, u_int index)
|
||||
return (bus_read_4(cfg->msix.msix_pba_res, offset) & bit);
|
||||
}
|
||||
|
||||
static int
|
||||
pci_alloc_msix(device_t dev, device_t child, int *count)
|
||||
/*
|
||||
* Attempt to allocate *count MSI-X messages. The actual number allocated is
|
||||
* returned in *count. After this function returns, each message will be
|
||||
* available to the driver as SYS_RES_IRQ resources starting at rid 1.
|
||||
*/
|
||||
int
|
||||
pci_alloc_msix_method(device_t dev, device_t child, int *count)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(child);
|
||||
pcicfgregs *cfg = &dinfo->cfg;
|
||||
struct resource_list_entry *rle;
|
||||
int actual, error, i, irq, max;
|
||||
|
||||
/* Don't let count == 0 get us into trouble. */
|
||||
if (*count == 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* If rid 0 is allocated, then fail. */
|
||||
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0);
|
||||
if (rle != NULL && rle->res != NULL)
|
||||
return (ENXIO);
|
||||
|
||||
/* Already have allocated messages? */
|
||||
if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0)
|
||||
return (ENXIO);
|
||||
|
||||
/* If MSI is blacklisted for this system, fail. */
|
||||
if (pci_msi_blacklisted())
|
||||
return (ENXIO);
|
||||
|
||||
/* MSI-X capability present? */
|
||||
if (cfg->msix.msix_location == 0 || !pci_do_msix)
|
||||
return (ENODEV);
|
||||
@ -1052,10 +1078,6 @@ pci_alloc_msix(device_t dev, device_t child, int *count)
|
||||
}
|
||||
cfg->msix.msix_pba_res = rle->res;
|
||||
|
||||
/* Already have allocated messages? */
|
||||
if (cfg->msix.msix_alloc != 0)
|
||||
return (ENXIO);
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(child,
|
||||
"attempting to allocate %d MSI-X vectors (%d supported)\n",
|
||||
@ -1132,24 +1154,105 @@ pci_alloc_msix(device_t dev, device_t child, int *count)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* By default, pci_alloc_msix() will assign the allocated IRQ resources to
|
||||
* the first N messages in the MSI-X table. However, device drivers may
|
||||
* want to use different layouts in the case that they do not allocate a
|
||||
* full table. This method allows the driver to specify what layout it
|
||||
* wants. It must be called after a successful pci_alloc_msix() but
|
||||
* before any of the associated SYS_RES_IRQ resources are allocated via
|
||||
* bus_alloc_resource(). The 'indices' array contains N (where N equals
|
||||
* the 'count' returned from pci_alloc_msix()) message indices. The
|
||||
* indices are 1-based (meaning the first message is at index 1). On
|
||||
* successful return, each of the messages in the 'indices' array will
|
||||
* have an associated SYS_RES_IRQ whose rid is equal to the index. Thus,
|
||||
* if indices contains { 2, 4 }, then upon successful return, the 'child'
|
||||
* device will have two SYS_RES_IRQ resources available at rids 2 and 4.
|
||||
*/
|
||||
int
|
||||
pci_remap_msix_method(device_t dev, device_t child, u_int *indices)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(child);
|
||||
pcicfgregs *cfg = &dinfo->cfg;
|
||||
struct resource_list_entry *rle;
|
||||
int count, error, i, j, *irqs;
|
||||
|
||||
/* Sanity check the indices. */
|
||||
for (i = 0; i < cfg->msix.msix_alloc; i++)
|
||||
if (indices[i] == 0 || indices[i] > cfg->msix.msix_msgnum)
|
||||
return (EINVAL);
|
||||
|
||||
/* Check for duplicates. */
|
||||
for (i = 0; i < cfg->msix.msix_alloc; i++)
|
||||
for (j = i + 1; j < cfg->msix.msix_alloc; j++)
|
||||
if (indices[i] == indices[j])
|
||||
return (EINVAL);
|
||||
|
||||
/* Make sure none of the resources are allocated. */
|
||||
for (i = 1, count = 0; count < cfg->msix.msix_alloc; i++) {
|
||||
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i);
|
||||
if (rle == NULL)
|
||||
continue;
|
||||
if (rle->res != NULL)
|
||||
return (EBUSY);
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Save the IRQ values and free the existing resources. */
|
||||
irqs = malloc(sizeof(int) * cfg->msix.msix_alloc, M_TEMP, M_WAITOK);
|
||||
for (i = 1, count = 0; count < cfg->msix.msix_alloc; i++) {
|
||||
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i);
|
||||
if (rle == NULL)
|
||||
continue;
|
||||
irqs[count] = rle->start;
|
||||
resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i);
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Map the IRQ values to the new message indices and rids. */
|
||||
for (i = 0; i < cfg->msix.msix_alloc; i++) {
|
||||
resource_list_add(&dinfo->resources, SYS_RES_IRQ, indices[i],
|
||||
irqs[i], irqs[i], 1);
|
||||
error = PCIB_REMAP_MSIX(device_get_parent(dev), child,
|
||||
indices[i], irqs[i]);
|
||||
KASSERT(error == 0, ("Failed to remap MSI-X message"));
|
||||
}
|
||||
if (bootverbose) {
|
||||
if (cfg->msix.msix_alloc == 1)
|
||||
device_printf(child,
|
||||
"Remapped MSI-X IRQ to index %d\n", indices[0]);
|
||||
else {
|
||||
device_printf(child, "Remapped MSI-X IRQs to indices");
|
||||
for (i = 0; i < cfg->msix.msix_alloc - 1; i++)
|
||||
printf(" %d,", indices[i]);
|
||||
printf(" %d\n", indices[cfg->msix.msix_alloc - 1]);
|
||||
}
|
||||
}
|
||||
free(irqs, M_TEMP);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
pci_release_msix(device_t dev, device_t child)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(child);
|
||||
pcicfgregs *cfg = &dinfo->cfg;
|
||||
struct resource_list_entry *rle;
|
||||
int i;
|
||||
int count, i;
|
||||
|
||||
/* Do we have any messages to release? */
|
||||
if (cfg->msix.msix_alloc == 0)
|
||||
return (ENODEV);
|
||||
|
||||
/* Make sure none of the resources are allocated. */
|
||||
for (i = 0; i < cfg->msix.msix_alloc; i++) {
|
||||
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
|
||||
KASSERT(rle != NULL, ("missing MSI resource"));
|
||||
for (i = 1, count = 0; count < cfg->msix.msix_alloc; i++) {
|
||||
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i);
|
||||
if (rle == NULL)
|
||||
continue;
|
||||
if (rle->res != NULL)
|
||||
return (EBUSY);
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Update control register with to disable MSI-X. */
|
||||
@ -1158,11 +1261,14 @@ pci_release_msix(device_t dev, device_t child)
|
||||
cfg->msix.msix_ctrl, 2);
|
||||
|
||||
/* Release the messages. */
|
||||
for (i = 0; i < cfg->msix.msix_alloc; i++) {
|
||||
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
|
||||
for (i = 1, count = 0; count < cfg->msix.msix_alloc; i++) {
|
||||
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i);
|
||||
if (rle == NULL)
|
||||
continue;
|
||||
PCIB_RELEASE_MSIX(device_get_parent(dev), child,
|
||||
rle->start);
|
||||
resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1);
|
||||
resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i);
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Update alloc count. */
|
||||
@ -1170,6 +1276,23 @@ pci_release_msix(device_t dev, device_t child)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the max supported MSI-X messages this device supports.
|
||||
* Basically, assuming the MD code can alloc messages, this function
|
||||
* should return the maximum value that pci_alloc_msix() can return.
|
||||
* Thus, it is subject to the tunables, etc.
|
||||
*/
|
||||
int
|
||||
pci_msix_count_method(device_t dev, device_t child)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(child);
|
||||
pcicfgregs *cfg = &dinfo->cfg;
|
||||
|
||||
if (pci_do_msix && cfg->msix.msix_location != 0)
|
||||
return (cfg->msix.msix_msgnum);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for MSI message signalled interrupts.
|
||||
*/
|
||||
@ -1294,23 +1417,18 @@ pci_alloc_msi_method(device_t dev, device_t child, int *count)
|
||||
if (rle != NULL && rle->res != NULL)
|
||||
return (ENXIO);
|
||||
|
||||
/* Already have allocated messages? */
|
||||
if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0)
|
||||
return (ENXIO);
|
||||
|
||||
/* If MSI is blacklisted for this system, fail. */
|
||||
if (pci_msi_blacklisted())
|
||||
return (ENXIO);
|
||||
|
||||
/* Try MSI-X first. */
|
||||
error = pci_alloc_msix(dev, child, count);
|
||||
if (error != ENODEV)
|
||||
return (error);
|
||||
|
||||
/* MSI capability present? */
|
||||
if (cfg->msi.msi_location == 0 || !pci_do_msi)
|
||||
return (ENODEV);
|
||||
|
||||
/* Already have allocated messages? */
|
||||
if (cfg->msi.msi_alloc != 0)
|
||||
return (ENXIO);
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(child,
|
||||
"attempting to allocate %d MSI vectors (%d supported)\n",
|
||||
@ -1444,10 +1562,10 @@ pci_release_msi_method(device_t dev, device_t child)
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the max supported MSI or MSI-X messages this device supports.
|
||||
* Return the max supported MSI messages this device supports.
|
||||
* Basically, assuming the MD code can alloc messages, this function
|
||||
* should return the maximum value that pci_alloc_msi() can return. Thus,
|
||||
* it is subject to the tunables, etc.
|
||||
* should return the maximum value that pci_alloc_msi() can return.
|
||||
* Thus, it is subject to the tunables, etc.
|
||||
*/
|
||||
int
|
||||
pci_msi_count_method(device_t dev, device_t child)
|
||||
@ -1455,8 +1573,6 @@ pci_msi_count_method(device_t dev, device_t child)
|
||||
struct pci_devinfo *dinfo = device_get_ivars(child);
|
||||
pcicfgregs *cfg = &dinfo->cfg;
|
||||
|
||||
if (pci_do_msix && cfg->msix.msix_location != 0)
|
||||
return (cfg->msix.msix_msgnum);
|
||||
if (pci_do_msi && cfg->msi.msi_location != 0)
|
||||
return (cfg->msi.msi_msgnum);
|
||||
return (0);
|
||||
|
@ -118,6 +118,18 @@ METHOD int alloc_msi {
|
||||
int *count;
|
||||
};
|
||||
|
||||
METHOD int alloc_msix {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
int *count;
|
||||
};
|
||||
|
||||
METHOD int remap_msix {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
u_int *indices;
|
||||
};
|
||||
|
||||
METHOD int release_msi {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
@ -127,3 +139,8 @@ METHOD int msi_count {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
} DEFAULT null_msi_count;
|
||||
|
||||
METHOD int msix_count {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
} DEFAULT null_msi_count;
|
||||
|
@ -82,6 +82,7 @@ static device_method_t pcib_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{ 0, 0 }
|
||||
@ -583,6 +584,16 @@ pcib_alloc_msix(device_t pcib, device_t dev, int index, int *irq)
|
||||
return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, index, irq));
|
||||
}
|
||||
|
||||
/* Pass request to remap an MSI-X message up to the parent bridge. */
|
||||
int
|
||||
pcib_remap_msix(device_t pcib, device_t dev, int index, int irq)
|
||||
{
|
||||
device_t bus;
|
||||
|
||||
bus = device_get_parent(pcib);
|
||||
return (PCIB_REMAP_MSIX(device_get_parent(bus), dev, index, irq));
|
||||
}
|
||||
|
||||
/* Pass request to release an MSI-X message up to the parent bridge. */
|
||||
int
|
||||
pcib_release_msix(device_t pcib, device_t dev, int irq)
|
||||
|
@ -67,8 +67,12 @@ int pci_disable_io_method(device_t dev, device_t child, int space);
|
||||
int pci_find_extcap_method(device_t dev, device_t child,
|
||||
int capability, int *capreg);
|
||||
int pci_alloc_msi_method(device_t dev, device_t child, int *count);
|
||||
int pci_alloc_msix_method(device_t dev, device_t child, int *count);
|
||||
int pci_remap_msix_method(device_t dev, device_t child,
|
||||
u_int *indices);
|
||||
int pci_release_msi_method(device_t dev, device_t child);
|
||||
int pci_msi_count_method(device_t dev, device_t child);
|
||||
int pci_msix_count_method(device_t dev, device_t child);
|
||||
struct resource *pci_alloc_resource(device_t dev, device_t child,
|
||||
int type, int *rid, u_long start, u_long end, u_long count,
|
||||
u_int flags);
|
||||
|
@ -125,6 +125,16 @@ METHOD int alloc_msix {
|
||||
int *irq;
|
||||
};
|
||||
|
||||
#
|
||||
# Remap a single MSI-X message to a different index.
|
||||
#
|
||||
METHOD int remap_msix {
|
||||
device_t pcib;
|
||||
device_t dev;
|
||||
int index;
|
||||
int irq;
|
||||
};
|
||||
|
||||
#
|
||||
# Release a single MSI-X message mapped onto 'irq'.
|
||||
#
|
||||
|
@ -78,6 +78,7 @@ int pcib_route_interrupt(device_t pcib, device_t dev, int pin);
|
||||
int pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs);
|
||||
int pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs);
|
||||
int pcib_alloc_msix(device_t pcib, device_t dev, int index, int *irq);
|
||||
int pcib_remap_msix(device_t pcib, device_t dev, int index, int irq);
|
||||
int pcib_release_msix(device_t pcib, device_t dev, int irq);
|
||||
|
||||
#endif
|
||||
|
@ -395,6 +395,18 @@ pci_alloc_msi(device_t dev, int *count)
|
||||
return (PCI_ALLOC_MSI(device_get_parent(dev), dev, count));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
pci_alloc_msix(device_t dev, int *count)
|
||||
{
|
||||
return (PCI_ALLOC_MSIX(device_get_parent(dev), dev, count));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
pci_remap_msix(device_t dev, u_int *indices)
|
||||
{
|
||||
return (PCI_REMAP_MSIX(device_get_parent(dev), dev, indices));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
pci_release_msi(device_t dev)
|
||||
{
|
||||
@ -407,6 +419,12 @@ pci_msi_count(device_t dev)
|
||||
return (PCI_MSI_COUNT(device_get_parent(dev), dev));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
pci_msix_count(device_t dev)
|
||||
{
|
||||
return (PCI_MSIX_COUNT(device_get_parent(dev), dev));
|
||||
}
|
||||
|
||||
device_t pci_find_bsf(uint8_t, uint8_t, uint8_t);
|
||||
device_t pci_find_device(uint16_t, uint16_t);
|
||||
|
||||
|
@ -120,6 +120,7 @@ static device_method_t mptable_hostb_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, mptable_hostb_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, mptable_hostb_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{ 0, 0 }
|
||||
@ -176,6 +177,7 @@ static device_method_t mptable_pcib_pci_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{0, 0}
|
||||
|
@ -479,6 +479,30 @@ msix_alloc(device_t dev, int index, int *irq, int *new)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
msix_remap(int index, int irq)
|
||||
{
|
||||
struct msi_intsrc *msi;
|
||||
|
||||
sx_xlock(&msi_sx);
|
||||
msi = (struct msi_intsrc *)intr_lookup_source(irq);
|
||||
if (msi == NULL) {
|
||||
sx_xunlock(&msi_sx);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
/* Make sure this is an MSI-X message. */
|
||||
if (!msi->msi_msix) {
|
||||
sx_xunlock(&msi_sx);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
KASSERT(msi->msi_dev != NULL, ("unowned message"));
|
||||
msi->msi_index = index;
|
||||
sx_xunlock(&msi_sx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
msix_release(int irq)
|
||||
{
|
||||
|
@ -113,6 +113,7 @@ static void nexus_delete_resource(device_t, device_t, int, int);
|
||||
static int nexus_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs);
|
||||
static int nexus_release_msi(device_t pcib, device_t dev, int count, int *irqs);
|
||||
static int nexus_alloc_msix(device_t pcib, device_t dev, int index, int *irq);
|
||||
static int nexus_remap_msix(device_t pcib, device_t dev, int index, int irq);
|
||||
static int nexus_release_msix(device_t pcib, device_t dev, int irq);
|
||||
#endif
|
||||
|
||||
@ -145,6 +146,7 @@ static device_method_t nexus_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, nexus_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, nexus_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, nexus_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, nexus_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, nexus_release_msix),
|
||||
#endif
|
||||
|
||||
@ -565,6 +567,13 @@ nexus_alloc_msix(device_t pcib, device_t dev, int index, int *irq)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_remap_msix(device_t pcib, device_t dev, int index, int irq)
|
||||
{
|
||||
|
||||
return (msix_remap(index, irq));
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_release_msix(device_t pcib, device_t dev, int irq)
|
||||
{
|
||||
|
@ -149,6 +149,7 @@ int msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
|
||||
void msi_init(void);
|
||||
int msi_release(int* irqs, int count);
|
||||
int msix_alloc(device_t dev, int index, int *irq, int *new);
|
||||
int msix_remap(int index, int irq);
|
||||
int msix_release(int irq);
|
||||
|
||||
#endif /* !LOCORE */
|
||||
|
@ -559,6 +559,7 @@ static device_method_t legacy_pcib_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{ 0, 0 }
|
||||
@ -652,6 +653,7 @@ static device_method_t pcibios_pcib_pci_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_remap_msix, pcib_remap_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
|
||||
{0, 0}
|
||||
|
Loading…
Reference in New Issue
Block a user