blob: df431e8a063197c744c3018d71b1a5afc1198100 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Macintosh Nubus Interface Code
3 *
4 * Originally by Alan Cox
5 *
6 * Mostly rewritten by David Huggins-Daines, C. Scott Ananian,
7 * and others.
8 */
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/string.h>
13#include <linux/nubus.h>
14#include <linux/errno.h>
15#include <linux/init.h>
Adrian Bunk99ffab82008-02-04 22:30:23 -080016#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <asm/setup.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <asm/page.h>
20#include <asm/hwtest.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/mac_via.h>
22#include <asm/mac_oss.h>
23
24extern void via_nubus_init(void);
25extern void oss_nubus_init(void);
26
27/* Constants */
28
29/* This is, of course, the size in bytelanes, rather than the size in
30 actual bytes */
31#define FORMAT_BLOCK_SIZE 20
32#define ROM_DIR_OFFSET 0x24
33
34#define NUBUS_TEST_PATTERN 0x5A932BC7
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036/* Globals */
37
Finn Thainf42e5552017-04-08 19:51:15 -040038struct nubus_dev *nubus_devices;
39struct nubus_board *nubus_boards;
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* Meaning of "bytelanes":
42
43 The card ROM may appear on any or all bytes of each long word in
44 NuBus memory. The low 4 bits of the "map" value found in the
45 format block (at the top of the slot address space, as well as at
46 the top of the MacOS ROM) tells us which bytelanes, i.e. which byte
47 offsets within each longword, are valid. Thus:
48
49 A map of 0x0f, as found in the MacOS ROM, means that all bytelanes
50 are valid.
51
52 A map of 0xf0 means that no bytelanes are valid (We pray that we
53 will never encounter this, but stranger things have happened)
54
55 A map of 0xe1 means that only the MSB of each long word is actually
56 part of the card ROM. (We hope to never encounter NuBus on a
57 little-endian machine. Again, stranger things have happened)
58
59 A map of 0x78 means that only the LSB of each long word is valid.
60
61 Etcetera, etcetera. Hopefully this clears up some confusion over
62 what the following code actually does. */
Finn Thainf42e5552017-04-08 19:51:15 -040063
Linus Torvalds1da177e2005-04-16 15:20:36 -070064static inline int not_useful(void *p, int map)
65{
Finn Thainf42e5552017-04-08 19:51:15 -040066 unsigned long pv = (unsigned long)p;
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 pv &= 3;
Finn Thainf42e5552017-04-08 19:51:15 -040069 if (map & (1 << pv))
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 return 0;
71 return 1;
72}
Finn Thainf42e5552017-04-08 19:51:15 -040073
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static unsigned long nubus_get_rom(unsigned char **ptr, int len, int map)
75{
76 /* This will hold the result */
77 unsigned long v = 0;
78 unsigned char *p = *ptr;
79
Finn Thainf42e5552017-04-08 19:51:15 -040080 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 v <<= 8;
Finn Thainf42e5552017-04-08 19:51:15 -040082 while (not_useful(p, map))
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 p++;
84 v |= *p++;
85 len--;
86 }
87 *ptr = p;
88 return v;
89}
90
91static void nubus_rewind(unsigned char **ptr, int len, int map)
92{
Finn Thainf42e5552017-04-08 19:51:15 -040093 unsigned char *p = *ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Finn Thainf42e5552017-04-08 19:51:15 -040095 while (len) {
96 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 p--;
Finn Thainf42e5552017-04-08 19:51:15 -040098 } while (not_useful(p, map));
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 len--;
100 }
Finn Thainf42e5552017-04-08 19:51:15 -0400101 *ptr = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103
104static void nubus_advance(unsigned char **ptr, int len, int map)
105{
106 unsigned char *p = *ptr;
Finn Thainf42e5552017-04-08 19:51:15 -0400107
Finn Thainf42e5552017-04-08 19:51:15 -0400108 while (len) {
109 while (not_useful(p, map))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 p++;
Ilpo Järvinen2e0eb732008-10-15 22:01:31 -0700111 p++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 len--;
113 }
114 *ptr = p;
115}
116
117static void nubus_move(unsigned char **ptr, int len, int map)
118{
Finn Thain85cc3132017-04-22 21:24:16 -0400119 unsigned long slot_space = (unsigned long)*ptr & 0xFF000000;
120
Finn Thainf42e5552017-04-08 19:51:15 -0400121 if (len > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 nubus_advance(ptr, len, map);
Finn Thainf42e5552017-04-08 19:51:15 -0400123 else if (len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 nubus_rewind(ptr, -len, map);
Finn Thain85cc3132017-04-22 21:24:16 -0400125
126 if (((unsigned long)*ptr & 0xFF000000) != slot_space)
127 pr_err("%s: moved out of slot address space!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128}
129
130/* Now, functions to read the sResource tree */
131
132/* Each sResource entry consists of a 1-byte ID and a 3-byte data
133 field. If that data field contains an offset, then obviously we
134 have to expand it from a 24-bit signed number to a 32-bit signed
135 number. */
136
137static inline long nubus_expand32(long foo)
138{
Finn Thainf42e5552017-04-08 19:51:15 -0400139 if (foo & 0x00800000) /* 24bit negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 foo |= 0xFF000000;
141 return foo;
142}
143
144static inline void *nubus_rom_addr(int slot)
Finn Thainf42e5552017-04-08 19:51:15 -0400145{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 /*
147 * Returns the first byte after the card. We then walk
148 * backwards to get the lane register and the config
149 */
Finn Thainf42e5552017-04-08 19:51:15 -0400150 return (void *)(0xF1000000 + (slot << 24));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151}
152
153static unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
154{
155 unsigned char *p = nd->base;
Finn Thainf42e5552017-04-08 19:51:15 -0400156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 /* Essentially, just step over the bytelanes using whatever
158 offset we might have found */
159 nubus_move(&p, nubus_expand32(nd->data), nd->mask);
160 /* And return the value */
161 return p;
162}
163
164/* These two are for pulling resource data blocks (i.e. stuff that's
165 pointed to with offsets) out of the card ROM. */
166
Finn Thainf42e5552017-04-08 19:51:15 -0400167void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 int len)
169{
170 unsigned char *t = (unsigned char *)dest;
171 unsigned char *p = nubus_dirptr(dirent);
Finn Thainf42e5552017-04-08 19:51:15 -0400172
173 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 *t++ = nubus_get_rom(&p, 1, dirent->mask);
175 len--;
176 }
177}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800178EXPORT_SYMBOL(nubus_get_rsrc_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Finn Thainf42e5552017-04-08 19:51:15 -0400180void nubus_get_rsrc_str(void *dest, const struct nubus_dirent *dirent,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 int len)
182{
Finn Thainf42e5552017-04-08 19:51:15 -0400183 unsigned char *t = (unsigned char *)dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 unsigned char *p = nubus_dirptr(dirent);
Finn Thainf42e5552017-04-08 19:51:15 -0400185
186 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 *t = nubus_get_rom(&p, 1, dirent->mask);
Finn Thainf42e5552017-04-08 19:51:15 -0400188 if (!*t++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 break;
190 len--;
191 }
192}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800193EXPORT_SYMBOL(nubus_get_rsrc_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Finn Thainf42e5552017-04-08 19:51:15 -0400195int nubus_get_root_dir(const struct nubus_board *board,
196 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197{
198 dir->ptr = dir->base = board->directory;
199 dir->done = 0;
200 dir->mask = board->lanes;
201 return 0;
202}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800203EXPORT_SYMBOL(nubus_get_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205/* This is a slyly renamed version of the above */
Finn Thainf42e5552017-04-08 19:51:15 -0400206int nubus_get_func_dir(const struct nubus_dev *dev,
207 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 dir->ptr = dir->base = dev->directory;
210 dir->done = 0;
211 dir->mask = dev->board->lanes;
212 return 0;
213}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800214EXPORT_SYMBOL(nubus_get_func_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Finn Thainf42e5552017-04-08 19:51:15 -0400216int nubus_get_board_dir(const struct nubus_board *board,
217 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218{
219 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 dir->ptr = dir->base = board->directory;
222 dir->done = 0;
223 dir->mask = board->lanes;
224
225 /* Now dereference it (the first directory is always the board
226 directory) */
227 if (nubus_readdir(dir, &ent) == -1)
228 return -1;
229 if (nubus_get_subdir(&ent, dir) == -1)
230 return -1;
231 return 0;
232}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800233EXPORT_SYMBOL(nubus_get_board_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235int nubus_get_subdir(const struct nubus_dirent *ent,
236 struct nubus_dir *dir)
237{
238 dir->ptr = dir->base = nubus_dirptr(ent);
239 dir->done = 0;
240 dir->mask = ent->mask;
241 return 0;
242}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800243EXPORT_SYMBOL(nubus_get_subdir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
246{
247 u32 resid;
Finn Thainf42e5552017-04-08 19:51:15 -0400248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 if (nd->done)
250 return -1;
251
252 /* Do this first, otherwise nubus_rewind & co are off by 4 */
253 ent->base = nd->ptr;
254
255 /* This moves nd->ptr forward */
256 resid = nubus_get_rom(&nd->ptr, 4, nd->mask);
257
258 /* EOL marker, as per the Apple docs */
Finn Thainf42e5552017-04-08 19:51:15 -0400259 if ((resid & 0xff000000) == 0xff000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 /* Mark it as done */
261 nd->done = 1;
262 return -1;
263 }
264
265 /* First byte is the resource ID */
Finn Thainf42e5552017-04-08 19:51:15 -0400266 ent->type = resid >> 24;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 /* Low 3 bytes might contain data (or might not) */
268 ent->data = resid & 0xffffff;
Finn Thainf42e5552017-04-08 19:51:15 -0400269 ent->mask = nd->mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 return 0;
271}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800272EXPORT_SYMBOL(nubus_readdir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Finn Thainf42e5552017-04-08 19:51:15 -0400274int nubus_rewinddir(struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
276 dir->ptr = dir->base;
David Huggins-Dainese36b9912017-04-08 19:51:15 -0400277 dir->done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 return 0;
279}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800280EXPORT_SYMBOL(nubus_rewinddir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282/* Driver interface functions, more or less like in pci.c */
283
284struct nubus_dev*
Finn Thainf42e5552017-04-08 19:51:15 -0400285nubus_find_device(unsigned short category, unsigned short type,
286 unsigned short dr_hw, unsigned short dr_sw,
287 const struct nubus_dev *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Finn Thainf42e5552017-04-08 19:51:15 -0400289 struct nubus_dev *itor = from ? from->next : nubus_devices;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 while (itor) {
Finn Thainf42e5552017-04-08 19:51:15 -0400292 if (itor->category == category && itor->type == type &&
293 itor->dr_hw == dr_hw && itor->dr_sw == dr_sw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 return itor;
295 itor = itor->next;
296 }
297 return NULL;
298}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800299EXPORT_SYMBOL(nubus_find_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301struct nubus_dev*
Finn Thainf42e5552017-04-08 19:51:15 -0400302nubus_find_type(unsigned short category, unsigned short type,
303 const struct nubus_dev *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
Finn Thainf42e5552017-04-08 19:51:15 -0400305 struct nubus_dev *itor = from ? from->next : nubus_devices;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
307 while (itor) {
Finn Thainf42e5552017-04-08 19:51:15 -0400308 if (itor->category == category && itor->type == type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 return itor;
310 itor = itor->next;
311 }
312 return NULL;
313}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800314EXPORT_SYMBOL(nubus_find_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316struct nubus_dev*
Finn Thainf42e5552017-04-08 19:51:15 -0400317nubus_find_slot(unsigned int slot, const struct nubus_dev *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Finn Thainf42e5552017-04-08 19:51:15 -0400319 struct nubus_dev *itor = from ? from->next : nubus_devices;
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 while (itor) {
322 if (itor->board->slot == slot)
323 return itor;
324 itor = itor->next;
325 }
326 return NULL;
327}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800328EXPORT_SYMBOL(nubus_find_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330int
Finn Thainf42e5552017-04-08 19:51:15 -0400331nubus_find_rsrc(struct nubus_dir *dir, unsigned char rsrc_type,
332 struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
334 while (nubus_readdir(dir, ent) != -1) {
335 if (ent->type == rsrc_type)
336 return 0;
Finn Thainf42e5552017-04-08 19:51:15 -0400337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 return -1;
339}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800340EXPORT_SYMBOL(nubus_find_rsrc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342/* Initialization functions - decide which slots contain stuff worth
343 looking at, and print out lots and lots of information from the
344 resource blocks. */
345
346/* FIXME: A lot of this stuff will eventually be useful after
Joe Perches081985a2008-02-03 17:23:36 +0200347 initialization, for intelligently probing Ethernet and video chips,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 among other things. The rest of it should go in the /proc code.
349 For now, we just use it to give verbose boot logs. */
350
Finn Thainf42e5552017-04-08 19:51:15 -0400351static int __init nubus_show_display_resource(struct nubus_dev *dev,
352 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
354 switch (ent->type) {
355 case NUBUS_RESID_GAMMADIR:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400356 pr_info(" gamma directory offset: 0x%06x\n", ent->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 break;
358 case 0x0080 ... 0x0085:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400359 pr_info(" mode %02X info offset: 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 ent->type, ent->data);
361 break;
362 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400363 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 ent->type, ent->data);
365 }
366 return 0;
367}
368
Finn Thainf42e5552017-04-08 19:51:15 -0400369static int __init nubus_show_network_resource(struct nubus_dev *dev,
370 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
372 switch (ent->type) {
373 case NUBUS_RESID_MAC_ADDRESS:
374 {
375 char addr[6];
Finn Thainf42e5552017-04-08 19:51:15 -0400376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 nubus_get_rsrc_mem(addr, ent, 6);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400378 pr_info(" MAC address: %pM\n", addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 break;
380 }
381 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400382 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 ent->type, ent->data);
384 }
385 return 0;
386}
387
Finn Thainf42e5552017-04-08 19:51:15 -0400388static int __init nubus_show_cpu_resource(struct nubus_dev *dev,
389 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
391 switch (ent->type) {
392 case NUBUS_RESID_MEMINFO:
393 {
394 unsigned long meminfo[2];
Finn Thainf42e5552017-04-08 19:51:15 -0400395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 nubus_get_rsrc_mem(&meminfo, ent, 8);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400397 pr_info(" memory: [ 0x%08lx 0x%08lx ]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 meminfo[0], meminfo[1]);
399 break;
400 }
401 case NUBUS_RESID_ROMINFO:
402 {
403 unsigned long rominfo[2];
Finn Thainf42e5552017-04-08 19:51:15 -0400404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 nubus_get_rsrc_mem(&rominfo, ent, 8);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400406 pr_info(" ROM: [ 0x%08lx 0x%08lx ]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 rominfo[0], rominfo[1]);
408 break;
409 }
410 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400411 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 ent->type, ent->data);
413 }
414 return 0;
415}
416
Finn Thainf42e5552017-04-08 19:51:15 -0400417static int __init nubus_show_private_resource(struct nubus_dev *dev,
418 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419{
420 switch (dev->category) {
421 case NUBUS_CAT_DISPLAY:
422 nubus_show_display_resource(dev, ent);
423 break;
424 case NUBUS_CAT_NETWORK:
425 nubus_show_network_resource(dev, ent);
426 break;
427 case NUBUS_CAT_CPU:
428 nubus_show_cpu_resource(dev, ent);
429 break;
430 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400431 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 ent->type, ent->data);
433 }
434 return 0;
435}
436
Finn Thainf42e5552017-04-08 19:51:15 -0400437static struct nubus_dev * __init
438nubus_get_functional_resource(struct nubus_board *board, int slot,
439 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
Finn Thainf42e5552017-04-08 19:51:15 -0400441 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400443 struct nubus_dev *dev;
444
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400445 pr_info(" Function 0x%02x:\n", parent->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 nubus_get_subdir(parent, &dir);
447
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400448 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
449 __func__, parent->base, dir.base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 /* Actually we should probably panic if this fails */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700452 if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
Finn Thainf42e5552017-04-08 19:51:15 -0400453 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 dev->resid = parent->type;
455 dev->directory = dir.base;
456 dev->board = board;
Finn Thainf42e5552017-04-08 19:51:15 -0400457
458 while (nubus_readdir(&dir, &ent) != -1) {
459 switch (ent.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 case NUBUS_RESID_TYPE:
461 {
462 unsigned short nbtdata[4];
Finn Thainf42e5552017-04-08 19:51:15 -0400463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 nubus_get_rsrc_mem(nbtdata, &ent, 8);
465 dev->category = nbtdata[0];
466 dev->type = nbtdata[1];
467 dev->dr_sw = nbtdata[2];
468 dev->dr_hw = nbtdata[3];
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400469 pr_info(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
470 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 break;
472 }
473 case NUBUS_RESID_NAME:
474 {
475 nubus_get_rsrc_str(dev->name, &ent, 64);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400476 pr_info(" name: %s\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 break;
478 }
479 case NUBUS_RESID_DRVRDIR:
480 {
481 /* MacOS driver. If we were NetBSD we might
482 use this :-) */
483 struct nubus_dir drvr_dir;
484 struct nubus_dirent drvr_ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 nubus_get_subdir(&ent, &drvr_dir);
487 nubus_readdir(&drvr_dir, &drvr_ent);
488 dev->driver = nubus_dirptr(&drvr_ent);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400489 pr_info(" driver at: 0x%p\n", dev->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 break;
491 }
492 case NUBUS_RESID_MINOR_BASEOS:
493 /* We will need this in order to support
494 multiple framebuffers. It might be handy
495 for Ethernet as well */
496 nubus_get_rsrc_mem(&dev->iobase, &ent, 4);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400497 pr_info(" memory offset: 0x%08lx\n", dev->iobase);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 break;
499 case NUBUS_RESID_MINOR_LENGTH:
500 /* Ditto */
501 nubus_get_rsrc_mem(&dev->iosize, &ent, 4);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400502 pr_info(" memory length: 0x%08lx\n", dev->iosize);
Finn Thainf42e5552017-04-08 19:51:15 -0400503 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 case NUBUS_RESID_FLAGS:
505 dev->flags = ent.data;
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400506 pr_info(" flags: 0x%06x\n", dev->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 break;
508 case NUBUS_RESID_HWDEVID:
509 dev->hwdevid = ent.data;
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400510 pr_info(" hwdevid: 0x%06x\n", dev->hwdevid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 break;
512 default:
513 /* Local/Private resources have their own
514 function */
515 nubus_show_private_resource(dev, &ent);
516 }
517 }
Finn Thainf42e5552017-04-08 19:51:15 -0400518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 return dev;
520}
521
522/* This is cool. */
Finn Thainf42e5552017-04-08 19:51:15 -0400523static int __init nubus_get_vidnames(struct nubus_board *board,
524 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525{
Finn Thainf42e5552017-04-08 19:51:15 -0400526 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 /* FIXME: obviously we want to put this in a header file soon */
530 struct vidmode {
531 u32 size;
532 /* Don't know what this is yet */
533 u16 id;
534 /* Longest one I've seen so far is 26 characters */
535 char name[32];
536 };
537
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400538 pr_info(" video modes supported:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 nubus_get_subdir(parent, &dir);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400540 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
541 __func__, parent->base, dir.base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
Finn Thainf42e5552017-04-08 19:51:15 -0400543 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 struct vidmode mode;
545 u32 size;
546
547 /* First get the length */
548 nubus_get_rsrc_mem(&size, &ent, 4);
Finn Thainf42e5552017-04-08 19:51:15 -0400549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 /* Now clobber the whole thing */
551 if (size > sizeof(mode) - 1)
552 size = sizeof(mode) - 1;
553 memset(&mode, 0, sizeof(mode));
554 nubus_get_rsrc_mem(&mode, &ent, size);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400555 pr_info(" %02X: (%02X) %s\n", ent.type,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 mode.id, mode.name);
557 }
558 return 0;
559}
560
561/* This is *really* cool. */
Finn Thainf42e5552017-04-08 19:51:15 -0400562static int __init nubus_get_icon(struct nubus_board *board,
563 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
565 /* Should be 32x32 if my memory serves me correctly */
566 unsigned char icon[128];
567 int x, y;
Finn Thainf42e5552017-04-08 19:51:15 -0400568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 nubus_get_rsrc_mem(&icon, ent, 128);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400570 pr_info(" icon:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572 /* We should actually plot these somewhere in the framebuffer
573 init. This is just to demonstrate that they do, in fact,
574 exist */
575 for (y = 0; y < 32; y++) {
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400576 pr_info(" ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 for (x = 0; x < 32; x++) {
Finn Thainf42e5552017-04-08 19:51:15 -0400578 if (icon[y * 4 + x / 8] & (0x80 >> (x % 8)))
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400579 pr_cont("*");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 else
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400581 pr_cont(" ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 }
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400583 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 }
585 return 0;
586}
587
Finn Thainf42e5552017-04-08 19:51:15 -0400588static int __init nubus_get_vendorinfo(struct nubus_board *board,
589 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590{
Finn Thainf42e5552017-04-08 19:51:15 -0400591 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400593 static char *vendor_fields[6] = { "ID", "serial", "revision",
594 "part", "date", "unknown field" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400596 pr_info(" vendor info:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 nubus_get_subdir(parent, &dir);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400598 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
599 __func__, parent->base, dir.base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Finn Thainf42e5552017-04-08 19:51:15 -0400601 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 char name[64];
Finn Thainf42e5552017-04-08 19:51:15 -0400603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 /* These are all strings, we think */
605 nubus_get_rsrc_str(name, &ent, 64);
606 if (ent.type > 5)
607 ent.type = 5;
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400608 pr_info(" %s: %s\n", vendor_fields[ent.type - 1], name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
610 return 0;
611}
612
Finn Thainf42e5552017-04-08 19:51:15 -0400613static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
614 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615{
Finn Thainf42e5552017-04-08 19:51:15 -0400616 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400618
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 nubus_get_subdir(parent, &dir);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400620 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
621 __func__, parent->base, dir.base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
Finn Thainf42e5552017-04-08 19:51:15 -0400623 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 switch (ent.type) {
625 case NUBUS_RESID_TYPE:
626 {
627 unsigned short nbtdata[4];
628 /* This type is always the same, and is not
629 useful except insofar as it tells us that
630 we really are looking at a board resource. */
631 nubus_get_rsrc_mem(nbtdata, &ent, 8);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400632 pr_info(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
633 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
635 nbtdata[2] != 0 || nbtdata[3] != 0)
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400636 pr_err("this sResource is not a board resource!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 break;
638 }
639 case NUBUS_RESID_NAME:
640 nubus_get_rsrc_str(board->name, &ent, 64);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400641 pr_info(" name: %s\n", board->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 break;
643 case NUBUS_RESID_ICON:
644 nubus_get_icon(board, &ent);
645 break;
646 case NUBUS_RESID_BOARDID:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400647 pr_info(" board id: 0x%x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 break;
649 case NUBUS_RESID_PRIMARYINIT:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400650 pr_info(" primary init offset: 0x%06x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 break;
652 case NUBUS_RESID_VENDORINFO:
653 nubus_get_vendorinfo(board, &ent);
654 break;
655 case NUBUS_RESID_FLAGS:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400656 pr_info(" flags: 0x%06x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 break;
658 case NUBUS_RESID_HWDEVID:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400659 pr_info(" hwdevid: 0x%06x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 break;
661 case NUBUS_RESID_SECONDINIT:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400662 pr_info(" secondary init offset: 0x%06x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 break;
Finn Thainf42e5552017-04-08 19:51:15 -0400664 /* WTF isn't this in the functional resources? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 case NUBUS_RESID_VIDNAMES:
666 nubus_get_vidnames(board, &ent);
667 break;
668 /* Same goes for this */
669 case NUBUS_RESID_VIDMODES:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400670 pr_info(" video mode parameter directory offset: 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 ent.data);
Finn Thainf42e5552017-04-08 19:51:15 -0400672 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400674 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 ent.type, ent.data);
676 }
677 }
678 return 0;
679}
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681/* Add a board (might be many devices) to the list */
Finn Thainf42e5552017-04-08 19:51:15 -0400682static struct nubus_board * __init nubus_add_board(int slot, int bytelanes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
Finn Thainf42e5552017-04-08 19:51:15 -0400684 struct nubus_board *board;
685 struct nubus_board **boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 unsigned char *rp;
687 unsigned long dpat;
688 struct nubus_dir dir;
689 struct nubus_dirent ent;
690
691 /* Move to the start of the format block */
Finn Thainf42e5552017-04-08 19:51:15 -0400692 rp = nubus_rom_addr(slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
694
695 /* Actually we should probably panic if this fails */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700696 if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
Finn Thainf42e5552017-04-08 19:51:15 -0400697 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 board->fblock = rp;
699
700 /* Dump the format block for debugging purposes */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400701 pr_debug("Slot %X, format block at 0x%p:\n", slot, rp);
702 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
703 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
704 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
705 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
706 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
707 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
708 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
709 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
710 rp = board->fblock;
711
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 board->slot = slot;
Finn Thainf42e5552017-04-08 19:51:15 -0400713 board->slot_addr = (unsigned long)nubus_slot_addr(slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 board->doffset = nubus_get_rom(&rp, 4, bytelanes);
715 /* rom_length is *supposed* to be the total length of the
716 * ROM. In practice it is the "amount of ROM used to compute
717 * the CRC." So some jokers decide to set it to zero and
718 * set the crc to zero so they don't have to do any math.
719 * See the Performa 460 ROM, for example. Those Apple "engineers".
720 */
721 board->rom_length = nubus_get_rom(&rp, 4, bytelanes);
722 board->crc = nubus_get_rom(&rp, 4, bytelanes);
723 board->rev = nubus_get_rom(&rp, 1, bytelanes);
Finn Thainf42e5552017-04-08 19:51:15 -0400724 board->format = nubus_get_rom(&rp, 1, bytelanes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 board->lanes = bytelanes;
726
727 /* Directory offset should be small and negative... */
Finn Thainf42e5552017-04-08 19:51:15 -0400728 if (!(board->doffset & 0x00FF0000))
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400729 pr_warn("Dodgy doffset!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 dpat = nubus_get_rom(&rp, 4, bytelanes);
Finn Thainf42e5552017-04-08 19:51:15 -0400731 if (dpat != NUBUS_TEST_PATTERN)
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400732 pr_warn("Wrong test pattern %08lx!\n", dpat);
Finn Thainf42e5552017-04-08 19:51:15 -0400733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /*
735 * I wonder how the CRC is meant to work -
736 * any takers ?
737 * CSA: According to MAC docs, not all cards pass the CRC anyway,
738 * since the initial Macintosh ROM releases skipped the check.
739 */
740
David Huggins-Daines475e6e12017-04-22 21:24:16 -0400741 /* Set up the directory pointer */
742 board->directory = board->fblock;
743 nubus_move(&board->directory, nubus_expand32(board->doffset),
744 board->lanes);
745
Finn Thainf42e5552017-04-08 19:51:15 -0400746 nubus_get_root_dir(board, &dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 /* We're ready to rock */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400749 pr_info("Slot %X:\n", slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751 /* Each slot should have one board resource and any number of
752 functional resources. So we'll fill in some fields in the
753 struct nubus_board from the board resource, then walk down
754 the list of functional resources, spinning out a nubus_dev
755 for each of them. */
756 if (nubus_readdir(&dir, &ent) == -1) {
757 /* We can't have this! */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400758 pr_err("Board resource not found!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return NULL;
760 } else {
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400761 pr_info(" Board resource:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 nubus_get_board_resource(board, slot, &ent);
763 }
764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 while (nubus_readdir(&dir, &ent) != -1) {
Finn Thainf42e5552017-04-08 19:51:15 -0400766 struct nubus_dev *dev;
767 struct nubus_dev **devp;
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 dev = nubus_get_functional_resource(board, slot, &ent);
770 if (dev == NULL)
771 continue;
772
773 /* We zeroed this out above */
774 if (board->first_dev == NULL)
775 board->first_dev = dev;
Finn Thainf42e5552017-04-08 19:51:15 -0400776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 /* Put it on the global NuBus device chain. Keep entries in order. */
Finn Thainf42e5552017-04-08 19:51:15 -0400778 for (devp = &nubus_devices; *devp != NULL;
779 devp = &((*devp)->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 /* spin */;
781 *devp = dev;
Finn Thainf42e5552017-04-08 19:51:15 -0400782 dev->next = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
784
785 /* Put it on the global NuBus board chain. Keep entries in order. */
Finn Thainf42e5552017-04-08 19:51:15 -0400786 for (boardp = &nubus_boards; *boardp != NULL;
787 boardp = &((*boardp)->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 /* spin */;
789 *boardp = board;
790 board->next = NULL;
Finn Thainf42e5552017-04-08 19:51:15 -0400791
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 return board;
793}
794
795void __init nubus_probe_slot(int slot)
796{
797 unsigned char dp;
Finn Thainf42e5552017-04-08 19:51:15 -0400798 unsigned char *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 int i;
800
Finn Thainf42e5552017-04-08 19:51:15 -0400801 rp = nubus_rom_addr(slot);
802 for (i = 4; i; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 int card_present;
804
805 rp--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 card_present = hwreg_present(rp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 if (!card_present)
808 continue;
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 dp = *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 /* The last byte of the format block consists of two
813 nybbles which are "mirror images" of each other.
814 These show us the valid bytelanes */
Finn Thainf42e5552017-04-08 19:51:15 -0400815 if ((((dp >> 4) ^ dp) & 0x0F) != 0x0F)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 continue;
817 /* Check that this value is actually *on* one of the
818 bytelanes it claims are valid! */
Finn Thain85cc3132017-04-22 21:24:16 -0400819 if (not_useful(rp, dp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 continue;
821
822 /* Looks promising. Let's put it on the list. */
823 nubus_add_board(slot, dp);
824
825 return;
826 }
827}
828
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829void __init nubus_scan_bus(void)
830{
831 int slot;
Finn Thainf42e5552017-04-08 19:51:15 -0400832
Finn Thainf42e5552017-04-08 19:51:15 -0400833 for (slot = 9; slot < 15; slot++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 nubus_probe_slot(slot);
835 }
836}
837
838static int __init nubus_init(void)
839{
Finn Thainf42e5552017-04-08 19:51:15 -0400840 if (!MACH_IS_MAC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 return 0;
842
843 /* Initialize the NuBus interrupts */
844 if (oss_present) {
845 oss_nubus_init();
846 } else {
847 via_nubus_init();
848 }
849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 /* And probe */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400851 pr_info("NuBus: Scanning NuBus slots.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 nubus_devices = NULL;
Finn Thainf42e5552017-04-08 19:51:15 -0400853 nubus_boards = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 nubus_scan_bus();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 nubus_proc_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return 0;
857}
858
859subsys_initcall(nubus_init);