diff options
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r-- | drivers/pci/msi.c | 47 |
1 files changed, 42 insertions, 5 deletions
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) |