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:
		
				
					committed by
					
						
						Philipp Deppenwiese
					
				
			
			
				
	
			
			
			
						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 */
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user