14f5e7dd7Smrg/* 24f5e7dd7Smrg * (C) Copyright IBM Corporation 2006 349310723Smrg * Copyright (c) 2007, 2009, 2011, 2012, 2016 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 */ 2849310723Smrg#ifdef HAVE_CONFIG_H 2949310723Smrg#include "config.h" 3049310723Smrg#endif 314f5e7dd7Smrg 324f5e7dd7Smrg#include <stdlib.h> 334f5e7dd7Smrg#include <strings.h> 344f5e7dd7Smrg#include <stdio.h> 354f5e7dd7Smrg#include <unistd.h> 364f5e7dd7Smrg#include <sys/types.h> 374f5e7dd7Smrg#include <fcntl.h> 384f5e7dd7Smrg#include <sys/mman.h> 394f5e7dd7Smrg#include <errno.h> 404f5e7dd7Smrg#include <sys/pci.h> 414f5e7dd7Smrg#include <libdevinfo.h> 424f5e7dd7Smrg#include "pci_tools.h" 434f5e7dd7Smrg 4486ea1d58Smrg#ifdef __x86 4586ea1d58Smrg# include <sys/sysi86.h> 4686ea1d58Smrg# include <sys/psw.h> 4786ea1d58Smrg#endif 4886ea1d58Smrg 494f5e7dd7Smrg#include "pciaccess.h" 504f5e7dd7Smrg#include "pciaccess_private.h" 514f5e7dd7Smrg 524f5e7dd7Smrg/* #define DEBUG */ 534f5e7dd7Smrg 54cad31331Smrg#define INITIAL_NUM_DEVICES 256 554f5e7dd7Smrg#define CELL_NUMS_1275 (sizeof(pci_regspec_t) / sizeof(uint_t)) 564f5e7dd7Smrg 574f5e7dd7Smrgtypedef struct i_devnode { 584f5e7dd7Smrg uint8_t bus; 594f5e7dd7Smrg uint8_t dev; 604f5e7dd7Smrg uint8_t func; 614f5e7dd7Smrg di_node_t node; 624f5e7dd7Smrg} i_devnode_t; 634f5e7dd7Smrg 644f5e7dd7Smrgtypedef struct nexus { 654f5e7dd7Smrg int first_bus; 664f5e7dd7Smrg int last_bus; 67cad31331Smrg int domain; 6849310723Smrg char *path; /* for open */ 69cad31331Smrg char *dev_path; 704f5e7dd7Smrg struct nexus *next; 714f5e7dd7Smrg} nexus_t; 724f5e7dd7Smrg 73cad31331Smrgtypedef struct probe_info { 74cad31331Smrg volatile size_t num_allocated_elems; 75cad31331Smrg volatile size_t num_devices; 76cad31331Smrg struct pci_device_private * volatile devices; 77cad31331Smrg} probe_info_t; 78cad31331Smrg 7986ea1d58Smrgtypedef struct probe_args { 8086ea1d58Smrg probe_info_t *pinfo; 8186ea1d58Smrg nexus_t *nexus; 8286ea1d58Smrg int ret; 8386ea1d58Smrg} probe_args_t; 8486ea1d58Smrg 8586ea1d58Smrgtypedef struct property_info { 8686ea1d58Smrg const char *name; 8786ea1d58Smrg int value; 8886ea1d58Smrg} property_info_t; 8986ea1d58Smrg 904f5e7dd7Smrgstatic nexus_t *nexus_list = NULL; 91cad31331Smrg#if !defined(__sparc) 924f5e7dd7Smrgstatic int xsvc_fd = -1; 93cad31331Smrg#endif 94cad31331Smrg 95cad31331Smrg#ifdef __sparc 96cad31331Smrgstatic di_prom_handle_t di_phdl; 9786ea1d58Smrgstatic size_t nexus_count = 0; 98cad31331Smrg#endif 994f5e7dd7Smrg 1004f5e7dd7Smrg/* 1014f5e7dd7Smrg * Read config space in native processor endianness. Endian-neutral 1024f5e7dd7Smrg * processing can then take place. On big endian machines, MSB and LSB 1034f5e7dd7Smrg * of little endian data end up switched if read as little endian. 1044f5e7dd7Smrg * They are in correct order if read as big endian. 1054f5e7dd7Smrg */ 1064f5e7dd7Smrg#if defined(__sparc) 1074f5e7dd7Smrg# define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_BIG 1084f5e7dd7Smrg#elif defined(__x86) 1094f5e7dd7Smrg# define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_LTL 1104f5e7dd7Smrg#else 1114f5e7dd7Smrg# error "ISA is neither __sparc nor __x86" 1124f5e7dd7Smrg#endif 1134f5e7dd7Smrg 114cad31331Smrg#ifdef __sparc 115cad31331Smrg#define MAPPING_DEV_PATH(dev) (((struct pci_device_private *) dev)->device_string) 116cad31331Smrg#endif 117cad31331Smrg 1184f5e7dd7Smrgstatic nexus_t * 119cad31331Smrgfind_nexus_for_bus( int domain, int bus ) 1204f5e7dd7Smrg{ 1214f5e7dd7Smrg nexus_t *nexus; 1224f5e7dd7Smrg 1234f5e7dd7Smrg for (nexus = nexus_list ; nexus != NULL ; nexus = nexus->next) { 124cad31331Smrg if ((domain == nexus->domain) && 125cad31331Smrg (bus >= nexus->first_bus) && (bus <= nexus->last_bus)) { 1264f5e7dd7Smrg return nexus; 1274f5e7dd7Smrg } 1284f5e7dd7Smrg } 1294f5e7dd7Smrg return NULL; 1304f5e7dd7Smrg} 1314f5e7dd7Smrg 1324f5e7dd7Smrg/* 1334f5e7dd7Smrg * Release all the resources 1344f5e7dd7Smrg * Solaris version 1354f5e7dd7Smrg */ 1364f5e7dd7Smrgstatic void 1374f5e7dd7Smrgpci_system_solx_devfs_destroy( void ) 1384f5e7dd7Smrg{ 1394f5e7dd7Smrg /* 1404f5e7dd7Smrg * The memory allocated for pci_sys & devices in create routines 1414f5e7dd7Smrg * will be freed in pci_system_cleanup. 1424f5e7dd7Smrg * Need to free system-specific allocations here. 1434f5e7dd7Smrg */ 1444f5e7dd7Smrg nexus_t *nexus, *next; 1454f5e7dd7Smrg 1464f5e7dd7Smrg for (nexus = nexus_list ; nexus != NULL ; nexus = next) { 1474f5e7dd7Smrg next = nexus->next; 1484f5e7dd7Smrg free(nexus->path); 149cad31331Smrg free(nexus->dev_path); 1504f5e7dd7Smrg free(nexus); 1514f5e7dd7Smrg } 1524f5e7dd7Smrg nexus_list = NULL; 1534f5e7dd7Smrg 154cad31331Smrg#ifdef __sparc 155cad31331Smrg if (di_phdl != DI_PROM_HANDLE_NIL) 156cad31331Smrg (void) di_prom_fini(di_phdl); 157cad31331Smrg#else 1584f5e7dd7Smrg if (xsvc_fd >= 0) { 1594f5e7dd7Smrg close(xsvc_fd); 1604f5e7dd7Smrg xsvc_fd = -1; 1614f5e7dd7Smrg } 162cad31331Smrg#endif 1634f5e7dd7Smrg} 1644f5e7dd7Smrg 16586ea1d58Smrg 16686ea1d58Smrg#ifdef __sparc 1674f5e7dd7Smrg/* 16886ea1d58Smrg * Release resources per device 1694f5e7dd7Smrg */ 17086ea1d58Smrgstatic void 17186ea1d58Smrgpci_system_solx_devfs_destroy_device( struct pci_device *dev ) 1724f5e7dd7Smrg{ 17386ea1d58Smrg if (MAPPING_DEV_PATH(dev)) 17486ea1d58Smrg di_devfs_path_free((char *) MAPPING_DEV_PATH(dev)); 1754f5e7dd7Smrg} 17686ea1d58Smrg#endif 1774f5e7dd7Smrg 1784f5e7dd7Smrg 1794f5e7dd7Smrgstatic int 18086ea1d58Smrgprobe_device_node(di_node_t node, void *arg) 1814f5e7dd7Smrg{ 18286ea1d58Smrg int *retbuf = NULL; 18386ea1d58Smrg int len = 0, i; 18486ea1d58Smrg struct pci_device *pci_base; 18586ea1d58Smrg probe_info_t *pinfo = ((probe_args_t *)arg)->pinfo; 18686ea1d58Smrg nexus_t *nexus = ((probe_args_t *)arg)->nexus; 18786ea1d58Smrg property_info_t property_list[] = { 18886ea1d58Smrg { "class-code", 0 }, 18986ea1d58Smrg { "device-id", 0 }, 19086ea1d58Smrg { "vendor-id", 0 }, 19186ea1d58Smrg { "revision-id", 0}, 19286ea1d58Smrg { "subsystem-vendor-id", 0}, 19386ea1d58Smrg { "subsystem-id", 0}, 19486ea1d58Smrg }; 19586ea1d58Smrg#define NUM_PROPERTIES sizeof(property_list)/sizeof(property_info_t) 1964f5e7dd7Smrg 19786ea1d58Smrg len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &retbuf); 1984f5e7dd7Smrg 199cad31331Smrg#ifdef __sparc 20086ea1d58Smrg if ((len <= 0) && di_phdl) 20186ea1d58Smrg len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &retbuf); 202cad31331Smrg#endif 2034f5e7dd7Smrg 20486ea1d58Smrg /* Exclude usb devices */ 20586ea1d58Smrg if (len < 5) { 20686ea1d58Smrg return DI_WALK_CONTINUE; 20786ea1d58Smrg } 2084f5e7dd7Smrg 20986ea1d58Smrg pci_base = &pinfo->devices[pinfo->num_devices].base; 2104f5e7dd7Smrg 21186ea1d58Smrg pci_base->domain = nexus->domain; 21286ea1d58Smrg pci_base->bus = PCI_REG_BUS_G(retbuf[0]); 21386ea1d58Smrg pci_base->dev = PCI_REG_DEV_G(retbuf[0]); 21486ea1d58Smrg pci_base->func = PCI_REG_FUNC_G(retbuf[0]); 2154f5e7dd7Smrg 21666337f63Smrg if (nexus->domain > 0xffff) 21766337f63Smrg pci_base->domain_16 = 0xffff; 21866337f63Smrg else 21966337f63Smrg pci_base->domain_16 = nexus->domain; 22066337f63Smrg 22186ea1d58Smrg /* Get property values */ 22286ea1d58Smrg for (i = 0; i < NUM_PROPERTIES; i++) { 22386ea1d58Smrg len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, 22486ea1d58Smrg property_list[i].name, &retbuf); 225cad31331Smrg#ifdef __sparc 22686ea1d58Smrg if ((len <= 0) && di_phdl) 22786ea1d58Smrg len = di_prom_prop_lookup_ints(di_phdl, node, 22886ea1d58Smrg property_list[i].name, &retbuf); 229cad31331Smrg#endif 2304f5e7dd7Smrg 23186ea1d58Smrg if (len > 0) 23286ea1d58Smrg property_list[i].value = retbuf[0]; 23386ea1d58Smrg else { 23486ea1d58Smrg /* a device must have property "class-code", "device-id", "vendor-id" */ 23586ea1d58Smrg if (i < 3) 23686ea1d58Smrg return DI_WALK_CONTINUE; 23786ea1d58Smrg#ifdef DEBUG 23886ea1d58Smrg fprintf(stderr, "cannot get property \"%s\" for nexus = %s :\n", 23986ea1d58Smrg property_list[i].name, nexus->path); 24086ea1d58Smrg fprintf(stderr, " domain = %x, busno = %x, devno = %x, funcno = %x\n", 24186ea1d58Smrg pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func); 24286ea1d58Smrg#endif 2434f5e7dd7Smrg } 2444f5e7dd7Smrg } 2454f5e7dd7Smrg 24686ea1d58Smrg if ((property_list[1].value == 0) && (property_list[2].value == 0)) 24786ea1d58Smrg return DI_WALK_CONTINUE; 248cad31331Smrg 24986ea1d58Smrg pci_base->device_class = property_list[0].value; 25086ea1d58Smrg pci_base->device_id = property_list[1].value; 25186ea1d58Smrg pci_base->vendor_id = property_list[2].value; 25286ea1d58Smrg pci_base->revision = property_list[3].value; 25386ea1d58Smrg pci_base->subvendor_id = property_list[4].value; 25486ea1d58Smrg pci_base->subdevice_id = property_list[5].value; 255cad31331Smrg 25686ea1d58Smrg#ifdef DEBUG 25786ea1d58Smrg fprintf(stderr, 25886ea1d58Smrg "nexus = %s, domain = %x, busno = %x, devno = %x, funcno = %x\n", 25986ea1d58Smrg nexus->path, pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func); 26086ea1d58Smrg#endif 261cad31331Smrg 26286ea1d58Smrg pinfo->num_devices++; 26386ea1d58Smrg if (pinfo->num_devices == pinfo->num_allocated_elems) { 26486ea1d58Smrg struct pci_device_private *new_devs; 26586ea1d58Smrg size_t new_num_elems = pinfo->num_allocated_elems * 2; 26686ea1d58Smrg 26786ea1d58Smrg new_devs = realloc(pinfo->devices, 26886ea1d58Smrg new_num_elems * sizeof (struct pci_device_private)); 26986ea1d58Smrg if (new_devs == NULL) { 27086ea1d58Smrg (void) fprintf(stderr, 27186ea1d58Smrg "Error allocating memory for PCI devices:" 27286ea1d58Smrg " %s\n discarding additional devices\n", 27386ea1d58Smrg strerror(errno)); 27486ea1d58Smrg ((probe_args_t *)arg)->ret = 1; 27586ea1d58Smrg return (DI_WALK_TERMINATE); 276cad31331Smrg } 27786ea1d58Smrg (void) memset(&new_devs[pinfo->num_devices], 0, 27886ea1d58Smrg pinfo->num_allocated_elems * 27986ea1d58Smrg sizeof (struct pci_device_private)); 28086ea1d58Smrg pinfo->num_allocated_elems = new_num_elems; 28186ea1d58Smrg pinfo->devices = new_devs; 282cad31331Smrg } 283cad31331Smrg 28486ea1d58Smrg return (DI_WALK_CONTINUE); 285cad31331Smrg} 2864f5e7dd7Smrg/* 2874f5e7dd7Smrg * This function is called from di_walk_minor() when any PROBE is processed 2884f5e7dd7Smrg */ 2894f5e7dd7Smrgstatic int 2904f5e7dd7Smrgprobe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) 2914f5e7dd7Smrg{ 292cad31331Smrg probe_info_t *pinfo = (probe_info_t *)arg; 293cad31331Smrg char *nexus_name, *nexus_dev_path; 2944f5e7dd7Smrg nexus_t *nexus; 2954f5e7dd7Smrg int fd; 2964f5e7dd7Smrg char nexus_path[MAXPATHLEN]; 2974f5e7dd7Smrg 2984f5e7dd7Smrg di_prop_t prop; 2994f5e7dd7Smrg char *strings; 3004f5e7dd7Smrg int *ints; 3014f5e7dd7Smrg int numval; 3024f5e7dd7Smrg int pci_node = 0; 3034f5e7dd7Smrg int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M); 304cad31331Smrg int domain = 0; 305cad31331Smrg#ifdef __sparc 306cad31331Smrg int bus_range_found = 0; 307cad31331Smrg int device_type_found = 0; 308cad31331Smrg di_prom_prop_t prom_prop; 309cad31331Smrg#endif 310cad31331Smrg 3114f5e7dd7Smrg#ifdef DEBUG 3124f5e7dd7Smrg nexus_name = di_devfs_minor_path(minor); 3134f5e7dd7Smrg fprintf(stderr, "-- device name: %s\n", nexus_name); 31486ea1d58Smrg di_devfs_path_free(nexus_name); 3154f5e7dd7Smrg#endif 3164f5e7dd7Smrg 3174f5e7dd7Smrg for (prop = di_prop_next(di_node, NULL); prop != NULL; 3184f5e7dd7Smrg prop = di_prop_next(di_node, prop)) { 3194f5e7dd7Smrg 3204f5e7dd7Smrg const char *prop_name = di_prop_name(prop); 3214f5e7dd7Smrg 3224f5e7dd7Smrg#ifdef DEBUG 3234f5e7dd7Smrg fprintf(stderr, " property: %s\n", prop_name); 3244f5e7dd7Smrg#endif 3254f5e7dd7Smrg 3264f5e7dd7Smrg if (strcmp(prop_name, "device_type") == 0) { 3274f5e7dd7Smrg numval = di_prop_strings(prop, &strings); 328cad31331Smrg if (numval == 1) { 329cad31331Smrg if (strncmp(strings, "pci", 3) != 0) 330cad31331Smrg /* not a PCI node, bail */ 331cad31331Smrg return (DI_WALK_CONTINUE); 332cad31331Smrg else { 333cad31331Smrg pci_node = 1; 334cad31331Smrg#ifdef __sparc 335cad31331Smrg device_type_found = 1; 336cad31331Smrg#endif 337cad31331Smrg } 3384f5e7dd7Smrg } 3394f5e7dd7Smrg } 3404f5e7dd7Smrg else if (strcmp(prop_name, "class-code") == 0) { 3414f5e7dd7Smrg /* not a root bus node, bail */ 3424f5e7dd7Smrg return (DI_WALK_CONTINUE); 3434f5e7dd7Smrg } 3444f5e7dd7Smrg else if (strcmp(prop_name, "bus-range") == 0) { 3454f5e7dd7Smrg numval = di_prop_ints(prop, &ints); 3464f5e7dd7Smrg if (numval == 2) { 3474f5e7dd7Smrg first_bus = ints[0]; 3484f5e7dd7Smrg last_bus = ints[1]; 349cad31331Smrg#ifdef __sparc 350cad31331Smrg bus_range_found = 1; 351cad31331Smrg#endif 352cad31331Smrg } 353cad31331Smrg } 35486ea1d58Smrg#ifdef __sparc 35586ea1d58Smrg domain = nexus_count; 35686ea1d58Smrg#else 357cad31331Smrg else if (strcmp(prop_name, "pciseg") == 0) { 358cad31331Smrg numval = di_prop_ints(prop, &ints); 359cad31331Smrg if (numval == 1) { 360cad31331Smrg domain = ints[0]; 3614f5e7dd7Smrg } 3624f5e7dd7Smrg } 36386ea1d58Smrg#endif 3644f5e7dd7Smrg } 3654f5e7dd7Smrg 366cad31331Smrg#ifdef __sparc 367cad31331Smrg if ((!device_type_found) && di_phdl) { 368cad31331Smrg numval = di_prom_prop_lookup_strings(di_phdl, di_node, 369cad31331Smrg "device_type", &strings); 370cad31331Smrg if (numval == 1) { 371cad31331Smrg if (strncmp(strings, "pci", 3) != 0) 372cad31331Smrg return (DI_WALK_CONTINUE); 373cad31331Smrg else 374cad31331Smrg pci_node = 1; 375cad31331Smrg } 376cad31331Smrg } 377cad31331Smrg 378cad31331Smrg if ((!bus_range_found) && di_phdl) { 379cad31331Smrg numval = di_prom_prop_lookup_ints(di_phdl, di_node, 380cad31331Smrg "bus-range", &ints); 381cad31331Smrg if (numval == 2) { 382cad31331Smrg first_bus = ints[0]; 383cad31331Smrg last_bus = ints[1]; 384cad31331Smrg } 385cad31331Smrg } 386cad31331Smrg#endif 387cad31331Smrg 3884f5e7dd7Smrg if (pci_node != 1) 3894f5e7dd7Smrg return (DI_WALK_CONTINUE); 3904f5e7dd7Smrg 3914f5e7dd7Smrg /* we have a PCI root bus node. */ 3924f5e7dd7Smrg nexus = calloc(1, sizeof(nexus_t)); 3934f5e7dd7Smrg if (nexus == NULL) { 3944f5e7dd7Smrg (void) fprintf(stderr, "Error allocating memory for nexus: %s\n", 3954f5e7dd7Smrg strerror(errno)); 3964f5e7dd7Smrg return (DI_WALK_TERMINATE); 3974f5e7dd7Smrg } 3984f5e7dd7Smrg nexus->first_bus = first_bus; 3994f5e7dd7Smrg nexus->last_bus = last_bus; 400cad31331Smrg nexus->domain = domain; 401cad31331Smrg 402cad31331Smrg#ifdef __sparc 40386ea1d58Smrg nexus_count++; 404cad31331Smrg#endif 4054f5e7dd7Smrg 4064f5e7dd7Smrg nexus_name = di_devfs_minor_path(minor); 4074f5e7dd7Smrg if (nexus_name == NULL) { 4084f5e7dd7Smrg (void) fprintf(stderr, "Error getting nexus path: %s\n", 4094f5e7dd7Smrg strerror(errno)); 4104f5e7dd7Smrg free(nexus); 4114f5e7dd7Smrg return (DI_WALK_CONTINUE); 4124f5e7dd7Smrg } 4134f5e7dd7Smrg 4144f5e7dd7Smrg snprintf(nexus_path, sizeof(nexus_path), "/devices%s", nexus_name); 4154f5e7dd7Smrg di_devfs_path_free(nexus_name); 4164f5e7dd7Smrg 4174f5e7dd7Smrg#ifdef DEBUG 4184f5e7dd7Smrg fprintf(stderr, "nexus = %s, bus-range = %d - %d\n", 4194f5e7dd7Smrg nexus_path, first_bus, last_bus); 4204f5e7dd7Smrg#endif 4214f5e7dd7Smrg 422cad31331Smrg if ((fd = open(nexus_path, O_RDWR | O_CLOEXEC)) >= 0) { 42386ea1d58Smrg probe_args_t args; 42486ea1d58Smrg 4254f5e7dd7Smrg nexus->path = strdup(nexus_path); 426cad31331Smrg nexus_dev_path = di_devfs_path(di_node); 427cad31331Smrg nexus->dev_path = strdup(nexus_dev_path); 428cad31331Smrg di_devfs_path_free(nexus_dev_path); 42986ea1d58Smrg 43086ea1d58Smrg /* Walk through devices under the rnode */ 43186ea1d58Smrg args.pinfo = pinfo; 43286ea1d58Smrg args.nexus = nexus; 43386ea1d58Smrg args.ret = 0; 43486ea1d58Smrg 43549310723Smrg (void) di_walk_node(di_node, DI_WALK_CLDFIRST, (void *)&args, probe_device_node); 43649310723Smrg 43749310723Smrg close(fd); 43849310723Smrg 43986ea1d58Smrg if (args.ret) { 44086ea1d58Smrg free(nexus->path); 44186ea1d58Smrg free(nexus->dev_path); 44286ea1d58Smrg free(nexus); 44386ea1d58Smrg return (DI_WALK_TERMINATE); 44486ea1d58Smrg } 44586ea1d58Smrg 44686ea1d58Smrg nexus->next = nexus_list; 44786ea1d58Smrg nexus_list = nexus; 4484f5e7dd7Smrg } else { 4494f5e7dd7Smrg (void) fprintf(stderr, "Error opening %s: %s\n", 4504f5e7dd7Smrg nexus_path, strerror(errno)); 4514f5e7dd7Smrg free(nexus); 4524f5e7dd7Smrg } 4534f5e7dd7Smrg 4544f5e7dd7Smrg return DI_WALK_CONTINUE; 4554f5e7dd7Smrg} 4564f5e7dd7Smrg 4574f5e7dd7Smrgstatic int 4584f5e7dd7Smrgfind_target_node(di_node_t node, void *arg) 4594f5e7dd7Smrg{ 4604f5e7dd7Smrg int *regbuf = NULL; 4614f5e7dd7Smrg int len = 0; 4624f5e7dd7Smrg uint32_t busno, funcno, devno; 4634f5e7dd7Smrg i_devnode_t *devnode = (i_devnode_t *)arg; 4644f5e7dd7Smrg 4654f5e7dd7Smrg /* 4664f5e7dd7Smrg * Test the property functions, only for testing 4674f5e7dd7Smrg */ 4684f5e7dd7Smrg /* 4694f5e7dd7Smrg void *prop = DI_PROP_NIL; 4704f5e7dd7Smrg 4714f5e7dd7Smrg (void) fprintf(stderr, "start of node 0x%x\n", node->nodeid); 4724f5e7dd7Smrg while ((prop = di_prop_hw_next(node, prop)) != DI_PROP_NIL) { 4734f5e7dd7Smrg int i; 4744f5e7dd7Smrg (void) fprintf(stderr, "name=%s: ", di_prop_name(prop)); 4754f5e7dd7Smrg len = 0; 4764f5e7dd7Smrg if (!strcmp(di_prop_name(prop), "reg")) { 4774f5e7dd7Smrg len = di_prop_ints(prop, ®buf); 4784f5e7dd7Smrg } 4794f5e7dd7Smrg for (i = 0; i < len; i++) { 4804f5e7dd7Smrg fprintf(stderr, "0x%0x.", regbuf[i]); 4814f5e7dd7Smrg } 4824f5e7dd7Smrg fprintf(stderr, "\n"); 4834f5e7dd7Smrg } 4844f5e7dd7Smrg (void) fprintf(stderr, "end of node 0x%x\n", node->nodeid); 4854f5e7dd7Smrg */ 4864f5e7dd7Smrg 4874f5e7dd7Smrg len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", ®buf); 4884f5e7dd7Smrg 489cad31331Smrg#ifdef __sparc 490cad31331Smrg if ((len <= 0) && di_phdl) 491cad31331Smrg len = di_prom_prop_lookup_ints(di_phdl, node, "reg", ®buf); 492cad31331Smrg#endif 493cad31331Smrg 4944f5e7dd7Smrg if (len <= 0) { 4954f5e7dd7Smrg#ifdef DEBUG 4964f5e7dd7Smrg fprintf(stderr, "error = %x\n", errno); 4974f5e7dd7Smrg fprintf(stderr, "can not find assigned-address\n"); 4984f5e7dd7Smrg#endif 4994f5e7dd7Smrg return (DI_WALK_CONTINUE); 5004f5e7dd7Smrg } 5014f5e7dd7Smrg 5024f5e7dd7Smrg busno = PCI_REG_BUS_G(regbuf[0]); 5034f5e7dd7Smrg devno = PCI_REG_DEV_G(regbuf[0]); 5044f5e7dd7Smrg funcno = PCI_REG_FUNC_G(regbuf[0]); 5054f5e7dd7Smrg 5064f5e7dd7Smrg if ((busno == devnode->bus) && 5074f5e7dd7Smrg (devno == devnode->dev) && 5084f5e7dd7Smrg (funcno == devnode->func)) { 5094f5e7dd7Smrg devnode->node = node; 5104f5e7dd7Smrg 5114f5e7dd7Smrg return (DI_WALK_TERMINATE); 5124f5e7dd7Smrg } 5134f5e7dd7Smrg 5144f5e7dd7Smrg return (DI_WALK_CONTINUE); 5154f5e7dd7Smrg} 5164f5e7dd7Smrg 5174f5e7dd7Smrg/* 5184f5e7dd7Smrg * Solaris version 5194f5e7dd7Smrg */ 5204f5e7dd7Smrgstatic int 5214f5e7dd7Smrgpci_device_solx_devfs_probe( struct pci_device * dev ) 5224f5e7dd7Smrg{ 523cad31331Smrg int err = 0; 5244f5e7dd7Smrg di_node_t rnode = DI_NODE_NIL; 5254f5e7dd7Smrg i_devnode_t args = { 0, 0, 0, DI_NODE_NIL }; 5264f5e7dd7Smrg int *regbuf; 5274f5e7dd7Smrg pci_regspec_t *reg; 5284f5e7dd7Smrg int i; 5294f5e7dd7Smrg int len = 0; 5304f5e7dd7Smrg uint ent = 0; 53186ea1d58Smrg struct pci_device_private *priv = 53286ea1d58Smrg (struct pci_device_private *) dev; 533cad31331Smrg nexus_t *nexus; 5344f5e7dd7Smrg 535cad31331Smrg if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL ) 536cad31331Smrg return ENODEV; 5374f5e7dd7Smrg 53886ea1d58Smrg pci_device_cfg_read_u8(dev, &priv->header_type, PCI_CONF_HEADER); 53986ea1d58Smrg 54086ea1d58Smrg pci_device_cfg_read_u8(dev, (uint8_t *)&dev->irq, PCI_CONF_ILINE); 54186ea1d58Smrg 542cad31331Smrg /* 543cad31331Smrg * starting to find if it is MEM/MEM64/IO 544cad31331Smrg * using libdevinfo 545cad31331Smrg */ 54649310723Smrg if ((rnode = di_init(nexus->dev_path, DINFOCACHE)) == DI_NODE_NIL) { 547cad31331Smrg err = errno; 548cad31331Smrg (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno)); 549cad31331Smrg } else { 550cad31331Smrg args.bus = dev->bus; 551cad31331Smrg args.dev = dev->dev; 552cad31331Smrg args.func = dev->func; 553cad31331Smrg (void) di_walk_node(rnode, DI_WALK_CLDFIRST, 554cad31331Smrg (void *)&args, find_target_node); 555cad31331Smrg } 5564f5e7dd7Smrg 557cad31331Smrg if (args.node != DI_NODE_NIL) { 55886ea1d58Smrg int *prop; 559cad31331Smrg#ifdef __sparc 560cad31331Smrg di_minor_t minor; 561cad31331Smrg#endif 5624f5e7dd7Smrg 56386ea1d58Smrg priv->is_primary = 0; 56486ea1d58Smrg 565cad31331Smrg#ifdef __sparc 566cad31331Smrg if (minor = di_minor_next(args.node, DI_MINOR_NIL)) 567cad31331Smrg MAPPING_DEV_PATH(dev) = di_devfs_minor_path (minor); 568cad31331Smrg else 569cad31331Smrg MAPPING_DEV_PATH(dev) = NULL; 570cad31331Smrg#endif 5714f5e7dd7Smrg 57286ea1d58Smrg if (di_prop_lookup_ints(DDI_DEV_T_ANY, args.node, 57386ea1d58Smrg "primary-controller", &prop) >= 1) { 57486ea1d58Smrg if (prop[0]) 57586ea1d58Smrg priv->is_primary = 1; 57686ea1d58Smrg } 57786ea1d58Smrg 5784f5e7dd7Smrg /* 5794f5e7dd7Smrg * It will succeed for sure, because it was 5804f5e7dd7Smrg * successfully called in find_target_node 5814f5e7dd7Smrg */ 5824f5e7dd7Smrg len = di_prop_lookup_ints(DDI_DEV_T_ANY, args.node, 5834f5e7dd7Smrg "assigned-addresses", 5844f5e7dd7Smrg ®buf); 5854f5e7dd7Smrg 586cad31331Smrg#ifdef __sparc 587cad31331Smrg if ((len <= 0) && di_phdl) { 588cad31331Smrg len = di_prom_prop_lookup_ints(di_phdl, args.node, 589cad31331Smrg "assigned-addresses", ®buf); 590cad31331Smrg } 591cad31331Smrg#endif 5924f5e7dd7Smrg } 5934f5e7dd7Smrg 5944f5e7dd7Smrg if (len <= 0) 5954f5e7dd7Smrg goto cleanup; 5964f5e7dd7Smrg 5974f5e7dd7Smrg /* 59886ea1d58Smrg * Each BAR address get its own region slot in sequence. 59986ea1d58Smrg * 32 bit BAR: 60086ea1d58Smrg * BAR 0x10 -> slot0, BAR 0x14 -> slot1... 60186ea1d58Smrg * 64 bit BAR: 60286ea1d58Smrg * BAR 0x10 -> slot0, BAR 0x18 -> slot2..., 60386ea1d58Smrg * slot1 is part of BAR 0x10 6044f5e7dd7Smrg * Linux give two region slot for 64 bit address. 6054f5e7dd7Smrg */ 60686ea1d58Smrg for (i = 0; i < len; i = i + (int)CELL_NUMS_1275) { 6074f5e7dd7Smrg 6084f5e7dd7Smrg reg = (pci_regspec_t *)®buf[i]; 6094f5e7dd7Smrg ent = reg->pci_phys_hi & 0xff; 61086ea1d58Smrg 61186ea1d58Smrg if (ent > PCI_CONF_ROM) { 6124f5e7dd7Smrg fprintf(stderr, "error ent = %d\n", ent); 6134f5e7dd7Smrg break; 6144f5e7dd7Smrg } 6154f5e7dd7Smrg /* 61686ea1d58Smrg * G35 broken in BAR0 6174f5e7dd7Smrg */ 61886ea1d58Smrg if (ent < PCI_CONF_BASE0) { 61986ea1d58Smrg /* 62086ea1d58Smrg * VGA resource here and ignore it 62186ea1d58Smrg */ 6224f5e7dd7Smrg break; 62386ea1d58Smrg } else if (ent == PCI_CONF_ROM) { 62486ea1d58Smrg priv->rom_base = reg->pci_phys_low | 62586ea1d58Smrg ((uint64_t)reg->pci_phys_mid << 32); 62686ea1d58Smrg dev->rom_size = reg->pci_size_low; 62786ea1d58Smrg } else { 62886ea1d58Smrg ent = (ent - PCI_CONF_BASE0) >> 2; 62986ea1d58Smrg /* 63086ea1d58Smrg * non relocatable resource is excluded 63186ea1d58Smrg * such like 0xa0000, 0x3b0. If it is met, 63286ea1d58Smrg * the loop is broken; 63386ea1d58Smrg */ 63486ea1d58Smrg if (!PCI_REG_REG_G(reg->pci_phys_hi)) 63586ea1d58Smrg break; 6364f5e7dd7Smrg 63786ea1d58Smrg if (reg->pci_phys_hi & PCI_PREFETCH_B) { 63886ea1d58Smrg dev->regions[ent].is_prefetchable = 1; 63986ea1d58Smrg } 6404f5e7dd7Smrg 6414f5e7dd7Smrg 64286ea1d58Smrg dev->regions[ent].base_addr = reg->pci_phys_low | 64386ea1d58Smrg ((uint64_t)reg->pci_phys_mid << 32); 64486ea1d58Smrg dev->regions[ent].size = reg->pci_size_low | 64586ea1d58Smrg ((uint64_t)reg->pci_size_hi << 32); 64686ea1d58Smrg 64786ea1d58Smrg switch (reg->pci_phys_hi & PCI_REG_ADDR_M) { 64886ea1d58Smrg case PCI_ADDR_IO: 64986ea1d58Smrg dev->regions[ent].is_IO = 1; 65086ea1d58Smrg break; 65186ea1d58Smrg case PCI_ADDR_MEM32: 65286ea1d58Smrg break; 65386ea1d58Smrg case PCI_ADDR_MEM64: 65486ea1d58Smrg dev->regions[ent].is_64 = 1; 65586ea1d58Smrg /* 65686ea1d58Smrg * Skip one slot for 64 bit address 65786ea1d58Smrg */ 65886ea1d58Smrg break; 65986ea1d58Smrg } 6604f5e7dd7Smrg } 6614f5e7dd7Smrg } 6624f5e7dd7Smrg 6634f5e7dd7Smrg cleanup: 6644f5e7dd7Smrg if (rnode != DI_NODE_NIL) { 6654f5e7dd7Smrg di_fini(rnode); 6664f5e7dd7Smrg } 6674f5e7dd7Smrg return (err); 6684f5e7dd7Smrg} 6694f5e7dd7Smrg 670cad31331Smrg/** 67186ea1d58Smrg * Map a memory region for a device using /dev/xsvc (x86) or fb device (sparc) 672cad31331Smrg * 673cad31331Smrg * \param dev Device whose memory region is to be mapped. 674cad31331Smrg * \param map Parameters of the mapping that is to be created. 675cad31331Smrg * 676cad31331Smrg * \return 677cad31331Smrg * Zero on success or an \c errno value on failure. 678cad31331Smrg */ 679cad31331Smrgstatic int 680cad31331Smrgpci_device_solx_devfs_map_range(struct pci_device *dev, 681cad31331Smrg struct pci_device_mapping *map) 682cad31331Smrg{ 683cad31331Smrg const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 684cad31331Smrg ? (PROT_READ | PROT_WRITE) : PROT_READ; 685cad31331Smrg int err = 0; 686cad31331Smrg 68786ea1d58Smrg const char *map_dev; 688cad31331Smrg int map_fd; 689cad31331Smrg 69086ea1d58Smrg#ifdef __sparc 69186ea1d58Smrg char map_dev_buf[128]; 692cad31331Smrg 69386ea1d58Smrg if (MAPPING_DEV_PATH(dev)) { 69486ea1d58Smrg snprintf(map_dev_buf, sizeof (map_dev_buf), "%s%s", 69586ea1d58Smrg "/devices", MAPPING_DEV_PATH(dev)); 69686ea1d58Smrg map_dev = map_dev_buf; 697cad31331Smrg } 69886ea1d58Smrg else 69986ea1d58Smrg map_dev = "/dev/fb0"; 700cad31331Smrg 70186ea1d58Smrg map_fd = -1; 702cad31331Smrg#else 703cad31331Smrg /* 70486ea1d58Smrg * Still uses xsvc to do the user space mapping on x86/x64, 70586ea1d58Smrg * caches open fd across multiple calls. 706cad31331Smrg */ 70786ea1d58Smrg map_dev = "/dev/xsvc"; 70886ea1d58Smrg map_fd = xsvc_fd; 70986ea1d58Smrg#endif 71086ea1d58Smrg 71186ea1d58Smrg if (map_fd < 0) { 71286ea1d58Smrg if ((map_fd = open(map_dev, O_RDWR | O_CLOEXEC)) < 0) { 713cad31331Smrg err = errno; 71486ea1d58Smrg (void) fprintf(stderr, "can not open %s: %s\n", map_dev, 715cad31331Smrg strerror(errno)); 716cad31331Smrg return err; 717cad31331Smrg } 7186a94483fSmrg#ifndef __sparc 7196a94483fSmrg xsvc_fd = map_fd; 7206a94483fSmrg#endif 721cad31331Smrg } 722cad31331Smrg 72386ea1d58Smrg map->memory = mmap(NULL, map->size, prot, MAP_SHARED, map_fd, map->base); 724cad31331Smrg if (map->memory == MAP_FAILED) { 725cad31331Smrg err = errno; 726cad31331Smrg 727cad31331Smrg (void) fprintf(stderr, "map rom region =%llx failed: %s\n", 72886ea1d58Smrg (unsigned long long) map->base, strerror(errno)); 729cad31331Smrg } 730cad31331Smrg 731cad31331Smrg#ifdef __sparc 732cad31331Smrg close (map_fd); 733cad31331Smrg#endif 734cad31331Smrg 735cad31331Smrg return err; 736cad31331Smrg} 737cad31331Smrg 7384f5e7dd7Smrg/* 7394f5e7dd7Smrg * Solaris version: read the VGA ROM data 7404f5e7dd7Smrg */ 7414f5e7dd7Smrgstatic int 7424f5e7dd7Smrgpci_device_solx_devfs_read_rom( struct pci_device * dev, void * buffer ) 7434f5e7dd7Smrg{ 7444f5e7dd7Smrg int err; 7454f5e7dd7Smrg struct pci_device_mapping prom = { 7464f5e7dd7Smrg .base = 0xC0000, 74786ea1d58Smrg .size = 0x10000, 7484f5e7dd7Smrg .flags = 0 7494f5e7dd7Smrg }; 75086ea1d58Smrg struct pci_device_private *priv = 75186ea1d58Smrg (struct pci_device_private *) dev; 75286ea1d58Smrg 75386ea1d58Smrg if (priv->rom_base) { 75486ea1d58Smrg prom.base = priv->rom_base; 75586ea1d58Smrg prom.size = dev->rom_size; 75686ea1d58Smrg } 7574f5e7dd7Smrg 7584f5e7dd7Smrg err = pci_device_solx_devfs_map_range(dev, &prom); 7594f5e7dd7Smrg if (err == 0) { 7604f5e7dd7Smrg (void) bcopy(prom.memory, buffer, dev->rom_size); 7614f5e7dd7Smrg 76286ea1d58Smrg if (munmap(prom.memory, prom.size) == -1) { 7634f5e7dd7Smrg err = errno; 7644f5e7dd7Smrg } 7654f5e7dd7Smrg } 7664f5e7dd7Smrg return err; 7674f5e7dd7Smrg} 7684f5e7dd7Smrg 7694f5e7dd7Smrg/* 7704f5e7dd7Smrg * solaris version: Read the configurations space of the devices 7714f5e7dd7Smrg */ 7724f5e7dd7Smrgstatic int 7734f5e7dd7Smrgpci_device_solx_devfs_read( struct pci_device * dev, void * data, 7744f5e7dd7Smrg pciaddr_t offset, pciaddr_t size, 7754f5e7dd7Smrg pciaddr_t * bytes_read ) 7764f5e7dd7Smrg{ 7774f5e7dd7Smrg pcitool_reg_t cfg_prg; 7784f5e7dd7Smrg int err = 0; 77986ea1d58Smrg unsigned int i = 0; 780cad31331Smrg nexus_t *nexus; 78149310723Smrg int fd; 782cad31331Smrg 783cad31331Smrg nexus = find_nexus_for_bus(dev->domain, dev->bus); 7844f5e7dd7Smrg 7854f5e7dd7Smrg *bytes_read = 0; 7864f5e7dd7Smrg 7874f5e7dd7Smrg if ( nexus == NULL ) { 7884f5e7dd7Smrg return ENODEV; 7894f5e7dd7Smrg } 7904f5e7dd7Smrg 7914f5e7dd7Smrg cfg_prg.offset = offset; 7924f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN; 7934f5e7dd7Smrg cfg_prg.bus_no = dev->bus; 7944f5e7dd7Smrg cfg_prg.dev_no = dev->dev; 7954f5e7dd7Smrg cfg_prg.func_no = dev->func; 7964f5e7dd7Smrg cfg_prg.barnum = 0; 7974f5e7dd7Smrg cfg_prg.user_version = PCITOOL_USER_VERSION; 7984f5e7dd7Smrg 79949310723Smrg if ((fd = open(nexus->path, O_RDWR | O_CLOEXEC)) < 0) 80049310723Smrg return ENOENT; 80149310723Smrg 8024f5e7dd7Smrg for (i = 0; i < size; i += PCITOOL_ACC_ATTR_SIZE(PCITOOL_ACC_ATTR_SIZE_1)) 8034f5e7dd7Smrg { 8044f5e7dd7Smrg cfg_prg.offset = offset + i; 8054f5e7dd7Smrg 80649310723Smrg if ((err = ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) { 8074f5e7dd7Smrg fprintf(stderr, "read bdf<%s,%x,%x,%x,%llx> config space failure\n", 8084f5e7dd7Smrg nexus->path, 8094f5e7dd7Smrg cfg_prg.bus_no, 8104f5e7dd7Smrg cfg_prg.dev_no, 8114f5e7dd7Smrg cfg_prg.func_no, 81286ea1d58Smrg (unsigned long long) cfg_prg.offset); 8134f5e7dd7Smrg fprintf(stderr, "Failure cause = %x\n", err); 8144f5e7dd7Smrg break; 8154f5e7dd7Smrg } 8164f5e7dd7Smrg 8174f5e7dd7Smrg ((uint8_t *)data)[i] = (uint8_t)cfg_prg.data; 8184f5e7dd7Smrg /* 8194f5e7dd7Smrg * DWORDS Offset or bytes Offset ?? 8204f5e7dd7Smrg */ 8214f5e7dd7Smrg } 8224f5e7dd7Smrg *bytes_read = i; 8234f5e7dd7Smrg 82449310723Smrg close(fd); 82549310723Smrg 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; 84149310723Smrg int fd; 842cad31331Smrg 843cad31331Smrg nexus = find_nexus_for_bus(dev->domain, dev->bus); 8444f5e7dd7Smrg 8454f5e7dd7Smrg if ( bytes_written != NULL ) { 8464f5e7dd7Smrg *bytes_written = 0; 8474f5e7dd7Smrg } 8484f5e7dd7Smrg 8494f5e7dd7Smrg if ( nexus == NULL ) { 8504f5e7dd7Smrg return ENODEV; 8514f5e7dd7Smrg } 8524f5e7dd7Smrg 8534f5e7dd7Smrg cfg_prg.offset = offset; 8544f5e7dd7Smrg switch (size) { 8554f5e7dd7Smrg case 1: 8564f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN; 857cad31331Smrg cfg_prg.data = *((const uint8_t *)data); 8584f5e7dd7Smrg break; 8594f5e7dd7Smrg case 2: 8604f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + NATIVE_ENDIAN; 861cad31331Smrg cfg_prg.data = *((const uint16_t *)data); 8624f5e7dd7Smrg break; 8634f5e7dd7Smrg case 4: 8644f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN; 865cad31331Smrg cfg_prg.data = *((const uint32_t *)data); 8664f5e7dd7Smrg break; 8674f5e7dd7Smrg case 8: 8684f5e7dd7Smrg cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 + NATIVE_ENDIAN; 869cad31331Smrg cfg_prg.data = *((const uint64_t *)data); 8704f5e7dd7Smrg break; 8714f5e7dd7Smrg default: 8724f5e7dd7Smrg return EINVAL; 8734f5e7dd7Smrg } 8744f5e7dd7Smrg cfg_prg.bus_no = dev->bus; 8754f5e7dd7Smrg cfg_prg.dev_no = dev->dev; 8764f5e7dd7Smrg cfg_prg.func_no = dev->func; 8774f5e7dd7Smrg cfg_prg.barnum = 0; 8784f5e7dd7Smrg cfg_prg.user_version = PCITOOL_USER_VERSION; 8794f5e7dd7Smrg 8804f5e7dd7Smrg /* 8814f5e7dd7Smrg * Check if this device is bridge device. 8824f5e7dd7Smrg * If it is, it is also a nexus node??? 8834f5e7dd7Smrg * It seems that there is no explicit 8844f5e7dd7Smrg * PCI nexus device for X86, so not applicable 8854f5e7dd7Smrg * from pcitool_bus_reg_ops in pci_tools.c 8864f5e7dd7Smrg */ 8874f5e7dd7Smrg cmd = PCITOOL_DEVICE_SET_REG; 8884f5e7dd7Smrg 88949310723Smrg if ((fd = open(nexus->path, O_RDWR | O_CLOEXEC)) < 0) 89049310723Smrg return ENOENT; 89149310723Smrg 89249310723Smrg if ((err = ioctl(fd, cmd, &cfg_prg)) != 0) { 89349310723Smrg close(fd); 8944f5e7dd7Smrg return (err); 8954f5e7dd7Smrg } 8964f5e7dd7Smrg *bytes_written = size; 8974f5e7dd7Smrg 89849310723Smrg close(fd); 89949310723Smrg 9004f5e7dd7Smrg return (err); 9014f5e7dd7Smrg} 9024f5e7dd7Smrg 90386ea1d58Smrgstatic int pci_device_solx_devfs_boot_vga(struct pci_device *dev) 90486ea1d58Smrg{ 90586ea1d58Smrg struct pci_device_private *priv = 90686ea1d58Smrg (struct pci_device_private *) dev; 90786ea1d58Smrg 90886ea1d58Smrg return (priv->is_primary); 90986ea1d58Smrg 91086ea1d58Smrg} 91186ea1d58Smrg 91286ea1d58Smrgstatic struct pci_io_handle * 91386ea1d58Smrgpci_device_solx_devfs_open_legacy_io(struct pci_io_handle *ret, 91486ea1d58Smrg struct pci_device *dev, 91586ea1d58Smrg pciaddr_t base, pciaddr_t size) 91686ea1d58Smrg{ 91786ea1d58Smrg#ifdef __x86 91886ea1d58Smrg if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) == 0) { 91986ea1d58Smrg ret->base = base; 92086ea1d58Smrg ret->size = size; 9216a94483fSmrg ret->is_legacy = 1; 92286ea1d58Smrg return ret; 92386ea1d58Smrg } 92486ea1d58Smrg#endif 92586ea1d58Smrg return NULL; 92686ea1d58Smrg} 92786ea1d58Smrg 92886ea1d58Smrgstatic uint32_t 92986ea1d58Smrgpci_device_solx_devfs_read32(struct pci_io_handle *handle, uint32_t reg) 93086ea1d58Smrg{ 93186ea1d58Smrg#ifdef __x86 93286ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 93386ea1d58Smrg uint32_t ret; 93486ea1d58Smrg __asm__ __volatile__("inl %1,%0":"=a"(ret):"d"(port)); 93586ea1d58Smrg return ret; 93686ea1d58Smrg#else 93786ea1d58Smrg return *(uint32_t *)((uintptr_t)handle->memory + reg); 93886ea1d58Smrg#endif 93986ea1d58Smrg} 94086ea1d58Smrg 94186ea1d58Smrgstatic uint16_t 94286ea1d58Smrgpci_device_solx_devfs_read16(struct pci_io_handle *handle, uint32_t reg) 94386ea1d58Smrg{ 94486ea1d58Smrg#ifdef __x86 94586ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 94686ea1d58Smrg uint16_t ret; 94786ea1d58Smrg __asm__ __volatile__("inw %1,%0":"=a"(ret):"d"(port)); 94886ea1d58Smrg return ret; 94986ea1d58Smrg#else 95086ea1d58Smrg return *(uint16_t *)((uintptr_t)handle->memory + reg); 95186ea1d58Smrg#endif 95286ea1d58Smrg} 95386ea1d58Smrg 95486ea1d58Smrgstatic uint8_t 95586ea1d58Smrgpci_device_solx_devfs_read8(struct pci_io_handle *handle, uint32_t reg) 95686ea1d58Smrg{ 95786ea1d58Smrg#ifdef __x86 95886ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 95986ea1d58Smrg uint8_t ret; 96086ea1d58Smrg __asm__ __volatile__("inb %1,%0":"=a"(ret):"d"(port)); 96186ea1d58Smrg return ret; 96286ea1d58Smrg#else 96386ea1d58Smrg return *(uint8_t *)((uintptr_t)handle->memory + reg); 96486ea1d58Smrg#endif 96586ea1d58Smrg} 96686ea1d58Smrg 96786ea1d58Smrgstatic void 96886ea1d58Smrgpci_device_solx_devfs_write32(struct pci_io_handle *handle, uint32_t reg, 96986ea1d58Smrg uint32_t data) 97086ea1d58Smrg{ 97186ea1d58Smrg#ifdef __x86 97286ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 97386ea1d58Smrg __asm__ __volatile__("outl %0,%1"::"a"(data), "d"(port)); 97486ea1d58Smrg#else 97586ea1d58Smrg *(uint16_t *)((uintptr_t)handle->memory + reg) = data; 97686ea1d58Smrg#endif 97786ea1d58Smrg} 97886ea1d58Smrg 97986ea1d58Smrgstatic void 98086ea1d58Smrgpci_device_solx_devfs_write16(struct pci_io_handle *handle, uint32_t reg, 98186ea1d58Smrg uint16_t data) 98286ea1d58Smrg{ 98386ea1d58Smrg#ifdef __x86 98486ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 98586ea1d58Smrg __asm__ __volatile__("outw %0,%1"::"a"(data), "d"(port)); 98686ea1d58Smrg#else 98786ea1d58Smrg *(uint8_t *)((uintptr_t)handle->memory + reg) = data; 98886ea1d58Smrg#endif 98986ea1d58Smrg} 99086ea1d58Smrg 99186ea1d58Smrgstatic void 99286ea1d58Smrgpci_device_solx_devfs_write8(struct pci_io_handle *handle, uint32_t reg, 99386ea1d58Smrg uint8_t data) 99486ea1d58Smrg{ 99586ea1d58Smrg#ifdef __x86 99686ea1d58Smrg uint16_t port = (uint16_t) (handle->base + reg); 99786ea1d58Smrg __asm__ __volatile__("outb %0,%1"::"a"(data), "d"(port)); 99886ea1d58Smrg#else 99986ea1d58Smrg *(uint32_t *)((uintptr_t)handle->memory + reg) = data; 100086ea1d58Smrg#endif 100186ea1d58Smrg} 100286ea1d58Smrg 100386ea1d58Smrgstatic int 100486ea1d58Smrgpci_device_solx_devfs_map_legacy(struct pci_device *dev, pciaddr_t base, 100586ea1d58Smrg pciaddr_t size, unsigned map_flags, 100686ea1d58Smrg void **addr) 100786ea1d58Smrg{ 100886ea1d58Smrg int err; 100986ea1d58Smrg struct pci_device_mapping map = { 101086ea1d58Smrg .base = base, 101186ea1d58Smrg .size = size, 101286ea1d58Smrg .flags = map_flags, 101386ea1d58Smrg }; 10144f5e7dd7Smrg 101586ea1d58Smrg err = pci_device_solx_devfs_map_range(dev, &map); 101686ea1d58Smrg if (err == 0) 101786ea1d58Smrg *addr = map.memory; 101886ea1d58Smrg return err; 101986ea1d58Smrg} 102086ea1d58Smrg 102186ea1d58Smrgstatic int 102286ea1d58Smrgpci_device_solx_devfs_unmap_legacy(struct pci_device *dev, 102386ea1d58Smrg void *addr, pciaddr_t size) 102486ea1d58Smrg{ 102586ea1d58Smrg struct pci_device_mapping map = { 102686ea1d58Smrg .memory = addr, 102786ea1d58Smrg .size = size, 102886ea1d58Smrg }; 102986ea1d58Smrg 103086ea1d58Smrg return pci_device_generic_unmap_range(dev, &map); 103186ea1d58Smrg} 1032cad31331Smrg 1033cad31331Smrgstatic const struct pci_system_methods solx_devfs_methods = { 1034cad31331Smrg .destroy = pci_system_solx_devfs_destroy, 103586ea1d58Smrg#ifdef __sparc 103686ea1d58Smrg .destroy_device = pci_system_solx_devfs_destroy_device, 103786ea1d58Smrg#else 1038cad31331Smrg .destroy_device = NULL, 103986ea1d58Smrg#endif 1040cad31331Smrg .read_rom = pci_device_solx_devfs_read_rom, 1041cad31331Smrg .probe = pci_device_solx_devfs_probe, 1042cad31331Smrg .map_range = pci_device_solx_devfs_map_range, 1043cad31331Smrg .unmap_range = pci_device_generic_unmap_range, 1044cad31331Smrg 1045cad31331Smrg .read = pci_device_solx_devfs_read, 1046cad31331Smrg .write = pci_device_solx_devfs_write, 1047cad31331Smrg 104886ea1d58Smrg .fill_capabilities = pci_fill_capabilities_generic, 104986ea1d58Smrg .boot_vga = pci_device_solx_devfs_boot_vga, 105086ea1d58Smrg 105186ea1d58Smrg .open_legacy_io = pci_device_solx_devfs_open_legacy_io, 105286ea1d58Smrg .read32 = pci_device_solx_devfs_read32, 105386ea1d58Smrg .read16 = pci_device_solx_devfs_read16, 105486ea1d58Smrg .read8 = pci_device_solx_devfs_read8, 105586ea1d58Smrg .write32 = pci_device_solx_devfs_write32, 105686ea1d58Smrg .write16 = pci_device_solx_devfs_write16, 105786ea1d58Smrg .write8 = pci_device_solx_devfs_write8, 105886ea1d58Smrg .map_legacy = pci_device_solx_devfs_map_legacy, 105986ea1d58Smrg .unmap_legacy = pci_device_solx_devfs_unmap_legacy, 1060cad31331Smrg}; 1061cad31331Smrg 1062cad31331Smrg/* 1063cad31331Smrg * Attempt to access PCI subsystem using Solaris's devfs interface. 1064cad31331Smrg * Solaris version 10654f5e7dd7Smrg */ 1066cad31331Smrg_pci_hidden int 1067cad31331Smrgpci_system_solx_devfs_create( void ) 10684f5e7dd7Smrg{ 10694f5e7dd7Smrg int err = 0; 1070cad31331Smrg di_node_t di_node; 1071cad31331Smrg probe_info_t pinfo; 1072cad31331Smrg struct pci_device_private *devices; 10734f5e7dd7Smrg 1074cad31331Smrg if (nexus_list != NULL) { 1075cad31331Smrg return 0; 10764f5e7dd7Smrg } 10774f5e7dd7Smrg 107849310723Smrg if ((di_node = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 10794f5e7dd7Smrg err = errno; 1080cad31331Smrg (void) fprintf(stderr, "di_init() failed: %s\n", 1081cad31331Smrg strerror(errno)); 1082cad31331Smrg return (err); 1083cad31331Smrg } 10844f5e7dd7Smrg 1085cad31331Smrg if ((devices = calloc(INITIAL_NUM_DEVICES, 1086cad31331Smrg sizeof (struct pci_device_private))) == NULL) { 1087cad31331Smrg err = errno; 1088cad31331Smrg di_fini(di_node); 1089cad31331Smrg return (err); 10904f5e7dd7Smrg } 10914f5e7dd7Smrg 1092cad31331Smrg#ifdef __sparc 1093cad31331Smrg if ((di_phdl = di_prom_init()) == DI_PROM_HANDLE_NIL) 1094cad31331Smrg (void) fprintf(stderr, "di_prom_init failed: %s\n", strerror(errno)); 1095cad31331Smrg#endif 1096cad31331Smrg 1097cad31331Smrg pinfo.num_allocated_elems = INITIAL_NUM_DEVICES; 1098cad31331Smrg pinfo.num_devices = 0; 1099cad31331Smrg pinfo.devices = devices; 110086ea1d58Smrg#ifdef __sparc 110186ea1d58Smrg nexus_count = 0; 110286ea1d58Smrg#endif 1103cad31331Smrg (void) di_walk_minor(di_node, DDI_NT_REGACC, 0, &pinfo, probe_nexus_node); 1104cad31331Smrg 1105cad31331Smrg di_fini(di_node); 1106cad31331Smrg 1107cad31331Smrg if ((pci_sys = calloc(1, sizeof (struct pci_system))) == NULL) { 1108cad31331Smrg err = errno; 1109cad31331Smrg free(devices); 1110cad31331Smrg return (err); 1111cad31331Smrg } 1112cad31331Smrg 1113cad31331Smrg pci_sys->methods = &solx_devfs_methods; 1114cad31331Smrg pci_sys->devices = pinfo.devices; 1115cad31331Smrg pci_sys->num_devices = pinfo.num_devices; 1116cad31331Smrg 1117cad31331Smrg return (err); 11184f5e7dd7Smrg} 1119