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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [powerpc/] [sysdev/] [mpic_u3msi.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Copyright 2006, Segher Boessenkool, IBM Corporation.
3
 * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; version 2 of the
8
 * License.
9
 *
10
 */
11
 
12
#include <linux/irq.h>
13
#include <linux/bootmem.h>
14
#include <linux/msi.h>
15
#include <asm/mpic.h>
16
#include <asm/prom.h>
17
#include <asm/hw_irq.h>
18
#include <asm/ppc-pci.h>
19
 
20
#include "mpic.h"
21
 
22
/* A bit ugly, can we get this from the pci_dev somehow? */
23
static struct mpic *msi_mpic;
24
 
25
static void mpic_u3msi_mask_irq(unsigned int irq)
26
{
27
        mask_msi_irq(irq);
28
        mpic_mask_irq(irq);
29
}
30
 
31
static void mpic_u3msi_unmask_irq(unsigned int irq)
32
{
33
        mpic_unmask_irq(irq);
34
        unmask_msi_irq(irq);
35
}
36
 
37
static struct irq_chip mpic_u3msi_chip = {
38
        .shutdown       = mpic_u3msi_mask_irq,
39
        .mask           = mpic_u3msi_mask_irq,
40
        .unmask         = mpic_u3msi_unmask_irq,
41
        .eoi            = mpic_end_irq,
42
        .set_type       = mpic_set_irq_type,
43
        .set_affinity   = mpic_set_affinity,
44
        .typename       = "MPIC-U3MSI",
45
};
46
 
47
static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos)
48
{
49
        u8 flags;
50
        u32 tmp;
51
        u64 addr;
52
 
53
        pci_read_config_byte(pdev, pos + HT_MSI_FLAGS, &flags);
54
 
55
        if (flags & HT_MSI_FLAGS_FIXED)
56
                return HT_MSI_FIXED_ADDR;
57
 
58
        pci_read_config_dword(pdev, pos + HT_MSI_ADDR_LO, &tmp);
59
        addr = tmp & HT_MSI_ADDR_LO_MASK;
60
        pci_read_config_dword(pdev, pos + HT_MSI_ADDR_HI, &tmp);
61
        addr = addr | ((u64)tmp << 32);
62
 
63
        return addr;
64
}
65
 
66
static u64 find_ht_magic_addr(struct pci_dev *pdev)
67
{
68
        struct pci_bus *bus;
69
        unsigned int pos;
70
 
71
        for (bus = pdev->bus; bus; bus = bus->parent) {
72
                pos = pci_find_ht_capability(bus->self, HT_CAPTYPE_MSI_MAPPING);
73
                if (pos)
74
                        return read_ht_magic_addr(bus->self, pos);
75
        }
76
 
77
        return 0;
78
}
79
 
80
static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
81
{
82
        if (type == PCI_CAP_ID_MSIX)
83
                pr_debug("u3msi: MSI-X untested, trying anyway.\n");
84
 
85
        /* If we can't find a magic address then MSI ain't gonna work */
86
        if (find_ht_magic_addr(pdev) == 0) {
87
                pr_debug("u3msi: no magic address found for %s\n",
88
                         pci_name(pdev));
89
                return -ENXIO;
90
        }
91
 
92
        return 0;
93
}
94
 
95
static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
96
{
97
        struct msi_desc *entry;
98
 
99
        list_for_each_entry(entry, &pdev->msi_list, list) {
100
                if (entry->irq == NO_IRQ)
101
                        continue;
102
 
103
                set_irq_msi(entry->irq, NULL);
104
                mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1);
105
                irq_dispose_mapping(entry->irq);
106
        }
107
 
108
        return;
109
}
110
 
111
static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
112
{
113
        irq_hw_number_t hwirq;
114
        unsigned int virq;
115
        struct msi_desc *entry;
116
        struct msi_msg msg;
117
        u64 addr;
118
 
119
        addr = find_ht_magic_addr(pdev);
120
        msg.address_lo = addr & 0xFFFFFFFF;
121
        msg.address_hi = addr >> 32;
122
 
123
        list_for_each_entry(entry, &pdev->msi_list, list) {
124
                hwirq = mpic_msi_alloc_hwirqs(msi_mpic, 1);
125
                if (hwirq < 0) {
126
                        pr_debug("u3msi: failed allocating hwirq\n");
127
                        return hwirq;
128
                }
129
 
130
                virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
131
                if (virq == NO_IRQ) {
132
                        pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq);
133
                        mpic_msi_free_hwirqs(msi_mpic, hwirq, 1);
134
                        return -ENOSPC;
135
                }
136
 
137
                set_irq_msi(virq, entry);
138
                set_irq_chip(virq, &mpic_u3msi_chip);
139
                set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
140
 
141
                pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n",
142
                          virq, hwirq, addr);
143
 
144
                msg.data = hwirq;
145
                write_msi_msg(virq, &msg);
146
 
147
                hwirq++;
148
        }
149
 
150
        return 0;
151
}
152
 
153
int mpic_u3msi_init(struct mpic *mpic)
154
{
155
        int rc;
156
 
157
        rc = mpic_msi_init_allocator(mpic);
158
        if (rc) {
159
                pr_debug("u3msi: Error allocating bitmap!\n");
160
                return rc;
161
        }
162
 
163
        pr_debug("u3msi: Registering MPIC U3 MSI callbacks.\n");
164
 
165
        BUG_ON(msi_mpic);
166
        msi_mpic = mpic;
167
 
168
        WARN_ON(ppc_md.setup_msi_irqs);
169
        ppc_md.setup_msi_irqs = u3msi_setup_msi_irqs;
170
        ppc_md.teardown_msi_irqs = u3msi_teardown_msi_irqs;
171
        ppc_md.msi_check_device = u3msi_msi_check_device;
172
 
173
        return 0;
174
}

powered by: WebSVN 2.1.0

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