Skip to content

Commit fcd097f

Browse files
Ben Hutchingsjbarnes993
authored andcommitted
PCI: MSI: Remove unsafe and unnecessary hardware access
During suspend on an SMP system, {read,write}_msi_msg_desc() may be called to mask and unmask interrupts on a device that is already in a reduced power state. At this point memory-mapped registers including MSI-X tables are not accessible, and config space may not be fully functional either. While a device is in a reduced power state its interrupts are effectively masked and its MSI(-X) state will be restored when it is brought back to D0. Therefore these functions can simply read and write msi_desc::msg for devices not in D0. Further, read_msi_msg_desc() should only ever be used to update a previously written message, so it can always read msi_desc::msg and never needs to touch the hardware. Tested-by: "Michael Chan" <[email protected]> Signed-off-by: Ben Hutchings <[email protected]> Signed-off-by: Jesse Barnes <[email protected]>
1 parent ea5f9fc commit fcd097f

File tree

1 file changed

+11
-23
lines changed

1 file changed

+11
-23
lines changed

drivers/pci/msi.c

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -196,30 +196,15 @@ void unmask_msi_irq(unsigned int irq)
196196
void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
197197
{
198198
struct msi_desc *entry = get_irq_desc_msi(desc);
199-
if (entry->msi_attrib.is_msix) {
200-
void __iomem *base = entry->mask_base +
201-
entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
202199

203-
msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR);
204-
msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR);
205-
msg->data = readl(base + PCI_MSIX_ENTRY_DATA);
206-
} else {
207-
struct pci_dev *dev = entry->dev;
208-
int pos = entry->msi_attrib.pos;
209-
u16 data;
200+
/* We do not touch the hardware (which may not even be
201+
* accessible at the moment) but return the last message
202+
* written. Assert that this is valid, assuming that
203+
* valid messages are not all-zeroes. */
204+
BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo |
205+
entry->msg.data));
210206

211-
pci_read_config_dword(dev, msi_lower_address_reg(pos),
212-
&msg->address_lo);
213-
if (entry->msi_attrib.is_64) {
214-
pci_read_config_dword(dev, msi_upper_address_reg(pos),
215-
&msg->address_hi);
216-
pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
217-
} else {
218-
msg->address_hi = 0;
219-
pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
220-
}
221-
msg->data = data;
222-
}
207+
*msg = entry->msg;
223208
}
224209

225210
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
@@ -232,7 +217,10 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
232217
void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
233218
{
234219
struct msi_desc *entry = get_irq_desc_msi(desc);
235-
if (entry->msi_attrib.is_msix) {
220+
221+
if (entry->dev->current_state != PCI_D0) {
222+
/* Don't touch the hardware now */
223+
} else if (entry->msi_attrib.is_msix) {
236224
void __iomem *base;
237225
base = entry->mask_base +
238226
entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;

0 commit comments

Comments
 (0)