Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/sgi-ip22/ip22-gio.c
25922 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
#include <linux/export.h>
3
#include <linux/kernel.h>
4
#include <linux/init.h>
5
#include <linux/slab.h>
6
7
#include <asm/addrspace.h>
8
#include <asm/paccess.h>
9
#include <asm/gio_device.h>
10
#include <asm/sgi/gio.h>
11
#include <asm/sgi/hpc3.h>
12
#include <asm/sgi/mc.h>
13
#include <asm/sgi/ip22.h>
14
15
static const struct bus_type gio_bus_type;
16
17
static struct {
18
const char *name;
19
__u8 id;
20
} gio_name_table[] = {
21
{ .name = "SGI Impact", .id = 0x10 },
22
{ .name = "Phobos G160", .id = 0x35 },
23
{ .name = "Phobos G130", .id = 0x36 },
24
{ .name = "Phobos G100", .id = 0x37 },
25
{ .name = "Set Engineering GFE", .id = 0x38 },
26
/* fake IDs */
27
{ .name = "SGI Newport", .id = 0x7e },
28
{ .name = "SGI GR2/GR3", .id = 0x7f },
29
};
30
31
static void gio_bus_release(struct device *dev)
32
{
33
kfree(dev);
34
}
35
36
static struct device gio_bus = {
37
.init_name = "gio",
38
.release = &gio_bus_release,
39
};
40
41
/**
42
* gio_match_device - Tell if an of_device structure has a matching
43
* gio_match structure
44
* @ids: array of of device match structures to search in
45
* @dev: the of device structure to match against
46
*
47
* Used by a driver to check whether an of_device present in the
48
* system is in its list of supported devices.
49
*/
50
static const struct gio_device_id *
51
gio_match_device(const struct gio_device_id *match,
52
const struct gio_device *dev)
53
{
54
const struct gio_device_id *ids;
55
56
for (ids = match; ids->id != 0xff; ids++)
57
if (ids->id == dev->id.id)
58
return ids;
59
60
return NULL;
61
}
62
63
struct gio_device *gio_dev_get(struct gio_device *dev)
64
{
65
struct device *tmp;
66
67
if (!dev)
68
return NULL;
69
tmp = get_device(&dev->dev);
70
if (tmp)
71
return to_gio_device(tmp);
72
else
73
return NULL;
74
}
75
EXPORT_SYMBOL_GPL(gio_dev_get);
76
77
void gio_dev_put(struct gio_device *dev)
78
{
79
if (dev)
80
put_device(&dev->dev);
81
}
82
EXPORT_SYMBOL_GPL(gio_dev_put);
83
84
/**
85
* gio_release_dev - free an gio device structure when all users of it are finished.
86
* @dev: device that's been disconnected
87
*
88
* Will be called only by the device core when all users of this gio device are
89
* done.
90
*/
91
void gio_release_dev(struct device *dev)
92
{
93
struct gio_device *giodev;
94
95
giodev = to_gio_device(dev);
96
kfree(giodev);
97
}
98
EXPORT_SYMBOL_GPL(gio_release_dev);
99
100
int gio_device_register(struct gio_device *giodev)
101
{
102
giodev->dev.bus = &gio_bus_type;
103
giodev->dev.parent = &gio_bus;
104
return device_register(&giodev->dev);
105
}
106
EXPORT_SYMBOL_GPL(gio_device_register);
107
108
void gio_device_unregister(struct gio_device *giodev)
109
{
110
device_unregister(&giodev->dev);
111
}
112
EXPORT_SYMBOL_GPL(gio_device_unregister);
113
114
static int gio_bus_match(struct device *dev, const struct device_driver *drv)
115
{
116
struct gio_device *gio_dev = to_gio_device(dev);
117
struct gio_driver *gio_drv = to_gio_driver(drv);
118
119
return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
120
}
121
122
static int gio_device_probe(struct device *dev)
123
{
124
int error = -ENODEV;
125
struct gio_driver *drv;
126
struct gio_device *gio_dev;
127
const struct gio_device_id *match;
128
129
drv = to_gio_driver(dev->driver);
130
gio_dev = to_gio_device(dev);
131
132
if (!drv->probe)
133
return error;
134
135
gio_dev_get(gio_dev);
136
137
match = gio_match_device(drv->id_table, gio_dev);
138
if (match)
139
error = drv->probe(gio_dev, match);
140
if (error)
141
gio_dev_put(gio_dev);
142
143
return error;
144
}
145
146
static void gio_device_remove(struct device *dev)
147
{
148
struct gio_device *gio_dev = to_gio_device(dev);
149
struct gio_driver *drv = to_gio_driver(dev->driver);
150
151
if (drv->remove)
152
drv->remove(gio_dev);
153
}
154
155
static void gio_device_shutdown(struct device *dev)
156
{
157
struct gio_device *gio_dev = to_gio_device(dev);
158
struct gio_driver *drv = to_gio_driver(dev->driver);
159
160
if (dev->driver && drv->shutdown)
161
drv->shutdown(gio_dev);
162
}
163
164
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
165
char *buf)
166
{
167
struct gio_device *gio_dev = to_gio_device(dev);
168
169
return sysfs_emit(buf, "gio:%x\n", gio_dev->id.id);
170
}
171
static DEVICE_ATTR_RO(modalias);
172
173
static ssize_t name_show(struct device *dev,
174
struct device_attribute *attr, char *buf)
175
{
176
struct gio_device *giodev;
177
178
giodev = to_gio_device(dev);
179
return sysfs_emit(buf, "%s\n", giodev->name);
180
}
181
static DEVICE_ATTR_RO(name);
182
183
static ssize_t id_show(struct device *dev,
184
struct device_attribute *attr, char *buf)
185
{
186
struct gio_device *giodev;
187
188
giodev = to_gio_device(dev);
189
return sysfs_emit(buf, "%x\n", giodev->id.id);
190
}
191
static DEVICE_ATTR_RO(id);
192
193
static struct attribute *gio_dev_attrs[] = {
194
&dev_attr_modalias.attr,
195
&dev_attr_name.attr,
196
&dev_attr_id.attr,
197
NULL,
198
};
199
ATTRIBUTE_GROUPS(gio_dev);
200
201
static int gio_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
202
{
203
const struct gio_device *gio_dev = to_gio_device(dev);
204
205
add_uevent_var(env, "MODALIAS=gio:%x", gio_dev->id.id);
206
return 0;
207
}
208
209
int gio_register_driver(struct gio_driver *drv)
210
{
211
/* initialize common driver fields */
212
if (!drv->driver.name)
213
drv->driver.name = drv->name;
214
if (!drv->driver.owner)
215
drv->driver.owner = drv->owner;
216
drv->driver.bus = &gio_bus_type;
217
218
/* register with core */
219
return driver_register(&drv->driver);
220
}
221
EXPORT_SYMBOL_GPL(gio_register_driver);
222
223
void gio_unregister_driver(struct gio_driver *drv)
224
{
225
driver_unregister(&drv->driver);
226
}
227
EXPORT_SYMBOL_GPL(gio_unregister_driver);
228
229
void gio_set_master(struct gio_device *dev)
230
{
231
u32 tmp = sgimc->giopar;
232
233
switch (dev->slotno) {
234
case 0:
235
tmp |= SGIMC_GIOPAR_MASTERGFX;
236
break;
237
case 1:
238
tmp |= SGIMC_GIOPAR_MASTEREXP0;
239
break;
240
case 2:
241
tmp |= SGIMC_GIOPAR_MASTEREXP1;
242
break;
243
}
244
sgimc->giopar = tmp;
245
}
246
EXPORT_SYMBOL_GPL(gio_set_master);
247
248
static void ip22_gio_set_64bit(int slotno)
249
{
250
u32 tmp = sgimc->giopar;
251
252
switch (slotno) {
253
case 0:
254
tmp |= SGIMC_GIOPAR_GFX64;
255
break;
256
case 1:
257
tmp |= SGIMC_GIOPAR_EXP064;
258
break;
259
case 2:
260
tmp |= SGIMC_GIOPAR_EXP164;
261
break;
262
}
263
sgimc->giopar = tmp;
264
}
265
266
static int ip22_gio_id(unsigned long addr, u32 *res)
267
{
268
u8 tmp8;
269
u8 tmp16;
270
u32 tmp32;
271
u8 *ptr8;
272
u16 *ptr16;
273
u32 *ptr32;
274
275
ptr32 = (void *)CKSEG1ADDR(addr);
276
if (!get_dbe(tmp32, ptr32)) {
277
/*
278
* We got no DBE, but this doesn't mean anything.
279
* If GIO is pipelined (which can't be disabled
280
* for GFX slot) we don't get a DBE, but we see
281
* the transfer size as data. So we do an 8bit
282
* and a 16bit access and check whether the common
283
* data matches
284
*/
285
ptr8 = (void *)CKSEG1ADDR(addr + 3);
286
if (get_dbe(tmp8, ptr8)) {
287
/*
288
* 32bit access worked, but 8bit doesn't
289
* so we don't see phantom reads on
290
* a pipelined bus, but a real card which
291
* doesn't support 8 bit reads
292
*/
293
*res = tmp32;
294
return 1;
295
}
296
ptr16 = (void *)CKSEG1ADDR(addr + 2);
297
get_dbe(tmp16, ptr16);
298
if (tmp8 == (tmp16 & 0xff) &&
299
tmp8 == (tmp32 & 0xff) &&
300
tmp16 == (tmp32 & 0xffff)) {
301
*res = tmp32;
302
return 1;
303
}
304
}
305
return 0; /* nothing here */
306
}
307
308
#define HQ2_MYSTERY_OFFS 0x6A07C
309
#define NEWPORT_USTATUS_OFFS 0xF133C
310
311
static int ip22_is_gr2(unsigned long addr)
312
{
313
u32 tmp;
314
u32 *ptr;
315
316
/* HQ2 only allows 32bit accesses */
317
ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
318
if (!get_dbe(tmp, ptr)) {
319
if (tmp == 0xdeadbeef)
320
return 1;
321
}
322
return 0;
323
}
324
325
326
static void ip22_check_gio(int slotno, unsigned long addr, int irq)
327
{
328
const char *name = "Unknown";
329
struct gio_device *gio_dev;
330
u32 tmp;
331
__u8 id;
332
int i;
333
334
/* first look for GR2/GR3 by checking mystery register */
335
if (ip22_is_gr2(addr))
336
tmp = 0x7f;
337
else {
338
if (!ip22_gio_id(addr, &tmp)) {
339
/*
340
* no GIO signature at start address of slot
341
* since Newport doesn't have one, we check if
342
* user status register is readable
343
*/
344
if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
345
tmp = 0x7e;
346
else
347
tmp = 0;
348
}
349
}
350
if (tmp) {
351
id = GIO_ID(tmp);
352
if (tmp & GIO_32BIT_ID) {
353
if (tmp & GIO_64BIT_IFACE)
354
ip22_gio_set_64bit(slotno);
355
}
356
for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
357
if (id == gio_name_table[i].id) {
358
name = gio_name_table[i].name;
359
break;
360
}
361
}
362
printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
363
slotno, name, id);
364
gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
365
if (!gio_dev)
366
return;
367
gio_dev->name = name;
368
gio_dev->slotno = slotno;
369
gio_dev->id.id = id;
370
gio_dev->resource.start = addr;
371
gio_dev->resource.end = addr + 0x3fffff;
372
gio_dev->resource.flags = IORESOURCE_MEM;
373
gio_dev->irq = irq;
374
dev_set_name(&gio_dev->dev, "%d", slotno);
375
gio_device_register(gio_dev);
376
} else
377
printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
378
}
379
380
static const struct bus_type gio_bus_type = {
381
.name = "gio",
382
.dev_groups = gio_dev_groups,
383
.match = gio_bus_match,
384
.probe = gio_device_probe,
385
.remove = gio_device_remove,
386
.shutdown = gio_device_shutdown,
387
.uevent = gio_device_uevent,
388
};
389
390
static struct resource gio_bus_resource = {
391
.start = GIO_SLOT_GFX_BASE,
392
.end = GIO_SLOT_GFX_BASE + 0x9fffff,
393
.name = "GIO Bus",
394
.flags = IORESOURCE_MEM,
395
};
396
397
static int __init ip22_gio_init(void)
398
{
399
unsigned int pbdma __maybe_unused;
400
int ret;
401
402
ret = device_register(&gio_bus);
403
if (ret) {
404
put_device(&gio_bus);
405
return ret;
406
}
407
408
ret = bus_register(&gio_bus_type);
409
if (!ret) {
410
request_resource(&iomem_resource, &gio_bus_resource);
411
printk(KERN_INFO "GIO: Probing bus...\n");
412
413
if (ip22_is_fullhouse()) {
414
/* Indigo2 */
415
ip22_check_gio(0, GIO_SLOT_GFX_BASE, SGI_GIO_1_IRQ);
416
ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIO_1_IRQ);
417
} else {
418
/* Indy/Challenge S */
419
if (get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1]))
420
ip22_check_gio(0, GIO_SLOT_GFX_BASE,
421
SGI_GIO_0_IRQ);
422
ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIOEXP0_IRQ);
423
ip22_check_gio(2, GIO_SLOT_EXP1_BASE, SGI_GIOEXP1_IRQ);
424
}
425
} else
426
device_unregister(&gio_bus);
427
428
return ret;
429
}
430
431
subsys_initcall(ip22_gio_init);
432
433