source: rtems/bsps/powerpc/beatnik/pci/pci_io_remap.c

Last change on this file was 5a4e3dc0, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 23, 2018 at 10:50:58 AM

bsps: Move PCI drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/* Adjust a PCI bus range's I/O address space by adding an offset */
2
3/*
4 * Authorship
5 * ----------
6 * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
7 *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
8 *      Stanford Linear Accelerator Center, Stanford University.
9 *
10 * Acknowledgement of sponsorship
11 * ------------------------------
12 * The 'beatnik' BSP was produced by
13 *     the Stanford Linear Accelerator Center, Stanford University,
14 *      under Contract DE-AC03-76SFO0515 with the Department of Energy.
15 *
16 * Government disclaimer of liability
17 * ----------------------------------
18 * Neither the United States nor the United States Department of Energy,
19 * nor any of their employees, makes any warranty, express or implied, or
20 * assumes any legal liability or responsibility for the accuracy,
21 * completeness, or usefulness of any data, apparatus, product, or process
22 * disclosed, or represents that its use would not infringe privately owned
23 * rights.
24 *
25 * Stanford disclaimer of liability
26 * --------------------------------
27 * Stanford University makes no representations or warranties, express or
28 * implied, nor assumes any liability for the use of this software.
29 *
30 * Stanford disclaimer of copyright
31 * --------------------------------
32 * Stanford University, owner of the copyright, hereby disclaims its
33 * copyright and all other rights in this software.  Hence, anyone may
34 * freely use it for any purpose without restriction. 
35 *
36 * Maintenance of notices
37 * ----------------------
38 * In the interest of clarity regarding the origin and status of this
39 * SLAC software, this and all the preceding Stanford University notices
40 * are to remain affixed to any copy or derivative of this software made
41 * or distributed by the recipient and are to be affixed to any copy of
42 * software made or distributed by the recipient that contains a copy or
43 * derivative of this software.
44 *
45 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
46 */ 
47
48#include <rtems.h>
49#include <rtems/bspIo.h>
50#include <bsp/pci.h>
51#include <stdint.h>
52#include "pci_io_remap.h"
53
54#ifndef PCI_MULTI_FUN
55#define PCI_MULTI_FUN 0x80
56#endif
57
58#ifndef PCI_HEADER_TYPE_MSK
59#define PCI_HEADER_TYPE_MSK 0x7f
60#endif
61
62/* Reconfigure all I/O base address registers for a range of PCI busses
63 * (from and including 'bus_from' up to and not including 'bus_to').
64 * adding an offset. This involves adjusting the base and limit registers
65 * of PCI-PCI bridges, too.
66 *
67 * RESTRICTIONS: 'offset' must be 4k aligned (PCI req.); no argument check
68 *       on the bus numbers is done.
69 *
70 * RETURNS: 0 on success and a number > 0 indicating the number of
71 *          non-32bit bridges found where the offset couldn't be added.
72 *          Devices behind such a bridge are not accessible through I/O
73 *          and should probably be switched off (not done by this code).
74 */
75int
76rtems_pci_io_remap(int bus_from, int bus_to, uint32_t offset)
77{
78  int           rval = 0;
79  int           bus, dev, fun, maxf;
80  int           bar, numBars = 0;
81  uint8_t       b;
82  uint16_t      s;
83  uint32_t      d;
84  unsigned int  bas, lim;
85
86  if ( offset & ((1<<12)-1) ) {
87    rtems_panic("rtems_pci_io_remap(): offset must be 4k aligned");
88    return -1;
89  }
90
91
92  for ( bus=bus_from; bus < bus_to; bus++ ) {
93    for ( dev = 0; dev<PCI_MAX_DEVICES; dev++ ) {
94
95      maxf = 1;
96
97      for ( fun = 0; fun < maxf; fun++ ) {
98        pci_read_config_word( bus, dev, fun, PCI_VENDOR_ID, &s );
99        if ( 0xffff == s )
100          continue;
101
102        pci_read_config_byte( bus, dev, fun, PCI_HEADER_TYPE, &b );
103
104        /* readjust the max. function number to scan if this is a multi-function
105         * device.
106         */
107        if ( 0 == fun && (PCI_MULTI_FUN & b) )
108          maxf = PCI_MAX_FUNCTIONS;
109
110        /* Check the header type; panic if unknown.
111         * header type 0 has 6 bars, header type 1 (PCI-PCI bridge) has 2
112         */
113        b &= PCI_HEADER_TYPE_MSK;
114        switch ( b ) {
115          default:
116            printk("PCI header type %i (@%i/%i/%i)\n", b, bus, dev, fun);
117            rtems_panic("rtems_pci_io_remap(): unknown PCI header type");
118          return -1; /* keep compiler happy */
119
120          case PCI_HEADER_TYPE_CARDBUS:
121            printk("PCI header type %i (@%i/%i/%i)\n", b, bus, dev, fun);
122            rtems_panic("rtems_pci_io_remap():  don't know how to deal with Cardbus bridge");
123          return -1;
124
125          case PCI_HEADER_TYPE_NORMAL:
126            numBars = 6*4;  /* loop below counts reg. offset in bytes */
127          break;
128
129          case PCI_HEADER_TYPE_BRIDGE:
130            numBars = 2*4;  /* loop below counts reg. offset in bytes */
131          break;
132
133        }
134
135        for ( bar = 0; bar < numBars; bar+=4 ) {
136          pci_read_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0 + bar, &d );
137          if ( PCI_BASE_ADDRESS_SPACE_IO & d ) {
138            /* It's an I/O BAR; remap */
139            d &= PCI_BASE_ADDRESS_IO_MASK;
140            if ( d ) {
141              /* IO bar was configured; add offset */
142              d += offset;
143              pci_write_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0 + bar, d );
144            }
145          } else {
146            /* skip upper half of 64-bit window */
147            d &= PCI_BASE_ADDRESS_MEM_TYPE_MASK;
148            if ( PCI_BASE_ADDRESS_MEM_TYPE_64 == d )
149              bar+=4;
150          }
151        }
152
153        /* Now it's time to deal with bridges */
154        if ( PCI_HEADER_TYPE_BRIDGE == b ) {
155          /* must adjust the limit registers */
156          pci_read_config_byte( bus, dev, fun, PCI_IO_LIMIT, &b );
157          pci_read_config_word( bus, dev, fun, PCI_IO_LIMIT_UPPER16, &s );
158          lim  = (s<<16) + (( b & PCI_IO_RANGE_MASK ) << 8);
159          lim += offset;
160
161          pci_read_config_byte( bus, dev, fun, PCI_IO_BASE, &b );
162          pci_read_config_word( bus, dev, fun, PCI_IO_BASE_UPPER16, &s );
163          bas  = (s<<16) + (( b & PCI_IO_RANGE_MASK ) << 8);
164          bas += offset;
165
166          b &= PCI_IO_RANGE_TYPE_MASK;
167          switch ( b ) {
168            default:
169              printk("Unknown IO range type 0x%x (@%i/%i/%i)\n", b, bus, dev, fun);
170              rtems_panic("rtems_pci_io_remap(): unknown IO range type");
171            return -1;
172
173            case PCI_IO_RANGE_TYPE_16:
174              if ( bas > 0xffff || lim > 0xffff ) {
175                printk("PCI I/O range type 1 (16bit) bridge (@%i/%i/%i) found:\n", bus, dev, fun);
176                printk("WARNING: base (0x%08x) or limit (0x%08x) exceed 16-bit;\n", bas, lim);
177                printk("         devices behind this bridge are NOT accessible!\n");
178
179                /* FIXME: should we disable devices behind this bridge ? */
180                bas = lim = 0;
181              }
182            break;
183
184            case PCI_IO_RANGE_TYPE_32:
185            break;
186          }
187
188          b = (uint8_t)((bas>>8) & PCI_IO_RANGE_MASK);
189          pci_write_config_byte( bus, dev, fun, PCI_IO_BASE, b );
190
191          s = (uint16_t)((bas>>16)&0xffff);
192          pci_write_config_word( bus, dev, fun, PCI_IO_BASE_UPPER16, s);
193
194          b = (uint8_t)((lim>>8) & PCI_IO_RANGE_MASK);
195          pci_write_config_byte( bus, dev, fun, PCI_IO_LIMIT, b );
196          s = (uint16_t)((lim>>16)&0xffff);
197          pci_write_config_word( bus, dev, fun, PCI_IO_LIMIT_UPPER16, s );
198        }
199      }
200    }
201  }
202  return rval;
203}
Note: See TracBrowser for help on using the repository browser.