solx_devfs.c revision 86ea1d58
14f5e7dd7Smrg/* 24f5e7dd7Smrg * (C) Copyright IBM Corporation 2006 386ea1d58Smrg * Copyright (c) 2007, 2009, 2011, 2012, 2013 Oracle and/or its affiliates. 44f5e7dd7Smrg * All Rights Reserved. 54f5e7dd7Smrg * 64f5e7dd7Smrg * Permission is hereby granted, free of charge, to any person obtaining a 74f5e7dd7Smrg * copy of this software and associated documentation files (the "Software"), 84f5e7dd7Smrg * to deal in the Software without restriction, including without limitation 94f5e7dd7Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 104f5e7dd7Smrg * license, and/or sell copies of the Software, and to permit persons to whom 114f5e7dd7Smrg * the Software is furnished to do so, subject to the following conditions: 124f5e7dd7Smrg * 134f5e7dd7Smrg * The above copyright notice and this permission notice (including the next 144f5e7dd7Smrg * paragraph) shall be included in all copies or substantial portions of the 154f5e7dd7Smrg * Software. 164f5e7dd7Smrg * 174f5e7dd7Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 184f5e7dd7Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 194f5e7dd7Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 204f5e7dd7Smrg * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 214f5e7dd7Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 224f5e7dd7Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 234f5e7dd7Smrg * DEALINGS IN THE SOFTWARE. 244f5e7dd7Smrg */ 254f5e7dd7Smrg/* 264f5e7dd7Smrg * Solaris devfs interfaces 274f5e7dd7Smrg */ 284f5e7dd7Smrg 294f5e7dd7Smrg#include <stdlib.h> 304f5e7dd7Smrg#include <strings.h> 314f5e7dd7Smrg#include <stdio.h> 324f5e7dd7Smrg#include <unistd.h> 334f5e7dd7Smrg#include <sys/types.h> 344f5e7dd7Smrg#include <fcntl.h> 354f5e7dd7Smrg#include <sys/mman.h> 364f5e7dd7Smrg#include <errno.h> 374f5e7dd7Smrg#include <sys/pci.h> 384f5e7dd7Smrg#include <libdevinfo.h> 394f5e7dd7Smrg#include "pci_tools.h" 404f5e7dd7Smrg 4186ea1d58Smrg#ifdef __x86 4286ea1d58Smrg# include <sys/sysi86.h> 4386ea1d58Smrg# include <sys/psw.h> 4486ea1d58Smrg#endif 4586ea1d58Smrg 464f5e7dd7Smrg#include "pciaccess.h" 474f5e7dd7Smrg#include "pciaccess_private.h" 484f5e7dd7Smrg 494f5e7dd7Smrg/* #define DEBUG */ 504f5e7dd7Smrg 51cad31331Smrg#define INITIAL_NUM_DEVICES 256 524f5e7dd7Smrg#define CELL_NUMS_1275 (sizeof(pci_regspec_t) / sizeof(uint_t)) 534f5e7dd7Smrg 544f5e7dd7Smrgtypedef struct i_devnode { 554f5e7dd7Smrg uint8_t bus; 564f5e7dd7Smrg uint8_t dev; 574f5e7dd7Smrg uint8_t func; 584f5e7dd7Smrg di_node_t node; 594f5e7dd7Smrg} i_devnode_t; 604f5e7dd7Smrg 614f5e7dd7Smrgtypedef struct nexus { 624f5e7dd7Smrg int fd; 634f5e7dd7Smrg int first_bus; 644f5e7dd7Smrg int last_bus; 65cad31331Smrg int domain; 664f5e7dd7Smrg char *path; /* for errors/debugging; fd is all we need */ 67cad31331Smrg char *dev_path; 684f5e7dd7Smrg struct nexus *next; 694f5e7dd7Smrg} nexus_t; 704f5e7dd7Smrg 71cad31331Smrgtypedef struct probe_info { 72cad31331Smrg volatile size_t num_allocated_elems; 73cad31331Smrg volatile size_t num_devices; 74cad31331Smrg struct pci_device_private * volatile devices; 75cad31331Smrg} probe_info_t; 76cad31331Smrg 7786ea1d58Smrgtypedef struct probe_args { 7886ea1d58Smrg probe_info_t *pinfo; 7986ea1d58Smrg nexus_t *nexus; 8086ea1d58Smrg int ret; 8186ea1d58Smrg} probe_args_t; 8286ea1d58Smrg 8386ea1d58Smrgtypedef struct property_info { 8486ea1d58Smrg const char *name; 8586ea1d58Smrg int value; 8686ea1d58Smrg} property_info_t; 8786ea1d58Smrg 884f5e7dd7Smrgstatic nexus_t *nexus_list = NULL; 89cad31331Smrg#if !defined(__sparc) 904f5e7dd7Smrgstatic int xsvc_fd = -1; 91cad31331Smrg#endif 92cad31331Smrg 93cad31331Smrg#ifdef __sparc 94cad31331Smrgstatic di_prom_handle_t di_phdl; 9586ea1d58Smrgstatic size_t nexus_count = 0; 96cad31331Smrg#endif 974f5e7dd7Smrg 984f5e7dd7Smrg/* 994f5e7dd7Smrg * Read config space in native processor endianness. Endian-neutral 1004f5e7dd7Smrg * processing can then take place. On big endian machines, MSB and LSB 1014f5e7dd7Smrg * of little endian data end up switched if read as little endian. 1024f5e7dd7Smrg * They are in correct order if read as big endian. 1034f5e7dd7Smrg */ 1044f5e7dd7Smrg#if defined(__sparc) 1054f5e7dd7Smrg# define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_BIG 1064f5e7dd7Smrg#elif defined(__x86) 1074f5e7dd7Smrg# define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_LTL 1084f5e7dd7Smrg#else 1094f5e7dd7Smrg# error "ISA is neither __sparc nor __x86" 1104f5e7dd7Smrg#endif 1114f5e7dd7Smrg 112cad31331Smrg#ifdef __sparc 113cad31331Smrg#define MAPPING_DEV_PATH(dev) (((struct pci_device_private *) dev)->device_string) 114cad31331Smrg#endif 115cad31331Smrg 1164f5e7dd7Smrgstatic nexus_t * 117cad31331Smrgfind_nexus_for_bus( int domain, int bus ) 1184f5e7dd7Smrg{ 1194f5e7dd7Smrg nexus_t *nexus; 1204f5e7dd7Smrg 1214f5e7dd7Smrg for (nexus = nexus_list ; nexus != NULL ; nexus = nexus->next) { 122cad31331Smrg if ((domain == nexus->domain) && 123cad31331Smrg (bus >= nexus->first_bus) && (bus <= nexus->last_bus)) { 1244f5e7dd7Smrg return nexus; 1254f5e7dd7Smrg } 1264f5e7dd7Smrg } 1274f5e7dd7Smrg return NULL; 1284f5e7dd7Smrg} 1294f5e7dd7Smrg 1304f5e7dd7Smrg/* 1314f5e7dd7Smrg * Release all the resources 1324f5e7dd7Smrg * Solaris version 1334f5e7dd7Smrg */ 1344f5e7dd7Smrgstatic void 1354f5e7dd7Smrgpci_system_solx_devfs_destroy( void ) 1364f5e7dd7Smrg{ 1374f5e7dd7Smrg /* 1384f5e7dd7Smrg * The memory allocated for pci_sys & devices in create routines 1394f5e7dd7Smrg * will be freed in pci_system_cleanup. 1404f5e7dd7Smrg * Need to free system-specific allocations here. 1414f5e7dd7Smrg */ 1424f5e7dd7Smrg nexus_t *nexus, *next; 1434f5e7dd7Smrg 1444f5e7dd7Smrg for (nexus = nexus_list ; nexus != NULL ; nexus = next) { 1454f5e7dd7Smrg next = nexus->next; 1464f5e7dd7Smrg close(nexus->fd); 1474f5e7dd7Smrg free(nexus->path); 148cad31331Smrg free(nexus->dev_path); 1494f5e7dd7Smrg free(nexus); 1504f5e7dd7Smrg } 1514f5e7dd7Smrg nexus_list = NULL; 1524f5e7dd7Smrg 153cad31331Smrg#ifdef __sparc 154cad31331Smrg if (di_phdl != DI_PROM_HANDLE_NIL) 155cad31331Smrg (void) di_prom_fini(di_phdl); 156cad31331Smrg#else 1574f5e7dd7Smrg if (xsvc_fd >= 0) { 1584f5e7dd7Smrg close(xsvc_fd); 1594f5e7dd7Smrg xsvc_fd = -1; 1604f5e7dd7Smrg } 161cad31331Smrg#endif 1624f5e7dd7Smrg} 1634f5e7dd7Smrg 16486ea1d58Smrg 16586ea1d58Smrg#ifdef __sparc 1664f5e7dd7Smrg/* 16786ea1d58Smrg * Release resources per device 1684f5e7dd7Smrg */ 16986ea1d58Smrgstatic void 17086ea1d58Smrgpci_system_solx_devfs_destroy_device( struct pci_device *dev ) 1714f5e7dd7Smrg{ 17286ea1d58Smrg if (MAPPING_DEV_PATH(dev)) 17386ea1d58Smrg di_devfs_path_free((char *) MAPPING_DEV_PATH(dev)); 1744f5e7dd7Smrg} 17586ea1d58Smrg#endif 1764f5e7dd7Smrg 1774f5e7dd7Smrg 1784f5e7dd7Smrgstatic int 17986ea1d58Smrgprobe_device_node(di_node_t node, void *arg) 1804f5e7dd7Smrg{ 18186ea1d58Smrg int *retbuf = NULL; 18286ea1d58Smrg int len = 0, i; 18386ea1d58Smrg struct pci_device *pci_base; 18486ea1d58Smrg probe_info_t *pinfo = ((probe_args_t *)arg)->pinfo; 18586ea1d58Smrg nexus_t *nexus = ((probe_args_t *)arg)->nexus; 18686ea1d58Smrg property_info_t property_list[] = { 18786ea1d58Smrg { "class-code", 0 }, 18886ea1d58Smrg { "device-id", 0 }, 18986ea1d58Smrg { "vendor-id", 0 }, 19086ea1d58Smrg { "revision-id", 0}, 19186ea1d58Smrg { "subsystem-vendor-id", 0}, 19286ea1d58Smrg { "subsystem-id", 0}, 19386ea1d58Smrg }; 19486ea1d58Smrg#define NUM_PROPERTIES sizeof(property_list)/sizeof(property_info_t) 1954f5e7dd7Smrg 19686ea1d58Smrg len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &retbuf); 1974f5e7dd7Smrg 198cad31331Smrg#ifdef __sparc 19986ea1d58Smrg if ((len <= 0) && di_phdl) 20086ea1d58Smrg len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &retbuf); 201cad31331Smrg#endif 2024f5e7dd7Smrg 20386ea1d58Smrg /* Exclude usb devices */ 20486ea1d58Smrg if (len < 5) { 20586ea1d58Smrg return DI_WALK_CONTINUE; 20686ea1d58Smrg } 2074f5e7dd7Smrg 20886ea1d58Smrg pci_base = &pinfo->devices[pinfo->num_devices].base; 2094f5e7dd7Smrg 21086ea1d58Smrg pci_base->domain = nexus->domain; 21186ea1d58Smrg pci_base->bus = PCI_REG_BUS_G(retbuf[0]); 21286ea1d58Smrg pci_base->dev = PCI_REG_DEV_G(retbuf[0]); 21386ea1d58Smrg pci_base->func = PCI_REG_FUNC_G(retbuf[0]); 2144f5e7dd7Smrg 21586ea1d58Smrg /* Get property values */ 21686ea1d58Smrg for (i = 0; i < NUM_PROPERTIES; i++) { 21786ea1d58Smrg len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, 21886ea1d58Smrg property_list[i].name, &retbuf); 219cad31331Smrg#ifdef __sparc 22086ea1d58Smrg if ((len <= 0) && di_phdl) 22186ea1d58Smrg len = di_prom_prop_lookup_ints(di_phdl, node, 22286ea1d58Smrg property_list[i].name, &retbuf); 223cad31331Smrg#endif 2244f5e7dd7Smrg 22586ea1d58Smrg if (len > 0) 22686ea1d58Smrg property_list[i].value = retbuf[0]; 22786ea1d58Smrg else { 22886ea1d58Smrg /* a device must have property "class-code", "device-id", "vendor-id" */ 22986ea1d58Smrg if (i < 3) 23086ea1d58Smrg return DI_WALK_CONTINUE; 23186ea1d58Smrg#ifdef DEBUG 23286ea1d58Smrg fprintf(stderr, "cannot get property \"%s\" for nexus = %s :\n", 23386ea1d58Smrg property_list[i].name, nexus->path); 23486ea1d58Smrg fprintf(stderr, " domain = %x, busno = %x, devno = %x, funcno = %x\n", 23586ea1d58Smrg pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func); 23686ea1d58Smrg#endif 2374f5e7dd7Smrg } 2384f5e7dd7Smrg } 2394f5e7dd7Smrg 24086ea1d58Smrg if ((property_list[1].value == 0) && (property_list[2].value == 0)) 24186ea1d58Smrg return DI_WALK_CONTINUE; 242cad31331Smrg 24386ea1d58Smrg pci_base->device_class = property_list[0].value; 24486ea1d58Smrg pci_base->device_id = property_list[1].value; 24586ea1d58Smrg pci_base->vendor_id = property_list[2].value; 24686ea1d58Smrg pci_base->revision = property_list[3].value; 24786ea1d58Smrg pci_base->subvendor_id = property_list[4].value; 24886ea1d58Smrg pci_base->subdevice_id = property_list[5].value; 249cad31331Smrg 25086ea1d58Smrg#ifdef DEBUG 25186ea1d58Smrg fprintf(stderr, 25286ea1d58Smrg "nexus = %s, domain = %x, busno = %x, devno = %x, funcno = %x\n", 25386ea1d58Smrg nexus->path, pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func); 25486ea1d58Smrg#endif 255cad31331Smrg 25686ea1d58Smrg pinfo->num_devices++; 25786ea1d58Smrg if (pinfo->num_devices == pinfo->num_allocated_elems) { 25886ea1d58Smrg struct pci_device_private *new_devs; 25986ea1d58Smrg size_t new_num_elems = pinfo->num_allocated_elems * 2; 26086ea1d58Smrg 26186ea1d58Smrg new_devs = realloc(pinfo->devices, 26286ea1d58Smrg new_num_elems * sizeof (struct pci_device_private)); 26386ea1d58Smrg if (new_devs == NULL) { 26486ea1d58Smrg (void) fprintf(stderr, 26586ea1d58Smrg "Error allocating memory for PCI devices:" 26686ea1d58Smrg " %s\n discarding additional devices\n", 26786ea1d58Smrg strerror(errno)); 26886ea1d58Smrg ((probe_args_t *)arg)->ret = 1; 26986ea1d58Smrg return (DI_WALK_TERMINATE); 270cad31331Smrg } 27186ea1d58Smrg (void) memset(&new_devs[pinfo->num_devices], 0, 27286ea1d58Smrg pinfo->num_allocated_elems * 27386ea1d58Smrg sizeof (struct pci_device_private)); 27486ea1d58Smrg pinfo->num_allocated_elems = new_num_elems; 27586ea1d58Smrg pinfo->devices = new_devs; 276cad31331Smrg } 277cad31331Smrg 27886ea1d58Smrg return (DI_WALK_CONTINUE); 279cad31331Smrg} 2804f5e7dd7Smrg/* 2814f5e7dd7Smrg * This function is called from di_walk_minor() when any PROBE is processed 2824f5e7dd7Smrg */ 2834f5e7dd7Smrgstatic int 2844f5e7dd7Smrgprobe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) 2854f5e7dd7Smrg{ 286cad31331Smrg probe_info_t *pinfo = (probe_info_t *)arg; 287cad31331Smrg char *nexus_name, *nexus_dev_path; 2884f5e7dd7Smrg nexus_t *nexus; 2894f5e7dd7Smrg int fd; 2904f5e7dd7Smrg char nexus_path[MAXPATHLEN]; 2914f5e7dd7Smrg 2924f5e7dd7Smrg di_prop_t prop; 2934f5e7dd7Smrg char *strings; 2944f5e7dd7Smrg int *ints; 2954f5e7dd7Smrg int numval; 2964f5e7dd7Smrg int pci_node = 0; 2974f5e7dd7Smrg int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M); 298cad31331Smrg int domain = 0; 29986ea1d58Smrg di_node_t rnode = DI_NODE_NIL; 300cad31331Smrg#ifdef __sparc 301cad31331Smrg int bus_range_found = 0; 302cad31331Smrg int device_type_found = 0; 303cad31331Smrg di_prom_prop_t prom_prop; 304cad31331Smrg#endif 305cad31331Smrg 3064f5e7dd7Smrg 3074f5e7dd7Smrg#ifdef DEBUG 3084f5e7dd7Smrg nexus_name = di_devfs_minor_path(minor); 3094f5e7dd7Smrg fprintf(stderr, "-- device name: %s\n", nexus_name); 31086ea1d58Smrg di_devfs_path_free(nexus_name); 3114f5e7dd7Smrg#endif 3124f5e7dd7Smrg 3134f5e7dd7Smrg for (prop = di_prop_next(di_node, NULL); prop != NULL; 3144f5e7dd7Smrg prop = di_prop_next(di_node, prop)) { 3154f5e7dd7Smrg 3164f5e7dd7Smrg const char *prop_name = di_prop_name(prop); 3174f5e7dd7Smrg 3184f5e7dd7Smrg#ifdef DEBUG 3194f5e7dd7Smrg fprintf(stderr, " property: %s\n", prop_name); 3204f5e7dd7Smrg#endif 3214f5e7dd7Smrg 3224f5e7dd7Smrg if (strcmp(prop_name, "device_type") == 0) { 3234f5e7dd7Smrg numval = di_prop_strings(prop, &strings); 324cad31331Smrg if (numval == 1) { 325cad31331Smrg if (strncmp(strings, "pci", 3) != 0) 326cad31331Smrg /* not a PCI node, bail */ 327cad31331Smrg return (DI_WALK_CONTINUE); 328cad31331Smrg else { 329cad31331Smrg pci_node = 1; 330cad31331Smrg#ifdef __sparc 331cad31331Smrg device_type_found = 1; 332cad31331Smrg#endif 333cad31331Smrg } 3344f5e7dd7Smrg } 3354f5e7dd7Smrg } 3364f5e7dd7Smrg else if (strcmp(prop_name, "class-code") == 0) { 3374f5e7dd7Smrg /* not a root bus node, bail */ 3384f5e7dd7Smrg return (DI_WALK_CONTINUE); 3394f5e7dd7Smrg } 3404f5e7dd7Smrg else if (strcmp(prop_name, "bus-range") == 0) { 3414f5e7dd7Smrg numval = di_prop_ints(prop, &ints); 3424f5e7dd7Smrg if (numval == 2) { 3434f5e7dd7Smrg first_bus = ints[0]; 3444f5e7dd7Smrg last_bus = ints[1]; 345cad31331Smrg#ifdef __sparc 346cad31331Smrg bus_range_found = 1; 347cad31331Smrg#endif 348cad31331Smrg } 349cad31331Smrg } 35086ea1d58Smrg#ifdef __sparc 35186ea1d58Smrg domain = nexus_count; 35286ea1d58Smrg#else 353cad31331Smrg else if (strcmp(prop_name, "pciseg") == 0) { 354cad31331Smrg numval = di_prop_ints(prop, &ints); 355cad31331Smrg if (numval == 1) { 356cad31331Smrg domain = ints[0]; 3574f5e7dd7Smrg } 3584f5e7dd7Smrg } 35986ea1d58Smrg#endif 3604f5e7dd7Smrg } 3614f5e7dd7Smrg 362cad31331Smrg#ifdef __sparc 363cad31331Smrg if ((!device_type_found) && di_phdl) { 364cad31331Smrg numval = di_prom_prop_lookup_strings(di_phdl, di_node, 365cad31331Smrg "device_type", &strings); 366cad31331Smrg if (numval == 1) { 367cad31331Smrg if (strncmp(strings, "pci", 3) != 0) 368cad31331Smrg return (DI_WALK_CONTINUE); 369cad31331Smrg else 370cad31331Smrg pci_node = 1; 371cad31331Smrg } 372cad31331Smrg } 373cad31331Smrg 374cad31331Smrg if ((!bus_range_found) && di_phdl) { 375cad31331Smrg numval = di_prom_prop_lookup_ints(di_phdl, di_node, 376cad31331Smrg "bus-range", &ints); 377cad31331Smrg if (numval == 2) { 378cad31331Smrg first_bus = ints[0]; 379cad31331Smrg last_bus = ints[1]; 380cad31331Smrg } 381cad31331Smrg } 382cad31331Smrg#endif 383cad31331Smrg 3844f5e7dd7Smrg if (pci_node != 1) 3854f5e7dd7Smrg return (DI_WALK_CONTINUE); 3864f5e7dd7Smrg 3874f5e7dd7Smrg /* we have a PCI root bus node. */ 3884f5e7dd7Smrg nexus = calloc(1, sizeof(nexus_t)); 3894f5e7dd7Smrg if (nexus == NULL) { 3904f5e7dd7Smrg (void) fprintf(stderr, "Error allocating memory for nexus: %s\n", 3914f5e7dd7Smrg strerror(errno)); 3924f5e7dd7Smrg return (DI_WALK_TERMINATE); 3934f5e7dd7Smrg } 3944f5e7dd7Smrg nexus->first_bus = first_bus; 3954f5e7dd7Smrg nexus->last_bus = last_bus; 396cad31331Smrg nexus->domain = domain; 397cad31331Smrg 398cad31331Smrg#ifdef __sparc 39986ea1d58Smrg nexus_count++; 400cad31331Smrg#endif 4014f5e7dd7Smrg 4024f5e7dd7Smrg nexus_name = di_devfs_minor_path(minor); 4034f5e7dd7Smrg if (nexus_name == NULL) { 4044f5e7dd7Smrg (void) fprintf(stderr, "Error getting nexus path: %s\n", 4054f5e7dd7Smrg strerror(errno)); 4064f5e7dd7Smrg free(nexus); 4074f5e7dd7Smrg return (DI_WALK_CONTINUE); 4084f5e7dd7Smrg } 4094f5e7dd7Smrg 4104f5e7dd7Smrg snprintf(nexus_path, sizeof(nexus_path), "/devices%s", nexus_name); 4114f5e7dd7Smrg di_devfs_path_free(nexus_name); 4124f5e7dd7Smrg 4134f5e7dd7Smrg#ifdef DEBUG 4144f5e7dd7Smrg fprintf(stderr, "nexus = %s, bus-range = %d - %d\n", 4154f5e7dd7Smrg nexus_path, first_bus, last_bus); 4164f5e7dd7Smrg#endif 4174f5e7dd7Smrg 418cad31331Smrg if ((fd = open(nexus_path, O_RDWR | O_CLOEXEC)) >= 0) { 41986ea1d58Smrg probe_args_t args; 42086ea1d58Smrg 4214f5e7dd7Smrg nexus->fd = fd; 4224f5e7dd7Smrg nexus->path = strdup(nexus_path); 423cad31331Smrg nexus_dev_path = di_devfs_path(di_node); 424cad31331Smrg nexus->dev_path = strdup(nexus_dev_path); 425cad31331Smrg di_devfs_path_free(nexus_dev_path); 42686ea1d58Smrg 42786ea1d58Smrg if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) { 42886ea1d58Smrg (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno)); 42986ea1d58Smrg close(nexus->fd); 4304f5e7dd7Smrg free(nexus->path); 431cad31331Smrg free(nexus->dev_path); 4324f5e7dd7Smrg free(nexus); 43386ea1d58Smrg return (DI_WALK_TERMINATE); 4344f5e7dd7Smrg } 43586ea1d58Smrg 43686ea1d58Smrg /* Walk through devices under the rnode */ 43786ea1d58Smrg args.pinfo = pinfo; 43886ea1d58Smrg args.nexus = nexus; 43986ea1d58Smrg args.ret = 0; 44086ea1d58Smrg 44186ea1d58Smrg (void) di_walk_node(rnode, DI_WALK_CLDFIRST, (void *)&args, probe_device_node); 44286ea1d58Smrg if (args.ret) { 44386ea1d58Smrg close(nexus->fd); 44486ea1d58Smrg free(nexus->path); 44586ea1d58Smrg free(nexus->dev_path); 44686ea1d58Smrg free(nexus); 44786ea1d58Smrg di_fini(rnode); 44886ea1d58Smrg return (DI_WALK_TERMINATE); 44986ea1d58Smrg } 45086ea1d58Smrg 45186ea1d58Smrg nexus->next = nexus_list; 45286ea1d58Smrg nexus_list = nexus; 4534f5e7dd7Smrg } else { 4544f5e7dd7Smrg (void) fprintf(stderr, "Error opening %s: %s\n", 4554f5e7dd7Smrg nexus_path, strerror(errno)); 4564f5e7dd7Smrg free(nexus); 4574f5e7dd7Smrg } 4584f5e7dd7Smrg 45986ea1d58Smrg if (rnode != DI_NODE_NIL) { 46086ea1d58Smrg di_fini(rnode); 46186ea1d58Smrg } 46286ea1d58Smrg 4634f5e7dd7Smrg return DI_WALK_CONTINUE; 4644f5e7dd7Smrg} 4654f5e7dd7Smrg 4664f5e7dd7Smrgstatic int 4674f5e7dd7Smrgfind_target_node(di_node_t node, void *arg) 4684f5e7dd7Smrg{ 4694f5e7dd7Smrg int *regbuf = NULL; 4704f5e7dd7Smrg int len = 0; 4714f5e7dd7Smrg uint32_t busno, funcno, devno; 4724f5e7dd7Smrg i_devnode_t *devnode = (i_devnode_t *)arg; 4734f5e7dd7Smrg 4744f5e7dd7Smrg /* 4754f5e7dd7Smrg * Test the property functions, only for testing 4764f5e7dd7Smrg */ 4774f5e7dd7Smrg /* 4784f5e7dd7Smrg void *prop = DI_PROP_NIL; 4794f5e7dd7Smrg 4804f5e7dd7Smrg (void) fprintf(stderr, "start of node 0x%x\n", node->nodeid); 4814f5e7dd7Smrg while ((prop = di_prop_hw_next(node, prop)) != DI_PROP_NIL) { 4824f5e7dd7Smrg int i; 4834f5e7dd7Smrg (void) fprintf(stderr, "name=%s: ", di_prop_name(prop)); 4844f5e7dd7Smrg len = 0; 4854f5e7dd7Smrg if (!strcmp(di_prop_name(prop), "reg")) { 4864f5e7dd7Smrg len = di_prop_ints(prop, ®buf); 4874f5e7dd7Smrg } 4884f5e7dd7Smrg for (i = 0; i < len; i++) { 4894f5e7dd7Smrg fprintf(stderr, "0x%0x.", regbuf[i]); 4904f5e7dd7Smrg } 4914f5e7dd7Smrg fprintf(stderr, "\n"); 4924f5e7dd7Smrg } 4934f5e7dd7Smrg (void) fprintf(stderr, "end of node 0x%x\n", node->nodeid); 4944f5e7dd7Smrg */ 4954f5e7dd7Smrg 4964f5e7dd7Smrg len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", ®buf); 4974f5e7dd7Smrg 498cad31331Smrg#ifdef __sparc 499cad31331Smrg if ((len <= 0) && di_phdl) 500cad31331Smrg len = di_prom_prop_lookup_ints(di_phdl, node, "reg", ®buf); 501cad31331Smrg#endif 502cad31331Smrg 5034f5e7dd7Smrg if (len <= 0) { 5044f5e7dd7Smrg#ifdef DEBUG 5054f5e7dd7Smrg fprintf(stderr, "error = %x\n", errno); 5064f5e7dd7Smrg fprintf(stderr, "can not find assigned-address\n"); 5074f5e7dd7Smrg#endif 5084f5e7dd7Smrg return (DI_WALK_CONTINUE); 5094f5e7dd7Smrg } 5104f5e7dd7Smrg 5114f5e7dd7Smrg busno = PCI_REG_BUS_G(regbuf[0]); 5124f5e7dd7Smrg devno = PCI_REG_DEV_G(regbuf[0]); 5134f5e7dd7Smrg funcno = PCI_REG_FUNC_G(regbuf[0]); 5144f5e7dd7Smrg 5154f5e7dd7Smrg if ((busno == devnode->bus) && 5164f5e7dd7Smrg (devno == devnode->dev) && 5174f5e7dd7Smrg (funcno == devnode->func)) { 5184f5e7dd7Smrg devnode->node = node; 5194f5e7dd7Smrg 5204f5e7dd7Smrg return (DI_WALK_TERMINATE); 5214f5e7dd7Smrg } 5224f5e7dd7Smrg 5234f5e7dd7Smrg return (DI_WALK_CONTINUE); 5244f5e7dd7Smrg} 5254f5e7dd7Smrg 5264f5e7dd7Smrg/* 5274f5e7dd7Smrg * Solaris version 5284f5e7dd7Smrg */ 5294f5e7dd7Smrgstatic int 5304f5e7dd7Smrgpci_device_solx_devfs_probe( struct pci_device * dev ) 5314f5e7dd7Smrg{ 532cad31331Smrg int err = 0; 5334f5e7dd7Smrg di_node_t rnode = DI_NODE_NIL; 5344f5e7dd7Smrg i_devnode_t args = { 0, 0, 0, DI_NODE_NIL }; 5354f5e7dd7Smrg int *regbuf; 5364f5e7dd7Smrg pci_regspec_t *reg; 5374f5e7dd7Smrg int i; 5384f5e7dd7Smrg int len = 0; 5394f5e7dd7Smrg uint ent = 0; 54086ea1d58Smrg struct pci_device_private *priv = 54186ea1d58Smrg (struct pci_device_private *) dev; 542cad31331Smrg nexus_t *nexus; 5434f5e7dd7Smrg 544cad31331Smrg if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL ) 545cad31331Smrg return ENODEV; 5464f5e7dd7Smrg 54786ea1d58Smrg pci_device_cfg_read_u8(dev, &priv->header_type, PCI_CONF_HEADER); 54886ea1d58Smrg 54986ea1d58Smrg pci_device_cfg_read_u8(dev, (uint8_t *)&dev->irq, PCI_CONF_ILINE); 55086ea1d58Smrg 551cad31331Smrg /* 552cad31331Smrg * starting to find if it is MEM/MEM64/IO 553cad31331Smrg * using libdevinfo 554cad31331Smrg */ 555cad31331Smrg if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) { 556cad31331Smrg err = errno; 557cad31331Smrg (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno)); 558cad31331Smrg } else { 559cad31331Smrg args.bus = dev->bus; 560cad31331Smrg args.dev = dev->dev; 561cad31331Smrg args.func = dev->func; 562cad31331Smrg (void) di_walk_node(rnode, DI_WALK_CLDFIRST, 563cad31331Smrg (void *)&args, find_target_node); 564cad31331Smrg } 5654f5e7dd7Smrg 566cad31331Smrg if (args.node != DI_NODE_NIL) { 56786ea1d58Smrg int *prop; 568cad31331Smrg#ifdef __sparc 569cad31331Smrg di_minor_t minor; 570cad31331Smrg#endif 5714f5e7dd7Smrg 57286ea1d58Smrg priv->is_primary = 0; 57386ea1d58Smrg 574cad31331Smrg#ifdef __sparc 575cad31331Smrg if (minor = di_minor_next(args.node, DI_MINOR_NIL)) 576cad31331Smrg MAPPING_DEV_PATH(dev) = di_devfs_minor_path (minor); 577cad31331Smrg else 578cad31331Smrg MAPPING_DEV_PATH(dev) = NULL; 579cad31331Smrg#endif 5804f5e7dd7Smrg 58186ea1d58Smrg if (di_prop_lookup_ints(DDI_DEV_T_ANY, args.node, 58286ea1d58Smrg "primary-controller", &prop) >= 1) { 58386ea1d58Smrg if (prop[0]) 58486ea1d58Smrg priv->is_primary = 1; 58586ea1d58Smrg } 58686ea1d58Smrg 5874f5e7dd7Smrg /* 5884f5e7dd7Smrg * It will succeed for sure, because it was 5894f5e7dd7Smrg * successfully called in find_target_node 5904f5e7dd7Smrg */ 5914f5e7dd7Smrg len = di_prop_lookup_ints(DDI_DEV_T_ANY, args.node, 5924f5e7dd7Smrg "assigned-addresses", 5934f5e7dd7Smrg ®buf); 5944f5e7dd7Smrg 595cad31331Smrg#ifdef __sparc 596cad31331Smrg if ((len <= 0) && di_phdl) { 597cad31331Smrg len = di_prom_prop_lookup_ints(di_phdl, args.node, 598cad31331Smrg "assigned-addresses", ®buf); 599cad31331Smrg } 600cad31331Smrg#endif 6014f5e7dd7Smrg } 6024f5e7dd7Smrg 6034f5e7dd7Smrg if (len <= 0) 6044f5e7dd7Smrg goto cleanup; 6054f5e7dd7Smrg 6064f5e7dd7Smrg /* 60786ea1d58Smrg * Each BAR address get its own region slot in sequence. 60886ea1d58Smrg * 32 bit BAR: 60986ea1d58Smrg * BAR 0x10 -> slot0, BAR 0x14 -> slot1... 61086ea1d58Smrg * 64 bit BAR: 61186ea1d58Smrg * BAR 0x10 -> slot0, BAR 0x18 -> slot2..., 61286ea1d58Smrg * slot1 is part of BAR 0x10 6134f5e7dd7Smrg * Linux give two region slot for 64 bit address. 6144f5e7dd7Smrg */ 61586ea1d58Smrg for (i = 0; i < len; i = i + (int)CELL_NUMS_1275) { 6164f5e7dd7Smrg 6174f5e7dd7Smrg reg = (pci_regspec_t *)®buf[i]; 6184f5e7dd7Smrg ent = reg->pci_phys_hi & 0xff; 61986ea1d58Smrg 62086ea1d58Smrg if (ent > PCI_CONF_ROM) { 6214f5e7dd7Smrg fprintf(stderr, "error ent = %d\n", ent); 6224f5e7dd7Smrg break; 6234f5e7dd7Smrg } 6244f5e7dd7Smrg /* 62586ea1d58Smrg * G35 broken in BAR0 6264f5e7dd7Smrg */ 62786ea1d58Smrg if (ent < PCI_CONF_BASE0) { 62886ea1d58Smrg /* 62986ea1d58Smrg * VGA resource here and ignore it 63086ea1d58Smrg */ 6314f5e7dd7Smrg break; 63286ea1d58Smrg } else if (ent == PCI_CONF_ROM) { 63386ea1d58Smrg priv->rom_base = reg->pci_phys_low | 63486ea1d58Smrg ((uint64_t)reg->pci_phys_mid << 32); 63586ea1d58Smrg dev->rom_size = reg->pci_size_low; 63686ea1d58Smrg } else { 63786ea1d58Smrg ent = (ent - PCI_CONF_BASE0) >> 2; 63886ea1d58Smrg /* 63986ea1d58Smrg * non relocatable resource is excluded 64086ea1d58Smrg * such like 0xa0000, 0x3b0. If it is met, 64186ea1d58Smrg * the loop is broken; 64286ea1d58Smrg */ 64386ea1d58Smrg if (!PCI_REG_REG_G(reg->pci_phys_hi)) 64486ea1d58Smrg break; 6454f5e7dd7Smrg 64686ea1d58Smrg if (reg->pci_phys_hi & PCI_PREFETCH_B) { 64786ea1d58Smrg dev->regions[ent].is_prefetchable = 1; 64886ea1d58Smrg } 6494f5e7dd7Smrg 6504f5e7dd7Smrg 65186ea1d58Smrg dev->regions[ent].base_addr = reg->pci_phys_low | 65286ea1d58Smrg ((uint64_t)reg->pci_phys_mid << 32); 65386ea1d58Smrg dev->regions[ent].size = reg->pci_size_low | 65486ea1d58Smrg ((uint64_t)reg->pci_size_hi << 32); 65586ea1d58Smrg 65686ea1d58Smrg switch (reg->pci_phys_hi & PCI_REG_ADDR_M) { 65786ea1d58Smrg case PCI_ADDR_IO: 65886ea1d58Smrg dev->regions[ent].is_IO = 1; 65986ea1d58Smrg break; 66086ea1d58Smrg case PCI_ADDR_MEM32: 66186ea1d58Smrg break; 66286ea1d58Smrg case PCI_ADDR_MEM64: 66386ea1d58Smrg dev->regions[ent].is_64 = 1; 66486ea1d58Smrg /* 66586ea1d58Smrg * Skip one slot for 64 bit address 66686ea1d58Smrg */ 66786ea1d58Smrg break; 66886ea1d58Smrg } 6694f5e7dd7Smrg } 6704f5e7dd7Smrg } 6714f5e7dd7Smrg 6724f5e7dd7Smrg cleanup: 6734f5e7dd7Smrg if (rnode != DI_NODE_NIL) { 6744f5e7dd7Smrg di_fini(rnode); 6754f5e7dd7Smrg } 6764f5e7dd7Smrg return (err); 6774f5e7dd7Smrg} 6784f5e7dd7Smrg 679cad31331Smrg/** 68086ea1d58Smrg * Map a memory region for a device using /dev/xsvc (x86) or fb device (sparc) 681cad31331Smrg * 682cad31331Smrg * \param dev Device whose memory region is to be mapped. 683cad31331Smrg * \param map Parameters of the mapping that is to be created. 684cad31331Smrg * 685cad31331Smrg * \return 686cad31331Smrg * Zero on success or an \c errno value on failure. 687cad31331Smrg */ 688cad31331Smrgstatic int 689cad31331Smrgpci_device_solx_devfs_map_range(struct pci_device *dev, 690cad31331Smrg struct pci_device_mapping *map) 691cad31331Smrg{ 692cad31331Smrg const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 693cad31331Smrg ? (PROT_READ | PROT_WRITE) : PROT_READ; 694cad31331Smrg int err = 0; 695cad31331Smrg 69686ea1d58Smrg const char *map_dev; 697cad31331Smrg int map_fd; 698cad31331Smrg 69986ea1d58Smrg#ifdef __sparc 70086ea1d58Smrg char map_dev_buf[128]; 701cad31331Smrg 70286ea1d58Smrg if (MAPPING_DEV_PATH(dev)) { 70386ea1d58Smrg snprintf(map_dev_buf, sizeof (map_dev_buf), "%s%s", 70486ea1d58Smrg "/devices", MAPPING_DEV_PATH(dev)); 70586ea1d58Smrg map_dev = map_dev_buf; 706cad31331Smrg } 70786ea1d58Smrg else 70886ea1d58Smrg map_dev = "/dev/fb0"; 709cad31331Smrg 71086ea1d58Smrg map_fd = -1; 711cad31331Smrg#else 712cad31331Smrg /* 71386ea1d58Smrg * Still uses xsvc to do the user space mapping on x86/x64, 71486ea1d58Smrg * caches open fd across multiple calls. 715cad31331Smrg */ 71686ea1d58Smrg map_dev = "/dev/xsvc"; 71786ea1d58Smrg map_fd = xsvc_fd; 71886ea1d58Smrg#endif 71986ea1d58Smrg 72086ea1d58Smrg if (map_fd < 0) { 72186ea1d58Smrg if ((map_fd = open(map_dev, O_RDWR | O_CLOEXEC)) < 0) { 722cad31331Smrg err = errno; 72386ea1d58Smrg (void) fprintf(stderr, "can not open %s: %s\n", map_dev, 724cad31331Smrg strerror(errno)); 725cad31331Smrg return err; 726cad31331Smrg } 727cad31331Smrg } 728cad31331Smrg 72986ea1d58Smrg map->memory = mmap(NULL, map->size, prot, MAP_SHARED, map_fd, map->base); 730cad31331Smrg if (map->memory == MAP_FAILED) { 731cad31331Smrg err = errno; 732cad31331Smrg 733cad31331Smrg (void) fprintf(stderr, "map rom region =%llx failed: %s\n", 73486ea1d58Smrg (unsigned long long) map->base, strerror(errno)); 735cad31331Smrg } 736cad31331Smrg 737cad31331Smrg#ifdef __sparc 738cad31331Smrg close (map_fd); 739cad31331Smrg#endif 740cad31331Smrg 741cad31331Smrg return err; 742cad31331Smrg} 743cad31331Smrg 7444f5e7dd7Smrg/* 7454f5e7dd7Smrg * Solaris version: read the VGA ROM data 7464f5e7dd7Smrg */ 7474f5e7dd7Smrgstatic int 7484f5e7dd7Smrgpci_device_solx_devfs_read_rom( struct pci_device * dev, void * buffer ) 7494f5e7dd7Smrg{ 7504f5e7dd7Smrg int err; 7514f5e7dd7Smrg struct pci_device_mapping prom = { 7524f5e7dd7Smrg .base = 0xC0000, 75386ea1d58Smrg .size = 0x10000, 7544f5e7dd7Smrg .flags = 0 7554f5e7dd7Smrg }; 75686ea1d58Smrg struct pci_device_private *priv = 75786ea1d58Smrg (struct pci_device_private *) dev; 75886ea1d58Smrg 75986ea1d58Smrg if (priv->rom_base) { 76086ea1d58Smrg prom.base = priv->rom_base; 76186ea1d58Smrg prom.size = dev->rom_size; 76286ea1d58Smrg } 7634f5e7dd7Smrg 7644f5e7dd7Smrg err = pci_device_solx_devfs_map_range(dev, &prom); 7654f5e7dd7Smrg if (err == 0) { 7664f5e7dd7Smrg (void) bcopy(prom.memory, buffer, dev->rom_size); 7674f5e7dd7Smrg 76886ea1d58Smrg if (munmap(prom.memory, prom.size) == -1) { 7694f5e7dd7Smrg err = errno; 7704f5e7dd7Smrg } 7714f5e7dd7Smrg } 7724f5e7dd7Smrg return err; 7734f5e7dd7Smrg} 7744f5e7dd7Smrg 7754f5e7dd7Smrg/* 7764f5e7dd7Smrg * solaris version: Read the configurations space of the devices 7774f5e7dd7Smrg */ 7784f5e7dd7Smrgstatic int 7794f5e7dd7Smrgpci_device_solx_devfs_read( struct pci_device * dev, void * data, 7804f5e7dd7Smrg pciaddr_t offset, pciaddr_t size, 7814f5e7dd7Smrg pciaddr_t * bytes_read ) 7824f5e7dd7Smrg{ 7834f5e7dd7Smrg pcitool_reg_t cfg_prg; 7844f5e7dd7Smrg int err = 0; 78586ea1d58Smrg unsigned int i = 0; 786cad31331Smrg nexus_t *nexus; 787cad31331Smrg 788cad31331Smrg nexus = find_nexus_for_bus(dev->domain, dev->bus); 7894f5e7dd7Smrg 7904f5e7dd7Smrg *bytes_read = 0; 7914f5e7dd7Smrg 7924f5e7dd7Smrg if ( nexus == NULL ) { 7934f5e7dd7Smrg return ENODEV; 7944f5e7dd7Smrg } 7954f5e7dd7Smrg 7964f5e7dd7Smrg cfg_prg.offset = offset; 7974f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN; 7984f5e7dd7Smrg cfg_prg.bus_no = dev->bus; 7994f5e7dd7Smrg cfg_prg.dev_no = dev->dev; 8004f5e7dd7Smrg cfg_prg.func_no = dev->func; 8014f5e7dd7Smrg cfg_prg.barnum = 0; 8024f5e7dd7Smrg cfg_prg.user_version = PCITOOL_USER_VERSION; 8034f5e7dd7Smrg 8044f5e7dd7Smrg for (i = 0; i < size; i += PCITOOL_ACC_ATTR_SIZE(PCITOOL_ACC_ATTR_SIZE_1)) 8054f5e7dd7Smrg { 8064f5e7dd7Smrg cfg_prg.offset = offset + i; 8074f5e7dd7Smrg 8084f5e7dd7Smrg if ((err = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) { 8094f5e7dd7Smrg fprintf(stderr, "read bdf<%s,%x,%x,%x,%llx> config space failure\n", 8104f5e7dd7Smrg nexus->path, 8114f5e7dd7Smrg cfg_prg.bus_no, 8124f5e7dd7Smrg cfg_prg.dev_no, 8134f5e7dd7Smrg cfg_prg.func_no, 81486ea1d58Smrg (unsigned long long) cfg_prg.offset); 8154f5e7dd7Smrg fprintf(stderr, "Failure cause = %x\n", err); 8164f5e7dd7Smrg break; 8174f5e7dd7Smrg } 8184f5e7dd7Smrg 8194f5e7dd7Smrg ((uint8_t *)data)[i] = (uint8_t)cfg_prg.data; 8204f5e7dd7Smrg /* 8214f5e7dd7Smrg * DWORDS Offset or bytes Offset ?? 8224f5e7dd7Smrg */ 8234f5e7dd7Smrg } 8244f5e7dd7Smrg *bytes_read = i; 8254f5e7dd7Smrg 8264f5e7dd7Smrg return (err); 8274f5e7dd7Smrg} 8284f5e7dd7Smrg 8294f5e7dd7Smrg/* 8304f5e7dd7Smrg * Solaris version 8314f5e7dd7Smrg */ 8324f5e7dd7Smrgstatic int 8334f5e7dd7Smrgpci_device_solx_devfs_write( struct pci_device * dev, const void * data, 8344f5e7dd7Smrg pciaddr_t offset, pciaddr_t size, 8354f5e7dd7Smrg pciaddr_t * bytes_written ) 8364f5e7dd7Smrg{ 8374f5e7dd7Smrg pcitool_reg_t cfg_prg; 8384f5e7dd7Smrg int err = 0; 8394f5e7dd7Smrg int cmd; 840cad31331Smrg nexus_t *nexus; 841cad31331Smrg 842cad31331Smrg nexus = find_nexus_for_bus(dev->domain, dev->bus); 8434f5e7dd7Smrg 8444f5e7dd7Smrg if ( bytes_written != NULL ) { 8454f5e7dd7Smrg *bytes_written = 0; 8464f5e7dd7Smrg } 8474f5e7dd7Smrg 8484f5e7dd7Smrg if ( nexus == NULL ) { 8494f5e7dd7Smrg return ENODEV; 8504f5e7dd7Smrg } 8514f5e7dd7Smrg 8524f5e7dd7Smrg cfg_prg.offset = offset; 8534f5e7dd7Smrg switch (size) { 8544f5e7dd7Smrg case 1: 8554f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN; 856cad31331Smrg cfg_prg.data = *((const uint8_t *)data); 8574f5e7dd7Smrg break; 8584f5e7dd7Smrg case 2: 8594f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + NATIVE_ENDIAN; 860cad31331Smrg cfg_prg.data = *((const uint16_t *)data); 8614f5e7dd7Smrg break; 8624f5e7dd7Smrg case 4: 8634f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN; 864cad31331Smrg cfg_prg.data = *((const uint32_t *)data); 8654f5e7dd7Smrg break; 8664f5e7dd7Smrg case 8: 8674f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 + NATIVE_ENDIAN; 868cad31331Smrg cfg_prg.data = *((const uint64_t *)data); 8694f5e7dd7Smrg break; 8704f5e7dd7Smrg default: 8714f5e7dd7Smrg return EINVAL; 8724f5e7dd7Smrg } 8734f5e7dd7Smrg cfg_prg.bus_no = dev->bus; 8744f5e7dd7Smrg cfg_prg.dev_no = dev->dev; 8754f5e7dd7Smrg cfg_prg.func_no = dev->func; 8764f5e7dd7Smrg cfg_prg.barnum = 0; 8774f5e7dd7Smrg cfg_prg.user_version = PCITOOL_USER_VERSION; 8784f5e7dd7Smrg 8794f5e7dd7Smrg /* 8804f5e7dd7Smrg * Check if this device is bridge device. 8814f5e7dd7Smrg * If it is, it is also a nexus node??? 8824f5e7dd7Smrg * It seems that there is no explicit 8834f5e7dd7Smrg * PCI nexus device for X86, so not applicable 8844f5e7dd7Smrg * from pcitool_bus_reg_ops in pci_tools.c 8854f5e7dd7Smrg */ 8864f5e7dd7Smrg cmd = PCITOOL_DEVICE_SET_REG; 8874f5e7dd7Smrg 8884f5e7dd7Smrg if ((err = ioctl(nexus->fd, cmd, &cfg_prg)) != 0) { 8894f5e7dd7Smrg return (err); 8904f5e7dd7Smrg } 8914f5e7dd7Smrg *bytes_written = size; 8924f5e7dd7Smrg 8934f5e7dd7Smrg return (err); 8944f5e7dd7Smrg} 8954f5e7dd7Smrg 89686ea1d58Smrgstatic int pci_device_solx_devfs_boot_vga(struct pci_device *dev) 89786ea1d58Smrg{ 89886ea1d58Smrg struct pci_device_private *priv = 89986ea1d58Smrg (struct pci_device_private *) dev; 90086ea1d58Smrg 90186ea1d58Smrg return (priv->is_primary); 90286ea1d58Smrg 90386ea1d58Smrg} 90486ea1d58Smrg 90586ea1d58Smrgstatic struct pci_io_handle * 90686ea1d58Smrgpci_device_solx_devfs_open_legacy_io(struct pci_io_handle *ret, 90786ea1d58Smrg struct pci_device *dev, 90886ea1d58Smrg pciaddr_t base, pciaddr_t size) 90986ea1d58Smrg{ 91086ea1d58Smrg#ifdef __x86 91186ea1d58Smrg if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) == 0) { 91286ea1d58Smrg ret->base = base; 91386ea1d58Smrg ret->size = size; 91486ea1d58Smrg return ret; 91586ea1d58Smrg } 91686ea1d58Smrg#endif 91786ea1d58Smrg return NULL; 91886ea1d58Smrg} 91986ea1d58Smrg 92086ea1d58Smrgstatic uint32_t 92186ea1d58Smrgpci_device_solx_devfs_read32(struct pci_io_handle *handle, uint32_t reg) 92286ea1d58Smrg{ 92386ea1d58Smrg#ifdef __x86 92486ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 92586ea1d58Smrg uint32_t ret; 92686ea1d58Smrg __asm__ __volatile__("inl %1,%0":"=a"(ret):"d"(port)); 92786ea1d58Smrg return ret; 92886ea1d58Smrg#else 92986ea1d58Smrg return *(uint32_t *)((uintptr_t)handle->memory + reg); 93086ea1d58Smrg#endif 93186ea1d58Smrg} 93286ea1d58Smrg 93386ea1d58Smrgstatic uint16_t 93486ea1d58Smrgpci_device_solx_devfs_read16(struct pci_io_handle *handle, uint32_t reg) 93586ea1d58Smrg{ 93686ea1d58Smrg#ifdef __x86 93786ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 93886ea1d58Smrg uint16_t ret; 93986ea1d58Smrg __asm__ __volatile__("inw %1,%0":"=a"(ret):"d"(port)); 94086ea1d58Smrg return ret; 94186ea1d58Smrg#else 94286ea1d58Smrg return *(uint16_t *)((uintptr_t)handle->memory + reg); 94386ea1d58Smrg#endif 94486ea1d58Smrg} 94586ea1d58Smrg 94686ea1d58Smrgstatic uint8_t 94786ea1d58Smrgpci_device_solx_devfs_read8(struct pci_io_handle *handle, uint32_t reg) 94886ea1d58Smrg{ 94986ea1d58Smrg#ifdef __x86 95086ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 95186ea1d58Smrg uint8_t ret; 95286ea1d58Smrg __asm__ __volatile__("inb %1,%0":"=a"(ret):"d"(port)); 95386ea1d58Smrg return ret; 95486ea1d58Smrg#else 95586ea1d58Smrg return *(uint8_t *)((uintptr_t)handle->memory + reg); 95686ea1d58Smrg#endif 95786ea1d58Smrg} 95886ea1d58Smrg 95986ea1d58Smrgstatic void 96086ea1d58Smrgpci_device_solx_devfs_write32(struct pci_io_handle *handle, uint32_t reg, 96186ea1d58Smrg uint32_t data) 96286ea1d58Smrg{ 96386ea1d58Smrg#ifdef __x86 96486ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 96586ea1d58Smrg __asm__ __volatile__("outl %0,%1"::"a"(data), "d"(port)); 96686ea1d58Smrg#else 96786ea1d58Smrg *(uint16_t *)((uintptr_t)handle->memory + reg) = data; 96886ea1d58Smrg#endif 96986ea1d58Smrg} 97086ea1d58Smrg 97186ea1d58Smrgstatic void 97286ea1d58Smrgpci_device_solx_devfs_write16(struct pci_io_handle *handle, uint32_t reg, 97386ea1d58Smrg uint16_t data) 97486ea1d58Smrg{ 97586ea1d58Smrg#ifdef __x86 97686ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 97786ea1d58Smrg __asm__ __volatile__("outw %0,%1"::"a"(data), "d"(port)); 97886ea1d58Smrg#else 97986ea1d58Smrg *(uint8_t *)((uintptr_t)handle->memory + reg) = data; 98086ea1d58Smrg#endif 98186ea1d58Smrg} 98286ea1d58Smrg 98386ea1d58Smrgstatic void 98486ea1d58Smrgpci_device_solx_devfs_write8(struct pci_io_handle *handle, uint32_t reg, 98586ea1d58Smrg uint8_t data) 98686ea1d58Smrg{ 98786ea1d58Smrg#ifdef __x86 98886ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 98986ea1d58Smrg __asm__ __volatile__("outb %0,%1"::"a"(data), "d"(port)); 99086ea1d58Smrg#else 99186ea1d58Smrg *(uint32_t *)((uintptr_t)handle->memory + reg) = data; 99286ea1d58Smrg#endif 99386ea1d58Smrg} 99486ea1d58Smrg 99586ea1d58Smrgstatic int 99686ea1d58Smrgpci_device_solx_devfs_map_legacy(struct pci_device *dev, pciaddr_t base, 99786ea1d58Smrg pciaddr_t size, unsigned map_flags, 99886ea1d58Smrg void **addr) 99986ea1d58Smrg{ 100086ea1d58Smrg int err; 100186ea1d58Smrg struct pci_device_mapping map = { 100286ea1d58Smrg .base = base, 100386ea1d58Smrg .size = size, 100486ea1d58Smrg .flags = map_flags, 100586ea1d58Smrg }; 10064f5e7dd7Smrg 100786ea1d58Smrg err = pci_device_solx_devfs_map_range(dev, &map); 100886ea1d58Smrg if (err == 0) 100986ea1d58Smrg *addr = map.memory; 101086ea1d58Smrg return err; 101186ea1d58Smrg} 101286ea1d58Smrg 101386ea1d58Smrgstatic int 101486ea1d58Smrgpci_device_solx_devfs_unmap_legacy(struct pci_device *dev, 101586ea1d58Smrg void *addr, pciaddr_t size) 101686ea1d58Smrg{ 101786ea1d58Smrg struct pci_device_mapping map = { 101886ea1d58Smrg .memory = addr, 101986ea1d58Smrg .size = size, 102086ea1d58Smrg }; 102186ea1d58Smrg 102286ea1d58Smrg return pci_device_generic_unmap_range(dev, &map); 102386ea1d58Smrg} 1024cad31331Smrg 1025cad31331Smrgstatic const struct pci_system_methods solx_devfs_methods = { 1026cad31331Smrg .destroy = pci_system_solx_devfs_destroy, 102786ea1d58Smrg#ifdef __sparc 102886ea1d58Smrg .destroy_device = pci_system_solx_devfs_destroy_device, 102986ea1d58Smrg#else 1030cad31331Smrg .destroy_device = NULL, 103186ea1d58Smrg#endif 1032cad31331Smrg .read_rom = pci_device_solx_devfs_read_rom, 1033cad31331Smrg .probe = pci_device_solx_devfs_probe, 1034cad31331Smrg .map_range = pci_device_solx_devfs_map_range, 1035cad31331Smrg .unmap_range = pci_device_generic_unmap_range, 1036cad31331Smrg 1037cad31331Smrg .read = pci_device_solx_devfs_read, 1038cad31331Smrg .write = pci_device_solx_devfs_write, 1039cad31331Smrg 104086ea1d58Smrg .fill_capabilities = pci_fill_capabilities_generic, 104186ea1d58Smrg .boot_vga = pci_device_solx_devfs_boot_vga, 104286ea1d58Smrg 104386ea1d58Smrg .open_legacy_io = pci_device_solx_devfs_open_legacy_io, 104486ea1d58Smrg .read32 = pci_device_solx_devfs_read32, 104586ea1d58Smrg .read16 = pci_device_solx_devfs_read16, 104686ea1d58Smrg .read8 = pci_device_solx_devfs_read8, 104786ea1d58Smrg .write32 = pci_device_solx_devfs_write32, 104886ea1d58Smrg .write16 = pci_device_solx_devfs_write16, 104986ea1d58Smrg .write8 = pci_device_solx_devfs_write8, 105086ea1d58Smrg .map_legacy = pci_device_solx_devfs_map_legacy, 105186ea1d58Smrg .unmap_legacy = pci_device_solx_devfs_unmap_legacy, 1052cad31331Smrg}; 1053cad31331Smrg 1054cad31331Smrg/* 1055cad31331Smrg * Attempt to access PCI subsystem using Solaris's devfs interface. 1056cad31331Smrg * Solaris version 10574f5e7dd7Smrg */ 1058cad31331Smrg_pci_hidden int 1059cad31331Smrgpci_system_solx_devfs_create( void ) 10604f5e7dd7Smrg{ 10614f5e7dd7Smrg int err = 0; 1062cad31331Smrg di_node_t di_node; 1063cad31331Smrg probe_info_t pinfo; 1064cad31331Smrg struct pci_device_private *devices; 10654f5e7dd7Smrg 1066cad31331Smrg if (nexus_list != NULL) { 1067cad31331Smrg return 0; 10684f5e7dd7Smrg } 10694f5e7dd7Smrg 1070cad31331Smrg if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 10714f5e7dd7Smrg err = errno; 1072cad31331Smrg (void) fprintf(stderr, "di_init() failed: %s\n", 1073cad31331Smrg strerror(errno)); 1074cad31331Smrg return (err); 1075cad31331Smrg } 10764f5e7dd7Smrg 1077cad31331Smrg if ((devices = calloc(INITIAL_NUM_DEVICES, 1078cad31331Smrg sizeof (struct pci_device_private))) == NULL) { 1079cad31331Smrg err = errno; 1080cad31331Smrg di_fini(di_node); 1081cad31331Smrg return (err); 10824f5e7dd7Smrg } 10834f5e7dd7Smrg 1084cad31331Smrg#ifdef __sparc 1085cad31331Smrg if ((di_phdl = di_prom_init()) == DI_PROM_HANDLE_NIL) 1086cad31331Smrg (void) fprintf(stderr, "di_prom_init failed: %s\n", strerror(errno)); 1087cad31331Smrg#endif 1088cad31331Smrg 1089cad31331Smrg pinfo.num_allocated_elems = INITIAL_NUM_DEVICES; 1090cad31331Smrg pinfo.num_devices = 0; 1091cad31331Smrg pinfo.devices = devices; 109286ea1d58Smrg#ifdef __sparc 109386ea1d58Smrg nexus_count = 0; 109486ea1d58Smrg#endif 1095cad31331Smrg (void) di_walk_minor(di_node, DDI_NT_REGACC, 0, &pinfo, probe_nexus_node); 1096cad31331Smrg 1097cad31331Smrg di_fini(di_node); 1098cad31331Smrg 1099cad31331Smrg if ((pci_sys = calloc(1, sizeof (struct pci_system))) == NULL) { 1100cad31331Smrg err = errno; 1101cad31331Smrg free(devices); 1102cad31331Smrg return (err); 1103cad31331Smrg } 1104cad31331Smrg 1105cad31331Smrg pci_sys->methods = &solx_devfs_methods; 1106cad31331Smrg pci_sys->devices = pinfo.devices; 1107cad31331Smrg pci_sys->num_devices = pinfo.num_devices; 1108cad31331Smrg 1109cad31331Smrg return (err); 11104f5e7dd7Smrg} 1111