diff options
Diffstat (limited to 'drivers/pci/msi.c')
| -rw-r--r-- | drivers/pci/msi.c | 180 | 
1 files changed, 82 insertions, 98 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 00cc78c7aa0..d40bed72676 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -22,10 +22,12 @@  #include <linux/slab.h>  #include "pci.h" -#include "msi.h"  static int pci_msi_enable = 1; +#define msix_table_size(flags)	((flags & PCI_MSIX_FLAGS_QSIZE) + 1) + +  /* Arch hooks */  #ifndef arch_msi_check_device @@ -111,32 +113,26 @@ void default_restore_msi_irqs(struct pci_dev *dev, int irq)  }  #endif -static void msi_set_enable(struct pci_dev *dev, int pos, int enable) +static void msi_set_enable(struct pci_dev *dev, int enable)  {  	u16 control; -	BUG_ON(!pos); - -	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); +	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);  	control &= ~PCI_MSI_FLAGS_ENABLE;  	if (enable)  		control |= PCI_MSI_FLAGS_ENABLE; -	pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); +	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);  }  static void msix_set_enable(struct pci_dev *dev, int enable)  { -	int pos;  	u16 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; -		if (enable) -			control |= PCI_MSIX_FLAGS_ENABLE; -		pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); -	} +	pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control); +	control &= ~PCI_MSIX_FLAGS_ENABLE; +	if (enable) +		control |= PCI_MSIX_FLAGS_ENABLE; +	pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);  }  static inline __attribute_const__ u32 msi_mask(unsigned x) @@ -247,18 +243,18 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)  		msg->data = readl(base + PCI_MSIX_ENTRY_DATA);  	} else {  		struct pci_dev *dev = entry->dev; -		int pos = entry->msi_attrib.pos; +		int pos = dev->msi_cap;  		u16 data; -		pci_read_config_dword(dev, msi_lower_address_reg(pos), -					&msg->address_lo); +		pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, +				      &msg->address_lo);  		if (entry->msi_attrib.is_64) { -			pci_read_config_dword(dev, msi_upper_address_reg(pos), -						&msg->address_hi); -			pci_read_config_word(dev, msi_data_reg(pos, 1), &data); +			pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, +					      &msg->address_hi); +			pci_read_config_word(dev, pos + PCI_MSI_DATA_64, &data);  		} else {  			msg->address_hi = 0; -			pci_read_config_word(dev, msi_data_reg(pos, 0), &data); +			pci_read_config_word(dev, pos + PCI_MSI_DATA_32, &data);  		}  		msg->data = data;  	} @@ -302,24 +298,24 @@ void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)  		writel(msg->data, base + PCI_MSIX_ENTRY_DATA);  	} else {  		struct pci_dev *dev = entry->dev; -		int pos = entry->msi_attrib.pos; +		int pos = dev->msi_cap;  		u16 msgctl; -		pci_read_config_word(dev, msi_control_reg(pos), &msgctl); +		pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);  		msgctl &= ~PCI_MSI_FLAGS_QSIZE;  		msgctl |= entry->msi_attrib.multiple << 4; -		pci_write_config_word(dev, msi_control_reg(pos), msgctl); +		pci_write_config_word(dev, pos + PCI_MSI_FLAGS, msgctl); -		pci_write_config_dword(dev, msi_lower_address_reg(pos), -					msg->address_lo); +		pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, +				       msg->address_lo);  		if (entry->msi_attrib.is_64) { -			pci_write_config_dword(dev, msi_upper_address_reg(pos), -						msg->address_hi); -			pci_write_config_word(dev, msi_data_reg(pos, 1), -						msg->data); +			pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, +					       msg->address_hi); +			pci_write_config_word(dev, pos + PCI_MSI_DATA_64, +					      msg->data);  		} else { -			pci_write_config_word(dev, msi_data_reg(pos, 0), -						msg->data); +			pci_write_config_word(dev, pos + PCI_MSI_DATA_32, +					      msg->data);  		}  	}  	entry->msg = *msg; @@ -391,7 +387,6 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable)  static void __pci_restore_msi_state(struct pci_dev *dev)  { -	int pos;  	u16 control;  	struct msi_desc *entry; @@ -399,22 +394,20 @@ static void __pci_restore_msi_state(struct pci_dev *dev)  		return;  	entry = irq_get_msi_desc(dev->irq); -	pos = entry->msi_attrib.pos;  	pci_intx_for_msi(dev, 0); -	msi_set_enable(dev, pos, 0); +	msi_set_enable(dev, 0);  	arch_restore_msi_irqs(dev, dev->irq); -	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); +	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);  	msi_mask_irq(entry, msi_capable_mask(control), entry->masked);  	control &= ~PCI_MSI_FLAGS_QSIZE;  	control |= (entry->msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE; -	pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); +	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);  }  static void __pci_restore_msix_state(struct pci_dev *dev)  { -	int pos;  	struct msi_desc *entry;  	u16 control; @@ -422,13 +415,12 @@ static void __pci_restore_msix_state(struct pci_dev *dev)  		return;  	BUG_ON(list_empty(&dev->msi_list));  	entry = list_first_entry(&dev->msi_list, struct msi_desc, list); -	pos = entry->msi_attrib.pos; -	pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); +	pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);  	/* route the table */  	pci_intx_for_msi(dev, 0);  	control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL; -	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); +	pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);  	list_for_each_entry(entry, &dev->msi_list, list) {  		arch_restore_msi_irqs(dev, entry->irq); @@ -436,7 +428,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)  	}  	control &= ~PCI_MSIX_FLAGS_MASKALL; -	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); +	pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);  }  void pci_restore_msi_state(struct pci_dev *dev) @@ -484,12 +476,12 @@ static struct msi_attribute mode_attribute =  	__ATTR(mode, S_IRUGO, show_msi_mode, NULL); -struct attribute *msi_irq_default_attrs[] = { +static struct attribute *msi_irq_default_attrs[] = {  	&mode_attribute.attr,  	NULL  }; -void msi_kobj_release(struct kobject *kobj) +static void msi_kobj_release(struct kobject *kobj)  {  	struct msi_desc *entry = to_msi_desc(kobj); @@ -552,27 +544,27 @@ out_unroll:  static int msi_capability_init(struct pci_dev *dev, int nvec)  {  	struct msi_desc *entry; -	int pos, ret; +	int ret;  	u16 control;  	unsigned mask; -	pos = pci_find_capability(dev, PCI_CAP_ID_MSI); -	msi_set_enable(dev, pos, 0);	/* Disable MSI during set up */ +	msi_set_enable(dev, 0);	/* Disable MSI during set up */ -	pci_read_config_word(dev, msi_control_reg(pos), &control); +	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);  	/* MSI Entry Initialization */  	entry = alloc_msi_entry(dev);  	if (!entry)  		return -ENOMEM;  	entry->msi_attrib.is_msix	= 0; -	entry->msi_attrib.is_64		= is_64bit_address(control); +	entry->msi_attrib.is_64		= !!(control & PCI_MSI_FLAGS_64BIT);  	entry->msi_attrib.entry_nr	= 0; -	entry->msi_attrib.maskbit	= is_mask_bit_support(control); +	entry->msi_attrib.maskbit	= !!(control & PCI_MSI_FLAGS_MASKBIT);  	entry->msi_attrib.default_irq	= dev->irq;	/* Save IOAPIC IRQ */ -	entry->msi_attrib.pos		= pos; +	entry->msi_attrib.pos		= dev->msi_cap; -	entry->mask_pos = msi_mask_reg(pos, entry->msi_attrib.is_64); +	entry->mask_pos = dev->msi_cap + (control & PCI_MSI_FLAGS_64BIT) ? +		PCI_MSI_MASK_64 : PCI_MSI_MASK_32;  	/* All MSIs are unmasked by default, Mask them all */  	if (entry->msi_attrib.maskbit)  		pci_read_config_dword(dev, entry->mask_pos, &entry->masked); @@ -598,31 +590,30 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)  	/* Set MSI enabled bits	 */  	pci_intx_for_msi(dev, 0); -	msi_set_enable(dev, pos, 1); +	msi_set_enable(dev, 1);  	dev->msi_enabled = 1;  	dev->irq = entry->irq;  	return 0;  } -static void __iomem *msix_map_region(struct pci_dev *dev, unsigned pos, -							unsigned nr_entries) +static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries)  {  	resource_size_t phys_addr;  	u32 table_offset;  	u8 bir; -	pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset); -	bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); -	table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; +	pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE, +			      &table_offset); +	bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR); +	table_offset &= PCI_MSIX_TABLE_OFFSET;  	phys_addr = pci_resource_start(dev, bir) + table_offset;  	return ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);  } -static int msix_setup_entries(struct pci_dev *dev, unsigned pos, -				void __iomem *base, struct msix_entry *entries, -				int nvec) +static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, +			      struct msix_entry *entries, int nvec)  {  	struct msi_desc *entry;  	int i; @@ -642,7 +633,7 @@ static int msix_setup_entries(struct pci_dev *dev, unsigned pos,  		entry->msi_attrib.is_64		= 1;  		entry->msi_attrib.entry_nr	= entries[i].entry;  		entry->msi_attrib.default_irq	= dev->irq; -		entry->msi_attrib.pos		= pos; +		entry->msi_attrib.pos		= dev->msix_cap;  		entry->mask_base		= base;  		list_add_tail(&entry->list, &dev->msi_list); @@ -652,7 +643,7 @@ static int msix_setup_entries(struct pci_dev *dev, unsigned pos,  }  static void msix_program_entries(struct pci_dev *dev, -					struct msix_entry *entries) +				 struct msix_entry *entries)  {  	struct msi_desc *entry;  	int i = 0; @@ -682,23 +673,22 @@ static void msix_program_entries(struct pci_dev *dev,  static int msix_capability_init(struct pci_dev *dev,  				struct msix_entry *entries, int nvec)  { -	int pos, ret; +	int ret;  	u16 control;  	void __iomem *base; -	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); -	pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); +	pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);  	/* Ensure MSI-X is disabled while it is set up */  	control &= ~PCI_MSIX_FLAGS_ENABLE; -	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); +	pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);  	/* Request & Map MSI-X table region */ -	base = msix_map_region(dev, pos, multi_msix_capable(control)); +	base = msix_map_region(dev, msix_table_size(control));  	if (!base)  		return -ENOMEM; -	ret = msix_setup_entries(dev, pos, base, entries, nvec); +	ret = msix_setup_entries(dev, base, entries, nvec);  	if (ret)  		return ret; @@ -712,7 +702,7 @@ static int msix_capability_init(struct pci_dev *dev,  	 * interrupts coming in before they're fully set up.  	 */  	control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE; -	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); +	pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);  	msix_program_entries(dev, entries); @@ -727,7 +717,7 @@ static int msix_capability_init(struct pci_dev *dev,  	dev->msix_enabled = 1;  	control &= ~PCI_MSIX_FLAGS_MASKALL; -	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); +	pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);  	return 0; @@ -795,9 +785,6 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)  	if (ret)  		return ret; -	if (!pci_find_capability(dev, type)) -		return -EINVAL; -  	return 0;  } @@ -816,13 +803,13 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)   */  int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)  { -	int status, pos, maxvec; +	int status, maxvec;  	u16 msgctl; -	pos = pci_find_capability(dev, PCI_CAP_ID_MSI); -	if (!pos) +	if (!dev->msi_cap)  		return -EINVAL; -	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl); + +	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);  	maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);  	if (nvec > maxvec)  		return maxvec; @@ -847,14 +834,13 @@ EXPORT_SYMBOL(pci_enable_msi_block);  int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec)  { -	int ret, pos, nvec; +	int ret, nvec;  	u16 msgctl; -	pos = pci_find_capability(dev, PCI_CAP_ID_MSI); -	if (!pos) +	if (!dev->msi_cap)  		return -EINVAL; -	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl); +	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);  	ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);  	if (maxvec) @@ -876,21 +862,19 @@ void pci_msi_shutdown(struct pci_dev *dev)  	struct msi_desc *desc;  	u32 mask;  	u16 ctrl; -	unsigned pos;  	if (!pci_msi_enable || !dev || !dev->msi_enabled)  		return;  	BUG_ON(list_empty(&dev->msi_list));  	desc = list_first_entry(&dev->msi_list, struct msi_desc, list); -	pos = desc->msi_attrib.pos; -	msi_set_enable(dev, pos, 0); +	msi_set_enable(dev, 0);  	pci_intx_for_msi(dev, 1);  	dev->msi_enabled = 0;  	/* Return the device with MSI unmasked as initial states */ -	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl); +	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);  	mask = msi_capable_mask(ctrl);  	/* Keep cached state to be restored */  	__msi_mask_irq(desc, mask, ~mask); @@ -917,15 +901,13 @@ EXPORT_SYMBOL(pci_disable_msi);   */  int pci_msix_table_size(struct pci_dev *dev)  { -	int pos;  	u16 control; -	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); -	if (!pos) +	if (!dev->msix_cap)  		return 0; -	pci_read_config_word(dev, msi_control_reg(pos), &control); -	return multi_msix_capable(control); +	pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control); +	return msix_table_size(control);  }  /** @@ -948,7 +930,7 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)  	int status, nr_entries;  	int i, j; -	if (!entries) +	if (!entries || !dev->msix_cap)  		return -EINVAL;  	status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX); @@ -1048,15 +1030,17 @@ EXPORT_SYMBOL(pci_msi_enabled);  void pci_msi_init_pci_dev(struct pci_dev *dev)  { -	int pos;  	INIT_LIST_HEAD(&dev->msi_list);  	/* Disable the msi hardware to avoid screaming interrupts  	 * during boot.  This is the power on reset default so  	 * usually this should be a noop.  	 */ -	pos = pci_find_capability(dev, PCI_CAP_ID_MSI); -	if (pos) -		msi_set_enable(dev, pos, 0); -	msix_set_enable(dev, 0); +	dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI); +	if (dev->msi_cap) +		msi_set_enable(dev, 0); + +	dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX); +	if (dev->msix_cap) +		msix_set_enable(dev, 0);  }  |