blob: bb0d63a44f418bb30d5d6f350d62c3841831018f [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * Macintosh Nubus Interface Code
4 *
5 * Originally by Alan Cox
6 *
7 * Mostly rewritten by David Huggins-Daines, C. Scott Ananian,
8 * and others.
9 */
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/types.h>
12#include <linux/kernel.h>
13#include <linux/string.h>
14#include <linux/nubus.h>
15#include <linux/errno.h>
16#include <linux/init.h>
Adrian Bunk99ffab82008-02-04 22:30:23 -080017#include <linux/module.h>
Finn Thain2f7dd072018-01-13 17:37:13 -050018#include <linux/seq_file.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090019#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <asm/setup.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/page.h>
22#include <asm/hwtest.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24/* Constants */
25
26/* This is, of course, the size in bytelanes, rather than the size in
27 actual bytes */
28#define FORMAT_BLOCK_SIZE 20
29#define ROM_DIR_OFFSET 0x24
30
31#define NUBUS_TEST_PATTERN 0x5A932BC7
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033/* Globals */
34
Finn Thain41b84812018-01-13 17:37:13 -050035LIST_HEAD(nubus_func_rsrcs);
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37/* Meaning of "bytelanes":
38
39 The card ROM may appear on any or all bytes of each long word in
40 NuBus memory. The low 4 bits of the "map" value found in the
41 format block (at the top of the slot address space, as well as at
42 the top of the MacOS ROM) tells us which bytelanes, i.e. which byte
43 offsets within each longword, are valid. Thus:
44
45 A map of 0x0f, as found in the MacOS ROM, means that all bytelanes
46 are valid.
47
48 A map of 0xf0 means that no bytelanes are valid (We pray that we
49 will never encounter this, but stranger things have happened)
50
51 A map of 0xe1 means that only the MSB of each long word is actually
52 part of the card ROM. (We hope to never encounter NuBus on a
53 little-endian machine. Again, stranger things have happened)
54
55 A map of 0x78 means that only the LSB of each long word is valid.
56
57 Etcetera, etcetera. Hopefully this clears up some confusion over
58 what the following code actually does. */
Finn Thainf42e5552017-04-08 19:51:15 -040059
Linus Torvalds1da177e2005-04-16 15:20:36 -070060static inline int not_useful(void *p, int map)
61{
Finn Thainf42e5552017-04-08 19:51:15 -040062 unsigned long pv = (unsigned long)p;
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 pv &= 3;
Finn Thainf42e5552017-04-08 19:51:15 -040065 if (map & (1 << pv))
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 return 0;
67 return 1;
68}
Finn Thainf42e5552017-04-08 19:51:15 -040069
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static unsigned long nubus_get_rom(unsigned char **ptr, int len, int map)
71{
72 /* This will hold the result */
73 unsigned long v = 0;
74 unsigned char *p = *ptr;
75
Finn Thainf42e5552017-04-08 19:51:15 -040076 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 v <<= 8;
Finn Thainf42e5552017-04-08 19:51:15 -040078 while (not_useful(p, map))
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 p++;
80 v |= *p++;
81 len--;
82 }
83 *ptr = p;
84 return v;
85}
86
87static void nubus_rewind(unsigned char **ptr, int len, int map)
88{
Finn Thainf42e5552017-04-08 19:51:15 -040089 unsigned char *p = *ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Finn Thainf42e5552017-04-08 19:51:15 -040091 while (len) {
92 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 p--;
Finn Thainf42e5552017-04-08 19:51:15 -040094 } while (not_useful(p, map));
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 len--;
96 }
Finn Thainf42e5552017-04-08 19:51:15 -040097 *ptr = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098}
99
100static void nubus_advance(unsigned char **ptr, int len, int map)
101{
102 unsigned char *p = *ptr;
Finn Thainf42e5552017-04-08 19:51:15 -0400103
Finn Thainf42e5552017-04-08 19:51:15 -0400104 while (len) {
105 while (not_useful(p, map))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 p++;
Ilpo Järvinen2e0eb732008-10-15 22:01:31 -0700107 p++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 len--;
109 }
110 *ptr = p;
111}
112
113static void nubus_move(unsigned char **ptr, int len, int map)
114{
Finn Thain85cc3132017-04-22 21:24:16 -0400115 unsigned long slot_space = (unsigned long)*ptr & 0xFF000000;
116
Finn Thainf42e5552017-04-08 19:51:15 -0400117 if (len > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 nubus_advance(ptr, len, map);
Finn Thainf42e5552017-04-08 19:51:15 -0400119 else if (len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 nubus_rewind(ptr, -len, map);
Finn Thain85cc3132017-04-22 21:24:16 -0400121
122 if (((unsigned long)*ptr & 0xFF000000) != slot_space)
123 pr_err("%s: moved out of slot address space!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124}
125
126/* Now, functions to read the sResource tree */
127
128/* Each sResource entry consists of a 1-byte ID and a 3-byte data
129 field. If that data field contains an offset, then obviously we
130 have to expand it from a 24-bit signed number to a 32-bit signed
131 number. */
132
133static inline long nubus_expand32(long foo)
134{
Finn Thainf42e5552017-04-08 19:51:15 -0400135 if (foo & 0x00800000) /* 24bit negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 foo |= 0xFF000000;
137 return foo;
138}
139
140static inline void *nubus_rom_addr(int slot)
Finn Thainf42e5552017-04-08 19:51:15 -0400141{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 /*
143 * Returns the first byte after the card. We then walk
144 * backwards to get the lane register and the config
145 */
Finn Thainf42e5552017-04-08 19:51:15 -0400146 return (void *)(0xF1000000 + (slot << 24));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147}
148
Finn Thain2f7dd072018-01-13 17:37:13 -0500149unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150{
151 unsigned char *p = nd->base;
Finn Thainf42e5552017-04-08 19:51:15 -0400152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 /* Essentially, just step over the bytelanes using whatever
154 offset we might have found */
155 nubus_move(&p, nubus_expand32(nd->data), nd->mask);
156 /* And return the value */
157 return p;
158}
159
160/* These two are for pulling resource data blocks (i.e. stuff that's
161 pointed to with offsets) out of the card ROM. */
162
Finn Thainf42e5552017-04-08 19:51:15 -0400163void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
Finn Thain2f828fb2018-01-13 17:37:13 -0500164 unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165{
166 unsigned char *t = (unsigned char *)dest;
167 unsigned char *p = nubus_dirptr(dirent);
Finn Thainf42e5552017-04-08 19:51:15 -0400168
169 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 *t++ = nubus_get_rom(&p, 1, dirent->mask);
171 len--;
172 }
173}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800174EXPORT_SYMBOL(nubus_get_rsrc_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Finn Thain2f7dd072018-01-13 17:37:13 -0500176unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
177 unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178{
Finn Thain2f828fb2018-01-13 17:37:13 -0500179 char *t = dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 unsigned char *p = nubus_dirptr(dirent);
Finn Thainf42e5552017-04-08 19:51:15 -0400181
Finn Thain2f828fb2018-01-13 17:37:13 -0500182 while (len > 1) {
183 unsigned char c = nubus_get_rom(&p, 1, dirent->mask);
184
185 if (!c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 break;
Finn Thain2f828fb2018-01-13 17:37:13 -0500187 *t++ = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 len--;
189 }
Finn Thain2f828fb2018-01-13 17:37:13 -0500190 if (len > 0)
191 *t = '\0';
Finn Thain2f7dd072018-01-13 17:37:13 -0500192 return t - dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800194EXPORT_SYMBOL(nubus_get_rsrc_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Finn Thain2f7dd072018-01-13 17:37:13 -0500196void nubus_seq_write_rsrc_mem(struct seq_file *m,
197 const struct nubus_dirent *dirent,
198 unsigned int len)
199{
200 unsigned long buf[32];
201 unsigned int buf_size = sizeof(buf);
202 unsigned char *p = nubus_dirptr(dirent);
203
204 /* If possible, write out full buffers */
205 while (len >= buf_size) {
206 unsigned int i;
207
208 for (i = 0; i < ARRAY_SIZE(buf); i++)
209 buf[i] = nubus_get_rom(&p, sizeof(buf[0]),
210 dirent->mask);
211 seq_write(m, buf, buf_size);
212 len -= buf_size;
213 }
214 /* If not, write out individual bytes */
215 while (len--)
216 seq_putc(m, nubus_get_rom(&p, 1, dirent->mask));
217}
218
Finn Thainf42e5552017-04-08 19:51:15 -0400219int nubus_get_root_dir(const struct nubus_board *board,
220 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221{
222 dir->ptr = dir->base = board->directory;
223 dir->done = 0;
224 dir->mask = board->lanes;
225 return 0;
226}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800227EXPORT_SYMBOL(nubus_get_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229/* This is a slyly renamed version of the above */
Finn Thain189e19e2018-01-13 17:37:13 -0500230int nubus_get_func_dir(const struct nubus_rsrc *fres, struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Finn Thain189e19e2018-01-13 17:37:13 -0500232 dir->ptr = dir->base = fres->directory;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 dir->done = 0;
Finn Thain189e19e2018-01-13 17:37:13 -0500234 dir->mask = fres->board->lanes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 return 0;
236}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800237EXPORT_SYMBOL(nubus_get_func_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Finn Thainf42e5552017-04-08 19:51:15 -0400239int nubus_get_board_dir(const struct nubus_board *board,
240 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
242 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 dir->ptr = dir->base = board->directory;
245 dir->done = 0;
246 dir->mask = board->lanes;
247
248 /* Now dereference it (the first directory is always the board
249 directory) */
250 if (nubus_readdir(dir, &ent) == -1)
251 return -1;
252 if (nubus_get_subdir(&ent, dir) == -1)
253 return -1;
254 return 0;
255}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800256EXPORT_SYMBOL(nubus_get_board_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258int nubus_get_subdir(const struct nubus_dirent *ent,
259 struct nubus_dir *dir)
260{
261 dir->ptr = dir->base = nubus_dirptr(ent);
262 dir->done = 0;
263 dir->mask = ent->mask;
264 return 0;
265}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800266EXPORT_SYMBOL(nubus_get_subdir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
269{
270 u32 resid;
Finn Thainf42e5552017-04-08 19:51:15 -0400271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 if (nd->done)
273 return -1;
274
275 /* Do this first, otherwise nubus_rewind & co are off by 4 */
276 ent->base = nd->ptr;
277
278 /* This moves nd->ptr forward */
279 resid = nubus_get_rom(&nd->ptr, 4, nd->mask);
280
281 /* EOL marker, as per the Apple docs */
Finn Thainf42e5552017-04-08 19:51:15 -0400282 if ((resid & 0xff000000) == 0xff000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 /* Mark it as done */
284 nd->done = 1;
285 return -1;
286 }
287
288 /* First byte is the resource ID */
Finn Thainf42e5552017-04-08 19:51:15 -0400289 ent->type = resid >> 24;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 /* Low 3 bytes might contain data (or might not) */
291 ent->data = resid & 0xffffff;
Finn Thainf42e5552017-04-08 19:51:15 -0400292 ent->mask = nd->mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 return 0;
294}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800295EXPORT_SYMBOL(nubus_readdir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Finn Thainf42e5552017-04-08 19:51:15 -0400297int nubus_rewinddir(struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
299 dir->ptr = dir->base;
David Huggins-Dainese36b9912017-04-08 19:51:15 -0400300 dir->done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 return 0;
302}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800303EXPORT_SYMBOL(nubus_rewinddir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305/* Driver interface functions, more or less like in pci.c */
306
Finn Thain41b84812018-01-13 17:37:13 -0500307struct nubus_rsrc *nubus_first_rsrc_or_null(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308{
Finn Thain41b84812018-01-13 17:37:13 -0500309 return list_first_entry_or_null(&nubus_func_rsrcs, struct nubus_rsrc,
310 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311}
Finn Thain41b84812018-01-13 17:37:13 -0500312EXPORT_SYMBOL(nubus_first_rsrc_or_null);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Finn Thain41b84812018-01-13 17:37:13 -0500314struct nubus_rsrc *nubus_next_rsrc_or_null(struct nubus_rsrc *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
Finn Thain41b84812018-01-13 17:37:13 -0500316 if (list_is_last(&from->list, &nubus_func_rsrcs))
317 return NULL;
318 return list_next_entry(from, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319}
Finn Thain41b84812018-01-13 17:37:13 -0500320EXPORT_SYMBOL(nubus_next_rsrc_or_null);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322int
Finn Thainf42e5552017-04-08 19:51:15 -0400323nubus_find_rsrc(struct nubus_dir *dir, unsigned char rsrc_type,
324 struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
326 while (nubus_readdir(dir, ent) != -1) {
327 if (ent->type == rsrc_type)
328 return 0;
Finn Thainf42e5552017-04-08 19:51:15 -0400329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 return -1;
331}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800332EXPORT_SYMBOL(nubus_find_rsrc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
334/* Initialization functions - decide which slots contain stuff worth
335 looking at, and print out lots and lots of information from the
336 resource blocks. */
337
Finn Thain883b8cb2018-01-13 17:37:13 -0500338static int __init nubus_get_block_rsrc_dir(struct nubus_board *board,
Finn Thain2f7dd072018-01-13 17:37:13 -0500339 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500340 const struct nubus_dirent *parent)
341{
342 struct nubus_dir dir;
343 struct nubus_dirent ent;
344
345 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500346 dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
Finn Thain883b8cb2018-01-13 17:37:13 -0500347
348 while (nubus_readdir(&dir, &ent) != -1) {
349 u32 size;
350
351 nubus_get_rsrc_mem(&size, &ent, 4);
352 pr_debug(" block (0x%x), size %d\n", ent.type, size);
Finn Thain2f7dd072018-01-13 17:37:13 -0500353 nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
Finn Thain883b8cb2018-01-13 17:37:13 -0500354 }
355 return 0;
356}
357
358static int __init nubus_get_display_vidmode(struct nubus_board *board,
Finn Thain2f7dd072018-01-13 17:37:13 -0500359 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500360 const struct nubus_dirent *parent)
361{
362 struct nubus_dir dir;
363 struct nubus_dirent ent;
364
365 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500366 dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
Finn Thain883b8cb2018-01-13 17:37:13 -0500367
368 while (nubus_readdir(&dir, &ent) != -1) {
369 switch (ent.type) {
370 case 1: /* mVidParams */
371 case 2: /* mTable */
372 {
373 u32 size;
374
375 nubus_get_rsrc_mem(&size, &ent, 4);
376 pr_debug(" block (0x%x), size %d\n", ent.type,
377 size);
Finn Thain2f7dd072018-01-13 17:37:13 -0500378 nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
Finn Thain883b8cb2018-01-13 17:37:13 -0500379 break;
380 }
381 default:
382 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
383 ent.type, ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500384 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
Finn Thain883b8cb2018-01-13 17:37:13 -0500385 }
386 }
387 return 0;
388}
389
Finn Thain189e19e2018-01-13 17:37:13 -0500390static int __init nubus_get_display_resource(struct nubus_rsrc *fres,
Finn Thain2f7dd072018-01-13 17:37:13 -0500391 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500392 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
394 switch (ent->type) {
395 case NUBUS_RESID_GAMMADIR:
Finn Thainf53bad02018-01-13 17:37:13 -0500396 pr_debug(" gamma directory offset: 0x%06x\n", ent->data);
Finn Thain189e19e2018-01-13 17:37:13 -0500397 nubus_get_block_rsrc_dir(fres->board, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 break;
399 case 0x0080 ... 0x0085:
Finn Thainf53bad02018-01-13 17:37:13 -0500400 pr_debug(" mode 0x%02x info offset: 0x%06x\n",
401 ent->type, ent->data);
Finn Thain189e19e2018-01-13 17:37:13 -0500402 nubus_get_display_vidmode(fres->board, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 break;
404 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500405 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
406 ent->type, ent->data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500407 nubus_proc_add_rsrc_mem(procdir, ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 }
409 return 0;
410}
411
Finn Thain189e19e2018-01-13 17:37:13 -0500412static int __init nubus_get_network_resource(struct nubus_rsrc *fres,
Finn Thain2f7dd072018-01-13 17:37:13 -0500413 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500414 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 switch (ent->type) {
417 case NUBUS_RESID_MAC_ADDRESS:
418 {
419 char addr[6];
Finn Thainf42e5552017-04-08 19:51:15 -0400420
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 nubus_get_rsrc_mem(addr, ent, 6);
Finn Thainf53bad02018-01-13 17:37:13 -0500422 pr_debug(" MAC address: %pM\n", addr);
Finn Thain2f7dd072018-01-13 17:37:13 -0500423 nubus_proc_add_rsrc_mem(procdir, ent, 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 break;
425 }
426 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500427 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
428 ent->type, ent->data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500429 nubus_proc_add_rsrc_mem(procdir, ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 }
431 return 0;
432}
433
Finn Thain189e19e2018-01-13 17:37:13 -0500434static int __init nubus_get_cpu_resource(struct nubus_rsrc *fres,
Finn Thain2f7dd072018-01-13 17:37:13 -0500435 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500436 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 switch (ent->type) {
439 case NUBUS_RESID_MEMINFO:
440 {
441 unsigned long meminfo[2];
Finn Thainf42e5552017-04-08 19:51:15 -0400442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 nubus_get_rsrc_mem(&meminfo, ent, 8);
Finn Thainf53bad02018-01-13 17:37:13 -0500444 pr_debug(" memory: [ 0x%08lx 0x%08lx ]\n",
445 meminfo[0], meminfo[1]);
Finn Thain2f7dd072018-01-13 17:37:13 -0500446 nubus_proc_add_rsrc_mem(procdir, ent, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 break;
448 }
449 case NUBUS_RESID_ROMINFO:
450 {
451 unsigned long rominfo[2];
Finn Thainf42e5552017-04-08 19:51:15 -0400452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 nubus_get_rsrc_mem(&rominfo, ent, 8);
Finn Thainf53bad02018-01-13 17:37:13 -0500454 pr_debug(" ROM: [ 0x%08lx 0x%08lx ]\n",
455 rominfo[0], rominfo[1]);
Finn Thain2f7dd072018-01-13 17:37:13 -0500456 nubus_proc_add_rsrc_mem(procdir, ent, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 break;
458 }
459 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500460 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
461 ent->type, ent->data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500462 nubus_proc_add_rsrc_mem(procdir, ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 }
464 return 0;
465}
466
Finn Thain189e19e2018-01-13 17:37:13 -0500467static int __init nubus_get_private_resource(struct nubus_rsrc *fres,
Finn Thain2f7dd072018-01-13 17:37:13 -0500468 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500469 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
Finn Thain189e19e2018-01-13 17:37:13 -0500471 switch (fres->category) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 case NUBUS_CAT_DISPLAY:
Finn Thain189e19e2018-01-13 17:37:13 -0500473 nubus_get_display_resource(fres, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 break;
475 case NUBUS_CAT_NETWORK:
Finn Thain189e19e2018-01-13 17:37:13 -0500476 nubus_get_network_resource(fres, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 break;
478 case NUBUS_CAT_CPU:
Finn Thain189e19e2018-01-13 17:37:13 -0500479 nubus_get_cpu_resource(fres, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 break;
481 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500482 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
483 ent->type, ent->data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500484 nubus_proc_add_rsrc_mem(procdir, ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 }
486 return 0;
487}
488
Finn Thain189e19e2018-01-13 17:37:13 -0500489static struct nubus_rsrc * __init
Finn Thainf42e5552017-04-08 19:51:15 -0400490nubus_get_functional_resource(struct nubus_board *board, int slot,
491 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
Finn Thainf42e5552017-04-08 19:51:15 -0400493 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 struct nubus_dirent ent;
Finn Thain189e19e2018-01-13 17:37:13 -0500495 struct nubus_rsrc *fres;
Finn Thainf42e5552017-04-08 19:51:15 -0400496
Finn Thainf53bad02018-01-13 17:37:13 -0500497 pr_debug(" Functional resource 0x%02x:\n", parent->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500499 dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 /* Actually we should probably panic if this fails */
Finn Thain189e19e2018-01-13 17:37:13 -0500502 fres = kzalloc(sizeof(*fres), GFP_ATOMIC);
503 if (!fres)
Finn Thainf42e5552017-04-08 19:51:15 -0400504 return NULL;
Finn Thain189e19e2018-01-13 17:37:13 -0500505 fres->resid = parent->type;
506 fres->directory = dir.base;
507 fres->board = board;
Finn Thainf42e5552017-04-08 19:51:15 -0400508
509 while (nubus_readdir(&dir, &ent) != -1) {
510 switch (ent.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 case NUBUS_RESID_TYPE:
512 {
513 unsigned short nbtdata[4];
Finn Thainf42e5552017-04-08 19:51:15 -0400514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 nubus_get_rsrc_mem(nbtdata, &ent, 8);
Finn Thain189e19e2018-01-13 17:37:13 -0500516 fres->category = nbtdata[0];
517 fres->type = nbtdata[1];
518 fres->dr_sw = nbtdata[2];
519 fres->dr_hw = nbtdata[3];
Finn Thainf53bad02018-01-13 17:37:13 -0500520 pr_debug(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
521 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
Finn Thain2f7dd072018-01-13 17:37:13 -0500522 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 break;
524 }
525 case NUBUS_RESID_NAME:
526 {
Finn Thain9f979772018-01-13 17:37:13 -0500527 char name[64];
Finn Thain2f7dd072018-01-13 17:37:13 -0500528 unsigned int len;
Finn Thain9f979772018-01-13 17:37:13 -0500529
Finn Thain2f7dd072018-01-13 17:37:13 -0500530 len = nubus_get_rsrc_str(name, &ent, sizeof(name));
Finn Thain9f979772018-01-13 17:37:13 -0500531 pr_debug(" name: %s\n", name);
Finn Thain2f7dd072018-01-13 17:37:13 -0500532 nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 break;
534 }
535 case NUBUS_RESID_DRVRDIR:
536 {
537 /* MacOS driver. If we were NetBSD we might
538 use this :-) */
Finn Thain883b8cb2018-01-13 17:37:13 -0500539 pr_debug(" driver directory offset: 0x%06x\n",
540 ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500541 nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 break;
543 }
544 case NUBUS_RESID_MINOR_BASEOS:
Finn Thain9f979772018-01-13 17:37:13 -0500545 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 /* We will need this in order to support
547 multiple framebuffers. It might be handy
548 for Ethernet as well */
Finn Thain9f979772018-01-13 17:37:13 -0500549 u32 base_offset;
550
551 nubus_get_rsrc_mem(&base_offset, &ent, 4);
552 pr_debug(" memory offset: 0x%08x\n", base_offset);
Finn Thain2f7dd072018-01-13 17:37:13 -0500553 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 break;
Finn Thain9f979772018-01-13 17:37:13 -0500555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 case NUBUS_RESID_MINOR_LENGTH:
Finn Thain9f979772018-01-13 17:37:13 -0500557 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 /* Ditto */
Finn Thain9f979772018-01-13 17:37:13 -0500559 u32 length;
560
561 nubus_get_rsrc_mem(&length, &ent, 4);
562 pr_debug(" memory length: 0x%08x\n", length);
Finn Thain2f7dd072018-01-13 17:37:13 -0500563 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
Finn Thainf42e5552017-04-08 19:51:15 -0400564 break;
Finn Thain9f979772018-01-13 17:37:13 -0500565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 case NUBUS_RESID_FLAGS:
Finn Thain9f979772018-01-13 17:37:13 -0500567 pr_debug(" flags: 0x%06x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500568 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 break;
570 case NUBUS_RESID_HWDEVID:
Finn Thain9f979772018-01-13 17:37:13 -0500571 pr_debug(" hwdevid: 0x%06x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500572 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 break;
574 default:
575 /* Local/Private resources have their own
576 function */
Finn Thain189e19e2018-01-13 17:37:13 -0500577 nubus_get_private_resource(fres, dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 }
579 }
Finn Thainf42e5552017-04-08 19:51:15 -0400580
Finn Thain189e19e2018-01-13 17:37:13 -0500581 return fres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582}
583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584/* This is *really* cool. */
Finn Thainf42e5552017-04-08 19:51:15 -0400585static int __init nubus_get_icon(struct nubus_board *board,
Finn Thain2f7dd072018-01-13 17:37:13 -0500586 struct proc_dir_entry *procdir,
Finn Thainf42e5552017-04-08 19:51:15 -0400587 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
589 /* Should be 32x32 if my memory serves me correctly */
Finn Thainf53bad02018-01-13 17:37:13 -0500590 u32 icon[32];
591 int i;
Finn Thainf42e5552017-04-08 19:51:15 -0400592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 nubus_get_rsrc_mem(&icon, ent, 128);
Finn Thainf53bad02018-01-13 17:37:13 -0500594 pr_debug(" icon:\n");
595 for (i = 0; i < 8; i++)
596 pr_debug(" %08x %08x %08x %08x\n",
597 icon[i * 4 + 0], icon[i * 4 + 1],
598 icon[i * 4 + 2], icon[i * 4 + 3]);
Finn Thain2f7dd072018-01-13 17:37:13 -0500599 nubus_proc_add_rsrc_mem(procdir, ent, 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 return 0;
602}
603
Finn Thainf42e5552017-04-08 19:51:15 -0400604static int __init nubus_get_vendorinfo(struct nubus_board *board,
Finn Thain2f7dd072018-01-13 17:37:13 -0500605 struct proc_dir_entry *procdir,
Finn Thainf42e5552017-04-08 19:51:15 -0400606 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
Finn Thainf42e5552017-04-08 19:51:15 -0400608 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400610 static char *vendor_fields[6] = { "ID", "serial", "revision",
611 "part", "date", "unknown field" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Finn Thainf53bad02018-01-13 17:37:13 -0500613 pr_debug(" vendor info:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500615 dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
Finn Thainf42e5552017-04-08 19:51:15 -0400617 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 char name[64];
Finn Thain2f7dd072018-01-13 17:37:13 -0500619 unsigned int len;
Finn Thainf42e5552017-04-08 19:51:15 -0400620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 /* These are all strings, we think */
Finn Thain2f7dd072018-01-13 17:37:13 -0500622 len = nubus_get_rsrc_str(name, &ent, sizeof(name));
Finn Thain2f828fb2018-01-13 17:37:13 -0500623 if (ent.type < 1 || ent.type > 5)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 ent.type = 5;
Finn Thainf53bad02018-01-13 17:37:13 -0500625 pr_debug(" %s: %s\n", vendor_fields[ent.type - 1], name);
Finn Thain2f7dd072018-01-13 17:37:13 -0500626 nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
628 return 0;
629}
630
Finn Thainf42e5552017-04-08 19:51:15 -0400631static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
632 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
Finn Thainf42e5552017-04-08 19:51:15 -0400634 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400636
Finn Thainf53bad02018-01-13 17:37:13 -0500637 pr_debug(" Board resource 0x%02x:\n", parent->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500639 dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Finn Thainf42e5552017-04-08 19:51:15 -0400641 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 switch (ent.type) {
643 case NUBUS_RESID_TYPE:
644 {
645 unsigned short nbtdata[4];
646 /* This type is always the same, and is not
647 useful except insofar as it tells us that
648 we really are looking at a board resource. */
649 nubus_get_rsrc_mem(nbtdata, &ent, 8);
Finn Thainf53bad02018-01-13 17:37:13 -0500650 pr_debug(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
651 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
653 nbtdata[2] != 0 || nbtdata[3] != 0)
Finn Thaind7811a32018-01-13 17:37:13 -0500654 pr_err("Slot %X: sResource is not a board resource!\n",
655 slot);
Finn Thain2f7dd072018-01-13 17:37:13 -0500656 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 break;
658 }
659 case NUBUS_RESID_NAME:
Finn Thain2f7dd072018-01-13 17:37:13 -0500660 {
661 unsigned int len;
662
663 len = nubus_get_rsrc_str(board->name, &ent,
664 sizeof(board->name));
Finn Thainf53bad02018-01-13 17:37:13 -0500665 pr_debug(" name: %s\n", board->name);
Finn Thain2f7dd072018-01-13 17:37:13 -0500666 nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 break;
Finn Thain2f7dd072018-01-13 17:37:13 -0500668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 case NUBUS_RESID_ICON:
Finn Thain2f7dd072018-01-13 17:37:13 -0500670 nubus_get_icon(board, dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 break;
672 case NUBUS_RESID_BOARDID:
Finn Thainf53bad02018-01-13 17:37:13 -0500673 pr_debug(" board id: 0x%x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500674 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 break;
676 case NUBUS_RESID_PRIMARYINIT:
Finn Thainf53bad02018-01-13 17:37:13 -0500677 pr_debug(" primary init offset: 0x%06x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500678 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 break;
680 case NUBUS_RESID_VENDORINFO:
Finn Thain2f7dd072018-01-13 17:37:13 -0500681 nubus_get_vendorinfo(board, dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 break;
683 case NUBUS_RESID_FLAGS:
Finn Thainf53bad02018-01-13 17:37:13 -0500684 pr_debug(" flags: 0x%06x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500685 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 break;
687 case NUBUS_RESID_HWDEVID:
Finn Thainf53bad02018-01-13 17:37:13 -0500688 pr_debug(" hwdevid: 0x%06x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500689 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 break;
691 case NUBUS_RESID_SECONDINIT:
Finn Thainf53bad02018-01-13 17:37:13 -0500692 pr_debug(" secondary init offset: 0x%06x\n",
693 ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500694 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 break;
Finn Thainf42e5552017-04-08 19:51:15 -0400696 /* WTF isn't this in the functional resources? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 case NUBUS_RESID_VIDNAMES:
Finn Thain883b8cb2018-01-13 17:37:13 -0500698 pr_debug(" vidnames directory offset: 0x%06x\n",
699 ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500700 nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 break;
702 /* Same goes for this */
703 case NUBUS_RESID_VIDMODES:
Finn Thainf53bad02018-01-13 17:37:13 -0500704 pr_debug(" video mode parameter directory offset: 0x%06x\n",
705 ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500706 nubus_proc_add_rsrc(dir.procdir, &ent);
Finn Thainf42e5552017-04-08 19:51:15 -0400707 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500709 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
710 ent.type, ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500711 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 }
713 }
714 return 0;
715}
716
Finn Thain7f86c762018-01-13 17:37:14 -0500717static void __init nubus_add_board(int slot, int bytelanes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
Finn Thainf42e5552017-04-08 19:51:15 -0400719 struct nubus_board *board;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 unsigned char *rp;
721 unsigned long dpat;
722 struct nubus_dir dir;
723 struct nubus_dirent ent;
Finn Thaind7811a32018-01-13 17:37:13 -0500724 int prev_resid = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 /* Move to the start of the format block */
Finn Thainf42e5552017-04-08 19:51:15 -0400727 rp = nubus_rom_addr(slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
729
730 /* Actually we should probably panic if this fails */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700731 if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
Finn Thain7f86c762018-01-13 17:37:14 -0500732 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 board->fblock = rp;
734
735 /* Dump the format block for debugging purposes */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400736 pr_debug("Slot %X, format block at 0x%p:\n", slot, rp);
Finn Thainf53bad02018-01-13 17:37:13 -0500737 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
738 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
739 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400740 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
741 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
742 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
743 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
744 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400745 rp = board->fblock;
746
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 board->slot = slot;
Finn Thainf42e5552017-04-08 19:51:15 -0400748 board->slot_addr = (unsigned long)nubus_slot_addr(slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 board->doffset = nubus_get_rom(&rp, 4, bytelanes);
750 /* rom_length is *supposed* to be the total length of the
751 * ROM. In practice it is the "amount of ROM used to compute
752 * the CRC." So some jokers decide to set it to zero and
753 * set the crc to zero so they don't have to do any math.
754 * See the Performa 460 ROM, for example. Those Apple "engineers".
755 */
756 board->rom_length = nubus_get_rom(&rp, 4, bytelanes);
757 board->crc = nubus_get_rom(&rp, 4, bytelanes);
758 board->rev = nubus_get_rom(&rp, 1, bytelanes);
Finn Thainf42e5552017-04-08 19:51:15 -0400759 board->format = nubus_get_rom(&rp, 1, bytelanes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 board->lanes = bytelanes;
761
762 /* Directory offset should be small and negative... */
Finn Thainf42e5552017-04-08 19:51:15 -0400763 if (!(board->doffset & 0x00FF0000))
Finn Thaind7811a32018-01-13 17:37:13 -0500764 pr_warn("Slot %X: Dodgy doffset!\n", slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 dpat = nubus_get_rom(&rp, 4, bytelanes);
Finn Thainf42e5552017-04-08 19:51:15 -0400766 if (dpat != NUBUS_TEST_PATTERN)
Finn Thaind7811a32018-01-13 17:37:13 -0500767 pr_warn("Slot %X: Wrong test pattern %08lx!\n", slot, dpat);
Finn Thainf42e5552017-04-08 19:51:15 -0400768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 /*
770 * I wonder how the CRC is meant to work -
771 * any takers ?
772 * CSA: According to MAC docs, not all cards pass the CRC anyway,
773 * since the initial Macintosh ROM releases skipped the check.
774 */
775
David Huggins-Daines475e6e12017-04-22 21:24:16 -0400776 /* Set up the directory pointer */
777 board->directory = board->fblock;
778 nubus_move(&board->directory, nubus_expand32(board->doffset),
779 board->lanes);
780
Finn Thainf42e5552017-04-08 19:51:15 -0400781 nubus_get_root_dir(board, &dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 /* We're ready to rock */
Finn Thainf53bad02018-01-13 17:37:13 -0500784 pr_debug("Slot %X resources:\n", slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
786 /* Each slot should have one board resource and any number of
Finn Thain189e19e2018-01-13 17:37:13 -0500787 * functional resources. So we'll fill in some fields in the
788 * struct nubus_board from the board resource, then walk down
789 * the list of functional resources, spinning out a nubus_rsrc
790 * for each of them.
791 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 if (nubus_readdir(&dir, &ent) == -1) {
793 /* We can't have this! */
Finn Thaind7811a32018-01-13 17:37:13 -0500794 pr_err("Slot %X: Board resource not found!\n", slot);
Finn Thain7f86c762018-01-13 17:37:14 -0500795 kfree(board);
796 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 }
798
Finn Thaind7811a32018-01-13 17:37:13 -0500799 if (ent.type < 1 || ent.type > 127)
800 pr_warn("Slot %X: Board resource ID is invalid!\n", slot);
801
Finn Thain2f7dd072018-01-13 17:37:13 -0500802 board->procdir = nubus_proc_add_board(board);
803
Finn Thaind7811a32018-01-13 17:37:13 -0500804 nubus_get_board_resource(board, slot, &ent);
805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 while (nubus_readdir(&dir, &ent) != -1) {
Finn Thain189e19e2018-01-13 17:37:13 -0500807 struct nubus_rsrc *fres;
Finn Thainf42e5552017-04-08 19:51:15 -0400808
Finn Thain189e19e2018-01-13 17:37:13 -0500809 fres = nubus_get_functional_resource(board, slot, &ent);
810 if (fres == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 continue;
812
Finn Thaind7811a32018-01-13 17:37:13 -0500813 /* Resources should appear in ascending ID order. This sanity
814 * check prevents duplicate resource IDs.
815 */
Finn Thain189e19e2018-01-13 17:37:13 -0500816 if (fres->resid <= prev_resid) {
817 kfree(fres);
Finn Thaind7811a32018-01-13 17:37:13 -0500818 continue;
819 }
Finn Thain189e19e2018-01-13 17:37:13 -0500820 prev_resid = fres->resid;
Finn Thaind7811a32018-01-13 17:37:13 -0500821
Finn Thain41b84812018-01-13 17:37:13 -0500822 list_add_tail(&fres->list, &nubus_func_rsrcs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 }
824
Finn Thain7f86c762018-01-13 17:37:14 -0500825 if (nubus_device_register(board))
826 put_device(&board->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827}
828
Finn Thain460cf952018-01-13 17:37:13 -0500829static void __init nubus_probe_slot(int slot)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830{
831 unsigned char dp;
Finn Thainf42e5552017-04-08 19:51:15 -0400832 unsigned char *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 int i;
834
Finn Thainf42e5552017-04-08 19:51:15 -0400835 rp = nubus_rom_addr(slot);
836 for (i = 4; i; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 rp--;
Finn Thain9f979772018-01-13 17:37:13 -0500838 if (!hwreg_present(rp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 continue;
840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 dp = *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843 /* The last byte of the format block consists of two
844 nybbles which are "mirror images" of each other.
845 These show us the valid bytelanes */
Finn Thainf42e5552017-04-08 19:51:15 -0400846 if ((((dp >> 4) ^ dp) & 0x0F) != 0x0F)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 continue;
848 /* Check that this value is actually *on* one of the
849 bytelanes it claims are valid! */
Finn Thain85cc3132017-04-22 21:24:16 -0400850 if (not_useful(rp, dp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 continue;
852
853 /* Looks promising. Let's put it on the list. */
854 nubus_add_board(slot, dp);
855
856 return;
857 }
858}
859
Finn Thain460cf952018-01-13 17:37:13 -0500860static void __init nubus_scan_bus(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
862 int slot;
Finn Thainf42e5552017-04-08 19:51:15 -0400863
Finn Thainf53bad02018-01-13 17:37:13 -0500864 pr_info("NuBus: Scanning NuBus slots.\n");
Finn Thainf42e5552017-04-08 19:51:15 -0400865 for (slot = 9; slot < 15; slot++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 nubus_probe_slot(slot);
867 }
868}
869
870static int __init nubus_init(void)
871{
Finn Thain7f86c762018-01-13 17:37:14 -0500872 int err;
873
Finn Thainf42e5552017-04-08 19:51:15 -0400874 if (!MACH_IS_MAC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 return 0;
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 nubus_proc_init();
Finn Thainbdeeed02018-05-09 11:04:48 +1000878 err = nubus_parent_device_register();
Finn Thain7f86c762018-01-13 17:37:14 -0500879 if (err)
880 return err;
Finn Thain2f7dd072018-01-13 17:37:13 -0500881 nubus_scan_bus();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return 0;
883}
884
885subsys_initcall(nubus_init);