Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * eisa_enumerator.c - provide support for EISA adapters in PA-RISC machines
0004  *
0005  * Copyright (c) 2002 Daniel Engstrom <5116@telia.com>
0006  */
0007 
0008 #include <linux/ioport.h>
0009 #include <linux/init.h>
0010 #include <linux/kernel.h>
0011 #include <linux/slab.h>
0012 #include <asm/io.h>
0013 #include <linux/uaccess.h>
0014 #include <asm/byteorder.h>
0015 
0016 #include <asm/eisa_bus.h>
0017 #include <asm/eisa_eeprom.h>
0018 
0019 
0020 /*
0021  * Todo:
0022  * 
0023  * PORT init with MASK attr and other size than byte
0024  * MEMORY with other decode than 20 bit
0025  * CRC stuff
0026  * FREEFORM stuff
0027  */
0028 
0029 #define EPI 0xc80
0030 #define NUM_SLOT 16
0031 #define SLOT2PORT(x) (x<<12)
0032 
0033 
0034 /* macros to handle unaligned accesses and 
0035  * byte swapping. The data in the EEPROM is
0036  * little-endian on the big-endian PAROSC */
0037 #define get_8(x) (*(u_int8_t*)(x))
0038 
0039 static inline u_int16_t get_16(const unsigned char *x)
0040 { 
0041     return (x[1] << 8) | x[0];
0042 }
0043 
0044 static inline u_int32_t get_32(const unsigned char *x)
0045 {
0046     return (x[3] << 24) | (x[2] << 16) | (x[1] << 8) | x[0];
0047 }
0048 
0049 static inline u_int32_t get_24(const unsigned char *x)
0050 {
0051     return (x[2] << 24) | (x[1] << 16) | (x[0] << 8);
0052 }
0053 
0054 static void print_eisa_id(char *s, u_int32_t id)
0055 {
0056     char vendor[4];
0057     int rev;
0058     int device;
0059     
0060     rev = id & 0xff;
0061     id >>= 8;
0062     device = id & 0xff;
0063     id >>= 8;
0064     vendor[3] = '\0';
0065     vendor[2] = '@' + (id & 0x1f);
0066     id >>= 5;   
0067     vendor[1] = '@' + (id & 0x1f);
0068     id >>= 5;   
0069     vendor[0] = '@' + (id & 0x1f);
0070     id >>= 5;   
0071     
0072     sprintf(s, "%s%02X%02X", vendor, device, rev);
0073 }
0074        
0075 static int configure_memory(const unsigned char *buf, 
0076                struct resource *mem_parent,
0077                char *name)
0078 {
0079     int len;
0080     u_int8_t c;
0081     int i;
0082     struct resource *res;
0083     
0084     len=0;
0085     
0086     for (i=0;i<HPEE_MEMORY_MAX_ENT;i++) {
0087         c = get_8(buf+len);
0088         
0089         if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
0090             int result;
0091             
0092             res->name = name;
0093             res->start = mem_parent->start + get_24(buf+len+2);
0094             res->end = res->start + get_16(buf+len+5)*1024;
0095             res->flags = IORESOURCE_MEM;
0096             pr_cont("memory %pR ", res);
0097             result = request_resource(mem_parent, res);
0098             if (result < 0) {
0099                 printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
0100                 return result;
0101             }
0102         }
0103             
0104         len+=7;      
0105     
0106         if (!(c & HPEE_MEMORY_MORE)) {
0107             break;
0108         }
0109     }
0110     
0111     return len;
0112 }
0113 
0114 
0115 static int configure_irq(const unsigned char *buf)
0116 {
0117     int len;
0118     u_int8_t c;
0119     int i;
0120     
0121     len=0;
0122     
0123     for (i=0;i<HPEE_IRQ_MAX_ENT;i++) {
0124         c = get_8(buf+len);
0125         
0126         pr_cont("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
0127         if (c & HPEE_IRQ_TRIG_LEVEL) {
0128             eisa_make_irq_level(c & HPEE_IRQ_CHANNEL_MASK);
0129         } else {
0130             eisa_make_irq_edge(c & HPEE_IRQ_CHANNEL_MASK);
0131         }
0132         
0133         len+=2; 
0134         /* hpux seems to allow for
0135          * two bytes of irq data but only defines one of
0136          * them, I think */
0137         if  (!(c & HPEE_IRQ_MORE)) {
0138             break;
0139         }
0140     }
0141     
0142     return len;
0143 }
0144 
0145 
0146 static int configure_dma(const unsigned char *buf)
0147 {
0148     int len;
0149     u_int8_t c;
0150     int i;
0151     
0152     len=0;
0153     
0154     for (i=0;i<HPEE_DMA_MAX_ENT;i++) {
0155         c = get_8(buf+len);
0156         pr_cont("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
0157         /* fixme: maybe initialize the dma channel withthe timing ? */
0158         len+=2;      
0159         if (!(c & HPEE_DMA_MORE)) {
0160             break;
0161         }
0162     }
0163     
0164     return len;
0165 }
0166 
0167 static int configure_port(const unsigned char *buf, struct resource *io_parent,
0168              char *board)
0169 {
0170     int len;
0171     u_int8_t c;
0172     int i;
0173     struct resource *res;
0174     int result;
0175     
0176     len=0;
0177     
0178     for (i=0;i<HPEE_PORT_MAX_ENT;i++) {
0179         c = get_8(buf+len);
0180         
0181         if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
0182             res->name = board;
0183             res->start = get_16(buf+len+1);
0184             res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
0185             res->flags = IORESOURCE_IO;
0186             pr_cont("ioports %pR ", res);
0187             result = request_resource(io_parent, res);
0188             if (result < 0) {
0189                 printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
0190                 return result;
0191             }
0192         }
0193 
0194         len+=3;      
0195         if (!(c & HPEE_PORT_MORE)) {
0196             break;
0197         }
0198     }
0199     
0200     return len;
0201 }
0202 
0203 
0204 /* byte 1 and 2 is the port number to write
0205  * and at byte 3 the value to write starts.
0206  * I assume that there are and- and or- masks
0207  * here when HPEE_PORT_INIT_MASK is set but I have 
0208  * not yet encountered this. */
0209 static int configure_port_init(const unsigned char *buf)
0210 {
0211     int len=0;
0212     u_int8_t c;
0213     
0214     while (len<HPEE_PORT_INIT_MAX_LEN) {
0215         int s=0;
0216         c = get_8(buf+len);
0217         
0218         switch (c & HPEE_PORT_INIT_WIDTH_MASK)  {
0219          case HPEE_PORT_INIT_WIDTH_BYTE:
0220             s=1;
0221             if (c & HPEE_PORT_INIT_MASK) {
0222                 printk(KERN_WARNING "port_init: unverified mask attribute\n");
0223                 outb((inb(get_16(buf+len+1) & 
0224                       get_8(buf+len+3)) | 
0225                       get_8(buf+len+4)), get_16(buf+len+1));
0226                       
0227             } else {
0228                 outb(get_8(buf+len+3), get_16(buf+len+1));
0229                       
0230             }
0231             break;
0232          case HPEE_PORT_INIT_WIDTH_WORD:
0233             s=2;
0234             if (c & HPEE_PORT_INIT_MASK) {
0235                 printk(KERN_WARNING "port_init: unverified mask attribute\n");
0236                        outw((inw(get_16(buf+len+1)) &
0237                          get_16(buf+len+3)) |
0238                         get_16(buf+len+5), 
0239                         get_16(buf+len+1));
0240             } else {
0241                 outw(cpu_to_le16(get_16(buf+len+3)), get_16(buf+len+1));
0242             }
0243             break;
0244          case HPEE_PORT_INIT_WIDTH_DWORD:
0245             s=4;
0246             if (c & HPEE_PORT_INIT_MASK) {
0247                 printk(KERN_WARNING "port_init: unverified mask attribute\n");
0248                 outl((inl(get_16(buf+len+1) &
0249                       get_32(buf+len+3)) |
0250                       get_32(buf+len+7)), get_16(buf+len+1));
0251             } else {
0252                 outl(cpu_to_le32(get_32(buf+len+3)), get_16(buf+len+1));
0253             }
0254 
0255             break;
0256          default:
0257             printk(KERN_ERR "Invalid port init word %02x\n", c);
0258             return 0;
0259         }
0260         
0261         if (c & HPEE_PORT_INIT_MASK) {   
0262             s*=2;
0263         }
0264         
0265         len+=s+3;
0266         if (!(c & HPEE_PORT_INIT_MORE)) {
0267             break;
0268         }
0269     }
0270     
0271     return len;
0272 }
0273 
0274 static int configure_choise(const unsigned char *buf, u_int8_t *info)
0275 {
0276     int len;
0277     
0278     /* theis record contain the value of the functions
0279      * configuration choises and an info byte which 
0280      * describes which other records to expect in this 
0281      * function */
0282     len = get_8(buf);
0283     *info=get_8(buf+len+1);
0284      
0285     return len+2;
0286 }
0287 
0288 static int configure_type_string(const unsigned char *buf) 
0289 {
0290     int len;
0291     
0292     /* just skip past the type field */
0293     len = get_8(buf);
0294     if (len > 80) {
0295         printk(KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)\n", len);
0296     }
0297     
0298     return 1+len;
0299 }
0300 
0301 static int configure_function(const unsigned char *buf, int *more) 
0302 {
0303     /* the init field seems to be a two-byte field
0304      * which is non-zero if there are an other function following
0305      * I think it is the length of the function def 
0306      */
0307     *more = get_16(buf);
0308     
0309     return 2;
0310 }
0311 
0312 static int parse_slot_config(int slot,
0313                  const unsigned char *buf,
0314                  struct eeprom_eisa_slot_info *es, 
0315                  struct resource *io_parent,
0316                  struct resource *mem_parent)
0317 {
0318     int res=0;
0319     int function_len;
0320     unsigned int pos=0;
0321     unsigned int maxlen;
0322     int num_func=0;
0323     u_int8_t flags;
0324     int p0;
0325     
0326     char *board;
0327     int id_string_used=0;
0328     
0329     if (NULL == (board = kmalloc(8, GFP_KERNEL))) {
0330         return -1;
0331     }
0332     print_eisa_id(board, es->eisa_slot_id);
0333     printk(KERN_INFO "EISA slot %d: %s %s ", 
0334            slot, board, es->flags&HPEE_FLAG_BOARD_IS_ISA ? "ISA" : "EISA");
0335     
0336     maxlen = es->config_data_length < HPEE_MAX_LENGTH ?
0337              es->config_data_length : HPEE_MAX_LENGTH;
0338     while ((pos < maxlen) && (num_func <= es->num_functions)) {
0339         pos+=configure_function(buf+pos, &function_len); 
0340         
0341         if (!function_len) {
0342             break;
0343         }
0344         num_func++;
0345         p0 = pos;
0346         pos += configure_choise(buf+pos, &flags);
0347 
0348         if (flags & HPEE_FUNCTION_INFO_F_DISABLED) {
0349             /* function disabled, skip silently */
0350             pos = p0 + function_len;
0351             continue;
0352         }
0353         if (flags & HPEE_FUNCTION_INFO_CFG_FREE_FORM) {
0354             /* I have no idea how to handle this */
0355             printk("function %d have free-form configuration, skipping ",
0356                 num_func);
0357             pos = p0 + function_len;
0358             continue;
0359         }
0360 
0361         /* the ordering of the sections need
0362          * more investigation.
0363          * Currently I think that memory comaed before IRQ
0364          * I assume the order is LSB to MSB in the 
0365          * info flags 
0366          * eg type, memory, irq, dma, port, HPEE_PORT_init 
0367          */
0368 
0369         if (flags & HPEE_FUNCTION_INFO_HAVE_TYPE) {
0370             pos += configure_type_string(buf+pos);
0371         }
0372         
0373         if (flags & HPEE_FUNCTION_INFO_HAVE_MEMORY) {
0374             id_string_used=1;
0375             pos += configure_memory(buf+pos, mem_parent, board);
0376         } 
0377         
0378         if (flags & HPEE_FUNCTION_INFO_HAVE_IRQ) {
0379             pos += configure_irq(buf+pos);
0380         } 
0381         
0382         if (flags & HPEE_FUNCTION_INFO_HAVE_DMA) {
0383             pos += configure_dma(buf+pos);
0384         } 
0385         
0386         if (flags & HPEE_FUNCTION_INFO_HAVE_PORT) {
0387             id_string_used=1;
0388             pos += configure_port(buf+pos, io_parent, board);
0389         } 
0390         
0391         if (flags &  HPEE_FUNCTION_INFO_HAVE_PORT_INIT) {
0392             pos += configure_port_init(buf+pos);
0393         }
0394         
0395         if (p0 + function_len < pos) {
0396             printk(KERN_ERR "eisa_enumerator: function %d length mis-match "
0397                    "got %d, expected %d\n",
0398                    num_func, pos-p0, function_len);
0399             res=-1;
0400             break;
0401         }
0402         pos = p0 + function_len;
0403     }
0404     pr_cont("\n");
0405     if (!id_string_used) {
0406         kfree(board);
0407     }
0408     
0409     if (pos != es->config_data_length) {
0410         printk(KERN_ERR "eisa_enumerator: config data length mis-match got %d, expected %d\n",
0411             pos, es->config_data_length);
0412         res=-1;
0413     }
0414     
0415     if (num_func != es->num_functions) {
0416         printk(KERN_ERR "eisa_enumerator: number of functions mis-match got %d, expected %d\n",
0417             num_func, es->num_functions);
0418         res=-2;
0419     }
0420     
0421     return res;
0422     
0423 }
0424 
0425 static int init_slot(int slot, struct eeprom_eisa_slot_info *es)
0426 {
0427     unsigned int id;
0428     
0429     char id_string[8];
0430     
0431     if (!(es->slot_info&HPEE_SLOT_INFO_NO_READID)) {
0432         /* try to read the id of the board in the slot */
0433         id = le32_to_cpu(inl(SLOT2PORT(slot)+EPI));
0434         
0435         if (0xffffffff == id) {
0436             /* Maybe we didn't expect a card to be here... */
0437             if (es->eisa_slot_id == 0xffffffff)
0438                 return -1;
0439             
0440             /* this board is not here or it does not 
0441              * support readid 
0442              */
0443             printk(KERN_ERR "EISA slot %d a configured board was not detected (", 
0444                    slot);
0445             
0446             print_eisa_id(id_string, es->eisa_slot_id);
0447             printk(" expected %s)\n", id_string);
0448         
0449             return -1;  
0450 
0451         }
0452         if (es->eisa_slot_id != id) {
0453             print_eisa_id(id_string, id);
0454             printk(KERN_ERR "EISA slot %d id mis-match: got %s", 
0455                    slot, id_string);
0456             
0457             print_eisa_id(id_string, es->eisa_slot_id);
0458             printk(" expected %s\n", id_string);
0459         
0460             return -1;  
0461             
0462         }
0463     }
0464     
0465     /* now: we need to enable the board if 
0466      * it supports enabling and run through
0467      * the port init sction if present
0468      * and finally record any interrupt polarity
0469      */
0470     if (es->slot_features & HPEE_SLOT_FEATURES_ENABLE) {
0471         /* enable board */
0472         outb(0x01| inb(SLOT2PORT(slot)+EPI+4),
0473              SLOT2PORT(slot)+EPI+4);
0474     }
0475     
0476     return 0;
0477 }
0478 
0479 
0480 int eisa_enumerator(unsigned long eeprom_addr,
0481             struct resource *io_parent, struct resource *mem_parent) 
0482 {
0483     int i;
0484     struct eeprom_header *eh;
0485     static char eeprom_buf[HPEE_MAX_LENGTH];
0486     
0487     for (i=0; i < HPEE_MAX_LENGTH; i++) {
0488         eeprom_buf[i] = gsc_readb(eeprom_addr+i);
0489     }
0490     
0491     printk(KERN_INFO "Enumerating EISA bus\n");
0492                 
0493     eh = (struct eeprom_header*)(eeprom_buf);
0494     for (i=0;i<eh->num_slots;i++) {
0495         struct eeprom_eisa_slot_info *es;
0496         
0497         es = (struct eeprom_eisa_slot_info*)
0498             (&eeprom_buf[HPEE_SLOT_INFO(i)]);
0499             
0500         if (-1==init_slot(i+1, es)) {
0501             continue;
0502         }
0503         
0504         if (es->config_data_offset < HPEE_MAX_LENGTH) {
0505             if (parse_slot_config(i+1, &eeprom_buf[es->config_data_offset],
0506                           es, io_parent, mem_parent)) {
0507                 return -1;
0508             }
0509         } else {
0510             printk (KERN_WARNING "EISA EEPROM offset 0x%x out of range\n",es->config_data_offset);
0511             return -1;
0512         }
0513     }
0514     return eh->num_slots;
0515 }
0516