diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2010-07-23 09:56:28 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-07-30 12:41:39 -0400 |
commit | 30da55242818a8ca08583188ebcbaccd283ad4d9 (patch) | |
tree | eaa39565cf37a2fbc739e1af02b569107aeee447 | |
parent | 911e1c9b05a8e3559a7aa89083930700a0b9e7ee (diff) |
PCI: MSI: Restore read_msi_msg_desc(); add get_cached_msi_msg_desc()
commit 2ca1af9aa3285c6a5f103ed31ad09f7399fc65d7 "PCI: MSI: Remove
unsafe and unnecessary hardware access" changed read_msi_msg_desc() to
return the last MSI message written instead of reading it from the
device, since it may be called while the device is in a reduced
power state.
However, the pSeries platform code really does need to read messages
from the device, since they are initially written by firmware.
Therefore:
- Restore the previous behaviour of read_msi_msg_desc()
- Add new functions get_cached_msi_msg{,_desc}() which return the
last MSI message written
- Use the new functions where appropriate
Acked-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r-- | arch/ia64/kernel/msi_ia64.c | 2 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/msi_sn.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 2 | ||||
-rw-r--r-- | drivers/pci/msi.c | 47 | ||||
-rw-r--r-- | include/linux/msi.h | 2 |
5 files changed, 47 insertions, 8 deletions
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c index 6c8922856049..4a746ea838ff 100644 --- a/arch/ia64/kernel/msi_ia64.c +++ b/arch/ia64/kernel/msi_ia64.c | |||
@@ -25,7 +25,7 @@ static int ia64_set_msi_irq_affinity(unsigned int irq, | |||
25 | if (irq_prepare_move(irq, cpu)) | 25 | if (irq_prepare_move(irq, cpu)) |
26 | return -1; | 26 | return -1; |
27 | 27 | ||
28 | read_msi_msg(irq, &msg); | 28 | get_cached_msi_msg(irq, &msg); |
29 | 29 | ||
30 | addr = msg.address_lo; | 30 | addr = msg.address_lo; |
31 | addr &= MSI_ADDR_DEST_ID_MASK; | 31 | addr &= MSI_ADDR_DEST_ID_MASK; |
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c index ebfdd6a9ae1a..0c72dd463831 100644 --- a/arch/ia64/sn/kernel/msi_sn.c +++ b/arch/ia64/sn/kernel/msi_sn.c | |||
@@ -175,7 +175,7 @@ static int sn_set_msi_irq_affinity(unsigned int irq, | |||
175 | * Release XIO resources for the old MSI PCI address | 175 | * Release XIO resources for the old MSI PCI address |
176 | */ | 176 | */ |
177 | 177 | ||
178 | read_msi_msg(irq, &msg); | 178 | get_cached_msi_msg(irq, &msg); |
179 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | 179 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; |
180 | pdev = sn_pdev->pdi_linux_pcidev; | 180 | pdev = sn_pdev->pdi_linux_pcidev; |
181 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | 181 | provider = SN_PCIDEV_BUSPROVIDER(pdev); |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e41ed24ab26d..4dc0084ec1b1 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -3397,7 +3397,7 @@ static int set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask) | |||
3397 | 3397 | ||
3398 | cfg = desc->chip_data; | 3398 | cfg = desc->chip_data; |
3399 | 3399 | ||
3400 | read_msi_msg_desc(desc, &msg); | 3400 | get_cached_msi_msg_desc(desc, &msg); |
3401 | 3401 | ||
3402 | msg.data &= ~MSI_DATA_VECTOR_MASK; | 3402 | msg.data &= ~MSI_DATA_VECTOR_MASK; |
3403 | msg.data |= MSI_DATA_VECTOR(cfg->vector); | 3403 | msg.data |= MSI_DATA_VECTOR(cfg->vector); |
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 4c14f31f2b4d..69b7be33b3a2 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -197,9 +197,46 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) | |||
197 | { | 197 | { |
198 | struct msi_desc *entry = get_irq_desc_msi(desc); | 198 | struct msi_desc *entry = get_irq_desc_msi(desc); |
199 | 199 | ||
200 | /* We do not touch the hardware (which may not even be | 200 | BUG_ON(entry->dev->current_state != PCI_D0); |
201 | * accessible at the moment) but return the last message | 201 | |
202 | * written. Assert that this is valid, assuming that | 202 | if (entry->msi_attrib.is_msix) { |
203 | void __iomem *base = entry->mask_base + | ||
204 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; | ||
205 | |||
206 | msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR); | ||
207 | msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR); | ||
208 | msg->data = readl(base + PCI_MSIX_ENTRY_DATA); | ||
209 | } else { | ||
210 | struct pci_dev *dev = entry->dev; | ||
211 | int pos = entry->msi_attrib.pos; | ||
212 | u16 data; | ||
213 | |||
214 | pci_read_config_dword(dev, msi_lower_address_reg(pos), | ||
215 | &msg->address_lo); | ||
216 | if (entry->msi_attrib.is_64) { | ||
217 | pci_read_config_dword(dev, msi_upper_address_reg(pos), | ||
218 | &msg->address_hi); | ||
219 | pci_read_config_word(dev, msi_data_reg(pos, 1), &data); | ||
220 | } else { | ||
221 | msg->address_hi = 0; | ||
222 | pci_read_config_word(dev, msi_data_reg(pos, 0), &data); | ||
223 | } | ||
224 | msg->data = data; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) | ||
229 | { | ||
230 | struct irq_desc *desc = irq_to_desc(irq); | ||
231 | |||
232 | read_msi_msg_desc(desc, msg); | ||
233 | } | ||
234 | |||
235 | void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) | ||
236 | { | ||
237 | struct msi_desc *entry = get_irq_desc_msi(desc); | ||
238 | |||
239 | /* Assert that the cache is valid, assuming that | ||
203 | * valid messages are not all-zeroes. */ | 240 | * valid messages are not all-zeroes. */ |
204 | BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo | | 241 | BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo | |
205 | entry->msg.data)); | 242 | entry->msg.data)); |
@@ -207,11 +244,11 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) | |||
207 | *msg = entry->msg; | 244 | *msg = entry->msg; |
208 | } | 245 | } |
209 | 246 | ||
210 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) | 247 | void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg) |
211 | { | 248 | { |
212 | struct irq_desc *desc = irq_to_desc(irq); | 249 | struct irq_desc *desc = irq_to_desc(irq); |
213 | 250 | ||
214 | read_msi_msg_desc(desc, msg); | 251 | get_cached_msi_msg_desc(desc, msg); |
215 | } | 252 | } |
216 | 253 | ||
217 | void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) | 254 | void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) |
diff --git a/include/linux/msi.h b/include/linux/msi.h index 6991ab5b24d1..91b05c171854 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h | |||
@@ -14,8 +14,10 @@ struct irq_desc; | |||
14 | extern void mask_msi_irq(unsigned int irq); | 14 | extern void mask_msi_irq(unsigned int irq); |
15 | extern void unmask_msi_irq(unsigned int irq); | 15 | extern void unmask_msi_irq(unsigned int irq); |
16 | extern void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg); | 16 | extern void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg); |
17 | extern void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg); | ||
17 | extern void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg); | 18 | extern void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg); |
18 | extern void read_msi_msg(unsigned int irq, struct msi_msg *msg); | 19 | extern void read_msi_msg(unsigned int irq, struct msi_msg *msg); |
20 | extern void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg); | ||
19 | extern void write_msi_msg(unsigned int irq, struct msi_msg *msg); | 21 | extern void write_msi_msg(unsigned int irq, struct msi_msg *msg); |
20 | 22 | ||
21 | struct msi_desc { | 23 | struct msi_desc { |