device/pci: Add MSI-X helper functions
Basic PCI MSI-X table helper functions. Imported from GNU/Linux kernel PCI subsystem. To be used on Cavium to configure MSI-X tables. Change-Id: I94413712e7986efd17e6b11ba59f6eb390384c8c Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-on: https://review.coreboot.org/26329 Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
fe98e90671
commit
4e2f95b789
|
@ -337,6 +337,74 @@ static void pci_get_rom_resource(struct device *dev, unsigned long index)
|
||||||
compact_resources(dev);
|
compact_resources(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a device, read the size of the MSI-X table.
|
||||||
|
*
|
||||||
|
* @param dev Pointer to the device structure.
|
||||||
|
* @return MSI-X table size or 0 if not MSI-X capable device
|
||||||
|
*/
|
||||||
|
size_t pci_msix_table_size(struct device *dev)
|
||||||
|
{
|
||||||
|
const size_t pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
|
||||||
|
if (!pos)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const u16 control = pci_read_config16(dev, pos + PCI_MSIX_FLAGS);
|
||||||
|
return (control & PCI_MSIX_FLAGS_QSIZE) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a device, return the table offset and bar the MSI-X tables resides in.
|
||||||
|
*
|
||||||
|
* @param dev Pointer to the device structure.
|
||||||
|
* @param offset Returned value gives the offset in bytes inside the PCI BAR.
|
||||||
|
* @param idx The returned value is the index of the PCI_BASE_ADDRESS register
|
||||||
|
* the MSI-X table is located in.
|
||||||
|
* @return Zero on success
|
||||||
|
*/
|
||||||
|
int pci_msix_table_bar(struct device *dev, u32 *offset, u8 *idx)
|
||||||
|
{
|
||||||
|
const size_t pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
|
||||||
|
if (!pos || !offset || !idx)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
*offset = pci_read_config32(dev, pos + PCI_MSIX_TABLE);
|
||||||
|
*idx = (u8)(*offset & PCI_MSIX_PBA_BIR);
|
||||||
|
*offset &= PCI_MSIX_PBA_OFFSET;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a device, return a msix_entry pointer or NULL if no table was found.
|
||||||
|
*
|
||||||
|
* @param dev Pointer to the device structure.
|
||||||
|
*
|
||||||
|
* @return NULL on error
|
||||||
|
*/
|
||||||
|
struct msix_entry *pci_msix_get_table(struct device *dev)
|
||||||
|
{
|
||||||
|
struct resource *res;
|
||||||
|
u32 offset;
|
||||||
|
u8 idx;
|
||||||
|
|
||||||
|
if (pci_msix_table_bar(dev, &offset, &idx))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (idx > 5)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
res = probe_resource(dev, idx * 4 + PCI_BASE_ADDRESS_0);
|
||||||
|
if (!res || !res->base || offset >= res->size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((res->flags & IORESOURCE_PCI64) &&
|
||||||
|
(uintptr_t)res->base != res->base)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (struct msix_entry *)((uintptr_t)res->base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the base address registers for a given device.
|
* Read the base address registers for a given device.
|
||||||
*
|
*
|
||||||
|
|
|
@ -56,6 +56,20 @@ struct pci_driver {
|
||||||
const unsigned short *devices;
|
const unsigned short *devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct msix_entry {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u32 lower_addr;
|
||||||
|
u32 upper_addr;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
u64 addr;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
u32 data;
|
||||||
|
u32 vec_control;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef __SIMPLE_DEVICE__
|
#ifdef __SIMPLE_DEVICE__
|
||||||
#define __pci_driver __attribute__((unused))
|
#define __pci_driver __attribute__((unused))
|
||||||
#else
|
#else
|
||||||
|
@ -104,6 +118,10 @@ void pci_assign_irqs(unsigned int bus, unsigned int slot,
|
||||||
const char *get_pci_class_name(struct device *dev);
|
const char *get_pci_class_name(struct device *dev);
|
||||||
const char *get_pci_subclass_name(struct device *dev);
|
const char *get_pci_subclass_name(struct device *dev);
|
||||||
|
|
||||||
|
size_t pci_msix_table_size(struct device *dev);
|
||||||
|
int pci_msix_table_bar(struct device *dev, u32 *offset, u8 *idx);
|
||||||
|
struct msix_entry *pci_msix_get_table(struct device *dev);
|
||||||
|
|
||||||
#define PCI_IO_BRIDGE_ALIGN 4096
|
#define PCI_IO_BRIDGE_ALIGN 4096
|
||||||
#define PCI_MEM_BRIDGE_ALIGN (1024*1024)
|
#define PCI_MEM_BRIDGE_ALIGN (1024*1024)
|
||||||
|
|
||||||
|
|
|
@ -292,6 +292,18 @@
|
||||||
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
|
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
|
||||||
#define PCI_MSI_MASK_BIT 16 /* Mask bits register */
|
#define PCI_MSI_MASK_BIT 16 /* Mask bits register */
|
||||||
|
|
||||||
|
/* MSI-X registers */
|
||||||
|
#define PCI_MSIX_FLAGS 2
|
||||||
|
#define PCI_MSIX_FLAGS_QSIZE 0x7FF /* table size */
|
||||||
|
#define PCI_MSIX_FLAGS_MASKALL 0x4000 /* Mask all vectors for this function */
|
||||||
|
#define PCI_MSIX_FLAGS_ENABLE 0x8000 /* MSI-X enable */
|
||||||
|
#define PCI_MSIX_TABLE 4 /* Table offset */
|
||||||
|
#define PCI_MSIX_PBA 8 /* Pending Bit Array offset */
|
||||||
|
#define PCI_MSIX_PBA_BIR 0x7 /* BAR index */
|
||||||
|
#define PCI_MSIX_PBA_OFFSET ~0x7 /* Offset into specified BAR */
|
||||||
|
#define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */
|
||||||
|
|
||||||
|
|
||||||
/* CompactPCI Hotswap Register */
|
/* CompactPCI Hotswap Register */
|
||||||
|
|
||||||
#define PCI_CHSWP_CSR 2 /* Control and Status Register */
|
#define PCI_CHSWP_CSR 2 /* Control and Status Register */
|
||||||
|
|
Loading…
Reference in New Issue