File indexing completed on 2025-05-11 08:23:52
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 #include <rtems.h>
0049 #include <rtems/bspIo.h>
0050 #include <bsp/pci.h>
0051 #include <stdint.h>
0052 #include "pci_io_remap.h"
0053
0054 #ifndef PCI_MULTI_FUN
0055 #define PCI_MULTI_FUN 0x80
0056 #endif
0057
0058 #ifndef PCI_HEADER_TYPE_MSK
0059 #define PCI_HEADER_TYPE_MSK 0x7f
0060 #endif
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075 int
0076 rtems_pci_io_remap(int bus_from, int bus_to, uint32_t offset)
0077 {
0078 int rval = 0;
0079 int bus, dev, fun, maxf;
0080 int bar, numBars = 0;
0081 uint8_t b;
0082 uint16_t s;
0083 uint32_t d;
0084 unsigned int bas, lim;
0085
0086 if ( offset & ((1<<12)-1) ) {
0087 rtems_panic("rtems_pci_io_remap(): offset must be 4k aligned");
0088 return -1;
0089 }
0090
0091
0092 for ( bus=bus_from; bus < bus_to; bus++ ) {
0093 for ( dev = 0; dev<PCI_MAX_DEVICES; dev++ ) {
0094
0095 maxf = 1;
0096
0097 for ( fun = 0; fun < maxf; fun++ ) {
0098 pci_read_config_word( bus, dev, fun, PCI_VENDOR_ID, &s );
0099 if ( 0xffff == s )
0100 continue;
0101
0102 pci_read_config_byte( bus, dev, fun, PCI_HEADER_TYPE, &b );
0103
0104
0105
0106
0107 if ( 0 == fun && (PCI_MULTI_FUN & b) )
0108 maxf = PCI_MAX_FUNCTIONS;
0109
0110
0111
0112
0113 b &= PCI_HEADER_TYPE_MSK;
0114 switch ( b ) {
0115 default:
0116 printk("PCI header type %i (@%i/%i/%i)\n", b, bus, dev, fun);
0117 rtems_panic("rtems_pci_io_remap(): unknown PCI header type");
0118 return -1;
0119
0120 case PCI_HEADER_TYPE_CARDBUS:
0121 printk("PCI header type %i (@%i/%i/%i)\n", b, bus, dev, fun);
0122 rtems_panic("rtems_pci_io_remap(): don't know how to deal with Cardbus bridge");
0123 return -1;
0124
0125 case PCI_HEADER_TYPE_NORMAL:
0126 numBars = 6*4;
0127 break;
0128
0129 case PCI_HEADER_TYPE_BRIDGE:
0130 numBars = 2*4;
0131 break;
0132
0133 }
0134
0135 for ( bar = 0; bar < numBars; bar+=4 ) {
0136 pci_read_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0 + bar, &d );
0137 if ( PCI_BASE_ADDRESS_SPACE_IO & d ) {
0138
0139 d &= PCI_BASE_ADDRESS_IO_MASK;
0140 if ( d ) {
0141
0142 d += offset;
0143 pci_write_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0 + bar, d );
0144 }
0145 } else {
0146
0147 d &= PCI_BASE_ADDRESS_MEM_TYPE_MASK;
0148 if ( PCI_BASE_ADDRESS_MEM_TYPE_64 == d )
0149 bar+=4;
0150 }
0151 }
0152
0153
0154 if ( PCI_HEADER_TYPE_BRIDGE == b ) {
0155
0156 pci_read_config_byte( bus, dev, fun, PCI_IO_LIMIT, &b );
0157 pci_read_config_word( bus, dev, fun, PCI_IO_LIMIT_UPPER16, &s );
0158 lim = (s<<16) + (( b & PCI_IO_RANGE_MASK ) << 8);
0159 lim += offset;
0160
0161 pci_read_config_byte( bus, dev, fun, PCI_IO_BASE, &b );
0162 pci_read_config_word( bus, dev, fun, PCI_IO_BASE_UPPER16, &s );
0163 bas = (s<<16) + (( b & PCI_IO_RANGE_MASK ) << 8);
0164 bas += offset;
0165
0166 b &= PCI_IO_RANGE_TYPE_MASK;
0167 switch ( b ) {
0168 default:
0169 printk("Unknown IO range type 0x%x (@%i/%i/%i)\n", b, bus, dev, fun);
0170 rtems_panic("rtems_pci_io_remap(): unknown IO range type");
0171 return -1;
0172
0173 case PCI_IO_RANGE_TYPE_16:
0174 if ( bas > 0xffff || lim > 0xffff ) {
0175 printk("PCI I/O range type 1 (16bit) bridge (@%i/%i/%i) found:\n", bus, dev, fun);
0176 printk("WARNING: base (0x%08x) or limit (0x%08x) exceed 16-bit;\n", bas, lim);
0177 printk(" devices behind this bridge are NOT accessible!\n");
0178
0179
0180 bas = lim = 0;
0181 }
0182 break;
0183
0184 case PCI_IO_RANGE_TYPE_32:
0185 break;
0186 }
0187
0188 b = (uint8_t)((bas>>8) & PCI_IO_RANGE_MASK);
0189 pci_write_config_byte( bus, dev, fun, PCI_IO_BASE, b );
0190
0191 s = (uint16_t)((bas>>16)&0xffff);
0192 pci_write_config_word( bus, dev, fun, PCI_IO_BASE_UPPER16, s);
0193
0194 b = (uint8_t)((lim>>8) & PCI_IO_RANGE_MASK);
0195 pci_write_config_byte( bus, dev, fun, PCI_IO_LIMIT, b );
0196 s = (uint16_t)((lim>>16)&0xffff);
0197 pci_write_config_word( bus, dev, fun, PCI_IO_LIMIT_UPPER16, s );
0198 }
0199 }
0200 }
0201 }
0202 return rval;
0203 }