Blame view

drivers/pci/msi.c 25.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   * File:	msi.c
   * Purpose:	PCI Message Signaled Interrupt (MSI)
   *
   * Copyright (C) 2003-2004 Intel
   * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
   */
1ce03373a   Eric W. Biederman   [PATCH] genirq: m...
8
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
  #include <linux/mm.h>
  #include <linux/irq.h>
  #include <linux/interrupt.h>
  #include <linux/init.h>
363c75db1   Paul Gortmaker   pci: Fix files ne...
13
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/ioport.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/pci.h>
  #include <linux/proc_fs.h>
3b7d1921f   Eric W. Biederman   [PATCH] msi: refa...
17
  #include <linux/msi.h>
4fdadebc3   Dan Williams   msi: fix ARM compile
18
  #include <linux/smp.h>
500559a92   Hidetoshi Seto   PCI MSI: Style cl...
19
20
  #include <linux/errno.h>
  #include <linux/io.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
  
  #include "pci.h"
  #include "msi.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  static int pci_msi_enable = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
27
  /* Arch hooks */
11df1f055   Michael Ellerman   PCI/MSI: Use #ifd...
28
29
  #ifndef arch_msi_check_device
  int arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
30
31
32
  {
  	return 0;
  }
11df1f055   Michael Ellerman   PCI/MSI: Use #ifd...
33
  #endif
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
34

11df1f055   Michael Ellerman   PCI/MSI: Use #ifd...
35
  #ifndef arch_setup_msi_irqs
1525bf0d8   Thomas Gleixner   msi: Introduce de...
36
37
38
39
40
41
  # define arch_setup_msi_irqs default_setup_msi_irqs
  # define HAVE_DEFAULT_MSI_SETUP_IRQS
  #endif
  
  #ifdef HAVE_DEFAULT_MSI_SETUP_IRQS
  int default_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
42
43
44
  {
  	struct msi_desc *entry;
  	int ret;
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
45
46
47
48
49
50
  	/*
  	 * If an architecture wants to support multiple MSI, it needs to
  	 * override arch_setup_msi_irqs()
  	 */
  	if (type == PCI_CAP_ID_MSI && nvec > 1)
  		return 1;
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
51
52
  	list_for_each_entry(entry, &dev->msi_list, list) {
  		ret = arch_setup_msi_irq(dev, entry);
b5fbf5332   Michael Ellerman   PCI/MSI: Allow ar...
53
  		if (ret < 0)
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
54
  			return ret;
b5fbf5332   Michael Ellerman   PCI/MSI: Allow ar...
55
56
  		if (ret > 0)
  			return -ENOSPC;
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
57
58
59
60
  	}
  
  	return 0;
  }
11df1f055   Michael Ellerman   PCI/MSI: Use #ifd...
61
  #endif
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
62

11df1f055   Michael Ellerman   PCI/MSI: Use #ifd...
63
  #ifndef arch_teardown_msi_irqs
1525bf0d8   Thomas Gleixner   msi: Introduce de...
64
65
66
67
68
69
  # define arch_teardown_msi_irqs default_teardown_msi_irqs
  # define HAVE_DEFAULT_MSI_TEARDOWN_IRQS
  #endif
  
  #ifdef HAVE_DEFAULT_MSI_TEARDOWN_IRQS
  void default_teardown_msi_irqs(struct pci_dev *dev)
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
70
71
72
73
  {
  	struct msi_desc *entry;
  
  	list_for_each_entry(entry, &dev->msi_list, list) {
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
74
75
76
77
78
79
  		int i, nvec;
  		if (entry->irq == 0)
  			continue;
  		nvec = 1 << entry->msi_attrib.multiple;
  		for (i = 0; i < nvec; i++)
  			arch_teardown_msi_irq(entry->irq + i);
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
80
81
  	}
  }
11df1f055   Michael Ellerman   PCI/MSI: Use #ifd...
82
  #endif
6a9e7f203   Adrian Bunk   PCI: drivers/pci/...
83

76ccc2970   Konrad Rzeszutek Wilk   x86/PCI: Expand t...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  #ifndef arch_restore_msi_irqs
  # define arch_restore_msi_irqs default_restore_msi_irqs
  # define HAVE_DEFAULT_MSI_RESTORE_IRQS
  #endif
  
  #ifdef HAVE_DEFAULT_MSI_RESTORE_IRQS
  void default_restore_msi_irqs(struct pci_dev *dev, int irq)
  {
  	struct msi_desc *entry;
  
  	entry = NULL;
  	if (dev->msix_enabled) {
  		list_for_each_entry(entry, &dev->msi_list, list) {
  			if (irq == entry->irq)
  				break;
  		}
  	} else if (dev->msi_enabled)  {
  		entry = irq_get_msi_desc(irq);
  	}
  
  	if (entry)
  		write_msi_msg(irq, &entry->msg);
  }
  #endif
110828c9c   Matthew Wilcox   PCI: remove redun...
108
  static void msi_set_enable(struct pci_dev *dev, int pos, int enable)
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
109
  {
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
110
  	u16 control;
110828c9c   Matthew Wilcox   PCI: remove redun...
111
  	BUG_ON(!pos);
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
112

110828c9c   Matthew Wilcox   PCI: remove redun...
113
114
115
116
117
  	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
  	control &= ~PCI_MSI_FLAGS_ENABLE;
  	if (enable)
  		control |= PCI_MSI_FLAGS_ENABLE;
  	pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
5ca5c02f0   Hidetoshi Seto   PCI/MSI: skip cal...
118
  }
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  static void msix_set_enable(struct pci_dev *dev, int enable)
  {
  	int pos;
  	u16 control;
  
  	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
  	if (pos) {
  		pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
  		control &= ~PCI_MSIX_FLAGS_ENABLE;
  		if (enable)
  			control |= PCI_MSIX_FLAGS_ENABLE;
  		pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
  	}
  }
bffac3c59   Matthew Wilcox   PCI MSI: Fix unde...
133
134
  static inline __attribute_const__ u32 msi_mask(unsigned x)
  {
0b49ec37a   Matthew Wilcox   PCI/MSI: fix msi_...
135
136
137
138
  	/* Don't shift by >= width of type */
  	if (x >= 5)
  		return 0xffffffff;
  	return (1 << (1 << x)) - 1;
bffac3c59   Matthew Wilcox   PCI MSI: Fix unde...
139
  }
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
140
  static inline __attribute_const__ u32 msi_capable_mask(u16 control)
988cbb15e   Mitch Williams   PCI: Flush MSI-X ...
141
  {
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
142
143
  	return msi_mask((control >> 1) & 7);
  }
988cbb15e   Mitch Williams   PCI: Flush MSI-X ...
144

f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
145
146
147
  static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
  {
  	return msi_mask((control >> 4) & 7);
988cbb15e   Mitch Williams   PCI: Flush MSI-X ...
148
  }
ce6fce429   Matthew Wilcox   PCI MSI: Don't di...
149
150
151
152
153
  /*
   * PCI 2.3 does not specify mask bits for each MSI interrupt.  Attempting to
   * mask all MSI interrupts by clearing the MSI enable bit does not work
   * reliably as devices without an INTx disable bit will then generate a
   * level IRQ which will never be cleared.
ce6fce429   Matthew Wilcox   PCI MSI: Don't di...
154
   */
12abb8ba8   Hidetoshi Seto   PCI MSI: Fix rest...
155
  static u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  {
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
157
  	u32 mask_bits = desc->masked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158

f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
159
  	if (!desc->msi_attrib.maskbit)
12abb8ba8   Hidetoshi Seto   PCI MSI: Fix rest...
160
  		return 0;
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
161
162
163
164
  
  	mask_bits &= ~mask;
  	mask_bits |= flag;
  	pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits);
12abb8ba8   Hidetoshi Seto   PCI MSI: Fix rest...
165
166
167
168
169
170
171
  
  	return mask_bits;
  }
  
  static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
  {
  	desc->masked = __msi_mask_irq(desc, mask, flag);
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
172
173
174
175
176
177
178
179
180
  }
  
  /*
   * This internal function does not flush PCI writes to the device.
   * All users must ensure that they read from the device before either
   * assuming that the device state is up to date, or returning out of this
   * file.  This saves a few milliseconds when initialising devices with lots
   * of MSI-X interrupts.
   */
12abb8ba8   Hidetoshi Seto   PCI MSI: Fix rest...
181
  static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag)
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
182
183
184
  {
  	u32 mask_bits = desc->masked;
  	unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
2c21fd4b3   Hidetoshi Seto   PCI MSI: shorten ...
185
  						PCI_MSIX_ENTRY_VECTOR_CTRL;
8d8052869   Sheng Yang   PCI: Add mask bit...
186
187
188
  	mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
  	if (flag)
  		mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
189
  	writel(mask_bits, desc->mask_base + offset);
12abb8ba8   Hidetoshi Seto   PCI MSI: Fix rest...
190
191
192
193
194
195
196
  
  	return mask_bits;
  }
  
  static void msix_mask_irq(struct msi_desc *desc, u32 flag)
  {
  	desc->masked = __msix_mask_irq(desc, flag);
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
197
  }
24d275533   Matthew Wilcox   PCI MSI: Replace ...
198

1c9db5253   Thomas Gleixner   pci: Convert msi ...
199
  static void msi_set_mask_bit(struct irq_data *data, u32 flag)
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
200
  {
1c9db5253   Thomas Gleixner   pci: Convert msi ...
201
  	struct msi_desc *desc = irq_data_get_msi(data);
24d275533   Matthew Wilcox   PCI MSI: Replace ...
202

f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
203
204
205
206
  	if (desc->msi_attrib.is_msix) {
  		msix_mask_irq(desc, flag);
  		readl(desc->mask_base);		/* Flush write to device */
  	} else {
1c9db5253   Thomas Gleixner   pci: Convert msi ...
207
  		unsigned offset = data->irq - desc->dev->irq;
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
208
  		msi_mask_irq(desc, 1 << offset, flag << offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
  	}
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
210
  }
1c9db5253   Thomas Gleixner   pci: Convert msi ...
211
  void mask_msi_irq(struct irq_data *data)
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
212
  {
1c9db5253   Thomas Gleixner   pci: Convert msi ...
213
  	msi_set_mask_bit(data, 1);
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
214
  }
1c9db5253   Thomas Gleixner   pci: Convert msi ...
215
  void unmask_msi_irq(struct irq_data *data)
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
216
  {
1c9db5253   Thomas Gleixner   pci: Convert msi ...
217
  	msi_set_mask_bit(data, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  }
39431acb1   Thomas Gleixner   pci: Cleanup the ...
219
  void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  {
30da55242   Ben Hutchings   PCI: MSI: Restore...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  	BUG_ON(entry->dev->current_state != PCI_D0);
  
  	if (entry->msi_attrib.is_msix) {
  		void __iomem *base = entry->mask_base +
  			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
  
  		msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR);
  		msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR);
  		msg->data = readl(base + PCI_MSIX_ENTRY_DATA);
  	} else {
  		struct pci_dev *dev = entry->dev;
  		int pos = entry->msi_attrib.pos;
  		u16 data;
  
  		pci_read_config_dword(dev, msi_lower_address_reg(pos),
  					&msg->address_lo);
  		if (entry->msi_attrib.is_64) {
  			pci_read_config_dword(dev, msi_upper_address_reg(pos),
  						&msg->address_hi);
  			pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
  		} else {
  			msg->address_hi = 0;
  			pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
  		}
  		msg->data = data;
  	}
  }
  
  void read_msi_msg(unsigned int irq, struct msi_msg *msg)
  {
dced35aeb   Thomas Gleixner   drivers: Final ir...
251
  	struct msi_desc *entry = irq_get_msi_desc(irq);
30da55242   Ben Hutchings   PCI: MSI: Restore...
252

39431acb1   Thomas Gleixner   pci: Cleanup the ...
253
  	__read_msi_msg(entry, msg);
30da55242   Ben Hutchings   PCI: MSI: Restore...
254
  }
39431acb1   Thomas Gleixner   pci: Cleanup the ...
255
  void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
30da55242   Ben Hutchings   PCI: MSI: Restore...
256
  {
30da55242   Ben Hutchings   PCI: MSI: Restore...
257
  	/* Assert that the cache is valid, assuming that
fcd097f31   Ben Hutchings   PCI: MSI: Remove ...
258
259
260
  	 * valid messages are not all-zeroes. */
  	BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo |
  		 entry->msg.data));
0366f8f71   Eric W. Biederman   [PATCH] genirq: m...
261

fcd097f31   Ben Hutchings   PCI: MSI: Remove ...
262
  	*msg = entry->msg;
0366f8f71   Eric W. Biederman   [PATCH] genirq: m...
263
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264

30da55242   Ben Hutchings   PCI: MSI: Restore...
265
  void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
0366f8f71   Eric W. Biederman   [PATCH] genirq: m...
266
  {
dced35aeb   Thomas Gleixner   drivers: Final ir...
267
  	struct msi_desc *entry = irq_get_msi_desc(irq);
3145e941f   Yinghai Lu   x86, MSI: pass ir...
268

39431acb1   Thomas Gleixner   pci: Cleanup the ...
269
  	__get_cached_msi_msg(entry, msg);
3145e941f   Yinghai Lu   x86, MSI: pass ir...
270
  }
39431acb1   Thomas Gleixner   pci: Cleanup the ...
271
  void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
3145e941f   Yinghai Lu   x86, MSI: pass ir...
272
  {
fcd097f31   Ben Hutchings   PCI: MSI: Remove ...
273
274
275
  	if (entry->dev->current_state != PCI_D0) {
  		/* Don't touch the hardware now */
  	} else if (entry->msi_attrib.is_msix) {
24d275533   Matthew Wilcox   PCI MSI: Replace ...
276
277
278
  		void __iomem *base;
  		base = entry->mask_base +
  			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
2c21fd4b3   Hidetoshi Seto   PCI MSI: shorten ...
279
280
281
  		writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
  		writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
  		writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
24d275533   Matthew Wilcox   PCI MSI: Replace ...
282
  	} else {
0366f8f71   Eric W. Biederman   [PATCH] genirq: m...
283
284
  		struct pci_dev *dev = entry->dev;
  		int pos = entry->msi_attrib.pos;
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
285
286
287
288
289
290
  		u16 msgctl;
  
  		pci_read_config_word(dev, msi_control_reg(pos), &msgctl);
  		msgctl &= ~PCI_MSI_FLAGS_QSIZE;
  		msgctl |= entry->msi_attrib.multiple << 4;
  		pci_write_config_word(dev, msi_control_reg(pos), msgctl);
0366f8f71   Eric W. Biederman   [PATCH] genirq: m...
291
292
293
294
295
296
297
298
299
300
301
302
  
  		pci_write_config_dword(dev, msi_lower_address_reg(pos),
  					msg->address_lo);
  		if (entry->msi_attrib.is_64) {
  			pci_write_config_dword(dev, msi_upper_address_reg(pos),
  						msg->address_hi);
  			pci_write_config_word(dev, msi_data_reg(pos, 1),
  						msg->data);
  		} else {
  			pci_write_config_word(dev, msi_data_reg(pos, 0),
  						msg->data);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  	}
392ee1e6d   Eric W. Biederman   [PATCH] msi: Safe...
304
  	entry->msg = *msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  }
0366f8f71   Eric W. Biederman   [PATCH] genirq: m...
306

3145e941f   Yinghai Lu   x86, MSI: pass ir...
307
308
  void write_msi_msg(unsigned int irq, struct msi_msg *msg)
  {
dced35aeb   Thomas Gleixner   drivers: Final ir...
309
  	struct msi_desc *entry = irq_get_msi_desc(irq);
3145e941f   Yinghai Lu   x86, MSI: pass ir...
310

39431acb1   Thomas Gleixner   pci: Cleanup the ...
311
  	__write_msi_msg(entry, msg);
3145e941f   Yinghai Lu   x86, MSI: pass ir...
312
  }
f56e44813   Hidetoshi Seto   PCI MSI: Unify ms...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  static void free_msi_irqs(struct pci_dev *dev)
  {
  	struct msi_desc *entry, *tmp;
  
  	list_for_each_entry(entry, &dev->msi_list, list) {
  		int i, nvec;
  		if (!entry->irq)
  			continue;
  		nvec = 1 << entry->msi_attrib.multiple;
  		for (i = 0; i < nvec; i++)
  			BUG_ON(irq_has_action(entry->irq + i));
  	}
  
  	arch_teardown_msi_irqs(dev);
  
  	list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
  		if (entry->msi_attrib.is_msix) {
  			if (list_is_last(&entry->list, &dev->msi_list))
  				iounmap(entry->mask_base);
  		}
424eb3915   Neil Horman   PCI: msi: fix imb...
333
334
335
336
337
338
339
340
341
342
343
  
  		/*
  		 * Its possible that we get into this path
  		 * When populate_msi_sysfs fails, which means the entries
  		 * were not registered with sysfs.  In that case don't
  		 * unregister them.
  		 */
  		if (entry->kobj.parent) {
  			kobject_del(&entry->kobj);
  			kobject_put(&entry->kobj);
  		}
f56e44813   Hidetoshi Seto   PCI MSI: Unify ms...
344
345
346
347
  		list_del(&entry->list);
  		kfree(entry);
  	}
  }
c54c18790   Satoru Takeuchi   PCI: cleanup MSI ...
348

379f5327a   Matthew Wilcox   PCI MSI: msi_desc...
349
  static struct msi_desc *alloc_msi_entry(struct pci_dev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  {
379f5327a   Matthew Wilcox   PCI MSI: msi_desc...
351
352
  	struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL);
  	if (!desc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  		return NULL;
379f5327a   Matthew Wilcox   PCI MSI: msi_desc...
354
355
  	INIT_LIST_HEAD(&desc->list);
  	desc->dev = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356

379f5327a   Matthew Wilcox   PCI MSI: msi_desc...
357
  	return desc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  }
ba698ad4b   David Miller   PCI: Add quirk fo...
359
360
361
362
363
  static void pci_intx_for_msi(struct pci_dev *dev, int enable)
  {
  	if (!(dev->dev_flags & PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG))
  		pci_intx(dev, enable);
  }
8fed4b652   Michael Ellerman   MSI: Combine pci_...
364
  static void __pci_restore_msi_state(struct pci_dev *dev)
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
365
  {
392ee1e6d   Eric W. Biederman   [PATCH] msi: Safe...
366
  	int pos;
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
367
  	u16 control;
392ee1e6d   Eric W. Biederman   [PATCH] msi: Safe...
368
  	struct msi_desc *entry;
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
369

b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
370
371
  	if (!dev->msi_enabled)
  		return;
dced35aeb   Thomas Gleixner   drivers: Final ir...
372
  	entry = irq_get_msi_desc(dev->irq);
392ee1e6d   Eric W. Biederman   [PATCH] msi: Safe...
373
  	pos = entry->msi_attrib.pos;
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
374

ba698ad4b   David Miller   PCI: Add quirk fo...
375
  	pci_intx_for_msi(dev, 0);
110828c9c   Matthew Wilcox   PCI: remove redun...
376
  	msi_set_enable(dev, pos, 0);
76ccc2970   Konrad Rzeszutek Wilk   x86/PCI: Expand t...
377
  	arch_restore_msi_irqs(dev, dev->irq);
392ee1e6d   Eric W. Biederman   [PATCH] msi: Safe...
378
379
  
  	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
380
  	msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
abad2ec98   Jesse Barnes   PCI: fully restor...
381
  	control &= ~PCI_MSI_FLAGS_QSIZE;
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
382
  	control |= (entry->msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
383
  	pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
8fed4b652   Michael Ellerman   MSI: Combine pci_...
384
385
386
  }
  
  static void __pci_restore_msix_state(struct pci_dev *dev)
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
387
  {
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
388
  	int pos;
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
389
  	struct msi_desc *entry;
392ee1e6d   Eric W. Biederman   [PATCH] msi: Safe...
390
  	u16 control;
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
391

ded86d8d3   Eric W. Biederman   msi: Kill msi_loo...
392
393
  	if (!dev->msix_enabled)
  		return;
f598282f5   Matthew Wilcox   PCI: Fix the NIU ...
394
  	BUG_ON(list_empty(&dev->msi_list));
9cc8d5481   Hidetoshi Seto   PCI MSI: Use list...
395
  	entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
f598282f5   Matthew Wilcox   PCI: Fix the NIU ...
396
397
  	pos = entry->msi_attrib.pos;
  	pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
ded86d8d3   Eric W. Biederman   msi: Kill msi_loo...
398

41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
399
  	/* route the table */
ba698ad4b   David Miller   PCI: Add quirk fo...
400
  	pci_intx_for_msi(dev, 0);
f598282f5   Matthew Wilcox   PCI: Fix the NIU ...
401
402
  	control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL;
  	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
403

4aa9bc955   Michael Ellerman   MSI: Use a list i...
404
  	list_for_each_entry(entry, &dev->msi_list, list) {
76ccc2970   Konrad Rzeszutek Wilk   x86/PCI: Expand t...
405
  		arch_restore_msi_irqs(dev, entry->irq);
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
406
  		msix_mask_irq(entry, entry->masked);
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
407
  	}
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
408

392ee1e6d   Eric W. Biederman   [PATCH] msi: Safe...
409
  	control &= ~PCI_MSIX_FLAGS_MASKALL;
392ee1e6d   Eric W. Biederman   [PATCH] msi: Safe...
410
  	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
411
  }
8fed4b652   Michael Ellerman   MSI: Combine pci_...
412
413
414
415
416
417
  
  void pci_restore_msi_state(struct pci_dev *dev)
  {
  	__pci_restore_msi_state(dev);
  	__pci_restore_msix_state(dev);
  }
94688cf24   Linas Vepstas   PCI: export pci_r...
418
  EXPORT_SYMBOL_GPL(pci_restore_msi_state);
41017f0ca   Shaohua Li   [PATCH] PCI: MSI(...
419

da8d1c8ba   Neil Horman   PCI/sysfs: add pe...
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
  
  #define to_msi_attr(obj) container_of(obj, struct msi_attribute, attr)
  #define to_msi_desc(obj) container_of(obj, struct msi_desc, kobj)
  
  struct msi_attribute {
  	struct attribute        attr;
  	ssize_t (*show)(struct msi_desc *entry, struct msi_attribute *attr,
  			char *buf);
  	ssize_t (*store)(struct msi_desc *entry, struct msi_attribute *attr,
  			 const char *buf, size_t count);
  };
  
  static ssize_t show_msi_mode(struct msi_desc *entry, struct msi_attribute *atr,
  			     char *buf)
  {
  	return sprintf(buf, "%s
  ", entry->msi_attrib.is_msix ? "msix" : "msi");
  }
  
  static ssize_t msi_irq_attr_show(struct kobject *kobj,
  				 struct attribute *attr, char *buf)
  {
  	struct msi_attribute *attribute = to_msi_attr(attr);
  	struct msi_desc *entry = to_msi_desc(kobj);
  
  	if (!attribute->show)
  		return -EIO;
  
  	return attribute->show(entry, attribute, buf);
  }
  
  static const struct sysfs_ops msi_irq_sysfs_ops = {
  	.show = msi_irq_attr_show,
  };
  
  static struct msi_attribute mode_attribute =
  	__ATTR(mode, S_IRUGO, show_msi_mode, NULL);
  
  
  struct attribute *msi_irq_default_attrs[] = {
  	&mode_attribute.attr,
  	NULL
  };
  
  void msi_kobj_release(struct kobject *kobj)
  {
  	struct msi_desc *entry = to_msi_desc(kobj);
  
  	pci_dev_put(entry->dev);
  }
  
  static struct kobj_type msi_irq_ktype = {
  	.release = msi_kobj_release,
  	.sysfs_ops = &msi_irq_sysfs_ops,
  	.default_attrs = msi_irq_default_attrs,
  };
  
  static int populate_msi_sysfs(struct pci_dev *pdev)
  {
  	struct msi_desc *entry;
  	struct kobject *kobj;
  	int ret;
  	int count = 0;
  
  	pdev->msi_kset = kset_create_and_add("msi_irqs", NULL, &pdev->dev.kobj);
  	if (!pdev->msi_kset)
  		return -ENOMEM;
  
  	list_for_each_entry(entry, &pdev->msi_list, list) {
  		kobj = &entry->kobj;
  		kobj->kset = pdev->msi_kset;
  		pci_dev_get(pdev);
  		ret = kobject_init_and_add(kobj, &msi_irq_ktype, NULL,
  				     "%u", entry->irq);
  		if (ret)
  			goto out_unroll;
  
  		count++;
  	}
  
  	return 0;
  
  out_unroll:
  	list_for_each_entry(entry, &pdev->msi_list, list) {
  		if (!count)
  			break;
  		kobject_del(&entry->kobj);
  		kobject_put(&entry->kobj);
  		count--;
  	}
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
  /**
   * msi_capability_init - configure device's MSI capability structure
   * @dev: pointer to the pci_dev data structure of MSI device function
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
515
   * @nvec: number of interrupts to allocate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
   *
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
517
518
519
520
521
522
523
   * Setup the MSI capability structure of the device with the requested
   * number of interrupts.  A return value of zero indicates the successful
   * setup of an entry with the new MSI irq.  A negative return value indicates
   * an error, and a positive return value indicates the number of interrupts
   * which could have been allocated.
   */
  static int msi_capability_init(struct pci_dev *dev, int nvec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
  {
  	struct msi_desc *entry;
7fe3730de   Michael Ellerman   MSI: arch must co...
526
  	int pos, ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  	u16 control;
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
528
  	unsigned mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529

500559a92   Hidetoshi Seto   PCI MSI: Style cl...
530
  	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
110828c9c   Matthew Wilcox   PCI: remove redun...
531
  	msi_set_enable(dev, pos, 0);	/* Disable MSI during set up */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  	pci_read_config_word(dev, msi_control_reg(pos), &control);
  	/* MSI Entry Initialization */
379f5327a   Matthew Wilcox   PCI MSI: msi_desc...
534
  	entry = alloc_msi_entry(dev);
f7feaca77   Eric W. Biederman   msi: Make MSI use...
535
536
  	if (!entry)
  		return -ENOMEM;
1ce03373a   Eric W. Biederman   [PATCH] genirq: m...
537

500559a92   Hidetoshi Seto   PCI MSI: Style cl...
538
539
540
541
542
543
  	entry->msi_attrib.is_msix	= 0;
  	entry->msi_attrib.is_64		= is_64bit_address(control);
  	entry->msi_attrib.entry_nr	= 0;
  	entry->msi_attrib.maskbit	= is_mask_bit_support(control);
  	entry->msi_attrib.default_irq	= dev->irq;	/* Save IOAPIC IRQ */
  	entry->msi_attrib.pos		= pos;
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
544

67b5db650   Hidetoshi Seto   PCI MSI: Define P...
545
  	entry->mask_pos = msi_mask_reg(pos, entry->msi_attrib.is_64);
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
546
547
548
549
550
  	/* All MSIs are unmasked by default, Mask them all */
  	if (entry->msi_attrib.maskbit)
  		pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
  	mask = msi_capable_mask(control);
  	msi_mask_irq(entry, mask, mask);
0dd11f9be   Eric W. Biederman   msi: fix the orde...
551
  	list_add_tail(&entry->list, &dev->msi_list);
9c8313343   Michael Ellerman   MSI: Give archs t...
552

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	/* Configure MSI capability structure */
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
554
  	ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
7fe3730de   Michael Ellerman   MSI: arch must co...
555
  	if (ret) {
7ba1930db   Hidetoshi Seto   PCI MSI: Unmask M...
556
  		msi_mask_irq(entry, mask, ~mask);
f56e44813   Hidetoshi Seto   PCI MSI: Unify ms...
557
  		free_msi_irqs(dev);
7fe3730de   Michael Ellerman   MSI: arch must co...
558
  		return ret;
fd58e55fc   Mark Maule   [PATCH] PCI: msi ...
559
  	}
f7feaca77   Eric W. Biederman   msi: Make MSI use...
560

da8d1c8ba   Neil Horman   PCI/sysfs: add pe...
561
562
563
564
565
566
  	ret = populate_msi_sysfs(dev);
  	if (ret) {
  		msi_mask_irq(entry, mask, ~mask);
  		free_msi_irqs(dev);
  		return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
  	/* Set MSI enabled bits	 */
ba698ad4b   David Miller   PCI: Add quirk fo...
568
  	pci_intx_for_msi(dev, 0);
110828c9c   Matthew Wilcox   PCI: remove redun...
569
  	msi_set_enable(dev, pos, 1);
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
570
  	dev->msi_enabled = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571

7fe3730de   Michael Ellerman   MSI: arch must co...
572
  	dev->irq = entry->irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
  	return 0;
  }
5a05a9d81   Hidetoshi Seto   PCI MSI: MSI-X cl...
575
576
577
  static void __iomem *msix_map_region(struct pci_dev *dev, unsigned pos,
  							unsigned nr_entries)
  {
4302e0fb7   Kenji Kaneshige   PCI: fix wrong me...
578
  	resource_size_t phys_addr;
5a05a9d81   Hidetoshi Seto   PCI MSI: MSI-X cl...
579
580
581
582
583
584
585
586
587
588
  	u32 table_offset;
  	u8 bir;
  
  	pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset);
  	bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
  	table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
  	phys_addr = pci_resource_start(dev, bir) + table_offset;
  
  	return ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
  }
d9d7070e6   Hidetoshi Seto   PCI MSI: MSI-X cl...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  static int msix_setup_entries(struct pci_dev *dev, unsigned pos,
  				void __iomem *base, struct msix_entry *entries,
  				int nvec)
  {
  	struct msi_desc *entry;
  	int i;
  
  	for (i = 0; i < nvec; i++) {
  		entry = alloc_msi_entry(dev);
  		if (!entry) {
  			if (!i)
  				iounmap(base);
  			else
  				free_msi_irqs(dev);
  			/* No enough memory. Don't try again */
  			return -ENOMEM;
  		}
  
  		entry->msi_attrib.is_msix	= 1;
  		entry->msi_attrib.is_64		= 1;
  		entry->msi_attrib.entry_nr	= entries[i].entry;
  		entry->msi_attrib.default_irq	= dev->irq;
  		entry->msi_attrib.pos		= pos;
  		entry->mask_base		= base;
  
  		list_add_tail(&entry->list, &dev->msi_list);
  	}
  
  	return 0;
  }
75cb34268   Hidetoshi Seto   PCI MSI: MSI-X cl...
619
620
621
622
623
624
625
626
627
628
629
  static void msix_program_entries(struct pci_dev *dev,
  					struct msix_entry *entries)
  {
  	struct msi_desc *entry;
  	int i = 0;
  
  	list_for_each_entry(entry, &dev->msi_list, list) {
  		int offset = entries[i].entry * PCI_MSIX_ENTRY_SIZE +
  						PCI_MSIX_ENTRY_VECTOR_CTRL;
  
  		entries[i].vector = entry->irq;
dced35aeb   Thomas Gleixner   drivers: Final ir...
630
  		irq_set_msi_desc(entry->irq, entry);
75cb34268   Hidetoshi Seto   PCI MSI: MSI-X cl...
631
632
633
634
635
  		entry->masked = readl(entry->mask_base + offset);
  		msix_mask_irq(entry, 1);
  		i++;
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
  /**
   * msix_capability_init - configure device's MSI-X capability
   * @dev: pointer to the pci_dev data structure of MSI-X device function
8f7020d36   Randy Dunlap   [PATCH] kernel-do...
639
640
   * @entries: pointer to an array of struct msix_entry entries
   * @nvec: number of @entries
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
   *
eaae4b3a8   Steven Cole   [PATCH] PCI: Spel...
642
   * Setup the MSI-X capability structure of device function with a
1ce03373a   Eric W. Biederman   [PATCH] genirq: m...
643
644
   * single MSI-X irq. A return of zero indicates the successful setup of
   * requested MSI-X entries with allocated irqs or non-zero for otherwise.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
   **/
  static int msix_capability_init(struct pci_dev *dev,
  				struct msix_entry *entries, int nvec)
  {
d9d7070e6   Hidetoshi Seto   PCI MSI: MSI-X cl...
649
  	int pos, ret;
5a05a9d81   Hidetoshi Seto   PCI MSI: MSI-X cl...
650
  	u16 control;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  	void __iomem *base;
500559a92   Hidetoshi Seto   PCI MSI: Style cl...
652
  	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
f598282f5   Matthew Wilcox   PCI: Fix the NIU ...
653
654
655
656
657
  	pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
  
  	/* Ensure MSI-X is disabled while it is set up */
  	control &= ~PCI_MSIX_FLAGS_ENABLE;
  	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  	/* Request & Map MSI-X table region */
5a05a9d81   Hidetoshi Seto   PCI MSI: MSI-X cl...
659
660
  	base = msix_map_region(dev, pos, multi_msix_capable(control));
  	if (!base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  		return -ENOMEM;
d9d7070e6   Hidetoshi Seto   PCI MSI: MSI-X cl...
662
663
664
  	ret = msix_setup_entries(dev, pos, base, entries, nvec);
  	if (ret)
  		return ret;
9c8313343   Michael Ellerman   MSI: Give archs t...
665
666
  
  	ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
583871d43   Hidetoshi Seto   PCI MSI: Relocate...
667
668
  	if (ret)
  		goto error;
9c8313343   Michael Ellerman   MSI: Give archs t...
669

f598282f5   Matthew Wilcox   PCI: Fix the NIU ...
670
671
672
673
674
675
676
  	/*
  	 * Some devices require MSI-X to be enabled before we can touch the
  	 * MSI-X registers.  We need to mask all the vectors to prevent
  	 * interrupts coming in before they're fully set up.
  	 */
  	control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE;
  	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
75cb34268   Hidetoshi Seto   PCI MSI: MSI-X cl...
677
  	msix_program_entries(dev, entries);
f598282f5   Matthew Wilcox   PCI: Fix the NIU ...
678

da8d1c8ba   Neil Horman   PCI/sysfs: add pe...
679
680
681
682
683
  	ret = populate_msi_sysfs(dev);
  	if (ret) {
  		ret = 0;
  		goto error;
  	}
f598282f5   Matthew Wilcox   PCI: Fix the NIU ...
684
  	/* Set MSI-X enabled bits and unmask the function */
ba698ad4b   David Miller   PCI: Add quirk fo...
685
  	pci_intx_for_msi(dev, 0);
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
686
  	dev->msix_enabled = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687

f598282f5   Matthew Wilcox   PCI: Fix the NIU ...
688
689
  	control &= ~PCI_MSIX_FLAGS_MASKALL;
  	pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
8d1810185   Matthew Wilcox   PCI MSI: Fix MSI-...
690

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  	return 0;
583871d43   Hidetoshi Seto   PCI MSI: Relocate...
692
693
694
695
696
697
698
  
  error:
  	if (ret < 0) {
  		/*
  		 * If we had some success, report the number of irqs
  		 * we succeeded in setting up.
  		 */
d9d7070e6   Hidetoshi Seto   PCI MSI: MSI-X cl...
699
  		struct msi_desc *entry;
583871d43   Hidetoshi Seto   PCI MSI: Relocate...
700
701
702
703
704
705
706
707
708
709
710
711
712
  		int avail = 0;
  
  		list_for_each_entry(entry, &dev->msi_list, list) {
  			if (entry->irq != 0)
  				avail++;
  		}
  		if (avail != 0)
  			ret = avail;
  	}
  
  	free_msi_irqs(dev);
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
  }
  
  /**
17bbc12ac   Michael Ellerman   MSI: Rename pci_m...
716
   * pci_msi_check_device - check whether MSI may be enabled on a device
24334a125   Brice Goglin   MSI: Factorize co...
717
   * @dev: pointer to the pci_dev data structure of MSI device function
c9953a73e   Michael Ellerman   MSI: Add an arch_...
718
   * @nvec: how many MSIs have been requested ?
b1e2303db   Michael Ellerman   MSI: Expand pci_m...
719
   * @type: are we checking for MSI or MSI-X ?
24334a125   Brice Goglin   MSI: Factorize co...
720
   *
0306ebfa3   Brice Goglin   PCI: Improve pci_...
721
   * Look at global flags, the device itself, and its parent busses
17bbc12ac   Michael Ellerman   MSI: Rename pci_m...
722
723
   * to determine if MSI/-X are supported for the device. If MSI/-X is
   * supported return 0, else return an error code.
24334a125   Brice Goglin   MSI: Factorize co...
724
   **/
500559a92   Hidetoshi Seto   PCI MSI: Style cl...
725
  static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
24334a125   Brice Goglin   MSI: Factorize co...
726
727
  {
  	struct pci_bus *bus;
c9953a73e   Michael Ellerman   MSI: Add an arch_...
728
  	int ret;
24334a125   Brice Goglin   MSI: Factorize co...
729

0306ebfa3   Brice Goglin   PCI: Improve pci_...
730
  	/* MSI must be globally enabled and supported by the device */
24334a125   Brice Goglin   MSI: Factorize co...
731
732
  	if (!pci_msi_enable || !dev || dev->no_msi)
  		return -EINVAL;
314e77b3e   Michael Ellerman   MSI: Remove dev->...
733
734
735
736
737
738
739
  	/*
  	 * You can't ask to have 0 or less MSIs configured.
  	 *  a) it's stupid ..
  	 *  b) the list manipulation code assumes nvec >= 1.
  	 */
  	if (nvec < 1)
  		return -ERANGE;
500559a92   Hidetoshi Seto   PCI MSI: Style cl...
740
741
742
  	/*
  	 * Any bridge which does NOT route MSI transactions from its
  	 * secondary bus to its primary bus must set NO_MSI flag on
0306ebfa3   Brice Goglin   PCI: Improve pci_...
743
744
745
746
  	 * the secondary pci_bus.
  	 * We expect only arch-specific PCI host bus controller driver
  	 * or quirks for specific PCI bridges to be setting NO_MSI.
  	 */
24334a125   Brice Goglin   MSI: Factorize co...
747
748
749
  	for (bus = dev->bus; bus; bus = bus->parent)
  		if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
  			return -EINVAL;
c9953a73e   Michael Ellerman   MSI: Add an arch_...
750
751
752
  	ret = arch_msi_check_device(dev, nvec, type);
  	if (ret)
  		return ret;
b1e2303db   Michael Ellerman   MSI: Expand pci_m...
753
754
  	if (!pci_find_capability(dev, type))
  		return -EINVAL;
24334a125   Brice Goglin   MSI: Factorize co...
755
756
757
758
  	return 0;
  }
  
  /**
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
759
760
761
   * pci_enable_msi_block - configure device's MSI capability structure
   * @dev: device to configure
   * @nvec: number of interrupts to configure
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
   *
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
763
764
765
766
767
768
769
770
771
   * Allocate IRQs for a device with the MSI capability.
   * This function returns a negative errno if an error occurs.  If it
   * is unable to allocate the number of interrupts requested, it returns
   * the number of interrupts it might be able to allocate.  If it successfully
   * allocates at least the number of interrupts requested, it returns 0 and
   * updates the @dev's irq member to the lowest new interrupt number; the
   * other interrupt numbers allocated to this device are consecutive.
   */
  int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
  {
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
773
774
775
776
777
778
779
780
781
782
  	int status, pos, maxvec;
  	u16 msgctl;
  
  	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
  	if (!pos)
  		return -EINVAL;
  	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
  	maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
  	if (nvec > maxvec)
  		return maxvec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783

1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
784
  	status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSI);
c9953a73e   Michael Ellerman   MSI: Add an arch_...
785
786
  	if (status)
  		return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787

ded86d8d3   Eric W. Biederman   msi: Kill msi_loo...
788
  	WARN_ON(!!dev->msi_enabled);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789

1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
790
  	/* Check whether driver already requested MSI-X irqs */
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
791
  	if (dev->msix_enabled) {
80ccba118   Bjorn Helgaas   PCI: use dev_prin...
792
793
794
  		dev_info(&dev->dev, "can't enable MSI "
  			 "(MSI-X already enabled)
  ");
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
795
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
  	}
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
797
798
  
  	status = msi_capability_init(dev, nvec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
  	return status;
  }
1c8d7b0a5   Matthew Wilcox   PCI MSI: Add supp...
801
  EXPORT_SYMBOL(pci_enable_msi_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802

f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
803
  void pci_msi_shutdown(struct pci_dev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  {
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
805
806
807
  	struct msi_desc *desc;
  	u32 mask;
  	u16 ctrl;
110828c9c   Matthew Wilcox   PCI: remove redun...
808
  	unsigned pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809

128bc5fce   Michael Ellerman   MSI: Consolidate ...
810
  	if (!pci_msi_enable || !dev || !dev->msi_enabled)
ded86d8d3   Eric W. Biederman   msi: Kill msi_loo...
811
  		return;
110828c9c   Matthew Wilcox   PCI: remove redun...
812
813
814
815
816
  	BUG_ON(list_empty(&dev->msi_list));
  	desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
  	pos = desc->msi_attrib.pos;
  
  	msi_set_enable(dev, pos, 0);
ba698ad4b   David Miller   PCI: Add quirk fo...
817
  	pci_intx_for_msi(dev, 1);
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
818
  	dev->msi_enabled = 0;
7bd007e48   Eric W. Biederman   [PATCH] genirq: m...
819

12abb8ba8   Hidetoshi Seto   PCI MSI: Fix rest...
820
  	/* Return the device with MSI unmasked as initial states */
110828c9c   Matthew Wilcox   PCI: remove redun...
821
  	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl);
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
822
  	mask = msi_capable_mask(ctrl);
12abb8ba8   Hidetoshi Seto   PCI MSI: Fix rest...
823
824
  	/* Keep cached state to be restored */
  	__msi_mask_irq(desc, mask, ~mask);
e387b9eef   Michael Ellerman   MSI: Simplify BUG...
825
826
  
  	/* Restore dev->irq to its default pin-assertion irq */
f2440d9ac   Matthew Wilcox   PCI MSI: Refactor...
827
  	dev->irq = desc->msi_attrib.default_irq;
d52877c7b   Yinghai Lu   pci/irq: let pci_...
828
  }
24d275533   Matthew Wilcox   PCI MSI: Replace ...
829

500559a92   Hidetoshi Seto   PCI MSI: Style cl...
830
  void pci_disable_msi(struct pci_dev *dev)
d52877c7b   Yinghai Lu   pci/irq: let pci_...
831
  {
d52877c7b   Yinghai Lu   pci/irq: let pci_...
832
833
834
835
  	if (!pci_msi_enable || !dev || !dev->msi_enabled)
  		return;
  
  	pci_msi_shutdown(dev);
f56e44813   Hidetoshi Seto   PCI MSI: Unify ms...
836
  	free_msi_irqs(dev);
da8d1c8ba   Neil Horman   PCI/sysfs: add pe...
837
838
  	kset_unregister(dev->msi_kset);
  	dev->msi_kset = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  }
4cc086fa5   Michael Ellerman   MSI: Move EXPORT_...
840
  EXPORT_SYMBOL(pci_disable_msi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
  /**
a52e2e351   Rafael J. Wysocki   PCI/MSI: Introduc...
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
   * pci_msix_table_size - return the number of device's MSI-X table entries
   * @dev: pointer to the pci_dev data structure of MSI-X device function
   */
  int pci_msix_table_size(struct pci_dev *dev)
  {
  	int pos;
  	u16 control;
  
  	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
  	if (!pos)
  		return 0;
  
  	pci_read_config_word(dev, msi_control_reg(pos), &control);
  	return multi_msix_capable(control);
  }
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
   * pci_enable_msix - configure device's MSI-X capability structure
   * @dev: pointer to the pci_dev data structure of MSI-X device function
70549ad9c   Greg Kroah-Hartman   [PATCH] PCI: clea...
862
   * @entries: pointer to an array of MSI-X entries
1ce03373a   Eric W. Biederman   [PATCH] genirq: m...
863
   * @nvec: number of MSI-X irqs requested for allocation by device driver
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
865
   *
   * Setup the MSI-X capability structure of device function with the number
1ce03373a   Eric W. Biederman   [PATCH] genirq: m...
866
   * of requested irqs upon its software driver call to request for
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
   * MSI-X mode enabled on its hardware device function. A return of zero
   * indicates the successful configuration of MSI-X capability structure
1ce03373a   Eric W. Biederman   [PATCH] genirq: m...
869
   * with new allocated MSI-X irqs. A return of < 0 indicates a failure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
   * Or a return of > 0 indicates that driver request is exceeding the number
57fbf52c8   Michael S. Tsirkin   PCI MSI: let driv...
871
872
   * of irqs or MSI-X vectors available. Driver should use the returned value to
   * re-send its request.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
   **/
500559a92   Hidetoshi Seto   PCI MSI: Style cl...
874
  int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
  {
a52e2e351   Rafael J. Wysocki   PCI/MSI: Introduc...
876
  	int status, nr_entries;
ded86d8d3   Eric W. Biederman   msi: Kill msi_loo...
877
  	int i, j;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878

c9953a73e   Michael Ellerman   MSI: Add an arch_...
879
  	if (!entries)
500559a92   Hidetoshi Seto   PCI MSI: Style cl...
880
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881

c9953a73e   Michael Ellerman   MSI: Add an arch_...
882
883
884
  	status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX);
  	if (status)
  		return status;
a52e2e351   Rafael J. Wysocki   PCI/MSI: Introduc...
885
  	nr_entries = pci_msix_table_size(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  	if (nvec > nr_entries)
57fbf52c8   Michael S. Tsirkin   PCI MSI: let driv...
887
  		return nr_entries;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
890
891
892
893
894
895
896
897
  
  	/* Check for any invalid entries */
  	for (i = 0; i < nvec; i++) {
  		if (entries[i].entry >= nr_entries)
  			return -EINVAL;		/* invalid entry */
  		for (j = i + 1; j < nvec; j++) {
  			if (entries[i].entry == entries[j].entry)
  				return -EINVAL;	/* duplicate entry */
  		}
  	}
ded86d8d3   Eric W. Biederman   msi: Kill msi_loo...
898
  	WARN_ON(!!dev->msix_enabled);
7bd007e48   Eric W. Biederman   [PATCH] genirq: m...
899

1ce03373a   Eric W. Biederman   [PATCH] genirq: m...
900
  	/* Check whether driver already requested for MSI irq */
500559a92   Hidetoshi Seto   PCI MSI: Style cl...
901
  	if (dev->msi_enabled) {
80ccba118   Bjorn Helgaas   PCI: use dev_prin...
902
903
904
  		dev_info(&dev->dev, "can't enable MSI-X "
  		       "(MSI IRQ already assigned)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
  	status = msix_capability_init(dev, entries, nvec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
  	return status;
  }
4cc086fa5   Michael Ellerman   MSI: Move EXPORT_...
910
  EXPORT_SYMBOL(pci_enable_msix);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911

500559a92   Hidetoshi Seto   PCI MSI: Style cl...
912
  void pci_msix_shutdown(struct pci_dev *dev)
fc4afc7b2   Michael Ellerman   MSI: Consolidate ...
913
  {
12abb8ba8   Hidetoshi Seto   PCI MSI: Fix rest...
914
  	struct msi_desc *entry;
128bc5fce   Michael Ellerman   MSI: Consolidate ...
915
  	if (!pci_msi_enable || !dev || !dev->msix_enabled)
ded86d8d3   Eric W. Biederman   msi: Kill msi_loo...
916
  		return;
12abb8ba8   Hidetoshi Seto   PCI MSI: Fix rest...
917
918
919
920
921
  	/* Return the device with MSI-X masked as initial states */
  	list_for_each_entry(entry, &dev->msi_list, list) {
  		/* Keep cached states to be restored */
  		__msix_mask_irq(entry, 1);
  	}
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
922
  	msix_set_enable(dev, 0);
ba698ad4b   David Miller   PCI: Add quirk fo...
923
  	pci_intx_for_msi(dev, 1);
b1cbf4e4d   Eric W. Biederman   [PATCH] msi: fix ...
924
  	dev->msix_enabled = 0;
d52877c7b   Yinghai Lu   pci/irq: let pci_...
925
  }
c901851fd   Hidetoshi Seto   PCI MSI: Remove a...
926

500559a92   Hidetoshi Seto   PCI MSI: Style cl...
927
  void pci_disable_msix(struct pci_dev *dev)
d52877c7b   Yinghai Lu   pci/irq: let pci_...
928
929
930
931
932
  {
  	if (!pci_msi_enable || !dev || !dev->msix_enabled)
  		return;
  
  	pci_msix_shutdown(dev);
f56e44813   Hidetoshi Seto   PCI MSI: Unify ms...
933
  	free_msi_irqs(dev);
da8d1c8ba   Neil Horman   PCI/sysfs: add pe...
934
935
  	kset_unregister(dev->msi_kset);
  	dev->msi_kset = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
  }
4cc086fa5   Michael Ellerman   MSI: Move EXPORT_...
937
  EXPORT_SYMBOL(pci_disable_msix);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
939
  
  /**
1ce03373a   Eric W. Biederman   [PATCH] genirq: m...
940
   * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
942
   * @dev: pointer to the pci_dev data structure of MSI(X) device function
   *
eaae4b3a8   Steven Cole   [PATCH] PCI: Spel...
943
   * Being called during hotplug remove, from which the device function
1ce03373a   Eric W. Biederman   [PATCH] genirq: m...
944
   * is hot-removed. All previous assigned MSI/MSI-X irqs, if
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
947
   * allocated for this device function, are reclaimed to unused state,
   * which may be used later on.
   **/
500559a92   Hidetoshi Seto   PCI MSI: Style cl...
948
  void msi_remove_pci_irq_vectors(struct pci_dev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  	if (!pci_msi_enable || !dev)
500559a92   Hidetoshi Seto   PCI MSI: Style cl...
951
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952

f56e44813   Hidetoshi Seto   PCI MSI: Unify ms...
953
954
  	if (dev->msi_enabled || dev->msix_enabled)
  		free_msi_irqs(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
  }
309e57df7   Matthew Wilcox   [PATCH] PCI: Prov...
956
957
958
959
  void pci_no_msi(void)
  {
  	pci_msi_enable = 0;
  }
c9953a73e   Michael Ellerman   MSI: Add an arch_...
960

07ae95f98   Andrew Patterson   ACPI/PCI: PCI MSI...
961
962
963
964
965
966
967
  /**
   * pci_msi_enabled - is MSI enabled?
   *
   * Returns true if MSI has not been disabled by the command-line option
   * pci=nomsi.
   **/
  int pci_msi_enabled(void)
d389fec6a   Taku Izumi   ACPI/PCI: Set sup...
968
  {
07ae95f98   Andrew Patterson   ACPI/PCI: PCI MSI...
969
  	return pci_msi_enable;
d389fec6a   Taku Izumi   ACPI/PCI: Set sup...
970
  }
07ae95f98   Andrew Patterson   ACPI/PCI: PCI MSI...
971
  EXPORT_SYMBOL(pci_msi_enabled);
d389fec6a   Taku Izumi   ACPI/PCI: Set sup...
972

07ae95f98   Andrew Patterson   ACPI/PCI: PCI MSI...
973
  void pci_msi_init_pci_dev(struct pci_dev *dev)
d389fec6a   Taku Izumi   ACPI/PCI: Set sup...
974
  {
d5dea7d95   Eric W. Biederman   PCI: msi: Disable...
975
  	int pos;
07ae95f98   Andrew Patterson   ACPI/PCI: PCI MSI...
976
  	INIT_LIST_HEAD(&dev->msi_list);
d5dea7d95   Eric W. Biederman   PCI: msi: Disable...
977
978
979
980
981
982
983
984
985
  
  	/* Disable the msi hardware to avoid screaming interrupts
  	 * during boot.  This is the power on reset default so
  	 * usually this should be a noop.
  	 */
  	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
  	if (pos)
  		msi_set_enable(dev, pos, 0);
  	msix_set_enable(dev, 0);
d389fec6a   Taku Izumi   ACPI/PCI: Set sup...
986
  }