OSDN Git Service

solx_devfs.c: fix gcc warnings about casting away const when reading data
[android-x86/external-libpciaccess.git] / src / solx_devfs.c
1 /*
2  * (C) Copyright IBM Corporation 2006
3  * Copyright (c) 2007, 2009, 2011, Oracle and/or its affiliates.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * on the rights to use, copy, modify, merge, publish, distribute, sub
10  * license, and/or sell copies of the Software, and to permit persons to whom
11  * the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
20  * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 /*
26  * Solaris devfs interfaces
27  */
28
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <sys/mman.h>
36 #include <errno.h>
37 #include <sys/pci.h>
38 #include <libdevinfo.h>
39 #include "pci_tools.h"
40
41 #include "pciaccess.h"
42 #include "pciaccess_private.h"
43
44 /* #define DEBUG */
45
46 #define INITIAL_NUM_DEVICES     256
47 #define CELL_NUMS_1275  (sizeof(pci_regspec_t) / sizeof(uint_t))
48
49 typedef union {
50     uint8_t bytes[16 * sizeof (uint32_t)];
51     uint32_t dwords[16];
52 } pci_conf_hdr_t;
53
54 typedef struct i_devnode {
55     uint8_t bus;
56     uint8_t dev;
57     uint8_t func;
58     di_node_t node;
59 } i_devnode_t;
60
61 typedef struct nexus {
62     int fd;
63     int first_bus;
64     int last_bus;
65     int domain;
66     char *path;                 /* for errors/debugging; fd is all we need */
67     char *dev_path;
68     struct nexus *next;
69 #ifdef __sparc
70     struct pci_device **devlist;
71     volatile size_t num_allocated_elems;
72     volatile size_t num_devices;
73 #endif
74 } nexus_t;
75
76 typedef struct probe_info {
77     volatile size_t num_allocated_elems;
78     volatile size_t num_devices;
79     struct pci_device_private * volatile devices;
80 } probe_info_t;
81
82 static nexus_t *nexus_list = NULL;
83 #if !defined(__sparc)
84 static int xsvc_fd = -1;
85 #endif
86
87 #ifdef __sparc
88 static di_prom_handle_t di_phdl;
89 #endif
90
91 /*
92  * Read config space in native processor endianness.  Endian-neutral
93  * processing can then take place.  On big endian machines, MSB and LSB
94  * of little endian data end up switched if read as little endian.
95  * They are in correct order if read as big endian.
96  */
97 #if defined(__sparc)
98 # define NATIVE_ENDIAN  PCITOOL_ACC_ATTR_ENDN_BIG
99 #elif defined(__x86)
100 # define NATIVE_ENDIAN  PCITOOL_ACC_ATTR_ENDN_LTL
101 #else
102 # error "ISA is neither __sparc nor __x86"
103 #endif
104
105 #ifdef __sparc
106 #define MAPPING_DEV_PATH(dev)    (((struct pci_device_private *) dev)->device_string)
107 #endif
108
109 /*
110  * Identify problematic southbridges.  These have device id 0x5249 and
111  * vendor id 0x10b9.  Check for revision ID 0 and class code 060400 as well.
112  * Values are little endian, so they are reversed for SPARC.
113  *
114  * Check for these southbridges on all architectures, as the issue is a
115  * southbridge issue, independent of processor.
116  *
117  * If one of these is found during probing, skip probing other devs/funcs on
118  * the rest of the bus, since the southbridge and all devs underneath will
119  * otherwise disappear.
120  */
121 #if (NATIVE_ENDIAN == PCITOOL_ACC_ATTR_ENDN_BIG)
122 # define U45_SB_DEVID_VID       0xb9104952
123 # define U45_SB_CLASS_RID       0x00000406
124 #else
125 # define U45_SB_DEVID_VID       0x524910b9
126 # define U45_SB_CLASS_RID       0x06040000
127 #endif
128
129 #ifdef __sparc
130 static nexus_t *
131 find_nexus_for_dev(struct pci_device *dev)
132 {
133     nexus_t *nexus;
134     int i;
135
136     for (nexus = nexus_list ; nexus != NULL ; nexus = nexus->next) {
137         for (i = 0; i < nexus->num_devices; i++) {
138             if (nexus->devlist[i] == dev)
139                 return nexus;
140         }
141     }
142     return NULL;
143 }
144 #else
145 static nexus_t *
146 find_nexus_for_bus( int domain, int bus )
147 {
148     nexus_t *nexus;
149
150     for (nexus = nexus_list ; nexus != NULL ; nexus = nexus->next) {
151         if ((domain == nexus->domain) &&
152             (bus >= nexus->first_bus) && (bus <= nexus->last_bus)) {
153             return nexus;
154         }
155     }
156     return NULL;
157 }
158 #endif
159
160 #define GET_CONFIG_VAL_8(offset) (config_hdr.bytes[offset])
161 #define GET_CONFIG_VAL_16(offset) \
162     (uint16_t) (GET_CONFIG_VAL_8(offset) + (GET_CONFIG_VAL_8(offset+1) << 8))
163 #define GET_CONFIG_VAL_32(offset) \
164     (uint32_t) (GET_CONFIG_VAL_8(offset) +              \
165                 (GET_CONFIG_VAL_8(offset+1) << 8) +     \
166                 (GET_CONFIG_VAL_8(offset+2) << 16) +    \
167                 (GET_CONFIG_VAL_8(offset+3) << 24))
168
169 /*
170  * Release all the resources
171  * Solaris version
172  */
173 static void
174 pci_system_solx_devfs_destroy( void )
175 {
176     /*
177      * The memory allocated for pci_sys & devices in create routines
178      * will be freed in pci_system_cleanup.
179      * Need to free system-specific allocations here.
180      */
181     nexus_t *nexus, *next;
182
183     for (nexus = nexus_list ; nexus != NULL ; nexus = next) {
184         next = nexus->next;
185         close(nexus->fd);
186         free(nexus->path);
187         free(nexus->dev_path);
188 #ifdef __sparc
189         {
190             struct pci_device *dev;
191             int i;
192
193             for (i = 0; i < nexus->num_devices; i++) {
194                 dev = nexus->devlist[i];
195                 if (MAPPING_DEV_PATH(dev))
196                     di_devfs_path_free((char *) MAPPING_DEV_PATH(dev));
197             }
198         }
199         free(nexus->devlist);
200 #endif
201         free(nexus);
202     }
203     nexus_list = NULL;
204
205 #ifdef __sparc
206     if (di_phdl != DI_PROM_HANDLE_NIL)
207         (void) di_prom_fini(di_phdl);
208 #else
209     if (xsvc_fd >= 0) {
210         close(xsvc_fd);
211         xsvc_fd = -1;
212     }
213 #endif
214 }
215
216 /*
217  * Retrieve first 16 dwords of device's config header, except for the first
218  * dword.  First 16 dwords are defined by the PCI specification.
219  */
220 static int
221 get_config_header(int fd, uint8_t bus_no, uint8_t dev_no, uint8_t func_no,
222                   pci_conf_hdr_t *config_hdr_p)
223 {
224     pcitool_reg_t cfg_prg;
225     int i;
226     int rval = 0;
227
228     /* Prepare a local pcitool_reg_t so as to not disturb the caller's. */
229     cfg_prg.offset = 0;
230     cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
231     cfg_prg.bus_no = bus_no;
232     cfg_prg.dev_no = dev_no;
233     cfg_prg.func_no = func_no;
234     cfg_prg.barnum = 0;
235     cfg_prg.user_version = PCITOOL_USER_VERSION;
236
237     /* Get dwords 1-15 of config space. They must be read as uint32_t. */
238     for (i = 1; i < (sizeof (pci_conf_hdr_t) / sizeof (uint32_t)); i++) {
239         cfg_prg.offset += sizeof (uint32_t);
240         if ((rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) {
241             break;
242         }
243         config_hdr_p->dwords[i] = (uint32_t)cfg_prg.data;
244     }
245
246     return (rval);
247 }
248
249
250 /*
251  * Probe device's functions.  Modifies many fields in the prg_p.
252  */
253 static int
254 probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, probe_info_t *pinfo)
255 {
256     pci_conf_hdr_t      config_hdr;
257     boolean_t           multi_function_device;
258     int8_t              func;
259     int8_t              first_func = 0;
260     int8_t              last_func = PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT;
261     int                 rval = 0;
262     struct pci_device * pci_base;
263
264     /*
265      * Loop through at least func=first_func.  Continue looping through
266      * functions if there are no errors and the device is a multi-function
267      * device.
268      *
269      * (Note, if first_func == 0, header will show whether multifunction
270      * device and set multi_function_device.  If first_func != 0, then we
271      * will force the loop as the user wants a specific function to be
272      * checked.
273      */
274     for (func = first_func, multi_function_device = B_FALSE;
275          ((func <= last_func) &&
276           ((func == first_func) || (multi_function_device)));
277          func++) {
278         prg_p->func_no = func;
279
280         /*
281          * Four things can happen here:
282          *
283          * 1) ioctl comes back as EFAULT and prg_p->status is
284          *    PCITOOL_INVALID_ADDRESS.  There is no device at this location.
285          *
286          * 2) ioctl comes back successful and the data comes back as
287          *    zero.  Config space is mapped but no device responded.
288          *
289          * 3) ioctl comes back successful and the data comes back as
290          *    non-zero.  We've found a device.
291          *
292          * 4) Some other error occurs in an ioctl.
293          */
294
295         prg_p->status = PCITOOL_SUCCESS;
296         prg_p->offset = 0;
297         prg_p->data = 0;
298         prg_p->user_version = PCITOOL_USER_VERSION;
299
300         errno = 0;
301         if (((rval = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, prg_p)) != 0) ||
302             (prg_p->data == 0xffffffff)) {
303
304             /*
305              * Accept errno == EINVAL along with status of
306              * PCITOOL_OUT_OF_RANGE because some systems
307              * don't implement the full range of config space.
308              * Leave the loop quietly in this case.
309              */
310             if ((errno == EINVAL) ||
311                 (prg_p->status == PCITOOL_OUT_OF_RANGE)) {
312                 break;
313             }
314
315             /*
316              * Exit silently with ENXIO as this means that there are
317              * no devices under the pci root nexus.
318              */
319             else if ((errno == ENXIO) &&
320                      (prg_p->status == PCITOOL_IO_ERROR)) {
321                 break;
322             }
323
324             /*
325              * Expect errno == EFAULT along with status of
326              * PCITOOL_INVALID_ADDRESS because there won't be
327              * devices at each stop.  Quit on any other error.
328              */
329             else if (((errno != EFAULT) ||
330                       (prg_p->status != PCITOOL_INVALID_ADDRESS)) &&
331                      (prg_p->data != 0xffffffff)) {
332 #ifdef __sparc
333 /* on sparc, devices can be enumerated discontiguously. Do not quit */
334                 rval = 0;
335 #endif
336                 break;
337             }
338
339             /*
340              * If no function at this location,
341              * just advance to the next function.
342              */
343             else {
344                 rval = 0;
345             }
346
347             /*
348              * Data came back as 0.
349              * Treat as unresponsive device and check next device.
350              */
351         } else if (prg_p->data == 0) {
352             rval = 0;
353             break;      /* Func loop. */
354
355             /* Found something. */
356         } else {
357             config_hdr.dwords[0] = (uint32_t)prg_p->data;
358
359             /* Get the rest of the PCI header. */
360             if ((rval = get_config_header(nexus->fd, prg_p->bus_no,
361                                           prg_p->dev_no, prg_p->func_no,
362                                           &config_hdr)) != 0) {
363                 break;
364             }
365
366             /*
367              * Special case for the type of Southbridge found on
368              * Ultra-45 and other sun4u fire workstations.
369              */
370             if ((config_hdr.dwords[0] == U45_SB_DEVID_VID) &&
371                 (config_hdr.dwords[2] == U45_SB_CLASS_RID)) {
372                 rval = ECANCELED;
373                 break;
374             }
375
376             /*
377              * Found one device with bus number, device number and
378              * function number.
379              */
380
381             pci_base = &pinfo->devices[pinfo->num_devices].base;
382
383             pci_base->domain = nexus->domain;
384             pci_base->bus = prg_p->bus_no;
385             pci_base->dev = prg_p->dev_no;
386             pci_base->func = func;
387
388             /*
389              * for the format of device_class, see struct pci_device;
390              */
391
392             pci_base->device_class =
393                 (GET_CONFIG_VAL_8(PCI_CONF_BASCLASS) << 16) |
394                 (GET_CONFIG_VAL_8(PCI_CONF_SUBCLASS) << 8) |
395                 GET_CONFIG_VAL_8(PCI_CONF_PROGCLASS);
396
397             pci_base->revision          = GET_CONFIG_VAL_8(PCI_CONF_REVID);
398             pci_base->vendor_id         = GET_CONFIG_VAL_16(PCI_CONF_VENID);
399             pci_base->device_id         = GET_CONFIG_VAL_16(PCI_CONF_DEVID);
400             pci_base->subvendor_id      = GET_CONFIG_VAL_16(PCI_CONF_SUBVENID);
401             pci_base->subdevice_id      = GET_CONFIG_VAL_16(PCI_CONF_SUBSYSID);
402             pci_base->irq               = GET_CONFIG_VAL_8(PCI_CONF_ILINE);
403
404             pinfo->devices[pinfo->num_devices].header_type
405                                         = GET_CONFIG_VAL_8(PCI_CONF_HEADER);
406
407 #ifdef DEBUG
408             fprintf(stderr,
409                     "nexus = %s, busno = %x, devno = %x, funcno = %x\n",
410                     nexus->path, prg_p->bus_no, prg_p->dev_no, func);
411 #endif
412
413             pinfo->num_devices++;
414             if (pinfo->num_devices == pinfo->num_allocated_elems) {
415                 struct pci_device_private *new_devs;
416                 size_t new_num_elems = pinfo->num_allocated_elems * 2;
417
418                 new_devs = realloc(pinfo->devices,
419                         new_num_elems * sizeof (struct pci_device_private));
420                 if (new_devs == NULL) {
421                     (void) fprintf(stderr,
422                                    "Error allocating memory for PCI devices:"
423                                    " %s\n discarding additional devices\n",
424                                    strerror(errno));
425                     return (rval);
426                 }
427                 (void) memset(&new_devs[pinfo->num_devices], 0,
428                         pinfo->num_allocated_elems *
429                         sizeof (struct pci_device_private));
430                 pinfo->num_allocated_elems = new_num_elems;
431                 pinfo->devices = new_devs;
432             }
433
434 #ifdef __sparc
435             nexus->devlist[nexus->num_devices++] = pci_base;
436
437             if (nexus->num_devices == nexus->num_allocated_elems) {
438                 struct pci_device **new_devs;
439                 size_t new_num_elems = nexus->num_allocated_elems * 2;
440
441                 new_devs = realloc(nexus->devlist,
442                         new_num_elems * sizeof (struct pci_device *));
443                 if (new_devs == NULL)
444                     return (rval);
445                 (void) memset(&new_devs[nexus->num_devices], 0,
446                         nexus->num_allocated_elems *
447                         sizeof (struct pci_device *));
448                 nexus->num_allocated_elems = new_num_elems;
449                 nexus->devlist = new_devs;
450             }
451 #endif
452
453             /*
454              * Accommodate devices which state their
455              * multi-functionality only in their function 0 config
456              * space.  Note multi-functionality throughout probing
457              * of all of this device's functions.
458              */
459             if (config_hdr.bytes[PCI_CONF_HEADER] & PCI_HEADER_MULTI) {
460                 multi_function_device = B_TRUE;
461             }
462         }
463     }
464
465     return (rval);
466 }
467
468
469 /*
470  * Solaris version
471  * Probe a given nexus config space for devices.
472  *
473  * fd is the file descriptor of the nexus.
474  * input_args contains commandline options as specified by the user.
475  */
476 static int
477 do_probe(nexus_t *nexus, probe_info_t *pinfo)
478 {
479     pcitool_reg_t prg;
480     uint32_t bus;
481     uint8_t dev;
482     uint32_t last_bus = nexus->last_bus;
483     uint8_t last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT;
484     uint8_t first_bus = nexus->first_bus;
485     uint8_t first_dev = 0;
486     int rval = 0;
487
488     prg.barnum = 0;     /* Config space. */
489
490     /* Must read in 4-byte quantities. */
491     prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
492
493     prg.data = 0;
494
495     /*
496      * Loop through all valid bus / dev / func combinations to check for
497      * all devices, with the following exceptions:
498      *
499      * When nothing is found at function 0 of a bus / dev combination, skip
500      * the other functions of that bus / dev combination.
501      *
502      * When a found device's function 0 is probed and it is determined that
503      * it is not a multifunction device, skip probing of that device's
504      * other functions.
505      */
506     for (bus = first_bus; ((bus <= last_bus) && (rval == 0)); bus++) {
507         prg.bus_no = (uint8_t)bus;
508
509         for (dev = first_dev; ((dev <= last_dev) && (rval == 0)); dev++) {
510             prg.dev_no = dev;
511             rval = probe_dev(nexus, &prg, pinfo);
512         }
513
514         /*
515          * Ultra-45 southbridge workaround:
516          * ECANCELED tells to skip to the next bus.
517          */
518         if (rval == ECANCELED) {
519             rval = 0;
520         }
521     }
522
523     return (rval);
524 }
525
526 /*
527  * This function is called from di_walk_minor() when any PROBE is processed
528  */
529 static int
530 probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg)
531 {
532     probe_info_t *pinfo = (probe_info_t *)arg;
533     char *nexus_name, *nexus_dev_path;
534     nexus_t *nexus;
535     int fd;
536     char nexus_path[MAXPATHLEN];
537
538     di_prop_t prop;
539     char *strings;
540     int *ints;
541     int numval;
542     int pci_node = 0;
543     int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M);
544     int domain = 0;
545 #ifdef __sparc
546     int bus_range_found = 0;
547     int device_type_found = 0;
548     di_prom_prop_t prom_prop;
549 #endif
550
551
552 #ifdef DEBUG
553     nexus_name = di_devfs_minor_path(minor);
554     fprintf(stderr, "-- device name: %s\n", nexus_name);
555 #endif
556
557     for (prop = di_prop_next(di_node, NULL); prop != NULL;
558          prop = di_prop_next(di_node, prop)) {
559
560         const char *prop_name = di_prop_name(prop);
561
562 #ifdef DEBUG
563         fprintf(stderr, "   property: %s\n", prop_name);
564 #endif
565
566         if (strcmp(prop_name, "device_type") == 0) {
567             numval = di_prop_strings(prop, &strings);
568             if (numval == 1) {
569                 if (strncmp(strings, "pci", 3) != 0)
570                     /* not a PCI node, bail */
571                     return (DI_WALK_CONTINUE);
572                 else {
573                     pci_node = 1;
574 #ifdef __sparc
575                     device_type_found =  1;
576 #endif
577                 }
578             }
579         }
580         else if (strcmp(prop_name, "class-code") == 0) {
581             /* not a root bus node, bail */
582             return (DI_WALK_CONTINUE);
583         }
584         else if (strcmp(prop_name, "bus-range") == 0) {
585             numval = di_prop_ints(prop, &ints);
586             if (numval == 2) {
587                 first_bus = ints[0];
588                 last_bus = ints[1];
589 #ifdef __sparc
590                 bus_range_found = 1;
591 #endif
592             }
593         }
594         else if (strcmp(prop_name, "pciseg") == 0) {
595             numval = di_prop_ints(prop, &ints);
596             if (numval == 1) {
597                 domain = ints[0];
598             }
599         }
600     }
601
602 #ifdef __sparc
603     if ((!device_type_found) && di_phdl) {
604         numval = di_prom_prop_lookup_strings(di_phdl, di_node,
605             "device_type", &strings);
606         if (numval == 1) {
607             if (strncmp(strings, "pci", 3) != 0)
608                 return (DI_WALK_CONTINUE);
609             else
610                 pci_node = 1;
611         }
612     }
613
614     if ((!bus_range_found) && di_phdl) {
615         numval = di_prom_prop_lookup_ints(di_phdl, di_node,
616             "bus-range", &ints);
617         if (numval == 2) {
618             first_bus = ints[0];
619             last_bus = ints[1];
620         }
621     }
622 #endif
623
624     if (pci_node != 1)
625         return (DI_WALK_CONTINUE);
626
627     /* we have a PCI root bus node. */
628     nexus = calloc(1, sizeof(nexus_t));
629     if (nexus == NULL) {
630         (void) fprintf(stderr, "Error allocating memory for nexus: %s\n",
631                        strerror(errno));
632         return (DI_WALK_TERMINATE);
633     }
634     nexus->first_bus = first_bus;
635     nexus->last_bus = last_bus;
636     nexus->domain = domain;
637
638 #ifdef __sparc
639     if ((nexus->devlist = calloc(INITIAL_NUM_DEVICES,
640                         sizeof (struct pci_device *))) == NULL) {
641         (void) fprintf(stderr, "Error allocating memory for nexus devlist: %s\n",
642                        strerror(errno));
643         free (nexus);
644         return (DI_WALK_TERMINATE);
645     }
646     nexus->num_allocated_elems = INITIAL_NUM_DEVICES;
647     nexus->num_devices = 0;
648 #endif
649
650     nexus_name = di_devfs_minor_path(minor);
651     if (nexus_name == NULL) {
652         (void) fprintf(stderr, "Error getting nexus path: %s\n",
653                        strerror(errno));
654         free(nexus);
655         return (DI_WALK_CONTINUE);
656     }
657
658     snprintf(nexus_path, sizeof(nexus_path), "/devices%s", nexus_name);
659     di_devfs_path_free(nexus_name);
660
661 #ifdef DEBUG
662     fprintf(stderr, "nexus = %s, bus-range = %d - %d\n",
663             nexus_path, first_bus, last_bus);
664 #endif
665
666     if ((fd = open(nexus_path, O_RDWR)) >= 0) {
667         nexus->fd = fd;
668         nexus->path = strdup(nexus_path);
669         nexus_dev_path = di_devfs_path(di_node);
670         nexus->dev_path = strdup(nexus_dev_path);
671         di_devfs_path_free(nexus_dev_path);
672         if ((do_probe(nexus, pinfo) != 0) && (errno != ENXIO)) {
673             (void) fprintf(stderr, "Error probing node %s: %s\n",
674                            nexus_path, strerror(errno));
675             (void) close(fd);
676             free(nexus->path);
677             free(nexus->dev_path);
678             free(nexus);
679         } else {
680             nexus->next = nexus_list;
681             nexus_list = nexus;
682         }
683     } else {
684         (void) fprintf(stderr, "Error opening %s: %s\n",
685                        nexus_path, strerror(errno));
686         free(nexus);
687     }
688
689     return DI_WALK_CONTINUE;
690 }
691
692 static int
693 find_target_node(di_node_t node, void *arg)
694 {
695     int *regbuf = NULL;
696     int len = 0;
697     uint32_t busno, funcno, devno;
698     i_devnode_t *devnode = (i_devnode_t *)arg;
699
700     /*
701      * Test the property functions, only for testing
702      */
703     /*
704     void *prop = DI_PROP_NIL;
705
706     (void) fprintf(stderr, "start of node 0x%x\n", node->nodeid);
707     while ((prop = di_prop_hw_next(node, prop)) != DI_PROP_NIL) {
708         int i;
709         (void) fprintf(stderr, "name=%s: ", di_prop_name(prop));
710         len = 0;
711         if (!strcmp(di_prop_name(prop), "reg")) {
712             len = di_prop_ints(prop, &regbuf);
713         }
714         for (i = 0; i < len; i++) {
715             fprintf(stderr, "0x%0x.", regbuf[i]);
716         }
717         fprintf(stderr, "\n");
718     }
719     (void) fprintf(stderr, "end of node 0x%x\n", node->nodeid);
720     */
721
722     len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &regbuf);
723
724 #ifdef __sparc
725     if ((len <= 0) && di_phdl)
726         len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &regbuf);
727 #endif
728
729     if (len <= 0) {
730 #ifdef DEBUG
731         fprintf(stderr, "error = %x\n", errno);
732         fprintf(stderr, "can not find assigned-address\n");
733 #endif
734         return (DI_WALK_CONTINUE);
735     }
736
737     busno = PCI_REG_BUS_G(regbuf[0]);
738     devno = PCI_REG_DEV_G(regbuf[0]);
739     funcno = PCI_REG_FUNC_G(regbuf[0]);
740
741     if ((busno == devnode->bus) &&
742         (devno == devnode->dev) &&
743         (funcno == devnode->func)) {
744         devnode->node = node;
745
746         return (DI_WALK_TERMINATE);
747     }
748
749     return (DI_WALK_CONTINUE);
750 }
751
752 /*
753  * Solaris version
754  */
755 static int
756 pci_device_solx_devfs_probe( struct pci_device * dev )
757 {
758     int err = 0;
759     di_node_t rnode = DI_NODE_NIL;
760     i_devnode_t args = { 0, 0, 0, DI_NODE_NIL };
761     int *regbuf;
762     pci_regspec_t *reg;
763     int i;
764     int len = 0;
765     uint ent = 0;
766     nexus_t *nexus;
767
768 #ifdef __sparc
769     if ( (nexus = find_nexus_for_dev(dev)) == NULL )
770 #else
771     if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL )
772 #endif
773         return ENODEV;
774
775     /*
776      * starting to find if it is MEM/MEM64/IO
777      * using libdevinfo
778      */
779     if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) {
780         err = errno;
781         (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
782     } else {
783         args.bus = dev->bus;
784         args.dev = dev->dev;
785         args.func = dev->func;
786         (void) di_walk_node(rnode, DI_WALK_CLDFIRST,
787                 (void *)&args, find_target_node);
788     }
789
790     if (args.node != DI_NODE_NIL) {
791 #ifdef __sparc
792         di_minor_t minor;
793 #endif
794
795 #ifdef __sparc
796         if (minor = di_minor_next(args.node, DI_MINOR_NIL))
797             MAPPING_DEV_PATH(dev) = di_devfs_minor_path (minor);
798         else
799             MAPPING_DEV_PATH(dev) = NULL;
800 #endif
801
802         /*
803          * It will succeed for sure, because it was
804          * successfully called in find_target_node
805          */
806         len = di_prop_lookup_ints(DDI_DEV_T_ANY, args.node,
807                                   "assigned-addresses",
808                                   &regbuf);
809
810 #ifdef __sparc
811         if ((len <= 0) && di_phdl) {
812             len = di_prom_prop_lookup_ints(di_phdl, args.node,
813                                 "assigned-addresses", &regbuf);
814         }
815 #endif
816     }
817
818     if (len <= 0)
819         goto cleanup;
820
821
822     /*
823      * how to find the size of rom???
824      * if the device has expansion rom,
825      * it must be listed in the last
826      * cells because solaris find probe
827      * the base address from offset 0x10
828      * to 0x30h. So only check the last
829      * item.
830      */
831     reg = (pci_regspec_t *)&regbuf[len - CELL_NUMS_1275];
832     if (PCI_REG_REG_G(reg->pci_phys_hi) == PCI_CONF_ROM) {
833         /*
834          * rom can only be 32 bits
835          */
836         dev->rom_size = reg->pci_size_low;
837         len = len - CELL_NUMS_1275;
838     }
839     else {
840         /*
841          * size default to 64K and base address
842          * default to 0xC0000
843          */
844         dev->rom_size = 0x10000;
845     }
846
847     /*
848      * Solaris has its own BAR index.
849      * Linux give two region slot for 64 bit address.
850      */
851     for (i = 0; i < len; i = i + CELL_NUMS_1275) {
852
853         reg = (pci_regspec_t *)&regbuf[i];
854         ent = reg->pci_phys_hi & 0xff;
855         /*
856          * G35 broken in BAR0
857          */
858         ent = (ent - PCI_CONF_BASE0) >> 2;
859         if (ent >= 6) {
860             fprintf(stderr, "error ent = %d\n", ent);
861             break;
862         }
863
864         /*
865          * non relocatable resource is excluded
866          * such like 0xa0000, 0x3b0. If it is met,
867          * the loop is broken;
868          */
869         if (!PCI_REG_REG_G(reg->pci_phys_hi))
870             break;
871
872         if (reg->pci_phys_hi & PCI_PREFETCH_B) {
873             dev->regions[ent].is_prefetchable = 1;
874         }
875
876
877         /*
878          * We split the shift count 32 into two 16 to
879          * avoid the complaining of the compiler
880          */
881         dev->regions[ent].base_addr = reg->pci_phys_low +
882             ((reg->pci_phys_mid << 16) << 16);
883         dev->regions[ent].size = reg->pci_size_low +
884             ((reg->pci_size_hi << 16) << 16);
885
886         switch (reg->pci_phys_hi & PCI_REG_ADDR_M) {
887             case PCI_ADDR_IO:
888                 dev->regions[ent].is_IO = 1;
889                 break;
890             case PCI_ADDR_MEM32:
891                 break;
892             case PCI_ADDR_MEM64:
893                 dev->regions[ent].is_64 = 1;
894                 /*
895                  * Skip one slot for 64 bit address
896                  */
897                 break;
898         }
899     }
900
901   cleanup:
902     if (rnode != DI_NODE_NIL) {
903         di_fini(rnode);
904     }
905     return (err);
906 }
907
908 /**
909  * Map a memory region for a device using /dev/xsvc.
910  *
911  * \param dev   Device whose memory region is to be mapped.
912  * \param map   Parameters of the mapping that is to be created.
913  *
914  * \return
915  * Zero on success or an \c errno value on failure.
916  */
917 static int
918 pci_device_solx_devfs_map_range(struct pci_device *dev,
919                                 struct pci_device_mapping *map)
920 {
921     const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0)
922                         ? (PROT_READ | PROT_WRITE) : PROT_READ;
923     int err = 0;
924
925 #ifdef __sparc
926     char        map_dev[128];
927     int         map_fd;
928
929     if (MAPPING_DEV_PATH(dev))
930         snprintf(map_dev, sizeof (map_dev), "%s%s", "/devices", MAPPING_DEV_PATH(dev));
931     else
932         strcpy (map_dev, "/dev/fb0");
933
934     if ((map_fd = open(map_dev, O_RDWR)) < 0) {
935         err = errno;
936         (void) fprintf(stderr, "can not open %s: %s\n", map_dev,
937                            strerror(errno));
938         return err;
939     }
940
941     map->memory = mmap(NULL, map->size, prot, MAP_SHARED, map_fd, map->base);
942 #else
943     /*
944      * Still used xsvc to do the user space mapping
945      */
946     if (xsvc_fd < 0) {
947         if ((xsvc_fd = open("/dev/xsvc", O_RDWR)) < 0) {
948             err = errno;
949             (void) fprintf(stderr, "can not open /dev/xsvc: %s\n",
950                            strerror(errno));
951             return err;
952         }
953     }
954
955     map->memory = mmap(NULL, map->size, prot, MAP_SHARED, xsvc_fd, map->base);
956 #endif
957
958     if (map->memory == MAP_FAILED) {
959         err = errno;
960
961         (void) fprintf(stderr, "map rom region =%llx failed: %s\n",
962                        map->base, strerror(errno));
963     }
964
965 #ifdef __sparc
966     close (map_fd);
967 #endif
968
969     return err;
970 }
971
972 /*
973  * Solaris version: read the VGA ROM data
974  */
975 static int
976 pci_device_solx_devfs_read_rom( struct pci_device * dev, void * buffer )
977 {
978     int err;
979     struct pci_device_mapping prom = {
980         .base = 0xC0000,
981         .size = dev->rom_size,
982         .flags = 0
983     };
984
985     err = pci_device_solx_devfs_map_range(dev, &prom);
986     if (err == 0) {
987         (void) bcopy(prom.memory, buffer, dev->rom_size);
988
989         if (munmap(prom.memory, dev->rom_size) == -1) {
990             err = errno;
991         }
992     }
993     return err;
994 }
995
996 /*
997  * solaris version: Read the configurations space of the devices
998  */
999 static int
1000 pci_device_solx_devfs_read( struct pci_device * dev, void * data,
1001                              pciaddr_t offset, pciaddr_t size,
1002                              pciaddr_t * bytes_read )
1003 {
1004     pcitool_reg_t cfg_prg;
1005     int err = 0;
1006     int i = 0;
1007     nexus_t *nexus;
1008
1009 #ifdef __sparc
1010     nexus = find_nexus_for_dev(dev);
1011 #else
1012     nexus = find_nexus_for_bus(dev->domain, dev->bus);
1013 #endif
1014
1015     *bytes_read = 0;
1016
1017     if ( nexus == NULL ) {
1018         return ENODEV;
1019     }
1020
1021     cfg_prg.offset = offset;
1022     cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
1023     cfg_prg.bus_no = dev->bus;
1024     cfg_prg.dev_no = dev->dev;
1025     cfg_prg.func_no = dev->func;
1026     cfg_prg.barnum = 0;
1027     cfg_prg.user_version = PCITOOL_USER_VERSION;
1028
1029     for (i = 0; i < size; i += PCITOOL_ACC_ATTR_SIZE(PCITOOL_ACC_ATTR_SIZE_1))
1030     {
1031         cfg_prg.offset = offset + i;
1032
1033         if ((err = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) {
1034             fprintf(stderr, "read bdf<%s,%x,%x,%x,%llx> config space failure\n",
1035                     nexus->path,
1036                     cfg_prg.bus_no,
1037                     cfg_prg.dev_no,
1038                     cfg_prg.func_no,
1039                     cfg_prg.offset);
1040             fprintf(stderr, "Failure cause = %x\n", err);
1041             break;
1042         }
1043
1044         ((uint8_t *)data)[i] = (uint8_t)cfg_prg.data;
1045         /*
1046          * DWORDS Offset or bytes Offset ??
1047          */
1048     }
1049     *bytes_read = i;
1050
1051     return (err);
1052 }
1053
1054 /*
1055  * Solaris version
1056  */
1057 static int
1058 pci_device_solx_devfs_write( struct pci_device * dev, const void * data,
1059                              pciaddr_t offset, pciaddr_t size,
1060                              pciaddr_t * bytes_written )
1061 {
1062     pcitool_reg_t cfg_prg;
1063     int err = 0;
1064     int cmd;
1065     nexus_t *nexus;
1066
1067 #ifdef __sparc
1068     nexus = find_nexus_for_dev(dev);
1069 #else
1070     nexus = find_nexus_for_bus(dev->domain, dev->bus);
1071 #endif
1072
1073     if ( bytes_written != NULL ) {
1074         *bytes_written = 0;
1075     }
1076
1077     if ( nexus == NULL ) {
1078         return ENODEV;
1079     }
1080
1081     cfg_prg.offset = offset;
1082     switch (size) {
1083         case 1:
1084             cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
1085             cfg_prg.data = *((const uint8_t *)data);
1086             break;
1087         case 2:
1088             cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + NATIVE_ENDIAN;
1089             cfg_prg.data = *((const uint16_t *)data);
1090             break;
1091         case 4:
1092             cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
1093             cfg_prg.data = *((const uint32_t *)data);
1094             break;
1095         case 8:
1096             cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 + NATIVE_ENDIAN;
1097             cfg_prg.data = *((const uint64_t *)data);
1098             break;
1099         default:
1100             return EINVAL;
1101     }
1102     cfg_prg.bus_no = dev->bus;
1103     cfg_prg.dev_no = dev->dev;
1104     cfg_prg.func_no = dev->func;
1105     cfg_prg.barnum = 0;
1106     cfg_prg.user_version = PCITOOL_USER_VERSION;
1107
1108     /*
1109      * Check if this device is bridge device.
1110      * If it is, it is also a nexus node???
1111      * It seems that there is no explicit
1112      * PCI nexus device for X86, so not applicable
1113      * from pcitool_bus_reg_ops in pci_tools.c
1114      */
1115     cmd = PCITOOL_DEVICE_SET_REG;
1116
1117     if ((err = ioctl(nexus->fd, cmd, &cfg_prg)) != 0) {
1118         return (err);
1119     }
1120     *bytes_written = size;
1121
1122     return (err);
1123 }
1124
1125
1126
1127 static const struct pci_system_methods solx_devfs_methods = {
1128     .destroy = pci_system_solx_devfs_destroy,
1129     .destroy_device = NULL,
1130     .read_rom = pci_device_solx_devfs_read_rom,
1131     .probe = pci_device_solx_devfs_probe,
1132     .map_range = pci_device_solx_devfs_map_range,
1133     .unmap_range = pci_device_generic_unmap_range,
1134
1135     .read = pci_device_solx_devfs_read,
1136     .write = pci_device_solx_devfs_write,
1137
1138     .fill_capabilities = pci_fill_capabilities_generic
1139 };
1140
1141 /*
1142  * Attempt to access PCI subsystem using Solaris's devfs interface.
1143  * Solaris version
1144  */
1145 _pci_hidden int
1146 pci_system_solx_devfs_create( void )
1147 {
1148     int err = 0;
1149     di_node_t di_node;
1150     probe_info_t pinfo;
1151     struct pci_device_private *devices;
1152
1153     if (nexus_list != NULL) {
1154         return 0;
1155     }
1156
1157     if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
1158         err = errno;
1159         (void) fprintf(stderr, "di_init() failed: %s\n",
1160                        strerror(errno));
1161         return (err);
1162     }
1163
1164     if ((devices = calloc(INITIAL_NUM_DEVICES,
1165                         sizeof (struct pci_device_private))) == NULL) {
1166         err = errno;
1167         di_fini(di_node);
1168         return (err);
1169     }
1170
1171 #ifdef __sparc
1172     if ((di_phdl = di_prom_init()) == DI_PROM_HANDLE_NIL)
1173         (void) fprintf(stderr, "di_prom_init failed: %s\n", strerror(errno));
1174 #endif
1175
1176     pinfo.num_allocated_elems = INITIAL_NUM_DEVICES;
1177     pinfo.num_devices = 0;
1178     pinfo.devices = devices;
1179     (void) di_walk_minor(di_node, DDI_NT_REGACC, 0, &pinfo, probe_nexus_node);
1180
1181     di_fini(di_node);
1182
1183     if ((pci_sys = calloc(1, sizeof (struct pci_system))) == NULL) {
1184         err = errno;
1185         free(devices);
1186         return (err);
1187     }
1188
1189     pci_sys->methods = &solx_devfs_methods;
1190     pci_sys->devices = pinfo.devices;
1191     pci_sys->num_devices = pinfo.num_devices;
1192
1193     return (err);
1194 }