mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	[PATCH] msi: sanely support hardware level msi disabling
In some cases when we are not using msi we need a way to ensure that the hardware does not have an msi capability enabled. Currently the code has been calling disable_msi_mode to try and achieve that. However disable_msi_mode has several other side effects and is only available when msi support is compiled in so it isn't really appropriate. Instead this patch implements pci_msi_off which disables all msi and msix capabilities unconditionally with no additional side effects. pci_disable_device was redundantly clearing the bus master enable flag and clearing the msi enable bit. A device that is not allowed to perform bus mastering operations cannot generate intx or msi interrupt messages as those are essentially a special case of dma, and require bus mastering. So the call in pci_disable_device to disable msi capabilities was redundant. quirk_pcie_pxh also called disable_msi_mode and is updated to use pci_msi_off. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Michael Ellerman <michael@ellerman.id.au> Cc: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									58a53b246b
								
							
						
					
					
						commit
						f5f2b13129
					
				
					 7 changed files with 35 additions and 16 deletions
				
			
		| 
						 | 
				
			
			@ -968,7 +968,6 @@ void pci_scan_msi_device(struct pci_dev *dev) {}
 | 
			
		|||
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;}
 | 
			
		||||
void pci_disable_msix(struct pci_dev *dev) {}
 | 
			
		||||
void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
 | 
			
		||||
void disable_msi_mode(struct pci_dev *dev, int pos, int type) {}
 | 
			
		||||
void pci_no_msi(void) {}
 | 
			
		||||
EXPORT_SYMBOL(pci_enable_msix);
 | 
			
		||||
EXPORT_SYMBOL(pci_disable_msix);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -211,7 +211,7 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
 | 
			
		|||
	pci_intx(dev, 0);  /* disable intx */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void disable_msi_mode(struct pci_dev *dev, int pos, int type)
 | 
			
		||||
static void disable_msi_mode(struct pci_dev *dev, int pos, int type)
 | 
			
		||||
{
 | 
			
		||||
	u16 control;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -881,13 +881,6 @@ pci_disable_device(struct pci_dev *dev)
 | 
			
		|||
	if (atomic_sub_return(1, &dev->enable_cnt) != 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (dev->msi_enabled)
 | 
			
		||||
		disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
 | 
			
		||||
			PCI_CAP_ID_MSI);
 | 
			
		||||
	if (dev->msix_enabled)
 | 
			
		||||
		disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
 | 
			
		||||
			PCI_CAP_ID_MSIX);
 | 
			
		||||
 | 
			
		||||
	pci_read_config_word(dev, PCI_COMMAND, &pci_command);
 | 
			
		||||
	if (pci_command & PCI_COMMAND_MASTER) {
 | 
			
		||||
		pci_command &= ~PCI_COMMAND_MASTER;
 | 
			
		||||
| 
						 | 
				
			
			@ -1277,6 +1270,33 @@ pci_intx(struct pci_dev *pdev, int enable)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pci_msi_off - disables any msi or msix capabilities
 | 
			
		||||
 * @pdev: the PCI device to operate on
 | 
			
		||||
 *
 | 
			
		||||
 * If you want to use msi see pci_enable_msi and friends.
 | 
			
		||||
 * This is a lower level primitive that allows us to disable
 | 
			
		||||
 * msi operation at the device level.
 | 
			
		||||
 */
 | 
			
		||||
void pci_msi_off(struct pci_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	int pos;
 | 
			
		||||
	u16 control;
 | 
			
		||||
 | 
			
		||||
	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
 | 
			
		||||
	if (pos) {
 | 
			
		||||
		pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
 | 
			
		||||
		control &= ~PCI_MSI_FLAGS_ENABLE;
 | 
			
		||||
		pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
 | 
			
		||||
	}
 | 
			
		||||
	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 | 
			
		||||
	if (pos) {
 | 
			
		||||
		pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
 | 
			
		||||
		control &= ~PCI_MSIX_FLAGS_ENABLE;
 | 
			
		||||
		pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef HAVE_ARCH_PCI_SET_DMA_MASK
 | 
			
		||||
/*
 | 
			
		||||
 * These can be overridden by arch-specific implementations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,10 +46,8 @@ extern struct rw_semaphore pci_bus_sem;
 | 
			
		|||
extern unsigned int pci_pm_d3_delay;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PCI_MSI
 | 
			
		||||
void disable_msi_mode(struct pci_dev *dev, int pos, int type);
 | 
			
		||||
void pci_no_msi(void);
 | 
			
		||||
#else
 | 
			
		||||
static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
 | 
			
		||||
static inline void pci_no_msi(void) { }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1438,8 +1438,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7525_MCH,	quir
 | 
			
		|||
 */
 | 
			
		||||
static void __devinit quirk_pcie_pxh(struct pci_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
 | 
			
		||||
					PCI_CAP_ID_MSI);
 | 
			
		||||
	pci_msi_off(dev);
 | 
			
		||||
 | 
			
		||||
	dev->no_msi = 1;
 | 
			
		||||
 | 
			
		||||
	printk(KERN_WARNING "PCI: PXH quirk detected, "
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -543,6 +543,7 @@ void pci_set_master(struct pci_dev *dev);
 | 
			
		|||
int __must_check pci_set_mwi(struct pci_dev *dev);
 | 
			
		||||
void pci_clear_mwi(struct pci_dev *dev);
 | 
			
		||||
void pci_intx(struct pci_dev *dev, int enable);
 | 
			
		||||
void pci_msi_off(struct pci_dev *dev);
 | 
			
		||||
int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
 | 
			
		||||
int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
 | 
			
		||||
void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -292,9 +292,10 @@
 | 
			
		|||
#define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
 | 
			
		||||
#define PCI_MSI_MASK_BIT	16	/* Mask bits register */
 | 
			
		||||
 | 
			
		||||
/* MSI-X registers (these are at offset PCI_MSI_FLAGS) */
 | 
			
		||||
#define PCI_MSIX_FLAGS_QSIZE	0x7FF
 | 
			
		||||
#define PCI_MSIX_FLAGS_ENABLE	(1 << 15)
 | 
			
		||||
/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
 | 
			
		||||
#define PCI_MSIX_FLAGS		2
 | 
			
		||||
#define  PCI_MSIX_FLAGS_QSIZE	0x7FF
 | 
			
		||||
#define  PCI_MSIX_FLAGS_ENABLE	(1 << 15)
 | 
			
		||||
#define PCI_MSIX_FLAGS_BIRMASK	(7 << 0)
 | 
			
		||||
#define PCI_MSIX_FLAGS_BITMASK	(1 << 0)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue