root/drivers/parisc/eisa_enumerator.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_16
  2. get_32
  3. get_24
  4. print_eisa_id
  5. configure_memory
  6. configure_irq
  7. configure_dma
  8. configure_port
  9. configure_port_init
  10. configure_choise
  11. configure_type_string
  12. configure_function
  13. parse_slot_config
  14. init_slot
  15. eisa_enumerator

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

/* [<][>][^][v][top][bottom][index][help] */