While the device driver or PCI core tries to enable PCI device, the platform dependent callback "ppc_md.pcibios_enable_device_hook" will be called to check if there has one associated PE for the PCI device. If we don't have the associated PE for the PCI device, it's not allowed to enable the PCI device. Unfortunately, there might have some cases we have to enable the PCI device (e.g. P2P bridge), but the PEs have not been created yet. The patch handles the unfortunate cases. Each PHB (struct pnv_phb) has one field "initialized" to trace if the PEs have been created and configured or not. When the PEs are not available, we won't check the associated PE for the PCI device to be enabled. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Reviewed-by: Ram Pai <linuxram@us.ibm.com> Reviewed-by: Richard Yang <weiyang@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
		
			
				
	
	
		
			155 lines
		
	
	
	
		
			3.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
	
		
			3.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
#ifndef __POWERNV_PCI_H
 | 
						|
#define __POWERNV_PCI_H
 | 
						|
 | 
						|
struct pci_dn;
 | 
						|
 | 
						|
enum pnv_phb_type {
 | 
						|
	PNV_PHB_P5IOC2,
 | 
						|
	PNV_PHB_IODA1,
 | 
						|
	PNV_PHB_IODA2,
 | 
						|
};
 | 
						|
 | 
						|
/* Precise PHB model for error management */
 | 
						|
enum pnv_phb_model {
 | 
						|
	PNV_PHB_MODEL_UNKNOWN,
 | 
						|
	PNV_PHB_MODEL_P5IOC2,
 | 
						|
	PNV_PHB_MODEL_P7IOC,
 | 
						|
};
 | 
						|
 | 
						|
#define PNV_PCI_DIAG_BUF_SIZE	4096
 | 
						|
#define PNV_IODA_PE_DEV		(1 << 0)	/* PE has single PCI device	*/
 | 
						|
#define PNV_IODA_PE_BUS		(1 << 1)	/* PE has primary PCI bus	*/
 | 
						|
#define PNV_IODA_PE_BUS_ALL	(1 << 2)	/* PE has subordinate buses	*/
 | 
						|
 | 
						|
/* Data associated with a PE, including IOMMU tracking etc.. */
 | 
						|
struct pnv_ioda_pe {
 | 
						|
	unsigned long		flags;
 | 
						|
 | 
						|
	/* A PE can be associated with a single device or an
 | 
						|
	 * entire bus (& children). In the former case, pdev
 | 
						|
	 * is populated, in the later case, pbus is.
 | 
						|
	 */
 | 
						|
	struct pci_dev		*pdev;
 | 
						|
	struct pci_bus		*pbus;
 | 
						|
 | 
						|
	/* Effective RID (device RID for a device PE and base bus
 | 
						|
	 * RID with devfn 0 for a bus PE)
 | 
						|
	 */
 | 
						|
	unsigned int		rid;
 | 
						|
 | 
						|
	/* PE number */
 | 
						|
	unsigned int		pe_number;
 | 
						|
 | 
						|
	/* "Weight" assigned to the PE for the sake of DMA resource
 | 
						|
	 * allocations
 | 
						|
	 */
 | 
						|
	unsigned int		dma_weight;
 | 
						|
 | 
						|
	/* "Base" iommu table, ie, 4K TCEs, 32-bit DMA */
 | 
						|
	int			tce32_seg;
 | 
						|
	int			tce32_segcount;
 | 
						|
	struct iommu_table	tce32_table;
 | 
						|
 | 
						|
	/* XXX TODO: Add support for additional 64-bit iommus */
 | 
						|
 | 
						|
	/* MSIs. MVE index is identical for for 32 and 64 bit MSI
 | 
						|
	 * and -1 if not supported. (It's actually identical to the
 | 
						|
	 * PE number)
 | 
						|
	 */
 | 
						|
	int			mve_number;
 | 
						|
 | 
						|
	/* Link in list of PE#s */
 | 
						|
	struct list_head	dma_link;
 | 
						|
	struct list_head	list;
 | 
						|
};
 | 
						|
 | 
						|
struct pnv_phb {
 | 
						|
	struct pci_controller	*hose;
 | 
						|
	enum pnv_phb_type	type;
 | 
						|
	enum pnv_phb_model	model;
 | 
						|
	u64			opal_id;
 | 
						|
	void __iomem		*regs;
 | 
						|
	int			initialized;
 | 
						|
	spinlock_t		lock;
 | 
						|
 | 
						|
#ifdef CONFIG_PCI_MSI
 | 
						|
	unsigned long		*msi_map;
 | 
						|
	unsigned int		msi_base;
 | 
						|
	unsigned int		msi_count;
 | 
						|
	unsigned int		msi_next;
 | 
						|
	unsigned int		msi32_support;
 | 
						|
#endif
 | 
						|
	int (*msi_setup)(struct pnv_phb *phb, struct pci_dev *dev,
 | 
						|
			 unsigned int hwirq, unsigned int is_64,
 | 
						|
			 struct msi_msg *msg);
 | 
						|
	void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev);
 | 
						|
	void (*fixup_phb)(struct pci_controller *hose);
 | 
						|
	u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn);
 | 
						|
 | 
						|
	union {
 | 
						|
		struct {
 | 
						|
			struct iommu_table iommu_table;
 | 
						|
		} p5ioc2;
 | 
						|
 | 
						|
		struct {
 | 
						|
			/* Global bridge info */
 | 
						|
			unsigned int		total_pe;
 | 
						|
			unsigned int		m32_size;
 | 
						|
			unsigned int		m32_segsize;
 | 
						|
			unsigned int		m32_pci_base;
 | 
						|
			unsigned int		io_size;
 | 
						|
			unsigned int		io_segsize;
 | 
						|
			unsigned int		io_pci_base;
 | 
						|
 | 
						|
			/* PE allocation bitmap */
 | 
						|
			unsigned long		*pe_alloc;
 | 
						|
 | 
						|
			/* M32 & IO segment maps */
 | 
						|
			unsigned int		*m32_segmap;
 | 
						|
			unsigned int		*io_segmap;
 | 
						|
			struct pnv_ioda_pe	*pe_array;
 | 
						|
 | 
						|
			/* Sorted list of used PE's based
 | 
						|
			 * on the sequence of creation
 | 
						|
			 */
 | 
						|
			struct list_head	pe_list;
 | 
						|
 | 
						|
			/* Reverse map of PEs, will have to extend if
 | 
						|
			 * we are to support more than 256 PEs, indexed
 | 
						|
			 * bus { bus, devfn }
 | 
						|
			 */
 | 
						|
			unsigned char		pe_rmap[0x10000];
 | 
						|
 | 
						|
			/* 32-bit TCE tables allocation */
 | 
						|
			unsigned long		tce32_count;
 | 
						|
 | 
						|
			/* Total "weight" for the sake of DMA resources
 | 
						|
			 * allocation
 | 
						|
			 */
 | 
						|
			unsigned int		dma_weight;
 | 
						|
			unsigned int		dma_pe_count;
 | 
						|
 | 
						|
			/* Sorted list of used PE's, sorted at
 | 
						|
			 * boot for resource allocation purposes
 | 
						|
			 */
 | 
						|
			struct list_head	pe_dma_list;
 | 
						|
		} ioda;
 | 
						|
	};
 | 
						|
 | 
						|
	/* PHB status structure */
 | 
						|
	union {
 | 
						|
		unsigned char			blob[PNV_PCI_DIAG_BUF_SIZE];
 | 
						|
		struct OpalIoP7IOCPhbErrorData	p7ioc;
 | 
						|
	} diag;
 | 
						|
};
 | 
						|
 | 
						|
extern struct pci_ops pnv_pci_ops;
 | 
						|
 | 
						|
extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
 | 
						|
				      void *tce_mem, u64 tce_size,
 | 
						|
				      u64 dma_offset);
 | 
						|
extern void pnv_pci_init_p5ioc2_hub(struct device_node *np);
 | 
						|
extern void pnv_pci_init_ioda_hub(struct device_node *np);
 | 
						|
 | 
						|
 | 
						|
#endif /* __POWERNV_PCI_H */
 |