~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to arch/powerpc/kernel/io-workarounds.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Support PCI IO workaround
 
3
 *
 
4
 *  Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
 
5
 *                     IBM, Corp.
 
6
 *  (C) Copyright 2007-2008 TOSHIBA CORPORATION
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License version 2 as
 
10
 * published by the Free Software Foundation.
 
11
 */
 
12
#undef DEBUG
 
13
 
 
14
#include <linux/kernel.h>
 
15
 
 
16
#include <asm/io.h>
 
17
#include <asm/machdep.h>
 
18
#include <asm/pgtable.h>
 
19
#include <asm/ppc-pci.h>
 
20
#include <asm/io-workarounds.h>
 
21
 
 
22
#define IOWA_MAX_BUS    8
 
23
 
 
24
static struct iowa_bus iowa_busses[IOWA_MAX_BUS];
 
25
static unsigned int iowa_bus_count;
 
26
 
 
27
static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr)
 
28
{
 
29
        int i, j;
 
30
        struct resource *res;
 
31
        unsigned long vstart, vend;
 
32
 
 
33
        for (i = 0; i < iowa_bus_count; i++) {
 
34
                struct iowa_bus *bus = &iowa_busses[i];
 
35
                struct pci_controller *phb = bus->phb;
 
36
 
 
37
                if (vaddr) {
 
38
                        vstart = (unsigned long)phb->io_base_virt;
 
39
                        vend = vstart + phb->pci_io_size - 1;
 
40
                        if ((vaddr >= vstart) && (vaddr <= vend))
 
41
                                return bus;
 
42
                }
 
43
 
 
44
                if (paddr)
 
45
                        for (j = 0; j < 3; j++) {
 
46
                                res = &phb->mem_resources[j];
 
47
                                if (paddr >= res->start && paddr <= res->end)
 
48
                                        return bus;
 
49
                        }
 
50
        }
 
51
 
 
52
        return NULL;
 
53
}
 
54
 
 
55
struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
 
56
{
 
57
        struct iowa_bus *bus;
 
58
        int token;
 
59
 
 
60
        token = PCI_GET_ADDR_TOKEN(addr);
 
61
 
 
62
        if (token && token <= iowa_bus_count)
 
63
                bus = &iowa_busses[token - 1];
 
64
        else {
 
65
                unsigned long vaddr, paddr;
 
66
                pte_t *ptep;
 
67
 
 
68
                vaddr = (unsigned long)PCI_FIX_ADDR(addr);
 
69
                if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
 
70
                        return NULL;
 
71
 
 
72
                ptep = find_linux_pte(init_mm.pgd, vaddr);
 
73
                if (ptep == NULL)
 
74
                        paddr = 0;
 
75
                else
 
76
                        paddr = pte_pfn(*ptep) << PAGE_SHIFT;
 
77
                bus = iowa_pci_find(vaddr, paddr);
 
78
 
 
79
                if (bus == NULL)
 
80
                        return NULL;
 
81
        }
 
82
 
 
83
        return bus;
 
84
}
 
85
 
 
86
struct iowa_bus *iowa_pio_find_bus(unsigned long port)
 
87
{
 
88
        unsigned long vaddr = (unsigned long)pci_io_base + port;
 
89
        return iowa_pci_find(vaddr, 0);
 
90
}
 
91
 
 
92
 
 
93
#define DEF_PCI_AC_RET(name, ret, at, al, space, aa)            \
 
94
static ret iowa_##name at                                       \
 
95
{                                                               \
 
96
        struct iowa_bus *bus;                                   \
 
97
        bus = iowa_##space##_find_bus(aa);                      \
 
98
        if (bus && bus->ops && bus->ops->name)                  \
 
99
                return bus->ops->name al;                       \
 
100
        return __do_##name al;                                  \
 
101
}
 
102
 
 
103
#define DEF_PCI_AC_NORET(name, at, al, space, aa)               \
 
104
static void iowa_##name at                                      \
 
105
{                                                               \
 
106
        struct iowa_bus *bus;                                   \
 
107
        bus = iowa_##space##_find_bus(aa);                      \
 
108
        if (bus && bus->ops && bus->ops->name) {                \
 
109
                bus->ops->name al;                              \
 
110
                return;                                         \
 
111
        }                                                       \
 
112
        __do_##name al;                                         \
 
113
}
 
114
 
 
115
#include <asm/io-defs.h>
 
116
 
 
117
#undef DEF_PCI_AC_RET
 
118
#undef DEF_PCI_AC_NORET
 
119
 
 
120
static const struct ppc_pci_io __devinitconst iowa_pci_io = {
 
121
 
 
122
#define DEF_PCI_AC_RET(name, ret, at, al, space, aa)    .name = iowa_##name,
 
123
#define DEF_PCI_AC_NORET(name, at, al, space, aa)       .name = iowa_##name,
 
124
 
 
125
#include <asm/io-defs.h>
 
126
 
 
127
#undef DEF_PCI_AC_RET
 
128
#undef DEF_PCI_AC_NORET
 
129
 
 
130
};
 
131
 
 
132
static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
 
133
                                  unsigned long flags, void *caller)
 
134
{
 
135
        struct iowa_bus *bus;
 
136
        void __iomem *res = __ioremap_caller(addr, size, flags, caller);
 
137
        int busno;
 
138
 
 
139
        bus = iowa_pci_find(0, (unsigned long)addr);
 
140
        if (bus != NULL) {
 
141
                busno = bus - iowa_busses;
 
142
                PCI_SET_ADDR_TOKEN(res, busno + 1);
 
143
        }
 
144
        return res;
 
145
}
 
146
 
 
147
/* Enable IO workaround */
 
148
static void __devinit io_workaround_init(void)
 
149
{
 
150
        static int io_workaround_inited;
 
151
 
 
152
        if (io_workaround_inited)
 
153
                return;
 
154
        ppc_pci_io = iowa_pci_io;
 
155
        ppc_md.ioremap = iowa_ioremap;
 
156
        io_workaround_inited = 1;
 
157
}
 
158
 
 
159
/* Register new bus to support workaround */
 
160
void __devinit iowa_register_bus(struct pci_controller *phb,
 
161
                        struct ppc_pci_io *ops,
 
162
                        int (*initfunc)(struct iowa_bus *, void *), void *data)
 
163
{
 
164
        struct iowa_bus *bus;
 
165
        struct device_node *np = phb->dn;
 
166
 
 
167
        io_workaround_init();
 
168
 
 
169
        if (iowa_bus_count >= IOWA_MAX_BUS) {
 
170
                pr_err("IOWA:Too many pci bridges, "
 
171
                       "workarounds disabled for %s\n", np->full_name);
 
172
                return;
 
173
        }
 
174
 
 
175
        bus = &iowa_busses[iowa_bus_count];
 
176
        bus->phb = phb;
 
177
        bus->ops = ops;
 
178
        bus->private = data;
 
179
 
 
180
        if (initfunc)
 
181
                if ((*initfunc)(bus, data))
 
182
                        return;
 
183
 
 
184
        iowa_bus_count++;
 
185
 
 
186
        pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name);
 
187
}
 
188