Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:41

0001 /**
0002  * @file
0003  *
0004  * PCI Support when Configuration Space is accessed via BIOS
0005  */
0006 
0007 /*
0008  * This software is Copyright (C) 1998 by T.sqware - all rights limited
0009  * It is provided in to the public domain "as is", can be freely modified
0010  * as far as this copyight notice is kept unchanged, but does not imply
0011  * an endorsement by T.sqware of the product in which it is included.
0012  */
0013 
0014 #include <rtems.h>
0015 #include <bsp.h>
0016 #include <rtems/pci.h>
0017 
0018 #include <string.h>  /* memcpy */
0019 
0020 /*
0021  * This is simpliest possible PCI BIOS, it assumes that addressing
0022  * is flat and that stack is big enough
0023  */
0024 static int pcibInitialized = 0;
0025 static unsigned int pcibEntry;
0026 
0027 /*
0028  * Array to pass data between c and __asm__ parts, at the time of
0029  * writing I am not yet that familiar with extended __asm__ feature
0030  * of gcc. This code is not on performance path, so we can care
0031  * relatively little about performance here
0032  */
0033 static volatile unsigned int pcibExchg[5];
0034 
0035 static int pcib_convert_err(int err);
0036 
0037 /** @brief
0038  * Make device signature from bus number, device numebr and function
0039  * number
0040  */
0041 #define PCIB_DEVSIG_MAKE(b,d,f) ((b<<8)|(d<<3)|(f))
0042 
0043 /** @brief
0044  * Extract valrous part from device signature
0045  */
0046 #define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
0047 #define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
0048 #define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
0049 
0050 /*
0051  * Forward reference. Initialized at bottom.
0052  */
0053 static const pci_config_access_functions pci_bios_indirect_functions;
0054 
0055 /* prototype before defining */
0056 const pci_config_access_functions *pci_bios_initialize(void);
0057 
0058 /*
0059  * Detects presense of PCI BIOS, returns pointer to accessor methods.
0060  */
0061 const pci_config_access_functions *pci_bios_initialize(void)
0062 {
0063   unsigned char *ucp;
0064   unsigned char  sum;
0065   int            i;
0066 
0067   pcibInitialized = 0;
0068 
0069   /* First, we have to look for BIOS-32 */
0070   for (ucp = (unsigned char *)0xE0000;
0071        ucp < (unsigned char *)0xFFFFF;
0072        ucp += 0x10) {
0073     if (memcmp(ucp, "_32_", 4) != 0) {
0074       continue;
0075     }
0076 
0077       /* Got signature, check length  */
0078     if (*(ucp + 9) != 1) {
0079       continue;
0080     }
0081 
0082     /* Verify checksum */
0083     sum = 0;
0084     for (i=0; i<16; i++) {
0085       sum += *(ucp+i);
0086     }
0087 
0088     if (sum == 0) {
0089       /* found */
0090       break;
0091     }
0092   }
0093 
0094   if (ucp >= (unsigned char *)0xFFFFF) {
0095     /* BIOS-32 not found */
0096     return NULL;
0097   }
0098 
0099   /* BIOS-32 found, let us find PCI BIOS */
0100   ucp += 4;
0101 
0102   pcibExchg[0] = *(unsigned int *)ucp;
0103 
0104   __asm__ ("    pusha");                  /* Push all registers */
0105   __asm__ ("    movl pcibExchg, %edi");   /* Move entry point to esi */
0106   __asm__ ("    movl $0x49435024, %eax"); /* Move signature to eax */
0107   __asm__ ("    xorl %ebx, %ebx");        /* Zero ebx */
0108   __asm__ ("    pushl %cs");
0109   __asm__ ("    call *%edi");             /* Call entry */
0110   __asm__ ("    movl %eax, pcibExchg");
0111   __asm__ ("    movl %ebx, pcibExchg+4");
0112   __asm__ ("    movl %ecx, pcibExchg+8");
0113   __asm__ ("    movl %edx, pcibExchg+12");
0114   __asm__ ("    popa");
0115 
0116   if ((pcibExchg[0] & 0xff) != 0) {
0117     /* Not found */
0118     return NULL;
0119   }
0120 
0121   /* Found PCI entry point */
0122   pcibEntry = pcibExchg[1] + pcibExchg[3];
0123 
0124   /* Let us check whether PCI bios is present */
0125   pcibExchg[0] = pcibEntry;
0126 
0127   __asm__ ("    pusha");
0128   __asm__ ("    movl pcibExchg, %edi");
0129   __asm__ ("    movb $0xb1, %ah");
0130   __asm__ ("    movb $0x01, %al");
0131   __asm__ ("    pushl %cs");
0132   __asm__ ("    call *%edi");
0133   __asm__ ("    movl %eax, pcibExchg");
0134   __asm__ ("    movl %ebx, pcibExchg+4");
0135   __asm__ ("    movl %ecx, pcibExchg+8");
0136   __asm__ ("    movl %edx, pcibExchg+12");
0137   __asm__ ("    popa");
0138 
0139   if ((pcibExchg[0] & 0xff00) != 0) {
0140     /* Not found */
0141     return NULL;
0142   }
0143 
0144   if (pcibExchg[3] != 0x20494350) {
0145     /* Signature does not match */
0146     return NULL;
0147   }
0148 
0149   /* Success */
0150   pcibInitialized = 1;
0151 
0152   return &pci_bios_indirect_functions;
0153 }
0154 
0155 /*
0156  * Read byte from config space
0157  */
0158 static int
0159 pcib_conf_read8(int sig, int off, uint8_t *data)
0160 {
0161   if (!pcibInitialized) {
0162     return PCIB_ERR_UNINITIALIZED;
0163   }
0164 
0165   pcibExchg[0] = pcibEntry;
0166   pcibExchg[1] = sig;
0167   pcibExchg[2] = off;
0168 
0169   __asm__ ("    pusha");
0170   __asm__ ("    movl pcibExchg, %esi");
0171   __asm__ ("    movb $0xb1, %ah");
0172   __asm__ ("    movb $0x08, %al");
0173   __asm__ ("    movl pcibExchg+4, %ebx");
0174   __asm__ ("    movl pcibExchg+8, %edi");
0175   __asm__ ("    pushl %cs");
0176   __asm__ ("    call *%esi");
0177   __asm__ ("    movl %eax, pcibExchg");
0178   __asm__ ("    movl %ecx, pcibExchg+4");
0179   __asm__ ("    popa");
0180 
0181   if ((pcibExchg[0] & 0xff00) != 0) {
0182     return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
0183   }
0184 
0185   *data = (unsigned char)pcibExchg[1] & 0xff;
0186 
0187   return PCIB_ERR_SUCCESS;
0188 }
0189 
0190 
0191 /*
0192  * Read word from config space
0193  */
0194 static int
0195 pcib_conf_read16(int sig, int off, uint16_t *data)
0196 {
0197   if (!pcibInitialized) {
0198     return PCIB_ERR_UNINITIALIZED;
0199   }
0200 
0201   pcibExchg[0] = pcibEntry;
0202   pcibExchg[1] = sig;
0203   pcibExchg[2] = off;
0204 
0205   __asm__ ("    pusha");
0206   __asm__ ("    movl pcibExchg, %esi");
0207   __asm__ ("    movb $0xb1, %ah");
0208   __asm__ ("    movb $0x09, %al");
0209   __asm__ ("    movl pcibExchg+4, %ebx");
0210   __asm__ ("    movl pcibExchg+8, %edi");
0211   __asm__ ("    pushl %cs");
0212   __asm__ ("    call *%esi");
0213   __asm__ ("    movl %eax, pcibExchg");
0214   __asm__ ("    movl %ecx, pcibExchg+4");
0215   __asm__ ("    popa");
0216 
0217   if ((pcibExchg[0] & 0xff00) != 0) {
0218     return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
0219   }
0220 
0221   *data = (unsigned short)pcibExchg[1] & 0xffff;
0222 
0223   return PCIB_ERR_SUCCESS;
0224 }
0225 
0226 
0227 /*
0228  * Read dword from config space
0229  */
0230 static int
0231 pcib_conf_read32(int sig, int off, uint32_t *data)
0232 {
0233   if (!pcibInitialized) {
0234     return PCIB_ERR_UNINITIALIZED;
0235   }
0236 
0237   pcibExchg[0] = pcibEntry;
0238   pcibExchg[1] = sig;
0239   pcibExchg[2] = off;
0240 
0241   __asm__ ("    pusha");
0242   __asm__ ("    movl pcibExchg, %esi");
0243   __asm__ ("    movb $0xb1, %ah");
0244   __asm__ ("    movb $0x0a, %al");
0245   __asm__ ("    movl pcibExchg+4, %ebx");
0246   __asm__ ("    movl pcibExchg+8, %edi");
0247   __asm__ ("    pushl %cs");
0248   __asm__ ("    call *%esi");
0249   __asm__ ("    movl %eax, pcibExchg");
0250   __asm__ ("    movl %ecx, pcibExchg+4");
0251   __asm__ ("    popa");
0252 
0253   if ((pcibExchg[0] & 0xff00) != 0) {
0254     return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
0255   }
0256 
0257   *data = (unsigned int)pcibExchg[1];
0258 
0259   return PCIB_ERR_SUCCESS;
0260 }
0261 
0262 
0263 /*
0264  * Write byte into  config space
0265  */
0266 static int
0267 pcib_conf_write8(int sig, int off, uint8_t data)
0268 {
0269   if (!pcibInitialized) {
0270     return PCIB_ERR_UNINITIALIZED;
0271   }
0272 
0273   pcibExchg[0] = pcibEntry;
0274   pcibExchg[1] = sig;
0275   pcibExchg[2] = off;
0276   pcibExchg[3] = data & 0xff;
0277 
0278   __asm__ ("    pusha");
0279   __asm__ ("    movl pcibExchg, %esi");
0280   __asm__ ("    movb $0xb1, %ah");
0281   __asm__ ("    movb $0x0b, %al");
0282   __asm__ ("    movl pcibExchg+4, %ebx");
0283   __asm__ ("    movl pcibExchg+8, %edi");
0284   __asm__ ("    movl pcibExchg+12, %ecx");
0285   __asm__ ("    pushl %cs");
0286   __asm__ ("    call *%esi");
0287   __asm__ ("    movl %eax, pcibExchg");
0288   __asm__ ("    popa");
0289 
0290   return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
0291 }
0292 
0293 /*
0294  * Write word into config space
0295  */
0296 static int
0297 pcib_conf_write16(int sig, int off, uint16_t data)
0298 {
0299   if (!pcibInitialized) {
0300     return PCIB_ERR_UNINITIALIZED;
0301   }
0302 
0303   pcibExchg[0] = pcibEntry;
0304   pcibExchg[1] = sig;
0305   pcibExchg[2] = off;
0306   pcibExchg[3] = data & 0xffff;
0307 
0308   __asm__ ("    pusha");
0309   __asm__ ("    movl pcibExchg, %esi");
0310   __asm__ ("    movb $0xb1, %ah");
0311   __asm__ ("    movb $0x0c, %al");
0312   __asm__ ("    movl pcibExchg+4, %ebx");
0313   __asm__ ("    movl pcibExchg+8, %edi");
0314   __asm__ ("    movl pcibExchg+12, %ecx");
0315   __asm__ ("    pushl %cs");
0316   __asm__ ("    call *%esi");
0317   __asm__ ("    movl %eax, pcibExchg");
0318   __asm__ ("    popa");
0319 
0320   return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
0321 }
0322 
0323 
0324 
0325 /*
0326  * Write dword into config space
0327  */
0328 static int
0329 pcib_conf_write32(int sig, int off, uint32_t data)
0330 {
0331   if (!pcibInitialized){
0332       return PCIB_ERR_UNINITIALIZED;
0333   }
0334 
0335   pcibExchg[0] = pcibEntry;
0336   pcibExchg[1] = sig;
0337   pcibExchg[2] = off;
0338   pcibExchg[3] = data;
0339 
0340   __asm__ ("    pusha");
0341   __asm__ ("    movl pcibExchg, %esi");
0342   __asm__ ("    movb $0xb1, %ah");
0343   __asm__ ("    movb $0x0d, %al");
0344   __asm__ ("    movl pcibExchg+4, %ebx");
0345   __asm__ ("    movl pcibExchg+8, %edi");
0346   __asm__ ("    movl pcibExchg+12, %ecx");
0347   __asm__ ("    pushl %cs");
0348   __asm__ ("    call *%esi");
0349   __asm__ ("    movl %eax, pcibExchg");
0350   __asm__ ("    popa");
0351 
0352   return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
0353 }
0354 
0355 
0356 static int
0357 pcib_convert_err(int err)
0358 {
0359   switch(err & 0xff){
0360     case 0:
0361       return PCIB_ERR_SUCCESS;
0362     case 0x81:
0363       return PCIB_ERR_NOFUNC;
0364     case 0x83:
0365       return PCIB_ERR_BADVENDOR;
0366     case 0x86:
0367       return PCIB_ERR_DEVNOTFOUND;
0368     case 0x87:
0369       return PCIB_ERR_BADREG;
0370     default:
0371       break;
0372   }
0373   return PCIB_ERR_NOFUNC;
0374 }
0375 
0376 static int
0377 BSP_pci_read_config_byte(
0378   unsigned char bus,
0379   unsigned char slot,
0380   unsigned char fun,
0381   unsigned char offset,
0382   unsigned char *val
0383 )
0384 {
0385   int sig;
0386 
0387   sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
0388   pcib_conf_read8(sig, offset, val);
0389   return PCIBIOS_SUCCESSFUL;
0390 }
0391 
0392 static int
0393 BSP_pci_read_config_word(
0394   unsigned char bus,
0395   unsigned char slot,
0396   unsigned char fun,
0397   unsigned char offset,
0398   unsigned short *val
0399 )
0400 {
0401   int sig;
0402 
0403   sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
0404   pcib_conf_read16(sig, offset, val);
0405   return PCIBIOS_SUCCESSFUL;
0406 }
0407 
0408 static int
0409 BSP_pci_read_config_dword(
0410   unsigned char bus,
0411   unsigned char slot,
0412   unsigned char fun,
0413   unsigned char offset,
0414   uint32_t     *val
0415 )
0416 {
0417   int sig;
0418 
0419   sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
0420   pcib_conf_read32(sig, offset, val);
0421   return PCIBIOS_SUCCESSFUL;
0422 }
0423 
0424 static int
0425 BSP_pci_write_config_byte(
0426   unsigned char bus,
0427   unsigned char slot,
0428   unsigned char fun,
0429   unsigned char offset,
0430   unsigned char val
0431 )
0432 {
0433   int sig;
0434 
0435   sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
0436   pcib_conf_write8(sig, offset, val);
0437   return PCIBIOS_SUCCESSFUL;
0438 }
0439 
0440 static int
0441 BSP_pci_write_config_word(
0442   unsigned char bus,
0443   unsigned char slot,
0444   unsigned char fun,
0445   unsigned char offset,
0446   unsigned short val
0447 )
0448 {
0449   int sig;
0450 
0451   sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
0452   pcib_conf_write16(sig, offset, val);
0453   return PCIBIOS_SUCCESSFUL;
0454 }
0455 
0456 static int
0457 BSP_pci_write_config_dword(
0458   unsigned char bus,
0459   unsigned char slot,
0460   unsigned char fun,
0461   unsigned char offset,
0462   uint32_t      val
0463 )
0464 {
0465   int sig;
0466 
0467   sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
0468   pcib_conf_write32(sig, offset, val);
0469   return PCIBIOS_SUCCESSFUL;
0470 }
0471 
0472 static const pci_config_access_functions pci_bios_indirect_functions = {
0473   BSP_pci_read_config_byte,
0474   BSP_pci_read_config_word,
0475   BSP_pci_read_config_dword,
0476   BSP_pci_write_config_byte,
0477   BSP_pci_write_config_word,
0478   BSP_pci_write_config_dword
0479 };