blob: ab0f32b901c84f52045096a904a5f50996eab30f [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 Thain72b44f62023-05-16 11:22:05 +100035/* The "nubus.populate_procfs" parameter makes slot resources available in
36 * procfs. It's deprecated and disabled by default because procfs is no longer
37 * thought to be suitable for that and some board ROMs make it too expensive.
38 */
39bool nubus_populate_procfs;
40module_param_named(populate_procfs, nubus_populate_procfs, bool, 0);
41
Finn Thain41b84812018-01-13 17:37:13 -050042LIST_HEAD(nubus_func_rsrcs);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44/* Meaning of "bytelanes":
45
46 The card ROM may appear on any or all bytes of each long word in
47 NuBus memory. The low 4 bits of the "map" value found in the
48 format block (at the top of the slot address space, as well as at
49 the top of the MacOS ROM) tells us which bytelanes, i.e. which byte
50 offsets within each longword, are valid. Thus:
51
52 A map of 0x0f, as found in the MacOS ROM, means that all bytelanes
53 are valid.
54
55 A map of 0xf0 means that no bytelanes are valid (We pray that we
56 will never encounter this, but stranger things have happened)
57
58 A map of 0xe1 means that only the MSB of each long word is actually
59 part of the card ROM. (We hope to never encounter NuBus on a
60 little-endian machine. Again, stranger things have happened)
61
62 A map of 0x78 means that only the LSB of each long word is valid.
63
64 Etcetera, etcetera. Hopefully this clears up some confusion over
65 what the following code actually does. */
Finn Thainf42e5552017-04-08 19:51:15 -040066
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static inline int not_useful(void *p, int map)
68{
Finn Thainf42e5552017-04-08 19:51:15 -040069 unsigned long pv = (unsigned long)p;
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 pv &= 3;
Finn Thainf42e5552017-04-08 19:51:15 -040072 if (map & (1 << pv))
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 return 0;
74 return 1;
75}
Finn Thainf42e5552017-04-08 19:51:15 -040076
Linus Torvalds1da177e2005-04-16 15:20:36 -070077static unsigned long nubus_get_rom(unsigned char **ptr, int len, int map)
78{
79 /* This will hold the result */
80 unsigned long v = 0;
81 unsigned char *p = *ptr;
82
Finn Thainf42e5552017-04-08 19:51:15 -040083 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 v <<= 8;
Finn Thainf42e5552017-04-08 19:51:15 -040085 while (not_useful(p, map))
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 p++;
87 v |= *p++;
88 len--;
89 }
90 *ptr = p;
91 return v;
92}
93
94static void nubus_rewind(unsigned char **ptr, int len, int map)
95{
Finn Thainf42e5552017-04-08 19:51:15 -040096 unsigned char *p = *ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Finn Thainf42e5552017-04-08 19:51:15 -040098 while (len) {
99 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 p--;
Finn Thainf42e5552017-04-08 19:51:15 -0400101 } while (not_useful(p, map));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 len--;
103 }
Finn Thainf42e5552017-04-08 19:51:15 -0400104 *ptr = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105}
106
107static void nubus_advance(unsigned char **ptr, int len, int map)
108{
109 unsigned char *p = *ptr;
Finn Thainf42e5552017-04-08 19:51:15 -0400110
Finn Thainf42e5552017-04-08 19:51:15 -0400111 while (len) {
112 while (not_useful(p, map))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 p++;
Ilpo Järvinen2e0eb732008-10-15 22:01:31 -0700114 p++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 len--;
116 }
117 *ptr = p;
118}
119
120static void nubus_move(unsigned char **ptr, int len, int map)
121{
Finn Thain85cc3132017-04-22 21:24:16 -0400122 unsigned long slot_space = (unsigned long)*ptr & 0xFF000000;
123
Finn Thainf42e5552017-04-08 19:51:15 -0400124 if (len > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 nubus_advance(ptr, len, map);
Finn Thainf42e5552017-04-08 19:51:15 -0400126 else if (len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 nubus_rewind(ptr, -len, map);
Finn Thain85cc3132017-04-22 21:24:16 -0400128
129 if (((unsigned long)*ptr & 0xFF000000) != slot_space)
130 pr_err("%s: moved out of slot address space!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
133/* Now, functions to read the sResource tree */
134
135/* Each sResource entry consists of a 1-byte ID and a 3-byte data
136 field. If that data field contains an offset, then obviously we
137 have to expand it from a 24-bit signed number to a 32-bit signed
138 number. */
139
140static inline long nubus_expand32(long foo)
141{
Finn Thainf42e5552017-04-08 19:51:15 -0400142 if (foo & 0x00800000) /* 24bit negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 foo |= 0xFF000000;
144 return foo;
145}
146
147static inline void *nubus_rom_addr(int slot)
Finn Thainf42e5552017-04-08 19:51:15 -0400148{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 /*
150 * Returns the first byte after the card. We then walk
151 * backwards to get the lane register and the config
152 */
Finn Thainf42e5552017-04-08 19:51:15 -0400153 return (void *)(0xF1000000 + (slot << 24));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154}
155
Finn Thain2f7dd072018-01-13 17:37:13 -0500156unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
158 unsigned char *p = nd->base;
Finn Thainf42e5552017-04-08 19:51:15 -0400159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 /* Essentially, just step over the bytelanes using whatever
161 offset we might have found */
162 nubus_move(&p, nubus_expand32(nd->data), nd->mask);
163 /* And return the value */
164 return p;
165}
166
167/* These two are for pulling resource data blocks (i.e. stuff that's
168 pointed to with offsets) out of the card ROM. */
169
Finn Thainf42e5552017-04-08 19:51:15 -0400170void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
Finn Thain2f828fb2018-01-13 17:37:13 -0500171 unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
Himanshu Jha51b67a62017-08-27 13:02:28 +0530173 unsigned char *t = dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 unsigned char *p = nubus_dirptr(dirent);
Finn Thainf42e5552017-04-08 19:51:15 -0400175
176 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 *t++ = nubus_get_rom(&p, 1, dirent->mask);
178 len--;
179 }
180}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800181EXPORT_SYMBOL(nubus_get_rsrc_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Finn Thain2f7dd072018-01-13 17:37:13 -0500183unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
184 unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
Finn Thain2f828fb2018-01-13 17:37:13 -0500186 char *t = dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 unsigned char *p = nubus_dirptr(dirent);
Finn Thainf42e5552017-04-08 19:51:15 -0400188
Finn Thain2f828fb2018-01-13 17:37:13 -0500189 while (len > 1) {
190 unsigned char c = nubus_get_rom(&p, 1, dirent->mask);
191
192 if (!c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 break;
Finn Thain2f828fb2018-01-13 17:37:13 -0500194 *t++ = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 len--;
196 }
Finn Thain2f828fb2018-01-13 17:37:13 -0500197 if (len > 0)
198 *t = '\0';
Finn Thain2f7dd072018-01-13 17:37:13 -0500199 return t - dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800201EXPORT_SYMBOL(nubus_get_rsrc_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Finn Thain2f7dd072018-01-13 17:37:13 -0500203void nubus_seq_write_rsrc_mem(struct seq_file *m,
204 const struct nubus_dirent *dirent,
205 unsigned int len)
206{
207 unsigned long buf[32];
208 unsigned int buf_size = sizeof(buf);
209 unsigned char *p = nubus_dirptr(dirent);
210
211 /* If possible, write out full buffers */
212 while (len >= buf_size) {
213 unsigned int i;
214
215 for (i = 0; i < ARRAY_SIZE(buf); i++)
216 buf[i] = nubus_get_rom(&p, sizeof(buf[0]),
217 dirent->mask);
218 seq_write(m, buf, buf_size);
219 len -= buf_size;
220 }
221 /* If not, write out individual bytes */
222 while (len--)
223 seq_putc(m, nubus_get_rom(&p, 1, dirent->mask));
224}
225
Finn Thainf42e5552017-04-08 19:51:15 -0400226int nubus_get_root_dir(const struct nubus_board *board,
227 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 dir->ptr = dir->base = board->directory;
230 dir->done = 0;
231 dir->mask = board->lanes;
232 return 0;
233}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800234EXPORT_SYMBOL(nubus_get_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
236/* This is a slyly renamed version of the above */
Finn Thain189e19e2018-01-13 17:37:13 -0500237int nubus_get_func_dir(const struct nubus_rsrc *fres, struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238{
Finn Thain189e19e2018-01-13 17:37:13 -0500239 dir->ptr = dir->base = fres->directory;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 dir->done = 0;
Finn Thain189e19e2018-01-13 17:37:13 -0500241 dir->mask = fres->board->lanes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 return 0;
243}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800244EXPORT_SYMBOL(nubus_get_func_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Finn Thainf42e5552017-04-08 19:51:15 -0400246int nubus_get_board_dir(const struct nubus_board *board,
247 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
249 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 dir->ptr = dir->base = board->directory;
252 dir->done = 0;
253 dir->mask = board->lanes;
254
255 /* Now dereference it (the first directory is always the board
256 directory) */
257 if (nubus_readdir(dir, &ent) == -1)
258 return -1;
259 if (nubus_get_subdir(&ent, dir) == -1)
260 return -1;
261 return 0;
262}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800263EXPORT_SYMBOL(nubus_get_board_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265int nubus_get_subdir(const struct nubus_dirent *ent,
266 struct nubus_dir *dir)
267{
268 dir->ptr = dir->base = nubus_dirptr(ent);
269 dir->done = 0;
270 dir->mask = ent->mask;
271 return 0;
272}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800273EXPORT_SYMBOL(nubus_get_subdir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
276{
277 u32 resid;
Finn Thainf42e5552017-04-08 19:51:15 -0400278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 if (nd->done)
280 return -1;
281
282 /* Do this first, otherwise nubus_rewind & co are off by 4 */
283 ent->base = nd->ptr;
284
285 /* This moves nd->ptr forward */
286 resid = nubus_get_rom(&nd->ptr, 4, nd->mask);
287
288 /* EOL marker, as per the Apple docs */
Finn Thainf42e5552017-04-08 19:51:15 -0400289 if ((resid & 0xff000000) == 0xff000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 /* Mark it as done */
291 nd->done = 1;
292 return -1;
293 }
294
295 /* First byte is the resource ID */
Finn Thainf42e5552017-04-08 19:51:15 -0400296 ent->type = resid >> 24;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 /* Low 3 bytes might contain data (or might not) */
298 ent->data = resid & 0xffffff;
Finn Thainf42e5552017-04-08 19:51:15 -0400299 ent->mask = nd->mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 return 0;
301}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800302EXPORT_SYMBOL(nubus_readdir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Finn Thainf42e5552017-04-08 19:51:15 -0400304int nubus_rewinddir(struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
306 dir->ptr = dir->base;
David Huggins-Dainese36b9912017-04-08 19:51:15 -0400307 dir->done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 return 0;
309}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800310EXPORT_SYMBOL(nubus_rewinddir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312/* Driver interface functions, more or less like in pci.c */
313
Finn Thain41b84812018-01-13 17:37:13 -0500314struct nubus_rsrc *nubus_first_rsrc_or_null(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
Finn Thain41b84812018-01-13 17:37:13 -0500316 return list_first_entry_or_null(&nubus_func_rsrcs, struct nubus_rsrc,
317 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318}
Finn Thain41b84812018-01-13 17:37:13 -0500319EXPORT_SYMBOL(nubus_first_rsrc_or_null);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Finn Thain41b84812018-01-13 17:37:13 -0500321struct nubus_rsrc *nubus_next_rsrc_or_null(struct nubus_rsrc *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
Finn Thain41b84812018-01-13 17:37:13 -0500323 if (list_is_last(&from->list, &nubus_func_rsrcs))
324 return NULL;
325 return list_next_entry(from, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
Finn Thain41b84812018-01-13 17:37:13 -0500327EXPORT_SYMBOL(nubus_next_rsrc_or_null);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329int
Finn Thainf42e5552017-04-08 19:51:15 -0400330nubus_find_rsrc(struct nubus_dir *dir, unsigned char rsrc_type,
331 struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
333 while (nubus_readdir(dir, ent) != -1) {
334 if (ent->type == rsrc_type)
335 return 0;
Finn Thainf42e5552017-04-08 19:51:15 -0400336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 return -1;
338}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800339EXPORT_SYMBOL(nubus_find_rsrc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341/* Initialization functions - decide which slots contain stuff worth
342 looking at, and print out lots and lots of information from the
343 resource blocks. */
344
Finn Thain883b8cb2018-01-13 17:37:13 -0500345static int __init nubus_get_block_rsrc_dir(struct nubus_board *board,
Finn Thain2f7dd072018-01-13 17:37:13 -0500346 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500347 const struct nubus_dirent *parent)
348{
349 struct nubus_dir dir;
350 struct nubus_dirent ent;
351
352 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500353 dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
Finn Thain883b8cb2018-01-13 17:37:13 -0500354
355 while (nubus_readdir(&dir, &ent) != -1) {
356 u32 size;
357
358 nubus_get_rsrc_mem(&size, &ent, 4);
359 pr_debug(" block (0x%x), size %d\n", ent.type, size);
Finn Thain2f7dd072018-01-13 17:37:13 -0500360 nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
Finn Thain883b8cb2018-01-13 17:37:13 -0500361 }
362 return 0;
363}
364
365static int __init nubus_get_display_vidmode(struct nubus_board *board,
Finn Thain2f7dd072018-01-13 17:37:13 -0500366 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500367 const struct nubus_dirent *parent)
368{
369 struct nubus_dir dir;
370 struct nubus_dirent ent;
371
372 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500373 dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
Finn Thain883b8cb2018-01-13 17:37:13 -0500374
375 while (nubus_readdir(&dir, &ent) != -1) {
376 switch (ent.type) {
377 case 1: /* mVidParams */
378 case 2: /* mTable */
379 {
380 u32 size;
381
382 nubus_get_rsrc_mem(&size, &ent, 4);
383 pr_debug(" block (0x%x), size %d\n", ent.type,
384 size);
Finn Thain2f7dd072018-01-13 17:37:13 -0500385 nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
Finn Thain883b8cb2018-01-13 17:37:13 -0500386 break;
387 }
388 default:
389 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
390 ent.type, ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500391 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
Finn Thain883b8cb2018-01-13 17:37:13 -0500392 }
393 }
394 return 0;
395}
396
Finn Thain189e19e2018-01-13 17:37:13 -0500397static int __init nubus_get_display_resource(struct nubus_rsrc *fres,
Finn Thain2f7dd072018-01-13 17:37:13 -0500398 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500399 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
401 switch (ent->type) {
402 case NUBUS_RESID_GAMMADIR:
Finn Thainf53bad02018-01-13 17:37:13 -0500403 pr_debug(" gamma directory offset: 0x%06x\n", ent->data);
Finn Thain189e19e2018-01-13 17:37:13 -0500404 nubus_get_block_rsrc_dir(fres->board, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 break;
406 case 0x0080 ... 0x0085:
Finn Thainf53bad02018-01-13 17:37:13 -0500407 pr_debug(" mode 0x%02x info offset: 0x%06x\n",
408 ent->type, ent->data);
Finn Thain189e19e2018-01-13 17:37:13 -0500409 nubus_get_display_vidmode(fres->board, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 break;
411 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500412 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
413 ent->type, ent->data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500414 nubus_proc_add_rsrc_mem(procdir, ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 }
416 return 0;
417}
418
Finn Thain189e19e2018-01-13 17:37:13 -0500419static int __init nubus_get_network_resource(struct nubus_rsrc *fres,
Finn Thain2f7dd072018-01-13 17:37:13 -0500420 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500421 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
423 switch (ent->type) {
424 case NUBUS_RESID_MAC_ADDRESS:
425 {
426 char addr[6];
Finn Thainf42e5552017-04-08 19:51:15 -0400427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 nubus_get_rsrc_mem(addr, ent, 6);
Finn Thainf53bad02018-01-13 17:37:13 -0500429 pr_debug(" MAC address: %pM\n", addr);
Finn Thain2f7dd072018-01-13 17:37:13 -0500430 nubus_proc_add_rsrc_mem(procdir, ent, 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 break;
432 }
433 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500434 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
435 ent->type, ent->data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500436 nubus_proc_add_rsrc_mem(procdir, ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
438 return 0;
439}
440
Finn Thain189e19e2018-01-13 17:37:13 -0500441static int __init nubus_get_cpu_resource(struct nubus_rsrc *fres,
Finn Thain2f7dd072018-01-13 17:37:13 -0500442 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500443 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
445 switch (ent->type) {
446 case NUBUS_RESID_MEMINFO:
447 {
448 unsigned long meminfo[2];
Finn Thainf42e5552017-04-08 19:51:15 -0400449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 nubus_get_rsrc_mem(&meminfo, ent, 8);
Finn Thainf53bad02018-01-13 17:37:13 -0500451 pr_debug(" memory: [ 0x%08lx 0x%08lx ]\n",
452 meminfo[0], meminfo[1]);
Finn Thain2f7dd072018-01-13 17:37:13 -0500453 nubus_proc_add_rsrc_mem(procdir, ent, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 break;
455 }
456 case NUBUS_RESID_ROMINFO:
457 {
458 unsigned long rominfo[2];
Finn Thainf42e5552017-04-08 19:51:15 -0400459
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 nubus_get_rsrc_mem(&rominfo, ent, 8);
Finn Thainf53bad02018-01-13 17:37:13 -0500461 pr_debug(" ROM: [ 0x%08lx 0x%08lx ]\n",
462 rominfo[0], rominfo[1]);
Finn Thain2f7dd072018-01-13 17:37:13 -0500463 nubus_proc_add_rsrc_mem(procdir, ent, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 break;
465 }
466 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500467 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
468 ent->type, ent->data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500469 nubus_proc_add_rsrc_mem(procdir, ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 }
471 return 0;
472}
473
Finn Thain189e19e2018-01-13 17:37:13 -0500474static int __init nubus_get_private_resource(struct nubus_rsrc *fres,
Finn Thain2f7dd072018-01-13 17:37:13 -0500475 struct proc_dir_entry *procdir,
Finn Thain883b8cb2018-01-13 17:37:13 -0500476 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
Finn Thain189e19e2018-01-13 17:37:13 -0500478 switch (fres->category) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 case NUBUS_CAT_DISPLAY:
Finn Thain189e19e2018-01-13 17:37:13 -0500480 nubus_get_display_resource(fres, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 break;
482 case NUBUS_CAT_NETWORK:
Finn Thain189e19e2018-01-13 17:37:13 -0500483 nubus_get_network_resource(fres, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 break;
485 case NUBUS_CAT_CPU:
Finn Thain189e19e2018-01-13 17:37:13 -0500486 nubus_get_cpu_resource(fres, procdir, ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 break;
488 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500489 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
490 ent->type, ent->data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500491 nubus_proc_add_rsrc_mem(procdir, ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
493 return 0;
494}
495
Finn Thain189e19e2018-01-13 17:37:13 -0500496static struct nubus_rsrc * __init
Finn Thainf42e5552017-04-08 19:51:15 -0400497nubus_get_functional_resource(struct nubus_board *board, int slot,
498 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Finn Thainf42e5552017-04-08 19:51:15 -0400500 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 struct nubus_dirent ent;
Finn Thain189e19e2018-01-13 17:37:13 -0500502 struct nubus_rsrc *fres;
Finn Thainf42e5552017-04-08 19:51:15 -0400503
Finn Thainf53bad02018-01-13 17:37:13 -0500504 pr_debug(" Functional resource 0x%02x:\n", parent->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500506 dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 /* Actually we should probably panic if this fails */
Finn Thain189e19e2018-01-13 17:37:13 -0500509 fres = kzalloc(sizeof(*fres), GFP_ATOMIC);
510 if (!fres)
Finn Thainf42e5552017-04-08 19:51:15 -0400511 return NULL;
Finn Thain189e19e2018-01-13 17:37:13 -0500512 fres->resid = parent->type;
513 fres->directory = dir.base;
514 fres->board = board;
Finn Thainf42e5552017-04-08 19:51:15 -0400515
516 while (nubus_readdir(&dir, &ent) != -1) {
517 switch (ent.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 case NUBUS_RESID_TYPE:
519 {
520 unsigned short nbtdata[4];
Finn Thainf42e5552017-04-08 19:51:15 -0400521
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 nubus_get_rsrc_mem(nbtdata, &ent, 8);
Finn Thain189e19e2018-01-13 17:37:13 -0500523 fres->category = nbtdata[0];
524 fres->type = nbtdata[1];
525 fres->dr_sw = nbtdata[2];
526 fres->dr_hw = nbtdata[3];
Finn Thainf53bad02018-01-13 17:37:13 -0500527 pr_debug(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
528 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
Finn Thain2f7dd072018-01-13 17:37:13 -0500529 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 break;
531 }
532 case NUBUS_RESID_NAME:
533 {
Finn Thain9f979772018-01-13 17:37:13 -0500534 char name[64];
Finn Thain2f7dd072018-01-13 17:37:13 -0500535 unsigned int len;
Finn Thain9f979772018-01-13 17:37:13 -0500536
Finn Thain2f7dd072018-01-13 17:37:13 -0500537 len = nubus_get_rsrc_str(name, &ent, sizeof(name));
Finn Thain9f979772018-01-13 17:37:13 -0500538 pr_debug(" name: %s\n", name);
Finn Thain2f7dd072018-01-13 17:37:13 -0500539 nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 break;
541 }
542 case NUBUS_RESID_DRVRDIR:
543 {
544 /* MacOS driver. If we were NetBSD we might
545 use this :-) */
Finn Thain883b8cb2018-01-13 17:37:13 -0500546 pr_debug(" driver directory offset: 0x%06x\n",
547 ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500548 nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 break;
550 }
551 case NUBUS_RESID_MINOR_BASEOS:
Finn Thain9f979772018-01-13 17:37:13 -0500552 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 /* We will need this in order to support
554 multiple framebuffers. It might be handy
555 for Ethernet as well */
Finn Thain9f979772018-01-13 17:37:13 -0500556 u32 base_offset;
557
558 nubus_get_rsrc_mem(&base_offset, &ent, 4);
559 pr_debug(" memory offset: 0x%08x\n", base_offset);
Finn Thain2f7dd072018-01-13 17:37:13 -0500560 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 break;
Finn Thain9f979772018-01-13 17:37:13 -0500562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 case NUBUS_RESID_MINOR_LENGTH:
Finn Thain9f979772018-01-13 17:37:13 -0500564 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 /* Ditto */
Finn Thain9f979772018-01-13 17:37:13 -0500566 u32 length;
567
568 nubus_get_rsrc_mem(&length, &ent, 4);
569 pr_debug(" memory length: 0x%08x\n", length);
Finn Thain2f7dd072018-01-13 17:37:13 -0500570 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
Finn Thainf42e5552017-04-08 19:51:15 -0400571 break;
Finn Thain9f979772018-01-13 17:37:13 -0500572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 case NUBUS_RESID_FLAGS:
Finn Thain9f979772018-01-13 17:37:13 -0500574 pr_debug(" flags: 0x%06x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500575 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 break;
577 case NUBUS_RESID_HWDEVID:
Finn Thain9f979772018-01-13 17:37:13 -0500578 pr_debug(" hwdevid: 0x%06x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500579 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 break;
581 default:
Finn Thain72b44f62023-05-16 11:22:05 +1000582 if (nubus_populate_procfs)
583 nubus_get_private_resource(fres, dir.procdir,
584 &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 }
586 }
Finn Thainf42e5552017-04-08 19:51:15 -0400587
Finn Thain189e19e2018-01-13 17:37:13 -0500588 return fres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589}
590
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591/* This is *really* cool. */
Finn Thainf42e5552017-04-08 19:51:15 -0400592static int __init nubus_get_icon(struct nubus_board *board,
Finn Thain2f7dd072018-01-13 17:37:13 -0500593 struct proc_dir_entry *procdir,
Finn Thainf42e5552017-04-08 19:51:15 -0400594 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595{
596 /* Should be 32x32 if my memory serves me correctly */
Finn Thainf53bad02018-01-13 17:37:13 -0500597 u32 icon[32];
598 int i;
Finn Thainf42e5552017-04-08 19:51:15 -0400599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 nubus_get_rsrc_mem(&icon, ent, 128);
Finn Thainf53bad02018-01-13 17:37:13 -0500601 pr_debug(" icon:\n");
602 for (i = 0; i < 8; i++)
603 pr_debug(" %08x %08x %08x %08x\n",
604 icon[i * 4 + 0], icon[i * 4 + 1],
605 icon[i * 4 + 2], icon[i * 4 + 3]);
Finn Thain2f7dd072018-01-13 17:37:13 -0500606 nubus_proc_add_rsrc_mem(procdir, ent, 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 return 0;
609}
610
Finn Thainf42e5552017-04-08 19:51:15 -0400611static int __init nubus_get_vendorinfo(struct nubus_board *board,
Finn Thain2f7dd072018-01-13 17:37:13 -0500612 struct proc_dir_entry *procdir,
Finn Thainf42e5552017-04-08 19:51:15 -0400613 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614{
Finn Thainf42e5552017-04-08 19:51:15 -0400615 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400617 static char *vendor_fields[6] = { "ID", "serial", "revision",
618 "part", "date", "unknown field" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Finn Thainf53bad02018-01-13 17:37:13 -0500620 pr_debug(" vendor info:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500622 dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Finn Thainf42e5552017-04-08 19:51:15 -0400624 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 char name[64];
Finn Thain2f7dd072018-01-13 17:37:13 -0500626 unsigned int len;
Finn Thainf42e5552017-04-08 19:51:15 -0400627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 /* These are all strings, we think */
Finn Thain2f7dd072018-01-13 17:37:13 -0500629 len = nubus_get_rsrc_str(name, &ent, sizeof(name));
Finn Thain2f828fb2018-01-13 17:37:13 -0500630 if (ent.type < 1 || ent.type > 5)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 ent.type = 5;
Finn Thainf53bad02018-01-13 17:37:13 -0500632 pr_debug(" %s: %s\n", vendor_fields[ent.type - 1], name);
Finn Thain2f7dd072018-01-13 17:37:13 -0500633 nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
635 return 0;
636}
637
Finn Thainf42e5552017-04-08 19:51:15 -0400638static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
639 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
Finn Thainf42e5552017-04-08 19:51:15 -0400641 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400643
Finn Thainf53bad02018-01-13 17:37:13 -0500644 pr_debug(" Board resource 0x%02x:\n", parent->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 nubus_get_subdir(parent, &dir);
Finn Thain2f7dd072018-01-13 17:37:13 -0500646 dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Finn Thainf42e5552017-04-08 19:51:15 -0400648 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 switch (ent.type) {
650 case NUBUS_RESID_TYPE:
651 {
652 unsigned short nbtdata[4];
653 /* This type is always the same, and is not
654 useful except insofar as it tells us that
655 we really are looking at a board resource. */
656 nubus_get_rsrc_mem(nbtdata, &ent, 8);
Finn Thainf53bad02018-01-13 17:37:13 -0500657 pr_debug(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
658 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
660 nbtdata[2] != 0 || nbtdata[3] != 0)
Finn Thaind7811a32018-01-13 17:37:13 -0500661 pr_err("Slot %X: sResource is not a board resource!\n",
662 slot);
Finn Thain2f7dd072018-01-13 17:37:13 -0500663 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 break;
665 }
666 case NUBUS_RESID_NAME:
Finn Thain2f7dd072018-01-13 17:37:13 -0500667 {
668 unsigned int len;
669
670 len = nubus_get_rsrc_str(board->name, &ent,
671 sizeof(board->name));
Finn Thainf53bad02018-01-13 17:37:13 -0500672 pr_debug(" name: %s\n", board->name);
Finn Thain2f7dd072018-01-13 17:37:13 -0500673 nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 break;
Finn Thain2f7dd072018-01-13 17:37:13 -0500675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 case NUBUS_RESID_ICON:
Finn Thain2f7dd072018-01-13 17:37:13 -0500677 nubus_get_icon(board, dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 break;
679 case NUBUS_RESID_BOARDID:
Finn Thainf53bad02018-01-13 17:37:13 -0500680 pr_debug(" board id: 0x%x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500681 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 break;
683 case NUBUS_RESID_PRIMARYINIT:
Finn Thainf53bad02018-01-13 17:37:13 -0500684 pr_debug(" primary init offset: 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_VENDORINFO:
Finn Thain2f7dd072018-01-13 17:37:13 -0500688 nubus_get_vendorinfo(board, dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 break;
690 case NUBUS_RESID_FLAGS:
Finn Thainf53bad02018-01-13 17:37:13 -0500691 pr_debug(" flags: 0x%06x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500692 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 break;
694 case NUBUS_RESID_HWDEVID:
Finn Thainf53bad02018-01-13 17:37:13 -0500695 pr_debug(" hwdevid: 0x%06x\n", ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500696 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 break;
698 case NUBUS_RESID_SECONDINIT:
Finn Thainf53bad02018-01-13 17:37:13 -0500699 pr_debug(" secondary init offset: 0x%06x\n",
700 ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500701 nubus_proc_add_rsrc(dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 break;
Finn Thainf42e5552017-04-08 19:51:15 -0400703 /* WTF isn't this in the functional resources? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 case NUBUS_RESID_VIDNAMES:
Finn Thain883b8cb2018-01-13 17:37:13 -0500705 pr_debug(" vidnames directory offset: 0x%06x\n",
706 ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500707 nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 break;
709 /* Same goes for this */
710 case NUBUS_RESID_VIDMODES:
Finn Thainf53bad02018-01-13 17:37:13 -0500711 pr_debug(" video mode parameter directory offset: 0x%06x\n",
712 ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500713 nubus_proc_add_rsrc(dir.procdir, &ent);
Finn Thainf42e5552017-04-08 19:51:15 -0400714 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 default:
Finn Thainf53bad02018-01-13 17:37:13 -0500716 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
717 ent.type, ent.data);
Finn Thain2f7dd072018-01-13 17:37:13 -0500718 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 }
720 }
721 return 0;
722}
723
Finn Thain7f86c762018-01-13 17:37:14 -0500724static void __init nubus_add_board(int slot, int bytelanes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725{
Finn Thainf42e5552017-04-08 19:51:15 -0400726 struct nubus_board *board;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 unsigned char *rp;
728 unsigned long dpat;
729 struct nubus_dir dir;
730 struct nubus_dirent ent;
Finn Thaind7811a32018-01-13 17:37:13 -0500731 int prev_resid = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733 /* Move to the start of the format block */
Finn Thainf42e5552017-04-08 19:51:15 -0400734 rp = nubus_rom_addr(slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
736
737 /* Actually we should probably panic if this fails */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700738 if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
Finn Thain7f86c762018-01-13 17:37:14 -0500739 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 board->fblock = rp;
741
742 /* Dump the format block for debugging purposes */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400743 pr_debug("Slot %X, format block at 0x%p:\n", slot, rp);
Finn Thainf53bad02018-01-13 17:37:13 -0500744 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
745 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
746 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400747 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
748 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
749 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
750 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
751 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400752 rp = board->fblock;
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 board->slot = slot;
Finn Thainf42e5552017-04-08 19:51:15 -0400755 board->slot_addr = (unsigned long)nubus_slot_addr(slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 board->doffset = nubus_get_rom(&rp, 4, bytelanes);
757 /* rom_length is *supposed* to be the total length of the
758 * ROM. In practice it is the "amount of ROM used to compute
759 * the CRC." So some jokers decide to set it to zero and
760 * set the crc to zero so they don't have to do any math.
761 * See the Performa 460 ROM, for example. Those Apple "engineers".
762 */
763 board->rom_length = nubus_get_rom(&rp, 4, bytelanes);
764 board->crc = nubus_get_rom(&rp, 4, bytelanes);
765 board->rev = nubus_get_rom(&rp, 1, bytelanes);
Finn Thainf42e5552017-04-08 19:51:15 -0400766 board->format = nubus_get_rom(&rp, 1, bytelanes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 board->lanes = bytelanes;
768
769 /* Directory offset should be small and negative... */
Finn Thainf42e5552017-04-08 19:51:15 -0400770 if (!(board->doffset & 0x00FF0000))
Finn Thaind7811a32018-01-13 17:37:13 -0500771 pr_warn("Slot %X: Dodgy doffset!\n", slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 dpat = nubus_get_rom(&rp, 4, bytelanes);
Finn Thainf42e5552017-04-08 19:51:15 -0400773 if (dpat != NUBUS_TEST_PATTERN)
Finn Thaind7811a32018-01-13 17:37:13 -0500774 pr_warn("Slot %X: Wrong test pattern %08lx!\n", slot, dpat);
Finn Thainf42e5552017-04-08 19:51:15 -0400775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 /*
777 * I wonder how the CRC is meant to work -
778 * any takers ?
779 * CSA: According to MAC docs, not all cards pass the CRC anyway,
780 * since the initial Macintosh ROM releases skipped the check.
781 */
782
David Huggins-Daines475e6e12017-04-22 21:24:16 -0400783 /* Set up the directory pointer */
784 board->directory = board->fblock;
785 nubus_move(&board->directory, nubus_expand32(board->doffset),
786 board->lanes);
787
Finn Thainf42e5552017-04-08 19:51:15 -0400788 nubus_get_root_dir(board, &dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 /* We're ready to rock */
Finn Thainf53bad02018-01-13 17:37:13 -0500791 pr_debug("Slot %X resources:\n", slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793 /* Each slot should have one board resource and any number of
Finn Thain189e19e2018-01-13 17:37:13 -0500794 * functional resources. So we'll fill in some fields in the
795 * struct nubus_board from the board resource, then walk down
796 * the list of functional resources, spinning out a nubus_rsrc
797 * for each of them.
798 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 if (nubus_readdir(&dir, &ent) == -1) {
800 /* We can't have this! */
Finn Thaind7811a32018-01-13 17:37:13 -0500801 pr_err("Slot %X: Board resource not found!\n", slot);
Finn Thain7f86c762018-01-13 17:37:14 -0500802 kfree(board);
803 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
805
Finn Thaind7811a32018-01-13 17:37:13 -0500806 if (ent.type < 1 || ent.type > 127)
807 pr_warn("Slot %X: Board resource ID is invalid!\n", slot);
808
Finn Thain2f7dd072018-01-13 17:37:13 -0500809 board->procdir = nubus_proc_add_board(board);
810
Finn Thaind7811a32018-01-13 17:37:13 -0500811 nubus_get_board_resource(board, slot, &ent);
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 while (nubus_readdir(&dir, &ent) != -1) {
Finn Thain189e19e2018-01-13 17:37:13 -0500814 struct nubus_rsrc *fres;
Finn Thainf42e5552017-04-08 19:51:15 -0400815
Finn Thain189e19e2018-01-13 17:37:13 -0500816 fres = nubus_get_functional_resource(board, slot, &ent);
817 if (fres == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 continue;
819
Finn Thaind7811a32018-01-13 17:37:13 -0500820 /* Resources should appear in ascending ID order. This sanity
821 * check prevents duplicate resource IDs.
822 */
Finn Thain189e19e2018-01-13 17:37:13 -0500823 if (fres->resid <= prev_resid) {
824 kfree(fres);
Finn Thaind7811a32018-01-13 17:37:13 -0500825 continue;
826 }
Finn Thain189e19e2018-01-13 17:37:13 -0500827 prev_resid = fres->resid;
Finn Thaind7811a32018-01-13 17:37:13 -0500828
Finn Thain41b84812018-01-13 17:37:13 -0500829 list_add_tail(&fres->list, &nubus_func_rsrcs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
831
Finn Thain7f86c762018-01-13 17:37:14 -0500832 if (nubus_device_register(board))
833 put_device(&board->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834}
835
Finn Thain460cf952018-01-13 17:37:13 -0500836static void __init nubus_probe_slot(int slot)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837{
838 unsigned char dp;
Finn Thainf42e5552017-04-08 19:51:15 -0400839 unsigned char *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 int i;
841
Finn Thainf42e5552017-04-08 19:51:15 -0400842 rp = nubus_rom_addr(slot);
843 for (i = 4; i; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 rp--;
Finn Thain9f979772018-01-13 17:37:13 -0500845 if (!hwreg_present(rp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 continue;
847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 dp = *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
850 /* The last byte of the format block consists of two
851 nybbles which are "mirror images" of each other.
852 These show us the valid bytelanes */
Finn Thainf42e5552017-04-08 19:51:15 -0400853 if ((((dp >> 4) ^ dp) & 0x0F) != 0x0F)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 continue;
855 /* Check that this value is actually *on* one of the
856 bytelanes it claims are valid! */
Finn Thain85cc3132017-04-22 21:24:16 -0400857 if (not_useful(rp, dp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 continue;
859
860 /* Looks promising. Let's put it on the list. */
861 nubus_add_board(slot, dp);
862
863 return;
864 }
865}
866
Finn Thain460cf952018-01-13 17:37:13 -0500867static void __init nubus_scan_bus(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868{
869 int slot;
Finn Thainf42e5552017-04-08 19:51:15 -0400870
Finn Thainf53bad02018-01-13 17:37:13 -0500871 pr_info("NuBus: Scanning NuBus slots.\n");
Finn Thainf42e5552017-04-08 19:51:15 -0400872 for (slot = 9; slot < 15; slot++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 nubus_probe_slot(slot);
874 }
875}
876
877static int __init nubus_init(void)
878{
Finn Thain7f86c762018-01-13 17:37:14 -0500879 int err;
880
Finn Thainf42e5552017-04-08 19:51:15 -0400881 if (!MACH_IS_MAC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return 0;
883
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 nubus_proc_init();
Finn Thainbdeeed02018-05-09 11:04:48 +1000885 err = nubus_parent_device_register();
Finn Thain7f86c762018-01-13 17:37:14 -0500886 if (err)
887 return err;
Finn Thain2f7dd072018-01-13 17:37:13 -0500888 nubus_scan_bus();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return 0;
890}
891
892subsys_initcall(nubus_init);