source: rtems/c/src/lib/libbsp/shared/pci/pci_find_device.c @ f770fcb

5
Last change on this file since f770fcb was f770fcb, checked in by Joel Sherrill <joel@…>, on Mar 3, 2016 at 4:36:24 PM

Add shared PCI support and enhance pc386 to support non-legacy PCI configuration space

This patch fundamentally results from enhancements to the pc386 BSP
to support systems which do NOT have the legacy PCI BIOS. The
patch adds support for detecting when legacy PCI BIOS is not
present and then using IO space to access to PCI Configuration Space.
This resulted in dynamically selected between two implementations
of PCI and refactoring out the shared methods.

This patch adds shared implementations of pci_bus_count() and
pci_find_device(). Subsequent patches will remove implementations
of these methods in other BSPs where possible.

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/**
2 * @file
3 *
4 * This file implements a BSP independent version of pci_find_device().
5 */
6
7/*
8 * The software in this file was based upon the pci_find_device()
9 * implementation provided by  Till Straumann under the following terms.
10 * That implementation had been copied to multiple BSPs. This implementation
11 * is BSP independent and follows RTEMS Project coding guidelines.
12 *
13 * COPYRIGHT (c) 2016.
14 * On-Line Applications Research Corporation (OAR).
15 *
16 * Authorship
17 * ----------
18 * This software was created by
19 *     Till Straumann <strauman@slac.stanford.edu>, 2001,
20 *      Stanford Linear Accelerator Center, Stanford University.
21 *
22 * Acknowledgement of sponsorship
23 * ------------------------------
24 * This software was produced by
25 *     the Stanford Linear Accelerator Center, Stanford University,
26 *      under Contract DE-AC03-76SFO0515 with the Department of Energy.
27 *
28 * Government disclaimer of liability
29 * ----------------------------------
30 * Neither the United States nor the United States Department of Energy,
31 * nor any of their employees, makes any warranty, express or implied, or
32 * assumes any legal liability or responsibility for the accuracy,
33 * completeness, or usefulness of any data, apparatus, product, or process
34 * disclosed, or represents that its use would not infringe privately owned
35 * rights.
36 *
37 * Stanford disclaimer of liability
38 * --------------------------------
39 * Stanford University makes no representations or warranties, express or
40 * implied, nor assumes any liability for the use of this software.
41 *
42 * Stanford disclaimer of copyright
43 * --------------------------------
44 * Stanford University, owner of the copyright, hereby disclaims its
45 * copyright and all other rights in this software.  Hence, anyone may
46 * freely use it for any purpose without restriction.
47 *
48 * Maintenance of notices
49 * ----------------------
50 * In the interest of clarity regarding the origin and status of this
51 * SLAC software, this and all the preceding Stanford University notices
52 * are to remain affixed to any copy or derivative of this software made
53 * or distributed by the recipient and are to be affixed to any copy of
54 * software made or distributed by the recipient that contains a copy or
55 * derivative of this software.
56 *
57 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
58 */
59
60
61#include <rtems/pci.h>
62#include <rtems/bspIo.h>
63#include <inttypes.h>
64#include <stdio.h>
65
66/*
67 *  Public methods from this file
68 */
69void pci_dump(FILE *f);
70
71/*
72 * These are used to construct the handle returned by pci_find_device()
73 * but the caller does not need to know how to decode them.
74 */
75#define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
76#define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
77#define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
78#define PCIB_DEVSIG_MAKE(b,d,f) ((b<<8)|(d<<3)|(f))
79
80/*
81 * Function pointer to helper function called during bus iteration.
82 */
83typedef int (*pci_scan_helper_t)(
84  int   bus,
85  int   dev,
86  int   fun,
87  void *uarg
88);
89
90/*
91 *
92 */
93static uint32_t pci_scan(
94  uint32_t           handle,
95  pci_scan_helper_t  helper,
96  void              *uarg
97);
98
99typedef struct {
100  uint16_t   vendor_id;
101  uint16_t   device_id;
102  int        instance;
103  uint8_t    bus;
104  uint8_t    device;
105  uint8_t    function;
106} pci_scan_arg_t;
107
108static int find_dev_helper(
109  int   bus,
110  int   device,
111  int   function,
112  void *uarg
113)
114{
115  pci_scan_arg_t  *scan = uarg;
116  uint16_t         vendor_tmp;
117  uint16_t         device_tmp;
118
119  pci_read_config_word(bus, device, function, PCI_VENDOR_ID, &vendor_tmp);
120  if (scan->vendor_id == vendor_tmp) {
121    pci_read_config_word(bus, device, function, PCI_DEVICE_ID, &device_tmp);
122    if (scan->device_id == device_tmp && scan->instance-- == 0) {
123      scan->bus      = bus;
124      scan->device   = device;
125      scan->function = function;
126
127      return 1;
128    }
129  }
130  return 0;
131}
132
133int pci_find_device(
134  uint16_t vendorid,
135  uint16_t deviceid,
136  int      instance,
137  int     *bus,
138  int     *device,
139  int     *function
140)
141{
142  pci_scan_arg_t  scan;
143
144  scan.instance   = instance;
145  scan.vendor_id  = vendorid;
146  scan.device_id  = deviceid;
147
148  if ( pci_scan(0, find_dev_helper, (void*)&scan) != 0 ) {
149    *bus      = scan.bus;
150    *device   = scan.device;
151    *function = scan.function;
152    return 0;
153  }
154  return -1;
155}
156
157static int dump_dev_helper(
158  int   bus,
159  int   device,
160  int   function,
161  void *arg
162)
163{
164  uint16_t  vendor_id;
165  uint16_t  device_id;
166  uint16_t  cmd;
167  uint16_t  status;
168  uint32_t  base0;
169  uint32_t  base1;
170  uint8_t   irq_pin;
171  uint8_t   int_line;
172  FILE     *fp = arg;
173
174  pci_read_config_word (bus, device, function, PCI_VENDOR_ID,      &vendor_id);
175  pci_read_config_word (bus, device, function, PCI_DEVICE_ID,      &device_id);
176  pci_read_config_word (bus, device, function, PCI_COMMAND,        &cmd);
177  pci_read_config_word (bus, device, function, PCI_STATUS,         &status);
178  pci_read_config_dword(bus, device, function, PCI_BASE_ADDRESS_0, &base0);
179  pci_read_config_dword(bus, device, function, PCI_BASE_ADDRESS_1, &base1);
180  pci_read_config_byte (bus, device, function, PCI_INTERRUPT_PIN,  &irq_pin);
181  pci_read_config_byte (bus, device, function, PCI_INTERRUPT_LINE, &int_line);
182
183  fprintf(
184    fp,
185    "%3d:0x%02x:%d   0x%04x:0x%04x 0x%04x 0x%04x 0x%08" PRIx32 " 0x%08" PRIx32 "   %d %3d(0x%02x)\n",
186    bus,
187    device,
188    function,
189    vendor_id,
190    device_id,
191    cmd,
192    status,
193    base0,
194    base1,
195    irq_pin,
196    int_line,
197    int_line
198  );
199  return 0;
200}
201
202void pci_dump(
203  FILE *fp
204)
205{
206  if ( !fp )
207    fp = stdout;
208  fprintf(
209    fp,
210    "BUS:SLOT:FUN VENDOR:DEV_ID   CMD  STAT   BASE_ADDR0 BASE_ADDR1 INTn IRQ_LINE\n"
211  );
212  pci_scan(0, dump_dev_helper, fp);
213}
214
215static uint32_t pci_scan(
216  uint32_t           handle,
217  pci_scan_helper_t  helper,
218  void               *arg
219)
220{
221  uint32_t vendor;
222  uint8_t  bus;
223  uint8_t  dev;
224  uint8_t  fun;
225  uint8_t  hd;
226
227  bus = PCIB_DEVSIG_BUS(  (unsigned long)handle );
228  dev = PCIB_DEVSIG_DEV(  (unsigned long)handle );
229  fun = PCIB_DEVSIG_FUNC( (unsigned long)handle );
230
231  hd = fun > 0 ? PCI_MAX_FUNCTIONS : 1;
232
233  for (; bus<pci_bus_count(); bus++, dev=0) {
234    for (; dev<PCI_MAX_DEVICES; dev++, fun=0) {
235      for (; fun<hd; fun++) {
236        /*
237         * The last devfn id/slot is special; must skip it
238         */
239        if ((PCI_MAX_DEVICES-1 == dev) && (PCI_MAX_FUNCTIONS-1 == fun) )
240          break;
241
242        (void)pci_read_config_dword(bus, dev, 0, PCI_VENDOR_ID, &vendor);
243        if (PCI_INVALID_VENDORDEVICEID == vendor)
244          continue;
245
246        if ( fun == 0 ) {
247          pci_read_config_byte(bus,dev, 0,  PCI_HEADER_TYPE, &hd);
248          hd = (hd & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1);
249        }
250
251        (void)pci_read_config_dword(bus, dev, fun, PCI_VENDOR_ID, &vendor);
252        if (PCI_INVALID_VENDORDEVICEID == vendor)
253          continue;
254        #ifdef PCI_DEBUG
255          fprintf(
256            stderr,
257            "pci_scan: found 0x%08" PRIx32 " at %d/x%02x/%d\n", vendor, bus, dev, fun
258          );
259        #endif
260        if ( (*helper)(bus, dev, fun, arg) > 0 ) {
261          if ( ++fun >= hd ) {
262            fun = 0;
263            if ( ++dev >= PCI_MAX_DEVICES ) {
264              dev = 0;
265              bus++;
266            }
267          }
268          return PCIB_DEVSIG_MAKE(bus,dev,fun);
269        }
270      }
271    }
272  }
273  return 0;
274}
Note: See TracBrowser for help on using the repository browser.