~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/powerpc/sysdev/indirect_pci.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Support for indirect PCI bridges.
 
3
 *
 
4
 * Copyright (C) 1998 Gabriel Paubert.
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License
 
8
 * as published by the Free Software Foundation; either version
 
9
 * 2 of the License, or (at your option) any later version.
 
10
 */
 
11
 
 
12
#include <linux/kernel.h>
 
13
#include <linux/pci.h>
 
14
#include <linux/delay.h>
 
15
#include <linux/string.h>
 
16
#include <linux/init.h>
 
17
 
 
18
#include <asm/io.h>
 
19
#include <asm/prom.h>
 
20
#include <asm/pci-bridge.h>
 
21
#include <asm/machdep.h>
 
22
 
 
23
static int
 
24
indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
 
25
                     int len, u32 *val)
 
26
{
 
27
        struct pci_controller *hose = pci_bus_to_host(bus);
 
28
        volatile void __iomem *cfg_data;
 
29
        u8 cfg_type = 0;
 
30
        u32 bus_no, reg;
 
31
 
 
32
        if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
 
33
                if (bus->number != hose->first_busno)
 
34
                        return PCIBIOS_DEVICE_NOT_FOUND;
 
35
                if (devfn != 0)
 
36
                        return PCIBIOS_DEVICE_NOT_FOUND;
 
37
        }
 
38
 
 
39
        if (ppc_md.pci_exclude_device)
 
40
                if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 
41
                        return PCIBIOS_DEVICE_NOT_FOUND;
 
42
 
 
43
        if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
 
44
                if (bus->number != hose->first_busno)
 
45
                        cfg_type = 1;
 
46
 
 
47
        bus_no = (bus->number == hose->first_busno) ?
 
48
                        hose->self_busno : bus->number;
 
49
 
 
50
        if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
 
51
                reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
 
52
        else
 
53
                reg = offset & 0xfc;
 
54
 
 
55
        if (hose->indirect_type & PPC_INDIRECT_TYPE_BIG_ENDIAN)
 
56
                out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
 
57
                         (devfn << 8) | reg | cfg_type));
 
58
        else
 
59
                out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
 
60
                         (devfn << 8) | reg | cfg_type));
 
61
 
 
62
        /*
 
63
         * Note: the caller has already checked that offset is
 
64
         * suitably aligned and that len is 1, 2 or 4.
 
65
         */
 
66
        cfg_data = hose->cfg_data + (offset & 3);
 
67
        switch (len) {
 
68
        case 1:
 
69
                *val = in_8(cfg_data);
 
70
                break;
 
71
        case 2:
 
72
                *val = in_le16(cfg_data);
 
73
                break;
 
74
        default:
 
75
                *val = in_le32(cfg_data);
 
76
                break;
 
77
        }
 
78
        return PCIBIOS_SUCCESSFUL;
 
79
}
 
80
 
 
81
static int
 
82
indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
 
83
                      int len, u32 val)
 
84
{
 
85
        struct pci_controller *hose = pci_bus_to_host(bus);
 
86
        volatile void __iomem *cfg_data;
 
87
        u8 cfg_type = 0;
 
88
        u32 bus_no, reg;
 
89
 
 
90
        if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
 
91
                if (bus->number != hose->first_busno)
 
92
                        return PCIBIOS_DEVICE_NOT_FOUND;
 
93
                if (devfn != 0)
 
94
                        return PCIBIOS_DEVICE_NOT_FOUND;
 
95
        }
 
96
 
 
97
        if (ppc_md.pci_exclude_device)
 
98
                if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 
99
                        return PCIBIOS_DEVICE_NOT_FOUND;
 
100
 
 
101
        if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
 
102
                if (bus->number != hose->first_busno)
 
103
                        cfg_type = 1;
 
104
 
 
105
        bus_no = (bus->number == hose->first_busno) ?
 
106
                        hose->self_busno : bus->number;
 
107
 
 
108
        if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
 
109
                reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
 
110
        else
 
111
                reg = offset & 0xfc;
 
112
 
 
113
        if (hose->indirect_type & PPC_INDIRECT_TYPE_BIG_ENDIAN)
 
114
                out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
 
115
                         (devfn << 8) | reg | cfg_type));
 
116
        else
 
117
                out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
 
118
                         (devfn << 8) | reg | cfg_type));
 
119
 
 
120
        /* suppress setting of PCI_PRIMARY_BUS */
 
121
        if (hose->indirect_type & PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
 
122
                if ((offset == PCI_PRIMARY_BUS) &&
 
123
                        (bus->number == hose->first_busno))
 
124
                val &= 0xffffff00;
 
125
 
 
126
        /* Workaround for PCI_28 Errata in 440EPx/GRx */
 
127
        if ((hose->indirect_type & PPC_INDIRECT_TYPE_BROKEN_MRM) &&
 
128
                        offset == PCI_CACHE_LINE_SIZE) {
 
129
                val = 0;
 
130
        }
 
131
 
 
132
        /*
 
133
         * Note: the caller has already checked that offset is
 
134
         * suitably aligned and that len is 1, 2 or 4.
 
135
         */
 
136
        cfg_data = hose->cfg_data + (offset & 3);
 
137
        switch (len) {
 
138
        case 1:
 
139
                out_8(cfg_data, val);
 
140
                break;
 
141
        case 2:
 
142
                out_le16(cfg_data, val);
 
143
                break;
 
144
        default:
 
145
                out_le32(cfg_data, val);
 
146
                break;
 
147
        }
 
148
        return PCIBIOS_SUCCESSFUL;
 
149
}
 
150
 
 
151
static struct pci_ops indirect_pci_ops =
 
152
{
 
153
        .read = indirect_read_config,
 
154
        .write = indirect_write_config,
 
155
};
 
156
 
 
157
void __init
 
158
setup_indirect_pci(struct pci_controller* hose,
 
159
                   resource_size_t cfg_addr,
 
160
                   resource_size_t cfg_data, u32 flags)
 
161
{
 
162
        resource_size_t base = cfg_addr & PAGE_MASK;
 
163
        void __iomem *mbase;
 
164
 
 
165
        mbase = ioremap(base, PAGE_SIZE);
 
166
        hose->cfg_addr = mbase + (cfg_addr & ~PAGE_MASK);
 
167
        if ((cfg_data & PAGE_MASK) != base)
 
168
                mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
 
169
        hose->cfg_data = mbase + (cfg_data & ~PAGE_MASK);
 
170
        hose->ops = &indirect_pci_ops;
 
171
        hose->indirect_type = flags;
 
172
}