diff options
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r-- | drivers/pci/msi.c | 155 |
1 files changed, 75 insertions, 80 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index fcde04df6dfe..adcc78242571 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -105,17 +105,14 @@ static inline __attribute_const__ u32 msi_mask(unsigned x) | |||
105 | return (1 << (1 << x)) - 1; | 105 | return (1 << (1 << x)) - 1; |
106 | } | 106 | } |
107 | 107 | ||
108 | static void msix_flush_writes(struct irq_desc *desc) | 108 | static inline __attribute_const__ u32 msi_capable_mask(u16 control) |
109 | { | 109 | { |
110 | struct msi_desc *entry; | 110 | return msi_mask((control >> 1) & 7); |
111 | } | ||
111 | 112 | ||
112 | entry = get_irq_desc_msi(desc); | 113 | static inline __attribute_const__ u32 msi_enabled_mask(u16 control) |
113 | BUG_ON(!entry); | 114 | { |
114 | if (entry->msi_attrib.is_msix) { | 115 | return msi_mask((control >> 4) & 7); |
115 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | ||
116 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; | ||
117 | readl(entry->mask_base + offset); | ||
118 | } | ||
119 | } | 116 | } |
120 | 117 | ||
121 | /* | 118 | /* |
@@ -127,32 +124,57 @@ static void msix_flush_writes(struct irq_desc *desc) | |||
127 | * Returns 1 if it succeeded in masking the interrupt and 0 if the device | 124 | * Returns 1 if it succeeded in masking the interrupt and 0 if the device |
128 | * doesn't support MSI masking. | 125 | * doesn't support MSI masking. |
129 | */ | 126 | */ |
130 | static int msi_set_mask_bits(struct irq_desc *desc, u32 mask, u32 flag) | 127 | static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) |
131 | { | 128 | { |
132 | struct msi_desc *entry; | 129 | u32 mask_bits = desc->masked; |
133 | 130 | ||
134 | entry = get_irq_desc_msi(desc); | 131 | if (!desc->msi_attrib.maskbit) |
135 | BUG_ON(!entry); | 132 | return; |
136 | if (entry->msi_attrib.is_msix) { | 133 | |
137 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | 134 | mask_bits &= ~mask; |
138 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; | 135 | mask_bits |= flag; |
139 | writel(flag, entry->mask_base + offset); | 136 | pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits); |
140 | readl(entry->mask_base + offset); | 137 | desc->masked = mask_bits; |
141 | } else { | 138 | } |
142 | int pos; | 139 | |
143 | u32 mask_bits; | 140 | /* |
141 | * This internal function does not flush PCI writes to the device. | ||
142 | * All users must ensure that they read from the device before either | ||
143 | * assuming that the device state is up to date, or returning out of this | ||
144 | * file. This saves a few milliseconds when initialising devices with lots | ||
145 | * of MSI-X interrupts. | ||
146 | */ | ||
147 | static void msix_mask_irq(struct msi_desc *desc, u32 flag) | ||
148 | { | ||
149 | u32 mask_bits = desc->masked; | ||
150 | unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | ||
151 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; | ||
152 | mask_bits &= ~1; | ||
153 | mask_bits |= flag; | ||
154 | writel(mask_bits, desc->mask_base + offset); | ||
155 | desc->masked = mask_bits; | ||
156 | } | ||
144 | 157 | ||
145 | if (!entry->msi_attrib.maskbit) | 158 | static void msi_set_mask_bit(unsigned irq, u32 flag) |
146 | return 0; | 159 | { |
160 | struct msi_desc *desc = get_irq_msi(irq); | ||
147 | 161 | ||
148 | pos = entry->mask_pos; | 162 | if (desc->msi_attrib.is_msix) { |
149 | pci_read_config_dword(entry->dev, pos, &mask_bits); | 163 | msix_mask_irq(desc, flag); |
150 | mask_bits &= ~mask; | 164 | readl(desc->mask_base); /* Flush write to device */ |
151 | mask_bits |= flag & mask; | 165 | } else { |
152 | pci_write_config_dword(entry->dev, pos, mask_bits); | 166 | msi_mask_irq(desc, 1, flag); |
153 | } | 167 | } |
154 | entry->msi_attrib.masked = !!flag; | 168 | } |
155 | return 1; | 169 | |
170 | void mask_msi_irq(unsigned int irq) | ||
171 | { | ||
172 | msi_set_mask_bit(irq, 1); | ||
173 | } | ||
174 | |||
175 | void unmask_msi_irq(unsigned int irq) | ||
176 | { | ||
177 | msi_set_mask_bit(irq, 0); | ||
156 | } | 178 | } |
157 | 179 | ||
158 | void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) | 180 | void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) |
@@ -230,22 +252,6 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) | |||
230 | write_msi_msg_desc(desc, msg); | 252 | write_msi_msg_desc(desc, msg); |
231 | } | 253 | } |
232 | 254 | ||
233 | void mask_msi_irq(unsigned int irq) | ||
234 | { | ||
235 | struct irq_desc *desc = irq_to_desc(irq); | ||
236 | |||
237 | msi_set_mask_bits(desc, 1, 1); | ||
238 | msix_flush_writes(desc); | ||
239 | } | ||
240 | |||
241 | void unmask_msi_irq(unsigned int irq) | ||
242 | { | ||
243 | struct irq_desc *desc = irq_to_desc(irq); | ||
244 | |||
245 | msi_set_mask_bits(desc, 1, 0); | ||
246 | msix_flush_writes(desc); | ||
247 | } | ||
248 | |||
249 | static int msi_free_irqs(struct pci_dev* dev); | 255 | static int msi_free_irqs(struct pci_dev* dev); |
250 | 256 | ||
251 | static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) | 257 | static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) |
@@ -281,13 +287,9 @@ static void __pci_restore_msi_state(struct pci_dev *dev) | |||
281 | pci_intx_for_msi(dev, 0); | 287 | pci_intx_for_msi(dev, 0); |
282 | msi_set_enable(dev, 0); | 288 | msi_set_enable(dev, 0); |
283 | write_msi_msg(dev->irq, &entry->msg); | 289 | write_msi_msg(dev->irq, &entry->msg); |
284 | if (entry->msi_attrib.maskbit) { | ||
285 | struct irq_desc *desc = irq_to_desc(dev->irq); | ||
286 | msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask, | ||
287 | entry->msi_attrib.masked); | ||
288 | } | ||
289 | 290 | ||
290 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); | 291 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); |
292 | msi_mask_irq(entry, msi_capable_mask(control), entry->masked); | ||
291 | control &= ~PCI_MSI_FLAGS_QSIZE; | 293 | control &= ~PCI_MSI_FLAGS_QSIZE; |
292 | control |= PCI_MSI_FLAGS_ENABLE; | 294 | control |= PCI_MSI_FLAGS_ENABLE; |
293 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); | 295 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); |
@@ -307,9 +309,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev) | |||
307 | msix_set_enable(dev, 0); | 309 | msix_set_enable(dev, 0); |
308 | 310 | ||
309 | list_for_each_entry(entry, &dev->msi_list, list) { | 311 | list_for_each_entry(entry, &dev->msi_list, list) { |
310 | struct irq_desc *desc = irq_to_desc(entry->irq); | ||
311 | write_msi_msg(entry->irq, &entry->msg); | 312 | write_msi_msg(entry->irq, &entry->msg); |
312 | msi_set_mask_bits(desc, 1, entry->msi_attrib.masked); | 313 | msix_mask_irq(entry, entry->masked); |
313 | } | 314 | } |
314 | 315 | ||
315 | BUG_ON(list_empty(&dev->msi_list)); | 316 | BUG_ON(list_empty(&dev->msi_list)); |
@@ -342,6 +343,7 @@ static int msi_capability_init(struct pci_dev *dev) | |||
342 | struct msi_desc *entry; | 343 | struct msi_desc *entry; |
343 | int pos, ret; | 344 | int pos, ret; |
344 | u16 control; | 345 | u16 control; |
346 | unsigned mask; | ||
345 | 347 | ||
346 | msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ | 348 | msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ |
347 | 349 | ||
@@ -356,21 +358,16 @@ static int msi_capability_init(struct pci_dev *dev) | |||
356 | entry->msi_attrib.is_64 = is_64bit_address(control); | 358 | entry->msi_attrib.is_64 = is_64bit_address(control); |
357 | entry->msi_attrib.entry_nr = 0; | 359 | entry->msi_attrib.entry_nr = 0; |
358 | entry->msi_attrib.maskbit = is_mask_bit_support(control); | 360 | entry->msi_attrib.maskbit = is_mask_bit_support(control); |
359 | entry->msi_attrib.masked = 1; | ||
360 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ | 361 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ |
361 | entry->msi_attrib.pos = pos; | 362 | entry->msi_attrib.pos = pos; |
362 | if (entry->msi_attrib.maskbit) { | 363 | |
363 | unsigned int base, maskbits, temp; | 364 | entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); |
364 | 365 | /* All MSIs are unmasked by default, Mask them all */ | |
365 | base = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); | 366 | if (entry->msi_attrib.maskbit) |
366 | entry->mask_pos = base; | 367 | pci_read_config_dword(dev, entry->mask_pos, &entry->masked); |
367 | /* All MSIs are unmasked by default, Mask them all */ | 368 | mask = msi_capable_mask(control); |
368 | pci_read_config_dword(dev, base, &maskbits); | 369 | msi_mask_irq(entry, mask, mask); |
369 | temp = msi_mask((control & PCI_MSI_FLAGS_QMASK) >> 1); | 370 | |
370 | maskbits |= temp; | ||
371 | pci_write_config_dword(dev, base, maskbits); | ||
372 | entry->msi_attrib.maskbits_mask = temp; | ||
373 | } | ||
374 | list_add_tail(&entry->list, &dev->msi_list); | 371 | list_add_tail(&entry->list, &dev->msi_list); |
375 | 372 | ||
376 | /* Configure MSI capability structure */ | 373 | /* Configure MSI capability structure */ |
@@ -435,11 +432,12 @@ static int msix_capability_init(struct pci_dev *dev, | |||
435 | entry->msi_attrib.is_msix = 1; | 432 | entry->msi_attrib.is_msix = 1; |
436 | entry->msi_attrib.is_64 = 1; | 433 | entry->msi_attrib.is_64 = 1; |
437 | entry->msi_attrib.entry_nr = j; | 434 | entry->msi_attrib.entry_nr = j; |
438 | entry->msi_attrib.maskbit = 1; | ||
439 | entry->msi_attrib.masked = 1; | ||
440 | entry->msi_attrib.default_irq = dev->irq; | 435 | entry->msi_attrib.default_irq = dev->irq; |
441 | entry->msi_attrib.pos = pos; | 436 | entry->msi_attrib.pos = pos; |
442 | entry->mask_base = base; | 437 | entry->mask_base = base; |
438 | entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
439 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | ||
440 | msix_mask_irq(entry, 1); | ||
443 | 441 | ||
444 | list_add_tail(&entry->list, &dev->msi_list); | 442 | list_add_tail(&entry->list, &dev->msi_list); |
445 | } | 443 | } |
@@ -556,9 +554,11 @@ int pci_enable_msi(struct pci_dev* dev) | |||
556 | } | 554 | } |
557 | EXPORT_SYMBOL(pci_enable_msi); | 555 | EXPORT_SYMBOL(pci_enable_msi); |
558 | 556 | ||
559 | void pci_msi_shutdown(struct pci_dev* dev) | 557 | void pci_msi_shutdown(struct pci_dev *dev) |
560 | { | 558 | { |
561 | struct msi_desc *entry; | 559 | struct msi_desc *desc; |
560 | u32 mask; | ||
561 | u16 ctrl; | ||
562 | 562 | ||
563 | if (!pci_msi_enable || !dev || !dev->msi_enabled) | 563 | if (!pci_msi_enable || !dev || !dev->msi_enabled) |
564 | return; | 564 | return; |
@@ -568,18 +568,13 @@ void pci_msi_shutdown(struct pci_dev* dev) | |||
568 | dev->msi_enabled = 0; | 568 | dev->msi_enabled = 0; |
569 | 569 | ||
570 | BUG_ON(list_empty(&dev->msi_list)); | 570 | BUG_ON(list_empty(&dev->msi_list)); |
571 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); | 571 | desc = list_first_entry(&dev->msi_list, struct msi_desc, list); |
572 | /* Return the the pci reset with msi irqs unmasked */ | 572 | pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl); |
573 | if (entry->msi_attrib.maskbit) { | 573 | mask = msi_capable_mask(ctrl); |
574 | u32 mask = entry->msi_attrib.maskbits_mask; | 574 | msi_mask_irq(desc, mask, ~mask); |
575 | struct irq_desc *desc = irq_to_desc(dev->irq); | ||
576 | msi_set_mask_bits(desc, mask, ~mask); | ||
577 | } | ||
578 | if (entry->msi_attrib.is_msix) | ||
579 | return; | ||
580 | 575 | ||
581 | /* Restore dev->irq to its default pin-assertion irq */ | 576 | /* Restore dev->irq to its default pin-assertion irq */ |
582 | dev->irq = entry->msi_attrib.default_irq; | 577 | dev->irq = desc->msi_attrib.default_irq; |
583 | } | 578 | } |
584 | 579 | ||
585 | void pci_disable_msi(struct pci_dev* dev) | 580 | void pci_disable_msi(struct pci_dev* dev) |