1 /*
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>
18 #include <linux/uaccess.h>
19 #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 
get_16(const unsigned char * x)44 static inline u_int16_t get_16(const unsigned char *x)
45 {
46 	return (x[1] << 8) | x[0];
47 }
48 
get_32(const unsigned char * x)49 static 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 
get_24(const unsigned char * x)54 static inline u_int32_t get_24(const unsigned char *x)
55 {
56 	return (x[2] << 24) | (x[1] << 16) | (x[0] << 8);
57 }
58 
print_eisa_id(char * s,u_int32_t id)59 static 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 
configure_memory(const unsigned char * buf,struct resource * mem_parent,char * name)80 static 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 
94 		if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
95 			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;
101 			printk("memory %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
102 			result = request_resource(mem_parent, res);
103 			if (result < 0) {
104 				printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
105 				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 
configure_irq(const unsigned char * buf)120 static 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 
configure_dma(const unsigned char * buf)151 static 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 
configure_port(const unsigned char * buf,struct resource * io_parent,char * board)172 static 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 
186 		if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
187 			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;
191 			printk("ioports %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
192 			result = request_resource(io_parent, res);
193 			if (result < 0) {
194 				printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
195 				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. */
configure_port_init(const unsigned char * buf)214 static 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) {
227 				printk(KERN_WARNING "port_init: unverified mask attribute\n");
228 				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) {
252  				printk(KERN_WARNING "port_init: unverified mask attribute\n");
253 				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:
262 			printk(KERN_ERR "Invalid port init word %02x\n", c);
263 			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 
configure_choise(const unsigned char * buf,u_int8_t * info)279 static 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 
configure_type_string(const unsigned char * buf)293 static 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) {
300 		printk(KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)\n", len);
301 	}
302 
303 	return 1+len;
304 }
305 
configure_function(const unsigned char * buf,int * more)306 static 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 
parse_slot_config(int slot,const unsigned char * buf,struct eeprom_eisa_slot_info * es,struct resource * io_parent,struct resource * mem_parent)317 static 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 */
360 			printk("function %d have free-form configuration, skipping ",
361 				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) {
401 			printk(KERN_ERR "eisa_enumerator: function %d length mis-match "
402 			       "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 
init_slot(int slot,struct eeprom_eisa_slot_info * es)430 static 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);
463 			printk(" expected %s\n", id_string);
464 
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 
eisa_enumerator(unsigned long eeprom_addr,struct resource * io_parent,struct resource * mem_parent)485 int 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 
522