Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/powerpc/powermac/grackle.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright 2003 by Peter Grehan. All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* 3. The name of the author may not be used to endorse or promote products
15
* derived from this software without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <sys/param.h>
31
#include <sys/systm.h>
32
#include <sys/module.h>
33
#include <sys/bus.h>
34
#include <sys/conf.h>
35
#include <sys/kernel.h>
36
#include <sys/proc.h>
37
#include <sys/rman.h>
38
39
#include <dev/ofw/openfirm.h>
40
#include <dev/ofw/ofw_pci.h>
41
#include <dev/ofw/ofw_bus.h>
42
#include <dev/ofw/ofw_bus_subr.h>
43
#include <dev/ofw/ofwpci.h>
44
45
#include <dev/pci/pcivar.h>
46
#include <dev/pci/pcireg.h>
47
48
#include <machine/bus.h>
49
#include <machine/intr_machdep.h>
50
#include <machine/md_var.h>
51
#include <machine/pio.h>
52
#include <machine/resource.h>
53
54
#include <powerpc/powermac/gracklevar.h>
55
56
#include <vm/vm.h>
57
#include <vm/pmap.h>
58
59
#include "pcib_if.h"
60
61
/*
62
* Device interface.
63
*/
64
static int grackle_probe(device_t);
65
static int grackle_attach(device_t);
66
67
/*
68
* pcib interface.
69
*/
70
static u_int32_t grackle_read_config(device_t, u_int, u_int, u_int,
71
u_int, int);
72
static void grackle_write_config(device_t, u_int, u_int, u_int,
73
u_int, u_int32_t, int);
74
75
/*
76
* Local routines.
77
*/
78
static int grackle_enable_config(struct grackle_softc *, u_int,
79
u_int, u_int, u_int);
80
static void grackle_disable_config(struct grackle_softc *);
81
static int badaddr(void *, size_t);
82
83
/*
84
* Driver methods.
85
*/
86
static device_method_t grackle_methods[] = {
87
/* Device interface */
88
DEVMETHOD(device_probe, grackle_probe),
89
DEVMETHOD(device_attach, grackle_attach),
90
91
/* pcib interface */
92
DEVMETHOD(pcib_read_config, grackle_read_config),
93
DEVMETHOD(pcib_write_config, grackle_write_config),
94
95
DEVMETHOD_END
96
};
97
98
DEFINE_CLASS_1(pcib, grackle_driver, grackle_methods,
99
sizeof(struct grackle_softc), ofw_pcib_driver);
100
DRIVER_MODULE(grackle, ofwbus, grackle_driver, 0, 0);
101
102
static int
103
grackle_probe(device_t dev)
104
{
105
const char *type, *compatible;
106
107
type = ofw_bus_get_type(dev);
108
compatible = ofw_bus_get_compat(dev);
109
110
if (type == NULL || compatible == NULL)
111
return (ENXIO);
112
113
if (strcmp(type, "pci") != 0 || strcmp(compatible, "grackle") != 0)
114
return (ENXIO);
115
116
device_set_desc(dev, "MPC106 (Grackle) Host-PCI bridge");
117
return (0);
118
}
119
120
static int
121
grackle_attach(device_t dev)
122
{
123
struct grackle_softc *sc;
124
125
sc = device_get_softc(dev);
126
127
/*
128
* The Grackle PCI config addr/data registers are actually in
129
* PCI space, but since they are needed to actually probe the
130
* PCI bus, use the fact that they are also available directly
131
* on the processor bus and map them
132
*/
133
sc->sc_addr = (vm_offset_t)pmap_mapdev(GRACKLE_ADDR, PAGE_SIZE);
134
sc->sc_data = (vm_offset_t)pmap_mapdev(GRACKLE_DATA, PAGE_SIZE);
135
136
return (ofw_pcib_attach(dev));
137
}
138
139
static u_int32_t
140
grackle_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
141
int width)
142
{
143
struct grackle_softc *sc;
144
vm_offset_t caoff;
145
u_int32_t retval = 0xffffffff;
146
147
sc = device_get_softc(dev);
148
caoff = sc->sc_data + (reg & 0x03);
149
150
if (grackle_enable_config(sc, bus, slot, func, reg) != 0) {
151
/*
152
* Config probes to non-existent devices on the
153
* secondary bus generates machine checks. Be sure
154
* to catch these.
155
*/
156
if (bus > 0) {
157
if (badaddr((void *)sc->sc_data, 4)) {
158
return (retval);
159
}
160
}
161
162
switch (width) {
163
case 1:
164
retval = (in8rb(caoff));
165
break;
166
case 2:
167
retval = (in16rb(caoff));
168
break;
169
case 4:
170
retval = (in32rb(caoff));
171
break;
172
}
173
}
174
grackle_disable_config(sc);
175
176
return (retval);
177
}
178
179
static void
180
grackle_write_config(device_t dev, u_int bus, u_int slot, u_int func,
181
u_int reg, u_int32_t val, int width)
182
{
183
struct grackle_softc *sc;
184
vm_offset_t caoff;
185
186
sc = device_get_softc(dev);
187
caoff = sc->sc_data + (reg & 0x03);
188
189
if (grackle_enable_config(sc, bus, slot, func, reg)) {
190
switch (width) {
191
case 1:
192
out8rb(caoff, val);
193
(void)in8rb(caoff);
194
break;
195
case 2:
196
out16rb(caoff, val);
197
(void)in16rb(caoff);
198
break;
199
case 4:
200
out32rb(caoff, val);
201
(void)in32rb(caoff);
202
break;
203
}
204
}
205
grackle_disable_config(sc);
206
}
207
208
static int
209
grackle_enable_config(struct grackle_softc *sc, u_int bus, u_int slot,
210
u_int func, u_int reg)
211
{
212
u_int32_t cfgval;
213
214
/*
215
* Unlike UniNorth, the format of the config word is the same
216
* for local (0) and remote busses.
217
*/
218
cfgval = (bus << 16) | (slot << 11) | (func << 8) | (reg & 0xFC)
219
| GRACKLE_CFG_ENABLE;
220
221
out32rb(sc->sc_addr, cfgval);
222
(void) in32rb(sc->sc_addr);
223
224
return (1);
225
}
226
227
static void
228
grackle_disable_config(struct grackle_softc *sc)
229
{
230
/*
231
* Clear the GRACKLE_CFG_ENABLE bit to prevent stray
232
* accesses from causing config cycles
233
*/
234
out32rb(sc->sc_addr, 0);
235
}
236
237
static int
238
badaddr(void *addr, size_t size)
239
{
240
struct thread *td;
241
jmp_buf env, *oldfaultbuf;
242
243
/* Get rid of any stale machine checks that have been waiting. */
244
__asm __volatile ("sync; isync");
245
246
td = curthread;
247
248
oldfaultbuf = td->td_pcb->pcb_onfault;
249
td->td_pcb->pcb_onfault = &env;
250
if (setjmp(env)) {
251
td->td_pcb->pcb_onfault = oldfaultbuf;
252
__asm __volatile ("sync");
253
return 1;
254
}
255
256
__asm __volatile ("sync");
257
258
switch (size) {
259
case 1:
260
(void)*(volatile int8_t *)addr;
261
break;
262
case 2:
263
(void)*(volatile int16_t *)addr;
264
break;
265
case 4:
266
(void)*(volatile int32_t *)addr;
267
break;
268
default:
269
panic("badaddr: invalid size (%zd)", size);
270
}
271
272
/* Make sure we took the machine check, if we caused one. */
273
__asm __volatile ("sync; isync");
274
275
td->td_pcb->pcb_onfault = oldfaultbuf;
276
__asm __volatile ("sync"); /* To be sure. */
277
278
return (0);
279
}
280
281
/*
282
* Driver to swallow Grackle host bridges from the PCI bus side.
283
*/
284
static int
285
grackle_hb_probe(device_t dev)
286
{
287
288
if (pci_get_devid(dev) == 0x00021057) {
289
device_set_desc(dev, "Grackle Host to PCI bridge");
290
device_quiet(dev);
291
return (0);
292
}
293
294
return (ENXIO);
295
}
296
297
static int
298
grackle_hb_attach(device_t dev)
299
{
300
301
return (0);
302
}
303
304
static device_method_t grackle_hb_methods[] = {
305
/* Device interface */
306
DEVMETHOD(device_probe, grackle_hb_probe),
307
DEVMETHOD(device_attach, grackle_hb_attach),
308
{ 0, 0 }
309
};
310
311
static driver_t grackle_hb_driver = {
312
"grackle_hb",
313
grackle_hb_methods,
314
1,
315
};
316
317
DRIVER_MODULE(grackle_hb, pci, grackle_hb_driver, 0, 0);
318
319