Chuck Ebbert c225210
From 30da55242818a8ca08583188ebcbaccd283ad4d9 Mon Sep 17 00:00:00 2001
Chuck Ebbert c225210
From: Ben Hutchings <bhutchings@solarflare.com>
Chuck Ebbert c225210
Date: Fri, 23 Jul 2010 14:56:28 +0100
Chuck Ebbert c225210
Subject: PCI: MSI: Restore read_msi_msg_desc(); add get_cached_msi_msg_desc()
Chuck Ebbert c225210
Chuck Ebbert c225210
From: Ben Hutchings <bhutchings@solarflare.com>
Chuck Ebbert c225210
Chuck Ebbert c225210
commit 30da55242818a8ca08583188ebcbaccd283ad4d9 upstream.
Chuck Ebbert c225210
Chuck Ebbert c225210
commit 2ca1af9aa3285c6a5f103ed31ad09f7399fc65d7 "PCI: MSI: Remove
Chuck Ebbert c225210
unsafe and unnecessary hardware access" changed read_msi_msg_desc() to
Chuck Ebbert c225210
return the last MSI message written instead of reading it from the
Chuck Ebbert c225210
device, since it may be called while the device is in a reduced
Chuck Ebbert c225210
power state.
Chuck Ebbert c225210
Chuck Ebbert c225210
However, the pSeries platform code really does need to read messages
Chuck Ebbert c225210
from the device, since they are initially written by firmware.
Chuck Ebbert c225210
Therefore:
Chuck Ebbert c225210
- Restore the previous behaviour of read_msi_msg_desc()
Chuck Ebbert c225210
- Add new functions get_cached_msi_msg{,_desc}() which return the
Chuck Ebbert c225210
  last MSI message written
Chuck Ebbert c225210
- Use the new functions where appropriate
Chuck Ebbert c225210
Chuck Ebbert c225210
Acked-by: Michael Ellerman <michael@ellerman.id.au>
Chuck Ebbert c225210
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Chuck Ebbert c225210
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Chuck Ebbert c225210
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Chuck Ebbert c225210
Chuck Ebbert c225210
---
Chuck Ebbert c225210
 arch/ia64/kernel/msi_ia64.c    |    2 -
Chuck Ebbert c225210
 arch/ia64/sn/kernel/msi_sn.c   |    2 -
Chuck Ebbert c225210
 arch/x86/kernel/apic/io_apic.c |    2 -
Chuck Ebbert c225210
 drivers/pci/msi.c              |   47 ++++++++++++++++++++++++++++++++++++-----
Chuck Ebbert c225210
 include/linux/msi.h            |    2 +
Chuck Ebbert c225210
 5 files changed, 47 insertions(+), 8 deletions(-)
Chuck Ebbert c225210
Chuck Ebbert c225210
--- a/arch/ia64/kernel/msi_ia64.c
Chuck Ebbert c225210
+++ b/arch/ia64/kernel/msi_ia64.c
Chuck Ebbert c225210
@@ -25,7 +25,7 @@ static int ia64_set_msi_irq_affinity(uns
Chuck Ebbert c225210
 	if (irq_prepare_move(irq, cpu))
Chuck Ebbert c225210
 		return -1;
Chuck Ebbert c225210
 
Chuck Ebbert c225210
-	read_msi_msg(irq, &msg;;
Chuck Ebbert c225210
+	get_cached_msi_msg(irq, &msg;;
Chuck Ebbert c225210
 
Chuck Ebbert c225210
 	addr = msg.address_lo;
Chuck Ebbert c225210
 	addr &= MSI_ADDR_DEST_ID_MASK;
Chuck Ebbert c225210
--- a/arch/ia64/sn/kernel/msi_sn.c
Chuck Ebbert c225210
+++ b/arch/ia64/sn/kernel/msi_sn.c
Chuck Ebbert c225210
@@ -174,7 +174,7 @@ static int sn_set_msi_irq_affinity(unsig
Chuck Ebbert c225210
 	 * Release XIO resources for the old MSI PCI address
Chuck Ebbert c225210
 	 */
Chuck Ebbert c225210
 
Chuck Ebbert c225210
-	read_msi_msg(irq, &msg;;
Chuck Ebbert c225210
+	get_cached_msi_msg(irq, &msg;;
Chuck Ebbert c225210
         sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
Chuck Ebbert c225210
 	pdev = sn_pdev->pdi_linux_pcidev;
Chuck Ebbert c225210
 	provider = SN_PCIDEV_BUSPROVIDER(pdev);
Chuck Ebbert c225210
--- a/arch/x86/kernel/apic/io_apic.c
Chuck Ebbert c225210
+++ b/arch/x86/kernel/apic/io_apic.c
Chuck Ebbert c225210
@@ -3338,7 +3338,7 @@ static int set_msi_irq_affinity(unsigned
Chuck Ebbert c225210
 
Chuck Ebbert c225210
 	cfg = desc->chip_data;
Chuck Ebbert c225210
 
Chuck Ebbert c225210
-	read_msi_msg_desc(desc, &msg;;
Chuck Ebbert c225210
+	get_cached_msi_msg_desc(desc, &msg;;
Chuck Ebbert c225210
 
Chuck Ebbert c225210
 	msg.data &= ~MSI_DATA_VECTOR_MASK;
Chuck Ebbert c225210
 	msg.data |= MSI_DATA_VECTOR(cfg->vector);
Chuck Ebbert c225210
--- a/drivers/pci/msi.c
Chuck Ebbert c225210
+++ b/drivers/pci/msi.c
Chuck Ebbert c225210
@@ -196,9 +196,46 @@ void read_msi_msg_desc(struct irq_desc *
Chuck Ebbert c225210
 {
Chuck Ebbert c225210
 	struct msi_desc *entry = get_irq_desc_msi(desc);
Chuck Ebbert c225210
 
Chuck Ebbert c225210
-	/* We do not touch the hardware (which may not even be
Chuck Ebbert c225210
-	 * accessible at the moment) but return the last message
Chuck Ebbert c225210
-	 * written.  Assert that this is valid, assuming that
Chuck Ebbert c225210
+	BUG_ON(entry->dev->current_state != PCI_D0);
Chuck Ebbert c225210
+
Chuck Ebbert c225210
+	if (entry->msi_attrib.is_msix) {
Chuck Ebbert c225210
+		void __iomem *base = entry->mask_base +
Chuck Ebbert c225210
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
Chuck Ebbert c225210
+
Chuck Ebbert c225210
+		msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR);
Chuck Ebbert c225210
+		msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR);
Chuck Ebbert c225210
+		msg->data = readl(base + PCI_MSIX_ENTRY_DATA);
Chuck Ebbert c225210
+	} else {
Chuck Ebbert c225210
+		struct pci_dev *dev = entry->dev;
Chuck Ebbert c225210
+		int pos = entry->msi_attrib.pos;
Chuck Ebbert c225210
+		u16 data;
Chuck Ebbert c225210
+
Chuck Ebbert c225210
+		pci_read_config_dword(dev, msi_lower_address_reg(pos),
Chuck Ebbert c225210
+					&msg->address_lo);
Chuck Ebbert c225210
+		if (entry->msi_attrib.is_64) {
Chuck Ebbert c225210
+			pci_read_config_dword(dev, msi_upper_address_reg(pos),
Chuck Ebbert c225210
+						&msg->address_hi);
Chuck Ebbert c225210
+			pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
Chuck Ebbert c225210
+		} else {
Chuck Ebbert c225210
+			msg->address_hi = 0;
Chuck Ebbert c225210
+			pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
Chuck Ebbert c225210
+		}
Chuck Ebbert c225210
+		msg->data = data;
Chuck Ebbert c225210
+	}
Chuck Ebbert c225210
+}
Chuck Ebbert c225210
+
Chuck Ebbert c225210
+void read_msi_msg(unsigned int irq, struct msi_msg *msg)
Chuck Ebbert c225210
+{
Chuck Ebbert c225210
+	struct irq_desc *desc = irq_to_desc(irq);
Chuck Ebbert c225210
+
Chuck Ebbert c225210
+	read_msi_msg_desc(desc, msg);
Chuck Ebbert c225210
+}
Chuck Ebbert c225210
+
Chuck Ebbert c225210
+void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
Chuck Ebbert c225210
+{
Chuck Ebbert c225210
+	struct msi_desc *entry = get_irq_desc_msi(desc);
Chuck Ebbert c225210
+
Chuck Ebbert c225210
+	/* Assert that the cache is valid, assuming that
Chuck Ebbert c225210
 	 * valid messages are not all-zeroes. */
Chuck Ebbert c225210
 	BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo |
Chuck Ebbert c225210
 		 entry->msg.data));
Chuck Ebbert c225210
@@ -206,11 +243,11 @@ void read_msi_msg_desc(struct irq_desc *
Chuck Ebbert c225210
 	*msg = entry->msg;
Chuck Ebbert c225210
 }
Chuck Ebbert c225210
 
Chuck Ebbert c225210
-void read_msi_msg(unsigned int irq, struct msi_msg *msg)
Chuck Ebbert c225210
+void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
Chuck Ebbert c225210
 {
Chuck Ebbert c225210
 	struct irq_desc *desc = irq_to_desc(irq);
Chuck Ebbert c225210
 
Chuck Ebbert c225210
-	read_msi_msg_desc(desc, msg);
Chuck Ebbert c225210
+	get_cached_msi_msg_desc(desc, msg);
Chuck Ebbert c225210
 }
Chuck Ebbert c225210
 
Chuck Ebbert c225210
 void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
Chuck Ebbert c225210
--- a/include/linux/msi.h
Chuck Ebbert c225210
+++ b/include/linux/msi.h
Chuck Ebbert c225210
@@ -14,8 +14,10 @@ struct irq_desc;
Chuck Ebbert c225210
 extern void mask_msi_irq(unsigned int irq);
Chuck Ebbert c225210
 extern void unmask_msi_irq(unsigned int irq);
Chuck Ebbert c225210
 extern void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
Chuck Ebbert c225210
+extern void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
Chuck Ebbert c225210
 extern void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
Chuck Ebbert c225210
 extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
Chuck Ebbert c225210
+extern void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
Chuck Ebbert c225210
 extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
Chuck Ebbert c225210
 
Chuck Ebbert c225210
 struct msi_desc {