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