blob: d9bffe8d29b967a8067b27c85183e73ccf32699d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * eisa_enumerator.c - provide support for EISA adapters in PA-RISC machines
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Copyright (c) 2002 Daniel Engstrom <5116@telia.com>
10 *
11 */
12
13#include <linux/ioport.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/slab.h>
17#include <asm/io.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080018#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <asm/byteorder.h>
20
21#include <asm/eisa_bus.h>
22#include <asm/eisa_eeprom.h>
23
24
25/*
26 * Todo:
27 *
28 * PORT init with MASK attr and other size than byte
29 * MEMORY with other decode than 20 bit
30 * CRC stuff
31 * FREEFORM stuff
32 */
33
34#define EPI 0xc80
35#define NUM_SLOT 16
36#define SLOT2PORT(x) (x<<12)
37
38
39/* macros to handle unaligned accesses and
40 * byte swapping. The data in the EEPROM is
41 * little-endian on the big-endian PAROSC */
42#define get_8(x) (*(u_int8_t*)(x))
43
44static inline u_int16_t get_16(const unsigned char *x)
45{
46 return (x[1] << 8) | x[0];
47}
48
49static inline u_int32_t get_32(const unsigned char *x)
50{
51 return (x[3] << 24) | (x[2] << 16) | (x[1] << 8) | x[0];
52}
53
54static inline u_int32_t get_24(const unsigned char *x)
55{
56 return (x[2] << 24) | (x[1] << 16) | (x[0] << 8);
57}
58
59static void print_eisa_id(char *s, u_int32_t id)
60{
61 char vendor[4];
62 int rev;
63 int device;
64
65 rev = id & 0xff;
66 id >>= 8;
67 device = id & 0xff;
68 id >>= 8;
69 vendor[3] = '\0';
70 vendor[2] = '@' + (id & 0x1f);
71 id >>= 5;
72 vendor[1] = '@' + (id & 0x1f);
73 id >>= 5;
74 vendor[0] = '@' + (id & 0x1f);
75 id >>= 5;
76
77 sprintf(s, "%s%02X%02X", vendor, device, rev);
78}
79
80static int configure_memory(const unsigned char *buf,
81 struct resource *mem_parent,
82 char *name)
83{
84 int len;
85 u_int8_t c;
86 int i;
87 struct resource *res;
88
89 len=0;
90
91 for (i=0;i<HPEE_MEMORY_MAX_ENT;i++) {
92 c = get_8(buf+len);
93
Toshi Kani9a975be2016-01-26 21:57:25 +010094 if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 int result;
96
97 res->name = name;
98 res->start = mem_parent->start + get_24(buf+len+2);
99 res->end = res->start + get_16(buf+len+5)*1024;
100 res->flags = IORESOURCE_MEM;
Alexander Beregalovc18b4602009-03-19 10:54:07 +0000101 printk("memory %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 result = request_resource(mem_parent, res);
103 if (result < 0) {
Joe Perchesad361c92009-07-06 13:05:40 -0700104 printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 return result;
106 }
107 }
108
109 len+=7;
110
111 if (!(c & HPEE_MEMORY_MORE)) {
112 break;
113 }
114 }
115
116 return len;
117}
118
119
120static int configure_irq(const unsigned char *buf)
121{
122 int len;
123 u_int8_t c;
124 int i;
125
126 len=0;
127
128 for (i=0;i<HPEE_IRQ_MAX_ENT;i++) {
129 c = get_8(buf+len);
130
131 printk("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
132 if (c & HPEE_IRQ_TRIG_LEVEL) {
133 eisa_make_irq_level(c & HPEE_IRQ_CHANNEL_MASK);
134 } else {
135 eisa_make_irq_edge(c & HPEE_IRQ_CHANNEL_MASK);
136 }
137
138 len+=2;
139 /* hpux seems to allow for
140 * two bytes of irq data but only defines one of
141 * them, I think */
142 if (!(c & HPEE_IRQ_MORE)) {
143 break;
144 }
145 }
146
147 return len;
148}
149
150
151static int configure_dma(const unsigned char *buf)
152{
153 int len;
154 u_int8_t c;
155 int i;
156
157 len=0;
158
159 for (i=0;i<HPEE_DMA_MAX_ENT;i++) {
160 c = get_8(buf+len);
161 printk("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
162 /* fixme: maybe initialize the dma channel withthe timing ? */
163 len+=2;
164 if (!(c & HPEE_DMA_MORE)) {
165 break;
166 }
167 }
168
169 return len;
170}
171
172static int configure_port(const unsigned char *buf, struct resource *io_parent,
173 char *board)
174{
175 int len;
176 u_int8_t c;
177 int i;
178 struct resource *res;
179 int result;
180
181 len=0;
182
183 for (i=0;i<HPEE_PORT_MAX_ENT;i++) {
184 c = get_8(buf+len);
185
Toshi Kani9a975be2016-01-26 21:57:25 +0100186 if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 res->name = board;
188 res->start = get_16(buf+len+1);
189 res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
190 res->flags = IORESOURCE_IO;
Alexander Beregalovc18b4602009-03-19 10:54:07 +0000191 printk("ioports %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 result = request_resource(io_parent, res);
193 if (result < 0) {
Joe Perchesad361c92009-07-06 13:05:40 -0700194 printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 return result;
196 }
197 }
198
199 len+=3;
200 if (!(c & HPEE_PORT_MORE)) {
201 break;
202 }
203 }
204
205 return len;
206}
207
208
209/* byte 1 and 2 is the port number to write
210 * and at byte 3 the value to write starts.
211 * I assume that there are and- and or- masks
212 * here when HPEE_PORT_INIT_MASK is set but I have
213 * not yet encountered this. */
214static int configure_port_init(const unsigned char *buf)
215{
216 int len=0;
217 u_int8_t c;
218
219 while (len<HPEE_PORT_INIT_MAX_LEN) {
220 int s=0;
221 c = get_8(buf+len);
222
223 switch (c & HPEE_PORT_INIT_WIDTH_MASK) {
224 case HPEE_PORT_INIT_WIDTH_BYTE:
225 s=1;
226 if (c & HPEE_PORT_INIT_MASK) {
Joe Perchesad361c92009-07-06 13:05:40 -0700227 printk(KERN_WARNING "port_init: unverified mask attribute\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 outb((inb(get_16(buf+len+1) &
229 get_8(buf+len+3)) |
230 get_8(buf+len+4)), get_16(buf+len+1));
231
232 } else {
233 outb(get_8(buf+len+3), get_16(buf+len+1));
234
235 }
236 break;
237 case HPEE_PORT_INIT_WIDTH_WORD:
238 s=2;
239 if (c & HPEE_PORT_INIT_MASK) {
240 printk(KERN_WARNING "port_init: unverified mask attribute\n");
241 outw((inw(get_16(buf+len+1)) &
242 get_16(buf+len+3)) |
243 get_16(buf+len+5),
244 get_16(buf+len+1));
245 } else {
246 outw(cpu_to_le16(get_16(buf+len+3)), get_16(buf+len+1));
247 }
248 break;
249 case HPEE_PORT_INIT_WIDTH_DWORD:
250 s=4;
251 if (c & HPEE_PORT_INIT_MASK) {
Joe Perchesad361c92009-07-06 13:05:40 -0700252 printk(KERN_WARNING "port_init: unverified mask attribute\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 outl((inl(get_16(buf+len+1) &
254 get_32(buf+len+3)) |
255 get_32(buf+len+7)), get_16(buf+len+1));
256 } else {
257 outl(cpu_to_le32(get_32(buf+len+3)), get_16(buf+len+1));
258 }
259
260 break;
261 default:
Joe Perchesad361c92009-07-06 13:05:40 -0700262 printk(KERN_ERR "Invalid port init word %02x\n", c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 return 0;
264 }
265
266 if (c & HPEE_PORT_INIT_MASK) {
267 s*=2;
268 }
269
270 len+=s+3;
271 if (!(c & HPEE_PORT_INIT_MORE)) {
272 break;
273 }
274 }
275
276 return len;
277}
278
279static int configure_choise(const unsigned char *buf, u_int8_t *info)
280{
281 int len;
282
283 /* theis record contain the value of the functions
284 * configuration choises and an info byte which
285 * describes which other records to expect in this
286 * function */
287 len = get_8(buf);
288 *info=get_8(buf+len+1);
289
290 return len+2;
291}
292
293static int configure_type_string(const unsigned char *buf)
294{
295 int len;
296
297 /* just skip past the type field */
298 len = get_8(buf);
299 if (len > 80) {
Joe Perchesad361c92009-07-06 13:05:40 -0700300 printk(KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)\n", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302
303 return 1+len;
304}
305
306static int configure_function(const unsigned char *buf, int *more)
307{
308 /* the init field seems to be a two-byte field
309 * which is non-zero if there are an other function following
310 * I think it is the length of the function def
311 */
312 *more = get_16(buf);
313
314 return 2;
315}
316
317static int parse_slot_config(int slot,
318 const unsigned char *buf,
319 struct eeprom_eisa_slot_info *es,
320 struct resource *io_parent,
321 struct resource *mem_parent)
322{
323 int res=0;
324 int function_len;
325 unsigned int pos=0;
326 unsigned int maxlen;
327 int num_func=0;
328 u_int8_t flags;
329 int p0;
330
331 char *board;
332 int id_string_used=0;
333
334 if (NULL == (board = kmalloc(8, GFP_KERNEL))) {
335 return -1;
336 }
337 print_eisa_id(board, es->eisa_slot_id);
338 printk(KERN_INFO "EISA slot %d: %s %s ",
339 slot, board, es->flags&HPEE_FLAG_BOARD_IS_ISA ? "ISA" : "EISA");
340
341 maxlen = es->config_data_length < HPEE_MAX_LENGTH ?
342 es->config_data_length : HPEE_MAX_LENGTH;
343 while ((pos < maxlen) && (num_func <= es->num_functions)) {
344 pos+=configure_function(buf+pos, &function_len);
345
346 if (!function_len) {
347 break;
348 }
349 num_func++;
350 p0 = pos;
351 pos += configure_choise(buf+pos, &flags);
352
353 if (flags & HPEE_FUNCTION_INFO_F_DISABLED) {
354 /* function disabled, skip silently */
355 pos = p0 + function_len;
356 continue;
357 }
358 if (flags & HPEE_FUNCTION_INFO_CFG_FREE_FORM) {
359 /* I have no idea how to handle this */
Masanari Iidad939be32015-02-27 23:52:31 +0900360 printk("function %d have free-form configuration, skipping ",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 num_func);
362 pos = p0 + function_len;
363 continue;
364 }
365
366 /* the ordering of the sections need
367 * more investigation.
368 * Currently I think that memory comaed before IRQ
369 * I assume the order is LSB to MSB in the
370 * info flags
371 * eg type, memory, irq, dma, port, HPEE_PORT_init
372 */
373
374 if (flags & HPEE_FUNCTION_INFO_HAVE_TYPE) {
375 pos += configure_type_string(buf+pos);
376 }
377
378 if (flags & HPEE_FUNCTION_INFO_HAVE_MEMORY) {
379 id_string_used=1;
380 pos += configure_memory(buf+pos, mem_parent, board);
381 }
382
383 if (flags & HPEE_FUNCTION_INFO_HAVE_IRQ) {
384 pos += configure_irq(buf+pos);
385 }
386
387 if (flags & HPEE_FUNCTION_INFO_HAVE_DMA) {
388 pos += configure_dma(buf+pos);
389 }
390
391 if (flags & HPEE_FUNCTION_INFO_HAVE_PORT) {
392 id_string_used=1;
393 pos += configure_port(buf+pos, io_parent, board);
394 }
395
396 if (flags & HPEE_FUNCTION_INFO_HAVE_PORT_INIT) {
397 pos += configure_port_init(buf+pos);
398 }
399
400 if (p0 + function_len < pos) {
Joe Perchesad361c92009-07-06 13:05:40 -0700401 printk(KERN_ERR "eisa_enumerator: function %d length mis-match "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 "got %d, expected %d\n",
403 num_func, pos-p0, function_len);
404 res=-1;
405 break;
406 }
407 pos = p0 + function_len;
408 }
409 printk("\n");
410 if (!id_string_used) {
411 kfree(board);
412 }
413
414 if (pos != es->config_data_length) {
415 printk(KERN_ERR "eisa_enumerator: config data length mis-match got %d, expected %d\n",
416 pos, es->config_data_length);
417 res=-1;
418 }
419
420 if (num_func != es->num_functions) {
421 printk(KERN_ERR "eisa_enumerator: number of functions mis-match got %d, expected %d\n",
422 num_func, es->num_functions);
423 res=-2;
424 }
425
426 return res;
427
428}
429
430static int init_slot(int slot, struct eeprom_eisa_slot_info *es)
431{
432 unsigned int id;
433
434 char id_string[8];
435
436 if (!(es->slot_info&HPEE_SLOT_INFO_NO_READID)) {
437 /* try to read the id of the board in the slot */
438 id = le32_to_cpu(inl(SLOT2PORT(slot)+EPI));
439
440 if (0xffffffff == id) {
441 /* Maybe we didn't expect a card to be here... */
442 if (es->eisa_slot_id == 0xffffffff)
443 return -1;
444
445 /* this board is not here or it does not
446 * support readid
447 */
448 printk(KERN_ERR "EISA slot %d a configured board was not detected (",
449 slot);
450
451 print_eisa_id(id_string, es->eisa_slot_id);
452 printk(" expected %s)\n", id_string);
453
454 return -1;
455
456 }
457 if (es->eisa_slot_id != id) {
458 print_eisa_id(id_string, id);
459 printk(KERN_ERR "EISA slot %d id mis-match: got %s",
460 slot, id_string);
461
462 print_eisa_id(id_string, es->eisa_slot_id);
Frans Popa3bee032010-02-06 17:47:14 +0000463 printk(" expected %s\n", id_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 return -1;
466
467 }
468 }
469
470 /* now: we need to enable the board if
471 * it supports enabling and run through
472 * the port init sction if present
473 * and finally record any interrupt polarity
474 */
475 if (es->slot_features & HPEE_SLOT_FEATURES_ENABLE) {
476 /* enable board */
477 outb(0x01| inb(SLOT2PORT(slot)+EPI+4),
478 SLOT2PORT(slot)+EPI+4);
479 }
480
481 return 0;
482}
483
484
485int eisa_enumerator(unsigned long eeprom_addr,
486 struct resource *io_parent, struct resource *mem_parent)
487{
488 int i;
489 struct eeprom_header *eh;
490 static char eeprom_buf[HPEE_MAX_LENGTH];
491
492 for (i=0; i < HPEE_MAX_LENGTH; i++) {
493 eeprom_buf[i] = gsc_readb(eeprom_addr+i);
494 }
495
496 printk(KERN_INFO "Enumerating EISA bus\n");
497
498 eh = (struct eeprom_header*)(eeprom_buf);
499 for (i=0;i<eh->num_slots;i++) {
500 struct eeprom_eisa_slot_info *es;
501
502 es = (struct eeprom_eisa_slot_info*)
503 (&eeprom_buf[HPEE_SLOT_INFO(i)]);
504
505 if (-1==init_slot(i+1, es)) {
506 continue;
507 }
508
509 if (es->config_data_offset < HPEE_MAX_LENGTH) {
510 if (parse_slot_config(i+1, &eeprom_buf[es->config_data_offset],
511 es, io_parent, mem_parent)) {
512 return -1;
513 }
514 } else {
515 printk (KERN_WARNING "EISA EEPROM offset 0x%x out of range\n",es->config_data_offset);
516 return -1;
517 }
518 }
519 return eh->num_slots;
520}
521