Skip to content

Commit f2440d9

Browse files
Matthew Wilcoxjbarnes993
authored andcommitted
PCI MSI: Refactor interrupt masking code
Since most of the callers already know whether they have an MSI or an MSI-X capability, split msi_set_mask_bits() into msi_mask_irq() and msix_mask_irq(). The only callers which don't (mask_msi_irq() and unmask_msi_irq()) can share code in msi_set_mask_bit(). This then becomes the only caller of msix_flush_writes(), so we can inline it. The flushing read can be to any address that belongs to the device, so we can eliminate the calculation too. We can also get rid of maskbits_mask from struct msi_desc and simply recalculate it on the rare occasion that we need it. The single-bit 'masked' element is replaced by a copy of the 32-bit 'masked' register, so this patch does not affect the size of msi_desc. Signed-off-by: Matthew Wilcox <[email protected]> Signed-off-by: Jesse Barnes <[email protected]>
1 parent 264d9ca commit f2440d9

File tree

2 files changed

+77
-83
lines changed

2 files changed

+77
-83
lines changed

drivers/pci/msi.c

Lines changed: 75 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,14 @@ static inline __attribute_const__ u32 msi_mask(unsigned x)
105105
return (1 << (1 << x)) - 1;
106106
}
107107

108-
static void msix_flush_writes(struct irq_desc *desc)
108+
static inline __attribute_const__ u32 msi_capable_mask(u16 control)
109109
{
110-
struct msi_desc *entry;
110+
return msi_mask((control >> 1) & 7);
111+
}
111112

112-
entry = get_irq_desc_msi(desc);
113-
BUG_ON(!entry);
114-
if (entry->msi_attrib.is_msix) {
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-
}
113+
static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
114+
{
115+
return msi_mask((control >> 4) & 7);
119116
}
120117

121118
/*
@@ -127,32 +124,57 @@ static void msix_flush_writes(struct irq_desc *desc)
127124
* Returns 1 if it succeeded in masking the interrupt and 0 if the device
128125
* doesn't support MSI masking.
129126
*/
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)
131128
{
132-
struct msi_desc *entry;
129+
u32 mask_bits = desc->masked;
133130

134-
entry = get_irq_desc_msi(desc);
135-
BUG_ON(!entry);
136-
if (entry->msi_attrib.is_msix) {
137-
int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
138-
PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
139-
writel(flag, entry->mask_base + offset);
140-
readl(entry->mask_base + offset);
141-
} else {
142-
int pos;
143-
u32 mask_bits;
131+
if (!desc->msi_attrib.maskbit)
132+
return;
133+
134+
mask_bits &= ~mask;
135+
mask_bits |= flag;
136+
pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits);
137+
desc->masked = mask_bits;
138+
}
139+
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+
}
144157

145-
if (!entry->msi_attrib.maskbit)
146-
return 0;
158+
static void msi_set_mask_bit(unsigned irq, u32 flag)
159+
{
160+
struct msi_desc *desc = get_irq_msi(irq);
147161

148-
pos = entry->mask_pos;
149-
pci_read_config_dword(entry->dev, pos, &mask_bits);
150-
mask_bits &= ~mask;
151-
mask_bits |= flag & mask;
152-
pci_write_config_dword(entry->dev, pos, mask_bits);
162+
if (desc->msi_attrib.is_msix) {
163+
msix_mask_irq(desc, flag);
164+
readl(desc->mask_base); /* Flush write to device */
165+
} else {
166+
msi_mask_irq(desc, 1, flag);
153167
}
154-
entry->msi_attrib.masked = !!flag;
155-
return 1;
168+
}
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);
156178
}
157179

158180
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)
230252
write_msi_msg_desc(desc, msg);
231253
}
232254

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-
249255
static int msi_free_irqs(struct pci_dev* dev);
250256

251257
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)
281287
pci_intx_for_msi(dev, 0);
282288
msi_set_enable(dev, 0);
283289
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-
}
289290

290291
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
292+
msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
291293
control &= ~PCI_MSI_FLAGS_QSIZE;
292294
control |= PCI_MSI_FLAGS_ENABLE;
293295
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
@@ -307,9 +309,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
307309
msix_set_enable(dev, 0);
308310

309311
list_for_each_entry(entry, &dev->msi_list, list) {
310-
struct irq_desc *desc = irq_to_desc(entry->irq);
311312
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);
313314
}
314315

315316
BUG_ON(list_empty(&dev->msi_list));
@@ -342,6 +343,7 @@ static int msi_capability_init(struct pci_dev *dev)
342343
struct msi_desc *entry;
343344
int pos, ret;
344345
u16 control;
346+
unsigned mask;
345347

346348
msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */
347349

@@ -356,21 +358,16 @@ static int msi_capability_init(struct pci_dev *dev)
356358
entry->msi_attrib.is_64 = is_64bit_address(control);
357359
entry->msi_attrib.entry_nr = 0;
358360
entry->msi_attrib.maskbit = is_mask_bit_support(control);
359-
entry->msi_attrib.masked = 1;
360361
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
361362
entry->msi_attrib.pos = pos;
362-
if (entry->msi_attrib.maskbit) {
363-
unsigned int base, maskbits, temp;
364-
365-
base = msi_mask_bits_reg(pos, entry->msi_attrib.is_64);
366-
entry->mask_pos = base;
367-
/* All MSIs are unmasked by default, Mask them all */
368-
pci_read_config_dword(dev, base, &maskbits);
369-
temp = msi_mask((control & PCI_MSI_FLAGS_QMASK) >> 1);
370-
maskbits |= temp;
371-
pci_write_config_dword(dev, base, maskbits);
372-
entry->msi_attrib.maskbits_mask = temp;
373-
}
363+
364+
entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64);
365+
/* All MSIs are unmasked by default, Mask them all */
366+
if (entry->msi_attrib.maskbit)
367+
pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
368+
mask = msi_capable_mask(control);
369+
msi_mask_irq(entry, mask, mask);
370+
374371
list_add_tail(&entry->list, &dev->msi_list);
375372

376373
/* Configure MSI capability structure */
@@ -435,11 +432,12 @@ static int msix_capability_init(struct pci_dev *dev,
435432
entry->msi_attrib.is_msix = 1;
436433
entry->msi_attrib.is_64 = 1;
437434
entry->msi_attrib.entry_nr = j;
438-
entry->msi_attrib.maskbit = 1;
439-
entry->msi_attrib.masked = 1;
440435
entry->msi_attrib.default_irq = dev->irq;
441436
entry->msi_attrib.pos = pos;
442437
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);
443441

444442
list_add_tail(&entry->list, &dev->msi_list);
445443
}
@@ -556,9 +554,11 @@ int pci_enable_msi(struct pci_dev* dev)
556554
}
557555
EXPORT_SYMBOL(pci_enable_msi);
558556

559-
void pci_msi_shutdown(struct pci_dev* dev)
557+
void pci_msi_shutdown(struct pci_dev *dev)
560558
{
561-
struct msi_desc *entry;
559+
struct msi_desc *desc;
560+
u32 mask;
561+
u16 ctrl;
562562

563563
if (!pci_msi_enable || !dev || !dev->msi_enabled)
564564
return;
@@ -568,18 +568,13 @@ void pci_msi_shutdown(struct pci_dev* dev)
568568
dev->msi_enabled = 0;
569569

570570
BUG_ON(list_empty(&dev->msi_list));
571-
entry = list_entry(dev->msi_list.next, struct msi_desc, list);
572-
/* Return the the pci reset with msi irqs unmasked */
573-
if (entry->msi_attrib.maskbit) {
574-
u32 mask = entry->msi_attrib.maskbits_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;
571+
desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
572+
pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl);
573+
mask = msi_capable_mask(ctrl);
574+
msi_mask_irq(desc, mask, ~mask);
580575

581576
/* 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;
583578
}
584579

585580
void pci_disable_msi(struct pci_dev* dev)

include/linux/msi.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@ struct msi_desc {
2222
struct {
2323
__u8 is_msix : 1;
2424
__u8 maskbit : 1; /* mask-pending bit supported ? */
25-
__u8 masked : 1;
2625
__u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */
2726
__u8 pos; /* Location of the msi capability */
2827
__u16 entry_nr; /* specific enabled entry */
29-
__u32 maskbits_mask; /* mask bits mask */
3028
unsigned default_irq; /* default pre-assigned irq */
31-
}msi_attrib;
29+
} msi_attrib;
3230

31+
u32 masked; /* mask bits */
3332
unsigned int irq;
3433
struct list_head list;
3534

0 commit comments

Comments
 (0)