162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * eisa_enumerator.c - provide support for EISA adapters in PA-RISC machines 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2002 Daniel Engstrom <5116@telia.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/ioport.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <asm/io.h> 1362306a36Sopenharmony_ci#include <linux/uaccess.h> 1462306a36Sopenharmony_ci#include <asm/byteorder.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/eisa_bus.h> 1762306a36Sopenharmony_ci#include <asm/eisa_eeprom.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * Todo: 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * PORT init with MASK attr and other size than byte 2462306a36Sopenharmony_ci * MEMORY with other decode than 20 bit 2562306a36Sopenharmony_ci * CRC stuff 2662306a36Sopenharmony_ci * FREEFORM stuff 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define EPI 0xc80 3062306a36Sopenharmony_ci#define NUM_SLOT 16 3162306a36Sopenharmony_ci#define SLOT2PORT(x) (x<<12) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* macros to handle unaligned accesses and 3562306a36Sopenharmony_ci * byte swapping. The data in the EEPROM is 3662306a36Sopenharmony_ci * little-endian on the big-endian PAROSC */ 3762306a36Sopenharmony_ci#define get_8(x) (*(u_int8_t*)(x)) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic inline u_int16_t get_16(const unsigned char *x) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci return (x[1] << 8) | x[0]; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic inline u_int32_t get_32(const unsigned char *x) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci return (x[3] << 24) | (x[2] << 16) | (x[1] << 8) | x[0]; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic inline u_int32_t get_24(const unsigned char *x) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci return (x[2] << 24) | (x[1] << 16) | (x[0] << 8); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void print_eisa_id(char *s, u_int32_t id) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci char vendor[4]; 5762306a36Sopenharmony_ci int rev; 5862306a36Sopenharmony_ci int device; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci rev = id & 0xff; 6162306a36Sopenharmony_ci id >>= 8; 6262306a36Sopenharmony_ci device = id & 0xff; 6362306a36Sopenharmony_ci id >>= 8; 6462306a36Sopenharmony_ci vendor[3] = '\0'; 6562306a36Sopenharmony_ci vendor[2] = '@' + (id & 0x1f); 6662306a36Sopenharmony_ci id >>= 5; 6762306a36Sopenharmony_ci vendor[1] = '@' + (id & 0x1f); 6862306a36Sopenharmony_ci id >>= 5; 6962306a36Sopenharmony_ci vendor[0] = '@' + (id & 0x1f); 7062306a36Sopenharmony_ci id >>= 5; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci sprintf(s, "%s%02X%02X", vendor, device, rev); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int configure_memory(const unsigned char *buf, 7662306a36Sopenharmony_ci struct resource *mem_parent, 7762306a36Sopenharmony_ci char *name) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci int len; 8062306a36Sopenharmony_ci u_int8_t c; 8162306a36Sopenharmony_ci int i; 8262306a36Sopenharmony_ci struct resource *res; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci len=0; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci for (i=0;i<HPEE_MEMORY_MAX_ENT;i++) { 8762306a36Sopenharmony_ci c = get_8(buf+len); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) { 9062306a36Sopenharmony_ci int result; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci res->name = name; 9362306a36Sopenharmony_ci res->start = mem_parent->start + get_24(buf+len+2); 9462306a36Sopenharmony_ci res->end = res->start + get_16(buf+len+5)*1024; 9562306a36Sopenharmony_ci res->flags = IORESOURCE_MEM; 9662306a36Sopenharmony_ci pr_cont("memory %pR ", res); 9762306a36Sopenharmony_ci result = request_resource(mem_parent, res); 9862306a36Sopenharmony_ci if (result < 0) { 9962306a36Sopenharmony_ci printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n"); 10062306a36Sopenharmony_ci return result; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci len+=7; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (!(c & HPEE_MEMORY_MORE)) { 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return len; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int configure_irq(const unsigned char *buf) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int len; 11862306a36Sopenharmony_ci u_int8_t c; 11962306a36Sopenharmony_ci int i; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci len=0; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci for (i=0;i<HPEE_IRQ_MAX_ENT;i++) { 12462306a36Sopenharmony_ci c = get_8(buf+len); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci pr_cont("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK); 12762306a36Sopenharmony_ci if (c & HPEE_IRQ_TRIG_LEVEL) { 12862306a36Sopenharmony_ci eisa_make_irq_level(c & HPEE_IRQ_CHANNEL_MASK); 12962306a36Sopenharmony_ci } else { 13062306a36Sopenharmony_ci eisa_make_irq_edge(c & HPEE_IRQ_CHANNEL_MASK); 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci len+=2; 13462306a36Sopenharmony_ci /* hpux seems to allow for 13562306a36Sopenharmony_ci * two bytes of irq data but only defines one of 13662306a36Sopenharmony_ci * them, I think */ 13762306a36Sopenharmony_ci if (!(c & HPEE_IRQ_MORE)) { 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return len; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int configure_dma(const unsigned char *buf) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci int len; 14962306a36Sopenharmony_ci u_int8_t c; 15062306a36Sopenharmony_ci int i; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci len=0; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci for (i=0;i<HPEE_DMA_MAX_ENT;i++) { 15562306a36Sopenharmony_ci c = get_8(buf+len); 15662306a36Sopenharmony_ci pr_cont("DMA %d ", c&HPEE_DMA_CHANNEL_MASK); 15762306a36Sopenharmony_ci /* fixme: maybe initialize the dma channel withthe timing ? */ 15862306a36Sopenharmony_ci len+=2; 15962306a36Sopenharmony_ci if (!(c & HPEE_DMA_MORE)) { 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return len; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int configure_port(const unsigned char *buf, struct resource *io_parent, 16862306a36Sopenharmony_ci char *board) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci int len; 17162306a36Sopenharmony_ci u_int8_t c; 17262306a36Sopenharmony_ci int i; 17362306a36Sopenharmony_ci struct resource *res; 17462306a36Sopenharmony_ci int result; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci len=0; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci for (i=0;i<HPEE_PORT_MAX_ENT;i++) { 17962306a36Sopenharmony_ci c = get_8(buf+len); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) { 18262306a36Sopenharmony_ci res->name = board; 18362306a36Sopenharmony_ci res->start = get_16(buf+len+1); 18462306a36Sopenharmony_ci res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1; 18562306a36Sopenharmony_ci res->flags = IORESOURCE_IO; 18662306a36Sopenharmony_ci pr_cont("ioports %pR ", res); 18762306a36Sopenharmony_ci result = request_resource(io_parent, res); 18862306a36Sopenharmony_ci if (result < 0) { 18962306a36Sopenharmony_ci printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n"); 19062306a36Sopenharmony_ci return result; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci len+=3; 19562306a36Sopenharmony_ci if (!(c & HPEE_PORT_MORE)) { 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return len; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* byte 1 and 2 is the port number to write 20562306a36Sopenharmony_ci * and at byte 3 the value to write starts. 20662306a36Sopenharmony_ci * I assume that there are and- and or- masks 20762306a36Sopenharmony_ci * here when HPEE_PORT_INIT_MASK is set but I have 20862306a36Sopenharmony_ci * not yet encountered this. */ 20962306a36Sopenharmony_cistatic int configure_port_init(const unsigned char *buf) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int len=0; 21262306a36Sopenharmony_ci u_int8_t c; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci while (len<HPEE_PORT_INIT_MAX_LEN) { 21562306a36Sopenharmony_ci int s=0; 21662306a36Sopenharmony_ci c = get_8(buf+len); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci switch (c & HPEE_PORT_INIT_WIDTH_MASK) { 21962306a36Sopenharmony_ci case HPEE_PORT_INIT_WIDTH_BYTE: 22062306a36Sopenharmony_ci s=1; 22162306a36Sopenharmony_ci if (c & HPEE_PORT_INIT_MASK) { 22262306a36Sopenharmony_ci printk(KERN_WARNING "port_init: unverified mask attribute\n"); 22362306a36Sopenharmony_ci outb((inb(get_16(buf+len+1) & 22462306a36Sopenharmony_ci get_8(buf+len+3)) | 22562306a36Sopenharmony_ci get_8(buf+len+4)), get_16(buf+len+1)); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci } else { 22862306a36Sopenharmony_ci outb(get_8(buf+len+3), get_16(buf+len+1)); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci break; 23262306a36Sopenharmony_ci case HPEE_PORT_INIT_WIDTH_WORD: 23362306a36Sopenharmony_ci s=2; 23462306a36Sopenharmony_ci if (c & HPEE_PORT_INIT_MASK) { 23562306a36Sopenharmony_ci printk(KERN_WARNING "port_init: unverified mask attribute\n"); 23662306a36Sopenharmony_ci outw((inw(get_16(buf+len+1)) & 23762306a36Sopenharmony_ci get_16(buf+len+3)) | 23862306a36Sopenharmony_ci get_16(buf+len+5), 23962306a36Sopenharmony_ci get_16(buf+len+1)); 24062306a36Sopenharmony_ci } else { 24162306a36Sopenharmony_ci outw(cpu_to_le16(get_16(buf+len+3)), get_16(buf+len+1)); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci case HPEE_PORT_INIT_WIDTH_DWORD: 24562306a36Sopenharmony_ci s=4; 24662306a36Sopenharmony_ci if (c & HPEE_PORT_INIT_MASK) { 24762306a36Sopenharmony_ci printk(KERN_WARNING "port_init: unverified mask attribute\n"); 24862306a36Sopenharmony_ci outl((inl(get_16(buf+len+1) & 24962306a36Sopenharmony_ci get_32(buf+len+3)) | 25062306a36Sopenharmony_ci get_32(buf+len+7)), get_16(buf+len+1)); 25162306a36Sopenharmony_ci } else { 25262306a36Sopenharmony_ci outl(cpu_to_le32(get_32(buf+len+3)), get_16(buf+len+1)); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci default: 25762306a36Sopenharmony_ci printk(KERN_ERR "Invalid port init word %02x\n", c); 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (c & HPEE_PORT_INIT_MASK) { 26262306a36Sopenharmony_ci s*=2; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci len+=s+3; 26662306a36Sopenharmony_ci if (!(c & HPEE_PORT_INIT_MORE)) { 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return len; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int configure_choise(const unsigned char *buf, u_int8_t *info) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci int len; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* theis record contain the value of the functions 27962306a36Sopenharmony_ci * configuration choises and an info byte which 28062306a36Sopenharmony_ci * describes which other records to expect in this 28162306a36Sopenharmony_ci * function */ 28262306a36Sopenharmony_ci len = get_8(buf); 28362306a36Sopenharmony_ci *info=get_8(buf+len+1); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return len+2; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int configure_type_string(const unsigned char *buf) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci int len; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* just skip past the type field */ 29362306a36Sopenharmony_ci len = get_8(buf); 29462306a36Sopenharmony_ci if (len > 80) { 29562306a36Sopenharmony_ci printk(KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)\n", len); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return 1+len; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic int configure_function(const unsigned char *buf, int *more) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci /* the init field seems to be a two-byte field 30462306a36Sopenharmony_ci * which is non-zero if there are an other function following 30562306a36Sopenharmony_ci * I think it is the length of the function def 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci *more = get_16(buf); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return 2; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int parse_slot_config(int slot, 31362306a36Sopenharmony_ci const unsigned char *buf, 31462306a36Sopenharmony_ci struct eeprom_eisa_slot_info *es, 31562306a36Sopenharmony_ci struct resource *io_parent, 31662306a36Sopenharmony_ci struct resource *mem_parent) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci int res=0; 31962306a36Sopenharmony_ci int function_len; 32062306a36Sopenharmony_ci unsigned int pos=0; 32162306a36Sopenharmony_ci unsigned int maxlen; 32262306a36Sopenharmony_ci int num_func=0; 32362306a36Sopenharmony_ci u_int8_t flags; 32462306a36Sopenharmony_ci int p0; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci char *board; 32762306a36Sopenharmony_ci int id_string_used=0; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (NULL == (board = kmalloc(8, GFP_KERNEL))) { 33062306a36Sopenharmony_ci return -1; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci print_eisa_id(board, es->eisa_slot_id); 33362306a36Sopenharmony_ci printk(KERN_INFO "EISA slot %d: %s %s ", 33462306a36Sopenharmony_ci slot, board, es->flags&HPEE_FLAG_BOARD_IS_ISA ? "ISA" : "EISA"); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci maxlen = es->config_data_length < HPEE_MAX_LENGTH ? 33762306a36Sopenharmony_ci es->config_data_length : HPEE_MAX_LENGTH; 33862306a36Sopenharmony_ci while ((pos < maxlen) && (num_func <= es->num_functions)) { 33962306a36Sopenharmony_ci pos+=configure_function(buf+pos, &function_len); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!function_len) { 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci num_func++; 34562306a36Sopenharmony_ci p0 = pos; 34662306a36Sopenharmony_ci pos += configure_choise(buf+pos, &flags); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (flags & HPEE_FUNCTION_INFO_F_DISABLED) { 34962306a36Sopenharmony_ci /* function disabled, skip silently */ 35062306a36Sopenharmony_ci pos = p0 + function_len; 35162306a36Sopenharmony_ci continue; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci if (flags & HPEE_FUNCTION_INFO_CFG_FREE_FORM) { 35462306a36Sopenharmony_ci /* I have no idea how to handle this */ 35562306a36Sopenharmony_ci printk("function %d have free-form configuration, skipping ", 35662306a36Sopenharmony_ci num_func); 35762306a36Sopenharmony_ci pos = p0 + function_len; 35862306a36Sopenharmony_ci continue; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* the ordering of the sections need 36262306a36Sopenharmony_ci * more investigation. 36362306a36Sopenharmony_ci * Currently I think that memory comaed before IRQ 36462306a36Sopenharmony_ci * I assume the order is LSB to MSB in the 36562306a36Sopenharmony_ci * info flags 36662306a36Sopenharmony_ci * eg type, memory, irq, dma, port, HPEE_PORT_init 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (flags & HPEE_FUNCTION_INFO_HAVE_TYPE) { 37062306a36Sopenharmony_ci pos += configure_type_string(buf+pos); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (flags & HPEE_FUNCTION_INFO_HAVE_MEMORY) { 37462306a36Sopenharmony_ci id_string_used=1; 37562306a36Sopenharmony_ci pos += configure_memory(buf+pos, mem_parent, board); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (flags & HPEE_FUNCTION_INFO_HAVE_IRQ) { 37962306a36Sopenharmony_ci pos += configure_irq(buf+pos); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (flags & HPEE_FUNCTION_INFO_HAVE_DMA) { 38362306a36Sopenharmony_ci pos += configure_dma(buf+pos); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (flags & HPEE_FUNCTION_INFO_HAVE_PORT) { 38762306a36Sopenharmony_ci id_string_used=1; 38862306a36Sopenharmony_ci pos += configure_port(buf+pos, io_parent, board); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (flags & HPEE_FUNCTION_INFO_HAVE_PORT_INIT) { 39262306a36Sopenharmony_ci pos += configure_port_init(buf+pos); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (p0 + function_len < pos) { 39662306a36Sopenharmony_ci printk(KERN_ERR "eisa_enumerator: function %d length mismatch " 39762306a36Sopenharmony_ci "got %d, expected %d\n", 39862306a36Sopenharmony_ci num_func, pos-p0, function_len); 39962306a36Sopenharmony_ci res=-1; 40062306a36Sopenharmony_ci break; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci pos = p0 + function_len; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci pr_cont("\n"); 40562306a36Sopenharmony_ci if (!id_string_used) { 40662306a36Sopenharmony_ci kfree(board); 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (pos != es->config_data_length) { 41062306a36Sopenharmony_ci printk(KERN_ERR "eisa_enumerator: config data length mismatch got %d, expected %d\n", 41162306a36Sopenharmony_ci pos, es->config_data_length); 41262306a36Sopenharmony_ci res=-1; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (num_func != es->num_functions) { 41662306a36Sopenharmony_ci printk(KERN_ERR "eisa_enumerator: number of functions mismatch got %d, expected %d\n", 41762306a36Sopenharmony_ci num_func, es->num_functions); 41862306a36Sopenharmony_ci res=-2; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return res; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int init_slot(int slot, struct eeprom_eisa_slot_info *es) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci unsigned int id; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci char id_string[8]; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (!(es->slot_info&HPEE_SLOT_INFO_NO_READID)) { 43262306a36Sopenharmony_ci /* try to read the id of the board in the slot */ 43362306a36Sopenharmony_ci id = le32_to_cpu(inl(SLOT2PORT(slot)+EPI)); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (0xffffffff == id) { 43662306a36Sopenharmony_ci /* Maybe we didn't expect a card to be here... */ 43762306a36Sopenharmony_ci if (es->eisa_slot_id == 0xffffffff) 43862306a36Sopenharmony_ci return -1; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* this board is not here or it does not 44162306a36Sopenharmony_ci * support readid 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_ci printk(KERN_ERR "EISA slot %d a configured board was not detected (", 44462306a36Sopenharmony_ci slot); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci print_eisa_id(id_string, es->eisa_slot_id); 44762306a36Sopenharmony_ci printk(" expected %s)\n", id_string); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci return -1; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci if (es->eisa_slot_id != id) { 45362306a36Sopenharmony_ci print_eisa_id(id_string, id); 45462306a36Sopenharmony_ci printk(KERN_ERR "EISA slot %d id mismatch: got %s", 45562306a36Sopenharmony_ci slot, id_string); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci print_eisa_id(id_string, es->eisa_slot_id); 45862306a36Sopenharmony_ci printk(" expected %s\n", id_string); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return -1; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* now: we need to enable the board if 46662306a36Sopenharmony_ci * it supports enabling and run through 46762306a36Sopenharmony_ci * the port init sction if present 46862306a36Sopenharmony_ci * and finally record any interrupt polarity 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci if (es->slot_features & HPEE_SLOT_FEATURES_ENABLE) { 47162306a36Sopenharmony_ci /* enable board */ 47262306a36Sopenharmony_ci outb(0x01| inb(SLOT2PORT(slot)+EPI+4), 47362306a36Sopenharmony_ci SLOT2PORT(slot)+EPI+4); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return 0; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ciint eisa_enumerator(unsigned long eeprom_addr, 48162306a36Sopenharmony_ci struct resource *io_parent, struct resource *mem_parent) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci int i; 48462306a36Sopenharmony_ci struct eeprom_header *eh; 48562306a36Sopenharmony_ci static char eeprom_buf[HPEE_MAX_LENGTH]; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci for (i=0; i < HPEE_MAX_LENGTH; i++) { 48862306a36Sopenharmony_ci eeprom_buf[i] = gsc_readb(eeprom_addr+i); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci printk(KERN_INFO "Enumerating EISA bus\n"); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci eh = (struct eeprom_header*)(eeprom_buf); 49462306a36Sopenharmony_ci for (i=0;i<eh->num_slots;i++) { 49562306a36Sopenharmony_ci struct eeprom_eisa_slot_info *es; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci es = (struct eeprom_eisa_slot_info*) 49862306a36Sopenharmony_ci (&eeprom_buf[HPEE_SLOT_INFO(i)]); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (-1==init_slot(i+1, es)) { 50162306a36Sopenharmony_ci continue; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (es->config_data_offset < HPEE_MAX_LENGTH) { 50562306a36Sopenharmony_ci if (parse_slot_config(i+1, &eeprom_buf[es->config_data_offset], 50662306a36Sopenharmony_ci es, io_parent, mem_parent)) { 50762306a36Sopenharmony_ci return -1; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci } else { 51062306a36Sopenharmony_ci printk (KERN_WARNING "EISA EEPROM offset 0x%x out of range\n",es->config_data_offset); 51162306a36Sopenharmony_ci return -1; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci return eh->num_slots; 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 517