OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [pci/] [msi.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * File:        msi.c
3
 * Purpose:     PCI Message Signaled Interrupt (MSI)
4
 *
5
 * Copyright (C) 2003-2004 Intel
6
 * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
7
 */
8
 
9
#include <linux/err.h>
10
#include <linux/mm.h>
11
#include <linux/irq.h>
12
#include <linux/interrupt.h>
13
#include <linux/init.h>
14
#include <linux/ioport.h>
15
#include <linux/pci.h>
16
#include <linux/proc_fs.h>
17
#include <linux/msi.h>
18
#include <linux/smp.h>
19
 
20
#include <asm/errno.h>
21
#include <asm/io.h>
22
 
23
#include "pci.h"
24
#include "msi.h"
25
 
26
static int pci_msi_enable = 1;
27
 
28
static void msi_set_enable(struct pci_dev *dev, int enable)
29
{
30
        int pos;
31
        u16 control;
32
 
33
        pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
34
        if (pos) {
35
                pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
36
                control &= ~PCI_MSI_FLAGS_ENABLE;
37
                if (enable)
38
                        control |= PCI_MSI_FLAGS_ENABLE;
39
                pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
40
        }
41
}
42
 
43
static void msix_set_enable(struct pci_dev *dev, int enable)
44
{
45
        int pos;
46
        u16 control;
47
 
48
        pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
49
        if (pos) {
50
                pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
51
                control &= ~PCI_MSIX_FLAGS_ENABLE;
52
                if (enable)
53
                        control |= PCI_MSIX_FLAGS_ENABLE;
54
                pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
55
        }
56
}
57
 
58
static void msix_flush_writes(unsigned int irq)
59
{
60
        struct msi_desc *entry;
61
 
62
        entry = get_irq_msi(irq);
63
        BUG_ON(!entry || !entry->dev);
64
        switch (entry->msi_attrib.type) {
65
        case PCI_CAP_ID_MSI:
66
                /* nothing to do */
67
                break;
68
        case PCI_CAP_ID_MSIX:
69
        {
70
                int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
71
                        PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
72
                readl(entry->mask_base + offset);
73
                break;
74
        }
75
        default:
76
                BUG();
77
                break;
78
        }
79
}
80
 
81
static void msi_set_mask_bit(unsigned int irq, int flag)
82
{
83
        struct msi_desc *entry;
84
 
85
        entry = get_irq_msi(irq);
86
        BUG_ON(!entry || !entry->dev);
87
        switch (entry->msi_attrib.type) {
88
        case PCI_CAP_ID_MSI:
89
                if (entry->msi_attrib.maskbit) {
90
                        int pos;
91
                        u32 mask_bits;
92
 
93
                        pos = (long)entry->mask_base;
94
                        pci_read_config_dword(entry->dev, pos, &mask_bits);
95
                        mask_bits &= ~(1);
96
                        mask_bits |= flag;
97
                        pci_write_config_dword(entry->dev, pos, mask_bits);
98
                } else {
99
                        msi_set_enable(entry->dev, !flag);
100
                }
101
                break;
102
        case PCI_CAP_ID_MSIX:
103
        {
104
                int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
105
                        PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
106
                writel(flag, entry->mask_base + offset);
107
                readl(entry->mask_base + offset);
108
                break;
109
        }
110
        default:
111
                BUG();
112
                break;
113
        }
114
        entry->msi_attrib.masked = !!flag;
115
}
116
 
117
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
118
{
119
        struct msi_desc *entry = get_irq_msi(irq);
120
        switch(entry->msi_attrib.type) {
121
        case PCI_CAP_ID_MSI:
122
        {
123
                struct pci_dev *dev = entry->dev;
124
                int pos = entry->msi_attrib.pos;
125
                u16 data;
126
 
127
                pci_read_config_dword(dev, msi_lower_address_reg(pos),
128
                                        &msg->address_lo);
129
                if (entry->msi_attrib.is_64) {
130
                        pci_read_config_dword(dev, msi_upper_address_reg(pos),
131
                                                &msg->address_hi);
132
                        pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
133
                } else {
134
                        msg->address_hi = 0;
135
                        pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
136
                }
137
                msg->data = data;
138
                break;
139
        }
140
        case PCI_CAP_ID_MSIX:
141
        {
142
                void __iomem *base;
143
                base = entry->mask_base +
144
                        entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
145
 
146
                msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
147
                msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
148
                msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
149
                break;
150
        }
151
        default:
152
                BUG();
153
        }
154
}
155
 
156
void write_msi_msg(unsigned int irq, struct msi_msg *msg)
157
{
158
        struct msi_desc *entry = get_irq_msi(irq);
159
        switch (entry->msi_attrib.type) {
160
        case PCI_CAP_ID_MSI:
161
        {
162
                struct pci_dev *dev = entry->dev;
163
                int pos = entry->msi_attrib.pos;
164
 
165
                pci_write_config_dword(dev, msi_lower_address_reg(pos),
166
                                        msg->address_lo);
167
                if (entry->msi_attrib.is_64) {
168
                        pci_write_config_dword(dev, msi_upper_address_reg(pos),
169
                                                msg->address_hi);
170
                        pci_write_config_word(dev, msi_data_reg(pos, 1),
171
                                                msg->data);
172
                } else {
173
                        pci_write_config_word(dev, msi_data_reg(pos, 0),
174
                                                msg->data);
175
                }
176
                break;
177
        }
178
        case PCI_CAP_ID_MSIX:
179
        {
180
                void __iomem *base;
181
                base = entry->mask_base +
182
                        entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
183
 
184
                writel(msg->address_lo,
185
                        base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
186
                writel(msg->address_hi,
187
                        base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
188
                writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
189
                break;
190
        }
191
        default:
192
                BUG();
193
        }
194
        entry->msg = *msg;
195
}
196
 
197
void mask_msi_irq(unsigned int irq)
198
{
199
        msi_set_mask_bit(irq, 1);
200
        msix_flush_writes(irq);
201
}
202
 
203
void unmask_msi_irq(unsigned int irq)
204
{
205
        msi_set_mask_bit(irq, 0);
206
        msix_flush_writes(irq);
207
}
208
 
209
static int msi_free_irqs(struct pci_dev* dev);
210
 
211
 
212
static struct msi_desc* alloc_msi_entry(void)
213
{
214
        struct msi_desc *entry;
215
 
216
        entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL);
217
        if (!entry)
218
                return NULL;
219
 
220
        INIT_LIST_HEAD(&entry->list);
221
        entry->irq = 0;
222
        entry->dev = NULL;
223
 
224
        return entry;
225
}
226
 
227
static void pci_intx_for_msi(struct pci_dev *dev, int enable)
228
{
229
        if (!(dev->dev_flags & PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG))
230
                pci_intx(dev, enable);
231
}
232
 
233
#ifdef CONFIG_PM
234
static void __pci_restore_msi_state(struct pci_dev *dev)
235
{
236
        int pos;
237
        u16 control;
238
        struct msi_desc *entry;
239
 
240
        if (!dev->msi_enabled)
241
                return;
242
 
243
        entry = get_irq_msi(dev->irq);
244
        pos = entry->msi_attrib.pos;
245
 
246
        pci_intx_for_msi(dev, 0);
247
        msi_set_enable(dev, 0);
248
        write_msi_msg(dev->irq, &entry->msg);
249
        if (entry->msi_attrib.maskbit)
250
                msi_set_mask_bit(dev->irq, entry->msi_attrib.masked);
251
 
252
        pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
253
        control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
254
        if (entry->msi_attrib.maskbit || !entry->msi_attrib.masked)
255
                control |= PCI_MSI_FLAGS_ENABLE;
256
        pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
257
}
258
 
259
static void __pci_restore_msix_state(struct pci_dev *dev)
260
{
261
        int pos;
262
        struct msi_desc *entry;
263
        u16 control;
264
 
265
        if (!dev->msix_enabled)
266
                return;
267
 
268
        /* route the table */
269
        pci_intx_for_msi(dev, 0);
270
        msix_set_enable(dev, 0);
271
 
272
        list_for_each_entry(entry, &dev->msi_list, list) {
273
                write_msi_msg(entry->irq, &entry->msg);
274
                msi_set_mask_bit(entry->irq, entry->msi_attrib.masked);
275
        }
276
 
277
        BUG_ON(list_empty(&dev->msi_list));
278
        entry = list_entry(dev->msi_list.next, struct msi_desc, list);
279
        pos = entry->msi_attrib.pos;
280
        pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
281
        control &= ~PCI_MSIX_FLAGS_MASKALL;
282
        control |= PCI_MSIX_FLAGS_ENABLE;
283
        pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
284
}
285
 
286
void pci_restore_msi_state(struct pci_dev *dev)
287
{
288
        __pci_restore_msi_state(dev);
289
        __pci_restore_msix_state(dev);
290
}
291
#endif  /* CONFIG_PM */
292
 
293
/**
294
 * msi_capability_init - configure device's MSI capability structure
295
 * @dev: pointer to the pci_dev data structure of MSI device function
296
 *
297
 * Setup the MSI capability structure of device function with a single
298
 * MSI irq, regardless of device function is capable of handling
299
 * multiple messages. A return of zero indicates the successful setup
300
 * of an entry zero with the new MSI irq or non-zero for otherwise.
301
 **/
302
static int msi_capability_init(struct pci_dev *dev)
303
{
304
        struct msi_desc *entry;
305
        int pos, ret;
306
        u16 control;
307
 
308
        msi_set_enable(dev, 0);  /* Ensure msi is disabled as I set it up */
309
 
310
        pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
311
        pci_read_config_word(dev, msi_control_reg(pos), &control);
312
        /* MSI Entry Initialization */
313
        entry = alloc_msi_entry();
314
        if (!entry)
315
                return -ENOMEM;
316
 
317
        entry->msi_attrib.type = PCI_CAP_ID_MSI;
318
        entry->msi_attrib.is_64 = is_64bit_address(control);
319
        entry->msi_attrib.entry_nr = 0;
320
        entry->msi_attrib.maskbit = is_mask_bit_support(control);
321
        entry->msi_attrib.masked = 1;
322
        entry->msi_attrib.default_irq = dev->irq;       /* Save IOAPIC IRQ */
323
        entry->msi_attrib.pos = pos;
324
        if (is_mask_bit_support(control)) {
325
                entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
326
                                is_64bit_address(control));
327
        }
328
        entry->dev = dev;
329
        if (entry->msi_attrib.maskbit) {
330
                unsigned int maskbits, temp;
331
                /* All MSIs are unmasked by default, Mask them all */
332
                pci_read_config_dword(dev,
333
                        msi_mask_bits_reg(pos, is_64bit_address(control)),
334
                        &maskbits);
335
                temp = (1 << multi_msi_capable(control));
336
                temp = ((temp - 1) & ~temp);
337
                maskbits |= temp;
338
                pci_write_config_dword(dev,
339
                        msi_mask_bits_reg(pos, is_64bit_address(control)),
340
                        maskbits);
341
        }
342
        list_add_tail(&entry->list, &dev->msi_list);
343
 
344
        /* Configure MSI capability structure */
345
        ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI);
346
        if (ret) {
347
                msi_free_irqs(dev);
348
                return ret;
349
        }
350
 
351
        /* Set MSI enabled bits  */
352
        pci_intx_for_msi(dev, 0);
353
        msi_set_enable(dev, 1);
354
        dev->msi_enabled = 1;
355
 
356
        dev->irq = entry->irq;
357
        return 0;
358
}
359
 
360
/**
361
 * msix_capability_init - configure device's MSI-X capability
362
 * @dev: pointer to the pci_dev data structure of MSI-X device function
363
 * @entries: pointer to an array of struct msix_entry entries
364
 * @nvec: number of @entries
365
 *
366
 * Setup the MSI-X capability structure of device function with a
367
 * single MSI-X irq. A return of zero indicates the successful setup of
368
 * requested MSI-X entries with allocated irqs or non-zero for otherwise.
369
 **/
370
static int msix_capability_init(struct pci_dev *dev,
371
                                struct msix_entry *entries, int nvec)
372
{
373
        struct msi_desc *entry;
374
        int pos, i, j, nr_entries, ret;
375
        unsigned long phys_addr;
376
        u32 table_offset;
377
        u16 control;
378
        u8 bir;
379
        void __iomem *base;
380
 
381
        msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */
382
 
383
        pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
384
        /* Request & Map MSI-X table region */
385
        pci_read_config_word(dev, msi_control_reg(pos), &control);
386
        nr_entries = multi_msix_capable(control);
387
 
388
        pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset);
389
        bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
390
        table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
391
        phys_addr = pci_resource_start (dev, bir) + table_offset;
392
        base = ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
393
        if (base == NULL)
394
                return -ENOMEM;
395
 
396
        /* MSI-X Table Initialization */
397
        for (i = 0; i < nvec; i++) {
398
                entry = alloc_msi_entry();
399
                if (!entry)
400
                        break;
401
 
402
                j = entries[i].entry;
403
                entry->msi_attrib.type = PCI_CAP_ID_MSIX;
404
                entry->msi_attrib.is_64 = 1;
405
                entry->msi_attrib.entry_nr = j;
406
                entry->msi_attrib.maskbit = 1;
407
                entry->msi_attrib.masked = 1;
408
                entry->msi_attrib.default_irq = dev->irq;
409
                entry->msi_attrib.pos = pos;
410
                entry->dev = dev;
411
                entry->mask_base = base;
412
 
413
                list_add_tail(&entry->list, &dev->msi_list);
414
        }
415
 
416
        ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
417
        if (ret) {
418
                int avail = 0;
419
                list_for_each_entry(entry, &dev->msi_list, list) {
420
                        if (entry->irq != 0) {
421
                                avail++;
422
                        }
423
                }
424
 
425
                msi_free_irqs(dev);
426
 
427
                /* If we had some success report the number of irqs
428
                 * we succeeded in setting up.
429
                 */
430
                if (avail == 0)
431
                        avail = ret;
432
                return avail;
433
        }
434
 
435
        i = 0;
436
        list_for_each_entry(entry, &dev->msi_list, list) {
437
                entries[i].vector = entry->irq;
438
                set_irq_msi(entry->irq, entry);
439
                i++;
440
        }
441
        /* Set MSI-X enabled bits */
442
        pci_intx_for_msi(dev, 0);
443
        msix_set_enable(dev, 1);
444
        dev->msix_enabled = 1;
445
 
446
        return 0;
447
}
448
 
449
/**
450
 * pci_msi_check_device - check whether MSI may be enabled on a device
451
 * @dev: pointer to the pci_dev data structure of MSI device function
452
 * @nvec: how many MSIs have been requested ?
453
 * @type: are we checking for MSI or MSI-X ?
454
 *
455
 * Look at global flags, the device itself, and its parent busses
456
 * to determine if MSI/-X are supported for the device. If MSI/-X is
457
 * supported return 0, else return an error code.
458
 **/
459
static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type)
460
{
461
        struct pci_bus *bus;
462
        int ret;
463
 
464
        /* MSI must be globally enabled and supported by the device */
465
        if (!pci_msi_enable || !dev || dev->no_msi)
466
                return -EINVAL;
467
 
468
        /*
469
         * You can't ask to have 0 or less MSIs configured.
470
         *  a) it's stupid ..
471
         *  b) the list manipulation code assumes nvec >= 1.
472
         */
473
        if (nvec < 1)
474
                return -ERANGE;
475
 
476
        /* Any bridge which does NOT route MSI transactions from it's
477
         * secondary bus to it's primary bus must set NO_MSI flag on
478
         * the secondary pci_bus.
479
         * We expect only arch-specific PCI host bus controller driver
480
         * or quirks for specific PCI bridges to be setting NO_MSI.
481
         */
482
        for (bus = dev->bus; bus; bus = bus->parent)
483
                if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
484
                        return -EINVAL;
485
 
486
        ret = arch_msi_check_device(dev, nvec, type);
487
        if (ret)
488
                return ret;
489
 
490
        if (!pci_find_capability(dev, type))
491
                return -EINVAL;
492
 
493
        return 0;
494
}
495
 
496
/**
497
 * pci_enable_msi - configure device's MSI capability structure
498
 * @dev: pointer to the pci_dev data structure of MSI device function
499
 *
500
 * Setup the MSI capability structure of device function with
501
 * a single MSI irq upon its software driver call to request for
502
 * MSI mode enabled on its hardware device function. A return of zero
503
 * indicates the successful setup of an entry zero with the new MSI
504
 * irq or non-zero for otherwise.
505
 **/
506
int pci_enable_msi(struct pci_dev* dev)
507
{
508
        int status;
509
 
510
        status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
511
        if (status)
512
                return status;
513
 
514
        WARN_ON(!!dev->msi_enabled);
515
 
516
        /* Check whether driver already requested for MSI-X irqs */
517
        if (dev->msix_enabled) {
518
                printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
519
                        "Device already has MSI-X enabled\n",
520
                        pci_name(dev));
521
                return -EINVAL;
522
        }
523
        status = msi_capability_init(dev);
524
        return status;
525
}
526
EXPORT_SYMBOL(pci_enable_msi);
527
 
528
void pci_disable_msi(struct pci_dev* dev)
529
{
530
        struct msi_desc *entry;
531
        int default_irq;
532
 
533
        if (!pci_msi_enable || !dev || !dev->msi_enabled)
534
                return;
535
 
536
        msi_set_enable(dev, 0);
537
        pci_intx_for_msi(dev, 1);
538
        dev->msi_enabled = 0;
539
 
540
        BUG_ON(list_empty(&dev->msi_list));
541
        entry = list_entry(dev->msi_list.next, struct msi_desc, list);
542
        if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
543
                return;
544
        }
545
 
546
        default_irq = entry->msi_attrib.default_irq;
547
        msi_free_irqs(dev);
548
 
549
        /* Restore dev->irq to its default pin-assertion irq */
550
        dev->irq = default_irq;
551
}
552
EXPORT_SYMBOL(pci_disable_msi);
553
 
554
static int msi_free_irqs(struct pci_dev* dev)
555
{
556
        struct msi_desc *entry, *tmp;
557
 
558
        list_for_each_entry(entry, &dev->msi_list, list) {
559
                if (entry->irq)
560
                        BUG_ON(irq_has_action(entry->irq));
561
        }
562
 
563
        arch_teardown_msi_irqs(dev);
564
 
565
        list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
566
                if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) {
567
                        writel(1, entry->mask_base + entry->msi_attrib.entry_nr
568
                                  * PCI_MSIX_ENTRY_SIZE
569
                                  + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
570
 
571
                        if (list_is_last(&entry->list, &dev->msi_list))
572
                                iounmap(entry->mask_base);
573
                }
574
                list_del(&entry->list);
575
                kfree(entry);
576
        }
577
 
578
        return 0;
579
}
580
 
581
/**
582
 * pci_enable_msix - configure device's MSI-X capability structure
583
 * @dev: pointer to the pci_dev data structure of MSI-X device function
584
 * @entries: pointer to an array of MSI-X entries
585
 * @nvec: number of MSI-X irqs requested for allocation by device driver
586
 *
587
 * Setup the MSI-X capability structure of device function with the number
588
 * of requested irqs upon its software driver call to request for
589
 * MSI-X mode enabled on its hardware device function. A return of zero
590
 * indicates the successful configuration of MSI-X capability structure
591
 * with new allocated MSI-X irqs. A return of < 0 indicates a failure.
592
 * Or a return of > 0 indicates that driver request is exceeding the number
593
 * of irqs available. Driver should use the returned value to re-send
594
 * its request.
595
 **/
596
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
597
{
598
        int status, pos, nr_entries;
599
        int i, j;
600
        u16 control;
601
 
602
        if (!entries)
603
                return -EINVAL;
604
 
605
        status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX);
606
        if (status)
607
                return status;
608
 
609
        pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
610
        pci_read_config_word(dev, msi_control_reg(pos), &control);
611
        nr_entries = multi_msix_capable(control);
612
        if (nvec > nr_entries)
613
                return -EINVAL;
614
 
615
        /* Check for any invalid entries */
616
        for (i = 0; i < nvec; i++) {
617
                if (entries[i].entry >= nr_entries)
618
                        return -EINVAL;         /* invalid entry */
619
                for (j = i + 1; j < nvec; j++) {
620
                        if (entries[i].entry == entries[j].entry)
621
                                return -EINVAL; /* duplicate entry */
622
                }
623
        }
624
        WARN_ON(!!dev->msix_enabled);
625
 
626
        /* Check whether driver already requested for MSI irq */
627
        if (dev->msi_enabled) {
628
                printk(KERN_INFO "PCI: %s: Can't enable MSI-X.  "
629
                       "Device already has an MSI irq assigned\n",
630
                       pci_name(dev));
631
                return -EINVAL;
632
        }
633
        status = msix_capability_init(dev, entries, nvec);
634
        return status;
635
}
636
EXPORT_SYMBOL(pci_enable_msix);
637
 
638
static void msix_free_all_irqs(struct pci_dev *dev)
639
{
640
        msi_free_irqs(dev);
641
}
642
 
643
void pci_disable_msix(struct pci_dev* dev)
644
{
645
        if (!pci_msi_enable || !dev || !dev->msix_enabled)
646
                return;
647
 
648
        msix_set_enable(dev, 0);
649
        pci_intx_for_msi(dev, 1);
650
        dev->msix_enabled = 0;
651
 
652
        msix_free_all_irqs(dev);
653
}
654
EXPORT_SYMBOL(pci_disable_msix);
655
 
656
/**
657
 * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state
658
 * @dev: pointer to the pci_dev data structure of MSI(X) device function
659
 *
660
 * Being called during hotplug remove, from which the device function
661
 * is hot-removed. All previous assigned MSI/MSI-X irqs, if
662
 * allocated for this device function, are reclaimed to unused state,
663
 * which may be used later on.
664
 **/
665
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
666
{
667
        if (!pci_msi_enable || !dev)
668
                return;
669
 
670
        if (dev->msi_enabled)
671
                msi_free_irqs(dev);
672
 
673
        if (dev->msix_enabled)
674
                msix_free_all_irqs(dev);
675
}
676
 
677
void pci_no_msi(void)
678
{
679
        pci_msi_enable = 0;
680
}
681
 
682
void pci_msi_init_pci_dev(struct pci_dev *dev)
683
{
684
        INIT_LIST_HEAD(&dev->msi_list);
685
}
686
 
687
 
688
/* Arch hooks */
689
 
690
int __attribute__ ((weak))
691
arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
692
{
693
        return 0;
694
}
695
 
696
int __attribute__ ((weak))
697
arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
698
{
699
        return 0;
700
}
701
 
702
int __attribute__ ((weak))
703
arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
704
{
705
        struct msi_desc *entry;
706
        int ret;
707
 
708
        list_for_each_entry(entry, &dev->msi_list, list) {
709
                ret = arch_setup_msi_irq(dev, entry);
710
                if (ret)
711
                        return ret;
712
        }
713
 
714
        return 0;
715
}
716
 
717
void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
718
{
719
        return;
720
}
721
 
722
void __attribute__ ((weak))
723
arch_teardown_msi_irqs(struct pci_dev *dev)
724
{
725
        struct msi_desc *entry;
726
 
727
        list_for_each_entry(entry, &dev->msi_list, list) {
728
                if (entry->irq != 0)
729
                        arch_teardown_msi_irq(entry->irq);
730
        }
731
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.